[evolution-data-server/eclient] EBook/CalClient uses EBook/CalClientView for views



commit d0b3dd1da6c391de1c79e915cc8bf448c3482b3b
Author: Milan Crha <mcrha redhat com>
Date:   Wed May 11 14:19:36 2011 +0200

    EBook/CalClient uses EBook/CalClientView for views

 addressbook/libebook/Makefile.am                   |    3 +
 addressbook/libebook/e-book-client-view-private.h  |   34 ++
 addressbook/libebook/e-book-client-view.c          |  379 ++++++++++++++
 addressbook/libebook/e-book-client-view.h          |   71 +++
 addressbook/libebook/e-book-client.c               |  126 ++----
 addressbook/libebook/e-book-client.h               |    7 +-
 addressbook/libebook/e-book-view-private.h         |    4 +-
 addressbook/libebook/e-book-view.c                 |   90 +---
 addressbook/libebook/e-book-view.h                 |   12 +-
 addressbook/libebook/e-book.c                      |    4 +-
 addressbook/libedata-book/e-data-book-view.c       |  112 ++++-
 addressbook/libedata-book/e-data-book-view.h       |    2 +
 addressbook/libegdbus/e-gdbus-book-view.c          |   90 +++-
 addressbook/libegdbus/e-gdbus-book-view.h          |   30 +-
 calendar/libecal/Makefile.am                       |    5 +-
 calendar/libecal/e-cal-client-view-private.h       |   35 ++
 calendar/libecal/e-cal-client-view.c               |  523 ++++++++++++++++++++
 calendar/libecal/e-cal-client-view.h               |   68 +++
 calendar/libecal/e-cal-client.c                    |  128 ++----
 calendar/libecal/e-cal-client.h                    |    6 +-
 calendar/libecal/e-cal-view-private.h              |    6 +-
 calendar/libecal/e-cal-view.c                      |  106 +----
 calendar/libecal/e-cal-view.h                      |   13 +-
 calendar/libecal/e-cal.c                           |    2 +-
 calendar/libedata-cal/e-cal-backend.c              |    5 +-
 calendar/libedata-cal/e-data-cal-view.c            |  110 ++++-
 calendar/libedata-cal/e-data-cal-view.h            |    1 +
 calendar/libegdbus/e-gdbus-cal-view.c              |   91 +++-
 calendar/libegdbus/e-gdbus-cal-view.h              |   27 +-
 libedataserver/e-client.c                          |   77 +++
 libedataserver/e-client.h                          |    7 +
 po/POTFILES.in                                     |    2 +
 tests/libebook/client/Makefile.am                  |    6 +-
 ...ient-get-book-view.c => test-client-get-view.c} |   44 +-
 tests/libebook/client/test-client-stress-views.c   |   34 +-
 tests/libecal/client/test-client-get-view.c        |   28 +-
 tests/libecal/client/test-client-stress-views.c    |   30 +-
 37 files changed, 1797 insertions(+), 521 deletions(-)
---
diff --git a/addressbook/libebook/Makefile.am b/addressbook/libebook/Makefile.am
index 682b37a..ea58210 100644
--- a/addressbook/libebook/Makefile.am
+++ b/addressbook/libebook/Makefile.am
@@ -22,6 +22,8 @@ libebook_1_2_la_SOURCES =				\
 	$(MARSHAL_GENERATED)				\
 	e-address-western.c				\
 	e-book-client.c					\
+	e-book-client-view.c				\
+	e-book-client-view-private.h			\
 	e-book-query.c					\
 	e-book-view-private.h				\
 	e-book-view.c					\
@@ -48,6 +50,7 @@ libebookincludedir = $(privincludedir)/libebook
 libebookinclude_HEADERS =				\
 	e-address-western.h				\
 	e-book-client.h					\
+	e-book-client-view.h				\
 	e-book-query.h					\
 	e-book-view.h					\
 	e-book-types.h					\
diff --git a/addressbook/libebook/e-book-client-view-private.h b/addressbook/libebook/e-book-client-view-private.h
new file mode 100644
index 0000000..26d8a7f
--- /dev/null
+++ b/addressbook/libebook/e-book-client-view-private.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Ross Burton <ross linux intel com>
+ */
+
+#ifndef E_BOOK_CLIENT_VIEW_PRIVATE_H
+#define E_BOOK_CLIENT_VIEW_PRIVATE_H
+
+#include "e-book-client.h"
+#include "e-book-view.h"
+
+struct _EGdbusBookView;
+
+EBookClientView *_e_book_client_view_new (EBookClient *book_client, struct _EGdbusBookView *gdbus_bookview);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CLIENT_VIEW_PRIVATE_H */
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
new file mode 100644
index 0000000..86ce7d7
--- /dev/null
+++ b/addressbook/libebook/e-book-client-view.c
@@ -0,0 +1,379 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Ross Burton <ross linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-book-client.h"
+#include "e-book-client-view.h"
+#include "e-book-client-view-private.h"
+#include "e-book-marshal.h"
+#include "libedata-book/e-data-book-types.h"
+#include "e-gdbus-book-view.h"
+
+G_DEFINE_TYPE (EBookClientView, e_book_client_view, G_TYPE_OBJECT);
+
+struct _EBookClientViewPrivate {
+	GDBusProxy *gdbus_bookview;
+	EBookClient *client;
+	gboolean running;
+};
+
+enum {
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	PROGRESS,
+	COMPLETE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+objects_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *contacts = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = vcards; *p; p++) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	}
+
+	contacts = g_slist_reverse (contacts);
+
+	g_signal_emit (view, signals[OBJECTS_ADDED], 0, contacts);
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+}
+
+static void
+objects_modified_cb (EGdbusBookView *object, const gchar * const *vcards, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *contacts = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = vcards; *p; p++) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	}
+	contacts = g_slist_reverse (contacts);
+
+	g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, contacts);
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+}
+
+static void
+objects_removed_cb (EGdbusBookView *object, const gchar * const *ids, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *list = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = ids; *p; p++) {
+		list = g_slist_prepend (list, (gchar *) *p);
+	}
+	list = g_slist_reverse (list);
+
+	g_signal_emit (view, signals[OBJECTS_REMOVED], 0, list);
+
+	/* No need to free the values, our caller will */
+	g_slist_free (list);
+}
+
+static void
+progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookClientView *view)
+{
+	if (!view->priv->running)
+		return;
+
+	g_signal_emit (view, signals[PROGRESS], 0, percent, message);
+}
+
+static void
+complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookClientView *view)
+{
+	GError *error;
+
+	if (!view->priv->running)
+		return;
+
+	error = e_gdbus_book_view_decode_error (in_error_strv);
+
+	g_signal_emit (view, signals[COMPLETE], 0, error);
+
+	if (error)
+		g_error_free (error);
+}
+
+/*
+ * _e_book_client_view_new:
+ * @book_client: an #EBookClient
+ * @gdbus_bookview: The #EGdbusBookView to get signals from
+ *
+ * Creates a new #EBookClientView based on #EBookClient and listening to @gdbus_bookview.
+ * This is a private function, applications should call e_book_client_get_view() or
+ * e_book_client_get_view_sync().
+ *
+ * Returns: A new #EBookClientView.
+ **/
+EBookClientView *
+_e_book_client_view_new (EBookClient *book_client, EGdbusBookView *gdbus_bookview)
+{
+	EBookClientView *view;
+	EBookClientViewPrivate *priv;
+
+	view = g_object_new (E_TYPE_BOOK_CLIENT_VIEW, NULL);
+	priv = view->priv;
+
+	priv->client = g_object_ref (book_client);
+
+	/* Take ownership of the gdbus_bookview object */
+	priv->gdbus_bookview = g_object_ref (G_DBUS_PROXY (gdbus_bookview));
+
+	g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
+	g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
+
+	return view;
+}
+
+/**
+ * e_book_client_view_get_client:
+ * @view: an #EBookClientView
+ *
+ * Returns the #EBookClient that this book view is monitoring.
+ *
+ * Returns: an #EBookClient.
+ **/
+EBookClient *
+e_book_client_view_get_client (EBookClientView *view)
+{
+	g_return_val_if_fail (E_IS_BOOK_CLIENT_VIEW (view), NULL);
+
+	return view->priv->client;
+}
+
+/**
+ * e_book_client_view_start:
+ * @error: A #GError
+ * @view: an #EBookClientView
+ *
+ * Tells @view to start processing events.
+ */
+void
+e_book_client_view_start (EBookClientView *view, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+
+		if (e_gdbus_book_view_call_start_sync (priv->gdbus_bookview, NULL, &local_error))
+			priv->running = TRUE;
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot start view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_book_client_view_stop:
+ * @view: an #EBookClientView
+ * @error: A #GError
+ *
+ * Tells @view to stop processing events.
+ **/
+void
+e_book_client_view_stop (EBookClientView *view, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+	priv->running = FALSE;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+
+		e_gdbus_book_view_call_stop_sync (priv->gdbus_bookview, NULL, &local_error);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot stop view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_book_client_view_set_restriction:
+ * @view: An #EBookClientView object
+ * @only_fields: List of field names to restrict result on
+ * @error: A #GError
+ *
+ * Client can instruct server to which fields it is interested in only, thus
+ * the server can return less data over the wire. The server can still return
+ * complete objects, this is just a hint to it that the listef fields will
+ * be used only. The UID field is returned always. Initial views has no restriction,
+ * and using %NULL for @only_fields will unset any previous changes.
+ **/
+void
+e_book_client_view_set_restriction (EBookClientView *view, const GSList *only_fields, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+		gchar **strv;
+
+		strv = e_client_util_slist_to_strv (only_fields);
+		e_gdbus_book_view_call_set_restriction_sync (priv->gdbus_bookview, (const gchar * const *) strv, NULL, &local_error);
+		g_strfreev (strv);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot set restriction, D-Bus proxy gone"));
+	}
+}
+
+static void
+e_book_client_view_init (EBookClientView *view)
+{
+	view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewPrivate);
+	view->priv->gdbus_bookview = NULL;
+
+	view->priv->client = NULL;
+	view->priv->running = FALSE;
+}
+
+static void
+book_client_view_dispose (GObject *object)
+{
+	EBookClientView *view = E_BOOK_CLIENT_VIEW (object);
+
+	if (view->priv->gdbus_bookview) {
+		GError *error = NULL;
+
+		g_signal_handlers_disconnect_matched (view->priv->gdbus_bookview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+		e_gdbus_book_view_call_dispose_sync (G_DBUS_PROXY (view->priv->gdbus_bookview), NULL, &error);
+		g_object_unref (view->priv->gdbus_bookview);
+		view->priv->gdbus_bookview = NULL;
+
+		if (error) {
+			g_warning ("Failed to dispose book view: %s", error->message);
+			g_error_free (error);
+		}
+	}
+
+	if (view->priv->client) {
+		g_object_unref (view->priv->client);
+		view->priv->client = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_book_client_view_parent_class)->dispose (object);
+}
+
+static void
+e_book_client_view_class_init (EBookClientViewClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EBookClientViewPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->dispose = book_client_view_dispose;
+
+	signals [OBJECTS_ADDED] =
+		g_signal_new ("objects-added",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [OBJECTS_MODIFIED] =
+		g_signal_new ("objects-modified",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_modified),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [OBJECTS_REMOVED] =
+		g_signal_new ("objects-removed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [PROGRESS] =
+		g_signal_new ("progress",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, progress),
+			      NULL, NULL,
+			      e_gdbus_marshallers_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+	signals [COMPLETE] =
+		g_signal_new ("complete",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, complete),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_ERROR);
+}
diff --git a/addressbook/libebook/e-book-client-view.h b/addressbook/libebook/e-book-client-view.h
new file mode 100644
index 0000000..ef814c5
--- /dev/null
+++ b/addressbook/libebook/e-book-client-view.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_BOOK_CLIENT_VIEW_H
+#define E_BOOK_CLIENT_VIEW_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define E_TYPE_BOOK_CLIENT_VIEW           (e_book_client_view_get_type ())
+#define E_BOOK_CLIENT_VIEW(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_CLIENT_VIEW, EBookClientView))
+#define E_BOOK_CLIENT_VIEW_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewClass))
+#define E_IS_BOOK_CLIENT_VIEW(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_CLIENT_VIEW))
+#define E_IS_BOOK_CLIENT_VIEW_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_CLIENT_VIEW))
+#define E_BOOK_CLIENT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookClientView        EBookClientView;
+typedef struct _EBookClientViewClass   EBookClientViewClass;
+typedef struct _EBookClientViewPrivate EBookClientViewPrivate;
+
+struct _EBookClient;  /* Forward reference */
+
+struct _EBookClientView {
+	GObject     parent;
+	/*< private >*/
+	EBookClientViewPrivate *priv;
+};
+
+struct _EBookClientViewClass {
+	GObjectClass parent;
+
+	/*
+	 * Signals.
+	 */
+	void (* objects_added)		(EBookClientView *view, const GSList *objects);
+	void (* objects_modified)	(EBookClientView *view, const GSList *objects);
+	void (* objects_removed)	(EBookClientView *view, const GSList *uids);
+
+	void (* progress)		(EBookClientView *view, const gchar *message);
+	void (* complete)		(EBookClientView *view, const GError *error);
+};
+
+GType			e_book_client_view_get_type		(void);
+struct _EBookClient *	e_book_client_view_get_client		(EBookClientView *view);
+gboolean		e_book_client_view_is_running		(EBookClientView *view);
+void			e_book_client_view_set_restriction	(EBookClientView *view, const GSList *only_fields, GError **error);
+void			e_book_client_view_start		(EBookClientView *view, GError **error);
+void			e_book_client_view_stop			(EBookClientView *view, GError **error);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CLIENT_VIEW_H */
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index c79e37d..3fa86b8 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -33,7 +33,7 @@
 #include "e-book-client.h"
 #include "e-contact.h"
 #include "e-name-western.h"
-#include "e-book-view-private.h"
+#include "e-book-client-view-private.h"
 
 #include "e-gdbus-book.h"
 #include "e-gdbus-book-factory.h"
@@ -104,17 +104,16 @@ e_book_client_error_to_string (EBookClientError code)
 }
 
 /**
- * If the GError is a remote error, extract the EBookClientError embedded inside.
- * Otherwise return DBUS_ERROR.
+ * If the specified GError is a remote error, then create a new error
+ * representing the remote error.  If the error is anything else, then
+ * leave it alone.
  */
-static void
-get_client_error_from_gerror (GError *error, GError **client_error)
+static gboolean
+unwrap_dbus_error (GError *error, GError **client_error)
 {
 	#define err(a,b) "org.gnome.evolution.dataserver.AddressBook." a, b
-	static struct {
-		const gchar *name;
-		gint err_code;
-	} book_errors[] = {
+	static struct EClientErrorsList
+	book_errors[] = {
 		{ err ("Success",				-1) },
 		{ err ("ContactNotFound",			E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND) },
 		{ err ("ContactIDAlreadyExists",		E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS) },
@@ -142,79 +141,11 @@ get_client_error_from_gerror (GError *error, GError **client_error)
 	};
 	#undef err
 
-	g_return_if_fail (client_error != NULL);
-
-	if G_LIKELY (error == NULL)
-		return;
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
-		gchar *name;
-		gint i;
-
-		name = g_dbus_error_get_remote_error (error);
-
-		for (i = 0; i < G_N_ELEMENTS (book_errors); i++) {
-			if (g_ascii_strcasecmp (book_errors[i].name, name) == 0) {
-				g_free (name);
-				g_dbus_error_strip_remote_error (error);
-
-				*client_error = g_error_new_literal (E_BOOK_CLIENT_ERROR, book_errors[i].err_code, error->message);
-				return;
-			}
-		}
-
-		for (i = 0; i < G_N_ELEMENTS (cl_errors); i++) {
-			if (g_ascii_strcasecmp (cl_errors[i].name, name) == 0) {
-				g_free (name);
-				g_dbus_error_strip_remote_error (error);
-
-				*client_error = g_error_new_literal (E_CLIENT_ERROR, cl_errors[i].err_code, error->message);
-				return;
-			}
-		}
-
-		g_warning (G_STRLOC ": Unmatched error name %s", name);
-		g_free (name);
-
-		g_dbus_error_strip_remote_error (error);
-		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, error->message);
-	} else if (error->domain == E_BOOK_CLIENT_ERROR || error->domain == E_CLIENT_ERROR) {
-		*client_error = g_error_copy (error);
-	} else {
-		/* In this case the error was caused by DBus. Dump the message to the
-		   console as otherwise we have no idea what the problem is. */
-		g_debug ("DBus error: %s", error->message);
-		g_dbus_error_strip_remote_error (error);
-
-		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, error->message);
-	}
-}
-
-/**
- * If the specified GError is a remote error, then create a new error
- * representing the remote error.  If the error is anything else, then
- * leave it alone.
- */
-static gboolean
-unwrap_dbus_error (GError *error, GError **client_error)
-{
 	if (error == NULL)
 		return TRUE;
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
-		if (client_error)
-			get_client_error_from_gerror (error, client_error);
-
-		g_error_free (error);
-	} else {
-		if (client_error) {
-			if (error->domain == G_DBUS_ERROR)
-				g_dbus_error_strip_remote_error (error);
-			*client_error = error;
-		} else {
-			g_error_free (error);
-		}
-	}
+	if (!e_client_util_unwrap_dbus_error (error, client_error, book_errors, G_N_ELEMENTS (book_errors), E_BOOK_CLIENT_ERROR, TRUE))
+		e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
 
 	return FALSE;
 }
@@ -1820,7 +1751,7 @@ e_book_client_get_contacts_sync (EBookClient *client, const gchar *sexp, GSList
  * @callback: callback to call when a result is ready
  * @user_data: user data for the @callback
  *
- * Query @client with @sexp, creating an #EBookView.
+ * Query @client with @sexp, creating an #EBookClientView.
  * The call is finished by e_book_client_get_view_finish()
  * from the @callback.
  *
@@ -1844,9 +1775,9 @@ e_book_client_get_view (EBookClient *client, const gchar *sexp, GCancellable *ca
 }
 
 static gboolean
-complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookView **book_view, GError **error)
+complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookClientView **view, GError **error)
 {
-	g_return_val_if_fail (book_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	if (view_path && res && book_factory_proxy) {
 		GError *local_error = NULL;
@@ -1860,20 +1791,21 @@ complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookVie
 								&local_error);
 
 		if (gdbus_bookview) {
-			*book_view = _e_book_view_new (client, gdbus_bookview);
+			*view = _e_book_client_view_new (client, gdbus_bookview);
+			g_object_unref (gdbus_bookview);
 		} else {
-			*book_view = NULL;
+			*view = NULL;
 			res = FALSE;
 		}
 
 		if (local_error)
 			unwrap_dbus_error (local_error, error);
 	} else {
-		*book_view = NULL;
+		*view = NULL;
 		res = FALSE;
 	}
 
-	if (!*book_view && error && !*error)
+	if (!*view && error && !*error)
 		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
 
 	g_free (view_path);
@@ -1885,11 +1817,11 @@ complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookVie
  * e_book_client_get_view_finish:
  * @client: an #EBookClient
  * @result: a #GAsyncResult
- * @book_view: (out) an #EBookView
+ * @view: (out) an #EBookClientView
  * @error: (out): a #GError to set an error, if any
  *
  * Finishes previous call of e_book_client_get_view().
- * If successful, then the @book_view is set to newly allocated #EBookView,
+ * If successful, then the @view is set to newly allocated #EBookClientView,
  * which should be freed with g_object_unref().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -1897,28 +1829,28 @@ complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookVie
  * Since: 3.2
  **/
 gboolean
-e_book_client_get_view_finish (EBookClient *client, GAsyncResult *result, EBookView **book_view, GError **error)
+e_book_client_get_view_finish (EBookClient *client, GAsyncResult *result, EBookClientView **view, GError **error)
 {
 	gboolean res;
 	gchar *view_path = NULL;
 
-	g_return_val_if_fail (book_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_book_client_get_view);
 
-	return complete_get_view (client, res, view_path, book_view, error);
+	return complete_get_view (client, res, view_path, view, error);
 }
 
 /**
  * e_book_client_get_view_sync:
  * @client: an #EBookClient
  * @sexp: an S-expression representing the query
- * @book_view: (out) an #EBookView
+ * @view: (out) an #EBookClientView
  * @cancellable: a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
- * Query @client with @sexp, creating an #EBookView.
- * If successful, then the @book_view is set to newly allocated #EBookView,
+ * Query @client with @sexp, creating an #EBookClientView.
+ * If successful, then the @view is set to newly allocated #EBookClientView,
  * which should be freed with g_object_unref().
  *
  * Note: @sexp can be obtained through #EBookQuery, by converting it
@@ -1929,7 +1861,7 @@ e_book_client_get_view_finish (EBookClient *client, GAsyncResult *result, EBookV
  * Since: 3.2
  **/
 gboolean
-e_book_client_get_view_sync (EBookClient *client, const gchar *sexp, EBookView **book_view, GCancellable *cancellable, GError **error)
+e_book_client_get_view_sync (EBookClient *client, const gchar *sexp, EBookClientView **view, GCancellable *cancellable, GError **error)
 {
 	gboolean res;
 	gchar *gdbus_sexp = NULL;
@@ -1939,7 +1871,7 @@ e_book_client_get_view_sync (EBookClient *client, const gchar *sexp, EBookView *
 	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
 	g_return_val_if_fail (client->priv != NULL, FALSE);
 	g_return_val_if_fail (sexp != NULL, FALSE);
-	g_return_val_if_fail (book_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	if (!client->priv->gdbus_book) {
 		set_proxy_gone_error (error);
@@ -1950,7 +1882,7 @@ e_book_client_get_view_sync (EBookClient *client, const gchar *sexp, EBookView *
 
 	g_free (gdbus_sexp);
 
-	return complete_get_view (client, res, view_path, book_view, error);
+	return complete_get_view (client, res, view_path, view, error);
 }
 
 static GDBusProxy *
diff --git a/addressbook/libebook/e-book-client.h b/addressbook/libebook/e-book-client.h
index 17eb9e2..2bd74f5 100644
--- a/addressbook/libebook/e-book-client.h
+++ b/addressbook/libebook/e-book-client.h
@@ -27,7 +27,8 @@
 
 #include <libedataserver/e-client.h>
 #include <libedataserver/e-source-list.h>
-#include <libebook/e-book-view.h>
+#include <libebook/e-book-client-view.h>
+#include <libebook/e-contact.h>
 
 G_BEGIN_DECLS
 
@@ -122,8 +123,8 @@ gboolean	e_book_client_get_contacts_finish		(EBookClient *client, GAsyncResult *
 gboolean	e_book_client_get_contacts_sync			(EBookClient *client, const gchar *sexp, GSList **contacts, GCancellable *cancellable, GError **error);
 
 void		e_book_client_get_view				(EBookClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean	e_book_client_get_view_finish			(EBookClient *client, GAsyncResult *result, EBookView **book_view, GError **error);
-gboolean	e_book_client_get_view_sync			(EBookClient *client, const gchar *sexp, EBookView **book_view, GCancellable *cancellable, GError **error);
+gboolean	e_book_client_get_view_finish			(EBookClient *client, GAsyncResult *result, EBookClientView **view, GError **error);
+gboolean	e_book_client_get_view_sync			(EBookClient *client, const gchar *sexp, EBookClientView **view, GCancellable *cancellable, GError **error);
 
 G_END_DECLS
 
diff --git a/addressbook/libebook/e-book-view-private.h b/addressbook/libebook/e-book-view-private.h
index f0acdca..1b49f60 100644
--- a/addressbook/libebook/e-book-view-private.h
+++ b/addressbook/libebook/e-book-view-private.h
@@ -28,9 +28,7 @@
 
 struct _EGdbusBookView;
 
-EBookView *_e_book_view_new (EBookClient *book_client, struct _EGdbusBookView *gdbus_bookview);
-
-EBookView *_e_book_view_new_with_book (EBook *book, struct _EGdbusBookView *gdbus_bookview);
+EBookView *_e_book_view_new (EBook *book, struct _EGdbusBookView *gdbus_bookview);
 
 G_END_DECLS
 
diff --git a/addressbook/libebook/e-book-view.c b/addressbook/libebook/e-book-view.c
index 417cba1..dd88218 100644
--- a/addressbook/libebook/e-book-view.c
+++ b/addressbook/libebook/e-book-view.c
@@ -22,11 +22,7 @@
 
 #include <glib-object.h>
 
-#ifndef E_BOOK_DISABLE_DEPRECATED
 #include "e-book.h"
-#endif
-
-#include "e-book-client.h"
 #include "e-book-view.h"
 #include "e-book-view-private.h"
 #include "e-book-marshal.h"
@@ -37,10 +33,7 @@ G_DEFINE_TYPE (EBookView, e_book_view, G_TYPE_OBJECT);
 
 struct _EBookViewPrivate {
 	EGdbusBookView *gdbus_bookview;
-	#ifndef E_BOOK_DISABLE_DEPRECATED
 	EBook *book;
-	#endif
-	EBookClient *book_client;
 	gboolean running;
 };
 
@@ -80,7 +73,7 @@ objects_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView
 }
 
 static void
-objects_changed_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
+objects_modified_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
 {
 	const gchar * const *p;
 	GList *contacts = NULL;
@@ -129,14 +122,17 @@ progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookV
 }
 
 static void
-complete_cb (EGdbusBookView *object, /* EDataBookStatus */ guint status, const gchar *message, EBookView *book_view)
+complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookView *book_view)
 {
+	GError *error;
 	EBookViewStatus bv_status = E_BOOK_VIEW_ERROR_OTHER_ERROR;
 
 	if (!book_view->priv->running)
 		return;
 
-	switch (status) {
+	error = e_gdbus_book_view_decode_error (in_error_strv);
+
+	switch (error ? error->code : E_DATA_BOOK_STATUS_SUCCESS) {
 	case E_DATA_BOOK_STATUS_SUCCESS:
 		bv_status = E_BOOK_VIEW_STATUS_OK;
 		break;
@@ -159,47 +155,14 @@ complete_cb (EGdbusBookView *object, /* EDataBookStatus */ guint status, const g
 	#ifndef E_BOOK_DISABLE_DEPRECATED
 	g_signal_emit (book_view, signals[SEQUENCE_COMPLETE], 0, bv_status);
 	#endif
-	g_signal_emit (book_view, signals[VIEW_COMPLETE], 0, bv_status, message);
-}
+	g_signal_emit (book_view, signals[VIEW_COMPLETE], 0, bv_status, error ? error->message : "");
 
-/*
- * _e_book_view_new:
- * @book_client: an #EBookClient
- * @gdbus_bookview: The #EGdbusBookView to get signals from
- *
- * Creates a new #EBookView based on #EBookClient and listening to @gdbus_bookview.
- * This is a private function, applications should call #e_book_get_book_view or
- * #e_book_async_get_book_view.
- *
- * Returns: A new #EBookView.
- **/
-EBookView *
-_e_book_view_new (EBookClient *book_client, EGdbusBookView *gdbus_bookview)
-{
-	EBookView *view;
-	EBookViewPrivate *priv;
-
-	view = g_object_new (E_TYPE_BOOK_VIEW, NULL);
-	priv = view->priv;
-
-	priv->book_client = g_object_ref (book_client);
-
-	/* Take ownership of the gdbus_bookview object */
-	priv->gdbus_bookview = gdbus_bookview;
-
-	g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
-	g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "objects-changed", G_CALLBACK (objects_changed_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
-
-	return view;
+	if (error)
+		g_error_free (error);
 }
 
-#ifndef E_BOOK_DISABLE_DEPRECATED
 EBookView *
-_e_book_view_new_with_book (EBook *book, EGdbusBookView *gdbus_bookview)
+_e_book_view_new (EBook *book, EGdbusBookView *gdbus_bookview)
 {
 	EBookView *view;
 	EBookViewPrivate *priv;
@@ -214,7 +177,7 @@ _e_book_view_new_with_book (EBook *book, EGdbusBookView *gdbus_bookview)
 
 	g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
 	g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "objects-changed", G_CALLBACK (objects_changed_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
 	g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
 	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
 	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
@@ -231,8 +194,6 @@ _e_book_view_new_with_book (EBook *book, EGdbusBookView *gdbus_bookview)
  * Returns: an #EBook.
  *
  * Since: 2.22
- *
- * Deprecated: 3.2: Use #EBookClient and e_book_view_get_book_client() instead
  **/
 EBook *
 e_book_view_get_book (EBookView *book_view)
@@ -241,25 +202,6 @@ e_book_view_get_book (EBookView *book_view)
 
 	return book_view->priv->book;
 }
-#endif /* E_BOOK_DISABLE_DEPRECATED */
-
-/**
- * e_book_view_get_book_client:
- * @book_view: an #EBookView
- *
- * Returns the #EBookClient that this book view is monitoring.
- *
- * Returns: an #EBookClient.
- *
- * Since: 3.2
- **/
-EBookClient *
-e_book_view_get_book_client (EBookView *book_view)
-{
-	g_return_val_if_fail (E_IS_BOOK_VIEW (book_view), NULL);
-
-	return book_view->priv->book_client;
-}
 
 /**
  * e_book_view_start:
@@ -324,10 +266,7 @@ e_book_view_init (EBookView *book_view)
 		book_view, E_TYPE_BOOK_VIEW, EBookViewPrivate);
 	book_view->priv->gdbus_bookview = NULL;
 
-	#ifndef E_BOOK_DISABLE_DEPRECATED	
 	book_view->priv->book = NULL;
-	#endif
-	book_view->priv->book_client = NULL;
 	book_view->priv->running = FALSE;
 }
 
@@ -350,17 +289,10 @@ e_book_view_dispose (GObject *object)
 		}
 	}
 
-	#ifndef E_BOOK_DISABLE_DEPRECATED
 	if (book_view->priv->book) {
 		g_object_unref (book_view->priv->book);
 		book_view->priv->book = NULL;
 	}
-	#endif
-
-	if (book_view->priv->book_client) {
-		g_object_unref (book_view->priv->book_client);
-		book_view->priv->book_client = NULL;
-	}
 
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_book_view_parent_class)->dispose (object);
diff --git a/addressbook/libebook/e-book-view.h b/addressbook/libebook/e-book-view.h
index 5566051..36d6620 100644
--- a/addressbook/libebook/e-book-view.h
+++ b/addressbook/libebook/e-book-view.h
@@ -11,6 +11,8 @@
 #ifndef __E_BOOK_VIEW_H__
 #define __E_BOOK_VIEW_H__
 
+#ifndef E_BOOK_DISABLE_DEPRECATED
+
 #include <glib.h>
 #include <glib-object.h>
 #include "e-book-types.h"
@@ -28,11 +30,7 @@ typedef struct _EBookView        EBookView;
 typedef struct _EBookViewClass   EBookViewClass;
 typedef struct _EBookViewPrivate EBookViewPrivate;
 
-#ifndef E_BOOK_DISABLE_DEPRECATED
 struct _EBook;  /* Forward reference */
-#endif /* E_BOOK_DISABLE_DEPRECATED */
-
-struct _EBookClient;  /* Forward reference */
 
 struct _EBookView {
 	GObject     parent;
@@ -68,12 +66,10 @@ GType			e_book_view_get_type		(void);
 void			e_book_view_start		(EBookView *book_view);
 void			e_book_view_stop		(EBookView *book_view);
 
-#ifndef E_BOOK_DISABLE_DEPRECATED
 struct _EBook *		e_book_view_get_book		(EBookView *book_view);
-#endif
-
-struct _EBookClient *	e_book_view_get_book_client	(EBookView *book_view);
 
 G_END_DECLS
 
+#endif /* E_BOOK_DISABLE_DEPRECATED */
+
 #endif /* __E_BOOK_VIEW_H__ */
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index 29fb733..a94106e 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -2023,7 +2023,7 @@ e_book_get_book_view (EBook       *book,
 							error);
 
 	if (gdbus_bookview) {
-		*book_view = _e_book_view_new_with_book (book, gdbus_bookview);
+		*book_view = _e_book_view_new (book, gdbus_bookview);
 	} else {
 		*book_view = NULL;
 		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_DBUS_EXCEPTION,
@@ -2061,7 +2061,7 @@ get_book_view_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 							NULL,
 							&error);
 		if (gdbus_bookview) {
-			view = _e_book_view_new_with_book (data->book, gdbus_bookview);
+			view = _e_book_view_new (data->book, gdbus_bookview);
 		}
 	}
 
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index f375875..358adaa 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -59,6 +59,9 @@ struct _EDataBookViewPrivate {
 	guint idle_id;
 
 	guint flush_id;
+
+	/* restriction which fields is listener interested in */
+	GHashTable *only_fields;
 };
 
 static void e_data_book_view_dispose (GObject *object);
@@ -75,6 +78,43 @@ e_data_book_view_class_init (EDataBookViewClass *klass)
 	object_class->finalize = e_data_book_view_finalize;
 }
 
+static guint
+str_ic_hash (gconstpointer key)
+{
+	guint32 hash = 5381;
+	const gchar *str = key;
+	gint ii;
+
+	if (!str)
+		return hash;
+
+	for (ii = 0; str[ii]; ii++) {
+		hash = hash * 33 + g_ascii_tolower (str[ii]);
+	}
+
+	return hash;
+}
+
+static gboolean
+str_ic_equal (gconstpointer a, gconstpointer b)
+{
+	const gchar *stra = a, *strb = b;
+	gint ii;
+
+	if (!stra && !strb)
+		return TRUE;
+
+	if (!stra || !strb)
+		return FALSE;
+
+	for (ii = 0; stra[ii] && strb[ii]; ii++) {
+		if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
+			return FALSE;
+	}
+
+	return stra[ii] == strb[ii];
+}
+
 /**
  * e_data_book_view_register_gdbus_object:
  *
@@ -128,7 +168,7 @@ send_pending_changes (EDataBookView *view)
 	if (priv->changes->len == 0)
 		return;
 
-	e_gdbus_book_view_emit_objects_changed (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
+	e_gdbus_book_view_emit_objects_modified (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
 	reset_array (priv->changes);
 }
 
@@ -243,6 +283,37 @@ notify_add (EDataBookView *view, const gchar *id, const gchar *vcard)
 	ensure_pending_flush_timeout (view);
 }
 
+static gboolean
+impl_DataBookView_setRestriction (EGdbusBookView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields, EDataBookView *view)
+{
+	EDataBookViewPrivate *priv;
+	gint ii;
+
+	g_return_val_if_fail (in_only_fields != NULL, TRUE);
+
+	priv = view->priv;
+
+	if (priv->only_fields)
+		g_hash_table_destroy (priv->only_fields);
+	priv->only_fields = NULL;
+
+	for (ii = 0; in_only_fields[ii]; ii++) {
+		const gchar *field = in_only_fields[ii];
+
+		if (!*field)
+			continue;
+
+		if (!priv->only_fields)
+			priv->only_fields = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
+
+		g_hash_table_insert (priv->only_fields, g_strdup (field), GINT_TO_POINTER (1));
+	}
+
+	e_gdbus_book_view_complete_set_restriction (object, invocation, NULL);
+
+	return TRUE;
+}
+
 static void
 reset_array (GArray *array)
 {
@@ -457,7 +528,7 @@ void
 e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
 {
 	EDataBookViewPrivate *priv = book_view->priv;
-	gchar *gdbus_error_msg = NULL;
+	gchar **strv_error;
 
 	if (!priv->running)
 		return;
@@ -470,12 +541,9 @@ e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
 
 	g_mutex_unlock (priv->pending_mutex);
 
-	/* We're done now, so tell the backend to stop?  TODO: this is a bit different to
-	   how the CORBA backend works... */
-
-	e_gdbus_book_view_emit_complete (priv->gdbus_object, error ? error->code : 0, e_util_ensure_gdbus_string (error ? error->message : "", &gdbus_error_msg));
-
-	g_free (gdbus_error_msg);
+	strv_error = e_gdbus_book_view_encode_error (error);
+	e_gdbus_book_view_emit_complete (priv->gdbus_object, (const gchar * const *) strv_error);
+	g_strfreev (strv_error);
 }
 
 /**
@@ -584,6 +652,9 @@ impl_DataBookView_dispose (EGdbusBookView *object, GDBusMethodInvocation *invoca
 {
 	e_gdbus_book_view_complete_dispose (object, invocation, NULL);
 
+	e_book_backend_stop_book_view (book_view->priv->backend, book_view);
+	book_view->priv->running = FALSE;
+
 	g_object_unref (book_view);
 
 	return TRUE;
@@ -601,7 +672,9 @@ e_data_book_view_init (EDataBookView *book_view)
 	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataBookView_start), book_view);
 	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataBookView_stop), book_view);
 	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataBookView_dispose), book_view);
+	g_signal_connect (priv->gdbus_object, "handle-set-restriction", G_CALLBACK (impl_DataBookView_setRestriction), book_view);
 
+	priv->only_fields = NULL;
 	priv->running = FALSE;
 	priv->pending_mutex = g_mutex_new ();
 
@@ -668,6 +741,9 @@ e_data_book_view_finalize (GObject *object)
 	g_array_free (priv->removes, TRUE);
 	g_free (priv->card_query);
 
+	if (priv->only_fields)
+		g_hash_table_destroy (priv->only_fields);
+
 	g_mutex_free (priv->pending_mutex);
 
 	g_hash_table_destroy (priv->ids);
@@ -726,6 +802,26 @@ e_data_book_view_get_backend (EDataBookView *book_view)
 }
 
 /**
+ * e_data_book_view_get_restriction:
+ * @view: A view object.
+ *
+ * Returns: Hash table of field names which the listener is interested in.
+ * Backends can return fully populated objects, but the listener advertised
+ * that it will use only these. Returns %NULL for all available fields.
+ *
+ * Note: The data pointer in the hash table has no special meaning, it's
+ * only GINT_TO_POINTER(1) for easier checking. Also, field names are
+ * compared case insensitively.
+ **/
+/* const */ GHashTable *
+e_data_book_view_get_restriction (EDataBookView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
+
+	return view->priv->only_fields;
+}
+
+/**
  * e_data_book_view_ref
  * @book_view: an #EBookView
  *
diff --git a/addressbook/libedata-book/e-data-book-view.h b/addressbook/libedata-book/e-data-book-view.h
index 71895ae..40ef59d 100644
--- a/addressbook/libedata-book/e-data-book-view.h
+++ b/addressbook/libedata-book/e-data-book-view.h
@@ -70,6 +70,8 @@ void			e_data_book_view_notify_progress        (EDataBookView *book_view, guint
 void			e_data_book_view_ref			(EDataBookView *book_view);
 void			e_data_book_view_unref			(EDataBookView *book_view);
 
+/* const */ GHashTable *e_data_book_view_get_restriction	(EDataBookView *view);
+
 G_END_DECLS
 
 #endif /* __E_DATA_BOOK_VIEW_H__ */
diff --git a/addressbook/libegdbus/e-gdbus-book-view.c b/addressbook/libegdbus/e-gdbus-book-view.c
index 633efe6..f8ff514 100644
--- a/addressbook/libegdbus/e-gdbus-book-view.c
+++ b/addressbook/libegdbus/e-gdbus-book-view.c
@@ -36,13 +36,14 @@ enum
 {
 	_0_SIGNAL,
 	__OBJECTS_ADDED_SIGNAL,
-	__OBJECTS_CHANGED_SIGNAL,
+	__OBJECTS_MODIFIED_SIGNAL,
 	__OBJECTS_REMOVED_SIGNAL,
 	__PROGRESS_SIGNAL,
 	__COMPLETE_SIGNAL,
 	__START_METHOD,
 	__STOP_METHOD,
 	__DISPOSE_METHOD,
+	__SET_RESTRICTION_METHOD,
 	__LAST_SIGNAL
 };
 
@@ -84,10 +85,10 @@ lookup_signal_type_from_signal_name (const gchar *signal_name)
 /* ------------------------------------------------------------------------- */
 
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_added)
-E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_changed)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_modified)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_removed)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_BOOK_VIEW_INTERFACE_NAME, progress)
-E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_BOOK_VIEW_INTERFACE_NAME, complete)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, complete)
 
 static void
 e_gdbus_book_view_default_init (EGdbusBookViewIface *iface)
@@ -101,15 +102,16 @@ e_gdbus_book_view_default_init (EGdbusBookViewIface *iface)
 	
 	/* GObject signals definitions for D-Bus signals: */
 	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsAdded",	objects_added, __OBJECTS_ADDED_SIGNAL)
-	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsChanged",	objects_changed, __OBJECTS_CHANGED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsModified",objects_modified, __OBJECTS_MODIFIED_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsRemoved",	objects_removed, __OBJECTS_REMOVED_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusBookViewIface, "Progress",	progress, __PROGRESS_SIGNAL)
-	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusBookViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
 
 	/* GObject signals definitions for D-Bus methods: */
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "start",		start, __START_METHOD)
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "stop",		stop, __STOP_METHOD)
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "dispose",	dispose, __DISPOSE_METHOD)
+	E_INIT_GDBUS_METHOD_STRV	(EGdbusBookViewIface, "setRestriction",	set_restriction, __SET_RESTRICTION_METHOD)
 }
 
 void
@@ -167,15 +169,33 @@ e_gdbus_book_view_call_dispose_sync (GDBusProxy *proxy, GCancellable *cancellabl
 }
 
 void
+e_gdbus_book_view_call_set_restriction (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("setRestriction", proxy, in_only_fields, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_view_call_set_restriction_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_view_call_set_restriction_sync (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("setRestriction", proxy, in_only_fields, cancellable, error);
+}
+
+void
 e_gdbus_book_view_emit_objects_added (EGdbusBookView *object, const gchar * const *arg_objects)
 {
 	g_signal_emit (object, signals[__OBJECTS_ADDED_SIGNAL], 0, arg_objects);
 }
 
 void
-e_gdbus_book_view_emit_objects_changed (EGdbusBookView *object, const gchar * const *arg_objects)
+e_gdbus_book_view_emit_objects_modified (EGdbusBookView *object, const gchar * const *arg_objects)
 {
-	g_signal_emit (object, signals[__OBJECTS_CHANGED_SIGNAL], 0, arg_objects);
+	g_signal_emit (object, signals[__OBJECTS_MODIFIED_SIGNAL], 0, arg_objects);
 }
 
 void
@@ -190,34 +210,80 @@ e_gdbus_book_view_emit_progress (EGdbusBookView *object, guint arg_percent, cons
 	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
 }
 
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_book_view_encode_error (const GError *in_error)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+
+	if (!in_error) {
+		strv[0] = g_strdup ("");
+		strv[1] = g_strdup ("");
+	} else {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
+
+		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
+		strv[1] = e_util_utf8_make_valid (in_error->message);
+
+		g_free (dbus_error_name);
+	}
+
+	return strv;
+}
+
+/* free returned pointer with g_error_free(), of not NULL */
+GError *
+e_gdbus_book_view_decode_error (const gchar * const *in_strv)
+{
+	GError *error = NULL;
+	const gchar *error_name, *error_message;
+
+	g_return_val_if_fail (in_strv != NULL, NULL);
+	g_return_val_if_fail (in_strv[0] != NULL, NULL);
+	g_return_val_if_fail (in_strv[1] != NULL, NULL);
+	g_return_val_if_fail (in_strv[2] == NULL, NULL);
+
+	error_name = in_strv[0];
+	error_message = in_strv[1];
+
+	if (error_name && *error_name && error_message)
+		error = g_dbus_error_new_for_dbus_error (error_name, error_message);
+
+	return error;
+}
+
 void
-e_gdbus_book_view_emit_complete (EGdbusBookView *object, guint arg_status, const gchar *arg_message)
+e_gdbus_book_view_emit_complete (EGdbusBookView *object, const gchar * const *arg_error)
 {
-	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_status, arg_message);
+	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_error);
 }
 
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsAdded, objects, "as")
-E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsChanged, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsModified, objects, "as")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsRemoved, uids, "as")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (book_view, Progress, percent, "u", message, "s")
-E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (book_view, Complete, status, "u", message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, Complete, error, "as")
 
 E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, start)
 E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, stop)
 E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, dispose)
+E_DECLARE_GDBUS_SYNC_METHOD_1	(book_view, setRestriction, only_fields, "as")
 
 static const GDBusMethodInfo * const e_gdbus_book_view_method_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, start),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, stop),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, dispose),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, setRestriction),
 	NULL
 };
 
 static const GDBusSignalInfo * const e_gdbus_book_view_signal_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsAdded),
-	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsChanged),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsModified),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsRemoved),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, Progress),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, Complete),
diff --git a/addressbook/libegdbus/e-gdbus-book-view.h b/addressbook/libegdbus/e-gdbus-book-view.h
index ab2cf3c..719bcbd 100644
--- a/addressbook/libegdbus/e-gdbus-book-view.h
+++ b/addressbook/libegdbus/e-gdbus-book-view.h
@@ -105,16 +105,17 @@ struct _EGdbusBookViewIface
 
 	/* Signal handlers for receiving D-Bus signals: */
 	void (*objects_added)		(EGdbusBookView *object, const gchar * const *arg_objects);
-	void (*objects_changed)		(EGdbusBookView *object, const gchar * const *arg_objects);
+	void (*objects_modified)	(EGdbusBookView *object, const gchar * const *arg_objects);
 	void (*objects_removed)		(EGdbusBookView *object, const gchar * const *arg_uids);
   
 	void (*progress)		(EGdbusBookView *object, guint arg_percent, const gchar *arg_message);
-	void (*complete)		(EGdbusBookView *object, guint arg_status, const gchar *arg_message);
+	void (*complete)		(EGdbusBookView *object, const gchar * const *arg_error);
 
 	/* Signal handlers for handling D-Bus method calls: */
-	gboolean (*handle_start)	(EGdbusBookView *object, GDBusMethodInvocation *invocation);
-	gboolean (*handle_stop)		(EGdbusBookView *object, GDBusMethodInvocation *invocation);
-	gboolean (*handle_dispose)	(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_start)		(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_stop)			(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_dispose)		(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_set_restriction)	(EGdbusBookView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields);
 };
 
 /* D-Bus Methods */
@@ -130,18 +131,27 @@ void		e_gdbus_book_view_call_dispose		(GDBusProxy *proxy, GCancellable *cancella
 gboolean	e_gdbus_book_view_call_dispose_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_book_view_call_dispose_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
 
+void		e_gdbus_book_view_call_set_restriction		(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_view_call_set_restriction_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_view_call_set_restriction_sync	(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GError **error);
+
 /* D-Bus Methods Completion Helpers */
-#define e_gdbus_book_view_complete_start	e_gdbus_complete_sync_method_void
-#define e_gdbus_book_view_complete_stop		e_gdbus_complete_sync_method_void
-#define e_gdbus_book_view_complete_dispose	e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_start		e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_stop			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_dispose		e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_set_restriction	e_gdbus_complete_sync_method_void
+
 
 /* D-Bus Signal Emission Helpers */
 void	e_gdbus_book_view_emit_objects_added	(EGdbusBookView *object, const gchar * const *arg_objects);
-void	e_gdbus_book_view_emit_objects_changed	(EGdbusBookView *object, const gchar * const *arg_objects);
+void	e_gdbus_book_view_emit_objects_modified	(EGdbusBookView *object, const gchar * const *arg_objects);
 void	e_gdbus_book_view_emit_objects_removed	(EGdbusBookView *object, const gchar * const *arg_uids);
 
 void	e_gdbus_book_view_emit_progress		(EGdbusBookView *object, guint arg_percent, const gchar *arg_message);
-void	e_gdbus_book_view_emit_complete		(EGdbusBookView *object, guint arg_status, const gchar *arg_message);
+
+gchar **e_gdbus_book_view_encode_error		(const GError *in_error);
+GError *e_gdbus_book_view_decode_error		(const gchar * const *in_strv);
+void	e_gdbus_book_view_emit_complete		(EGdbusBookView *object, const gchar * const *arg_error);
 
 G_END_DECLS
 
diff --git a/calendar/libecal/Makefile.am b/calendar/libecal/Makefile.am
index 1e3d679..109d108 100644
--- a/calendar/libecal/Makefile.am
+++ b/calendar/libecal/Makefile.am
@@ -15,7 +15,7 @@ libecal_INCLUDES = \
 
 libecal_1_2_la_CPPFLAGS =			\
 	$(AM_CPPFLAGS)				\
-	$(libecal_INCLUDES)				\
+	$(libecal_INCLUDES)			\
 	-DG_LOG_DOMAIN=\"libecal\"		\
 	$(LIBICAL_CFLAGS)			\
 	$(EVOLUTION_CALENDAR_CFLAGS)
@@ -24,6 +24,8 @@ libecal_1_2_la_SOURCES =			\
 	$(MARSHAL_GENERATED)			\
 	e-cal.c					\
 	e-cal-client.c				\
+	e-cal-client-view.c			\
+	e-cal-client-view-private.h		\
 	e-cal-component.c			\
 	e-cal-recur.c				\
 	e-cal-time-util.c			\
@@ -48,6 +50,7 @@ libecalincludedir = $(privincludedir)/libecal
 libecalinclude_HEADERS =	\
 	e-cal.h			\
 	e-cal-client.h		\
+	e-cal-client-view.h	\
 	e-cal-component.h	\
 	e-cal-recur.h		\
 	e-cal-time-util.h	\
diff --git a/calendar/libecal/e-cal-client-view-private.h b/calendar/libecal/e-cal-client-view-private.h
new file mode 100644
index 0000000..8a99f54
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view-private.h
@@ -0,0 +1,35 @@
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Author: Federico Mena-Quintero <federico ximian com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CAL_CLIENT_VIEW_PRIVATE_H
+#define E_CAL_CLIENT_VIEW_PRIVATE_H
+
+#include "libecal/e-cal-client-view.h"
+
+G_BEGIN_DECLS
+
+struct _EGdbusCalView;
+struct _ECalClient;
+
+ECalClientView *_e_cal_client_view_new (struct _ECalClient *client,  struct _EGdbusCalView *gdbus_calview);
+
+G_END_DECLS
+
+#endif
diff --git a/calendar/libecal/e-cal-client-view.c b/calendar/libecal/e-cal-client-view.c
new file mode 100644
index 0000000..1ffb0ff
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view.c
@@ -0,0 +1,523 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * Authors: Federico Mena-Quintero <federico ximian com>
+ *          Ross Burton <ross linux intel com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <string.h>
+#include "e-cal-client.h"
+#include "e-cal-client-view.h"
+#include "e-cal-client-view-private.h"
+
+#include "libedataserver/e-gdbus-marshallers.h"
+
+#include "e-gdbus-cal-view.h"
+
+G_DEFINE_TYPE (ECalClientView, e_cal_client_view, G_TYPE_OBJECT);
+
+/* Private part of the ECalClientView structure */
+struct _ECalClientViewPrivate {
+	GDBusProxy *gdbus_calview;
+	ECalClient *client;
+	gboolean running;
+};
+
+/* Property IDs */
+enum props {
+	PROP_0,
+	PROP_VIEW,
+	PROP_CLIENT
+};
+
+/* Signal IDs */
+enum {
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	PROGRESS,
+	COMPLETE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static GSList *
+build_object_list (const gchar * const *seq)
+{
+	GSList *list;
+	gint i;
+
+	list = NULL;
+	for (i = 0; seq[i]; i++) {
+		icalcomponent *comp;
+
+		comp = icalcomponent_new_from_string ((gchar *)seq[i]);
+		if (!comp)
+			continue;
+
+		list = g_slist_prepend (list, comp);
+	}
+
+	return g_slist_reverse (list);
+}
+
+static GSList *
+build_id_list (const gchar * const *seq)
+{
+	GSList *list;
+	gint i;
+
+	list = NULL;
+	for (i = 0; seq[i]; i++) {
+		ECalComponentId *id;
+		id = g_new (ECalComponentId, 1);
+		id->uid = g_strdup (seq[i]);
+		id->rid = NULL; /* TODO */
+		list = g_slist_prepend (list, id);
+	}
+
+	return g_slist_reverse (list);
+}
+
+static void
+objects_added_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_object_list (objects);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_ADDED], 0, list);
+
+	g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+objects_modified_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_object_list (objects);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_MODIFIED], 0, list);
+
+	g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+objects_removed_cb (EGdbusCalView *gdbus_calview, const gchar * const *uids, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_id_list (uids);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_REMOVED], 0, list);
+
+	g_slist_foreach (list, (GFunc) e_cal_component_free_id, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message, ECalClientView *view)
+{
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_signal_emit (G_OBJECT (view), signals[PROGRESS], 0, percent, message);
+}
+
+static void
+complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalClientView *view)
+{
+	GError *error;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	error = e_gdbus_cal_view_decode_error (arg_error);
+
+	g_signal_emit (G_OBJECT (view), signals[COMPLETE], 0, error);
+
+	if (error)
+		g_error_free (error);
+}
+
+/* Object initialization function for the calendar view */
+static void
+e_cal_client_view_init (ECalClientView *view)
+{
+	view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, E_TYPE_CAL_CLIENT_VIEW, ECalClientViewPrivate);
+	view->priv->running = FALSE;
+}
+
+static void
+cal_client_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id) {
+	case PROP_VIEW:
+		/* gdbus_calview can be set only once */
+		g_return_if_fail (priv->gdbus_calview == NULL);
+
+		priv->gdbus_calview = g_object_ref (g_value_get_pointer (value));
+		g_signal_connect (priv->gdbus_calview, "objects-added", G_CALLBACK (objects_added_cb), view);
+		g_signal_connect (priv->gdbus_calview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
+		g_signal_connect (priv->gdbus_calview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
+		g_signal_connect (priv->gdbus_calview, "progress", G_CALLBACK (progress_cb), view);
+		g_signal_connect (priv->gdbus_calview, "complete", G_CALLBACK (complete_cb), view);
+		break;
+	case PROP_CLIENT:
+		priv->client = E_CAL_CLIENT (g_value_dup_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+cal_client_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id) {
+	case PROP_VIEW:
+		g_value_set_pointer (value, priv->gdbus_calview);
+		break;
+	case PROP_CLIENT:
+		g_value_set_object (value, priv->client);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+/* Finalize handler for the calendar view */
+static void
+cal_client_view_finalize (GObject *object)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (object));
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	if (priv->gdbus_calview != NULL) {
+		GError *error = NULL;
+
+		g_signal_handlers_disconnect_matched (priv->gdbus_calview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+		e_gdbus_cal_view_call_dispose_sync (priv->gdbus_calview, NULL, &error);
+		g_object_unref (priv->gdbus_calview);
+		priv->gdbus_calview = NULL;
+
+		if (error) {
+			g_warning ("Failed to dispose cal view: %s", error->message);
+			g_error_free (error);
+		}
+	}
+
+	if (priv->client) {
+		g_object_unref (priv->client);
+		priv->client = NULL;
+	}
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_cal_client_view_parent_class)->finalize (object);
+}
+
+/* Class initialization function for the calendar view */
+static void
+e_cal_client_view_class_init (ECalClientViewClass *klass)
+{
+	GObjectClass *object_class;
+
+	object_class = (GObjectClass *) klass;
+
+	object_class->set_property = cal_client_view_set_property;
+	object_class->get_property = cal_client_view_get_property;
+	object_class->finalize = cal_client_view_finalize;
+
+	g_type_class_add_private (klass, sizeof (ECalClientViewPrivate));
+
+	g_object_class_install_property (object_class, PROP_VIEW,
+		g_param_spec_pointer ("view", "The GDBus view proxy", NULL,
+				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (object_class, PROP_CLIENT,
+		g_param_spec_object ("client", "The e-cal-client for the view", NULL, E_TYPE_CAL_CLIENT,
+				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+        /**
+         * ECalClientView::objects-added:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type long):
+         */
+	signals[OBJECTS_ADDED] =
+		g_signal_new ("objects-added",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+        /**
+         * ECalClientView::objects-modified:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type long):
+         */
+	signals[OBJECTS_MODIFIED] =
+		g_signal_new ("objects-modified",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_modified),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+        /**
+         * ECalClientView::objects-removed:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type ECalComponentId):
+         */
+	signals[OBJECTS_REMOVED] =
+		g_signal_new ("objects-removed",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals[PROGRESS] =
+		g_signal_new ("progress",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, progress),
+			      NULL, NULL,
+			      e_gdbus_marshallers_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+	signals[COMPLETE] =
+		g_signal_new ("complete",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, complete),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_ERROR);
+}
+
+/**
+ * _e_cal_client_view_new:
+ * @client: An #ECalClient object.
+ * @gdbuc_calview: The GDBus object for the view.
+ *
+ * Creates a new view object by issuing the view creation request to the
+ * calendar server.
+ *
+ * Returns: A newly-created view object, or NULL if the request failed.
+ **/
+ECalClientView *
+_e_cal_client_view_new (ECalClient *client, EGdbusCalView *gdbus_calview)
+{
+	ECalClientView *view;
+
+	view = g_object_new (E_TYPE_CAL_CLIENT_VIEW,
+		"client", client,
+		"view", gdbus_calview,
+		NULL);
+
+	return view;
+}
+
+/**
+ * e_cal_client_view_get_client
+ * @view: A #ECalClientView object.
+ *
+ * Get the #ECalClient associated with this view.
+ *
+ * Returns: the associated client.
+ **/
+ECalClient *
+e_cal_client_view_get_client (ECalClientView *view)
+{
+	g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), NULL);
+
+	return view->priv->client;
+}
+
+/**
+ * e_cal_client_view_is_running:
+ * @view: an #ECalClientView
+ *
+ * Retunrs: Whether view is running. Not running views are ignoring
+ * all events sent from the server.
+ **/
+gboolean
+e_cal_client_view_is_running (ECalClientView *view)
+{
+	g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), FALSE);
+
+	return view->priv->running;
+}
+
+/**
+ * e_cal_client_view_start:
+ * @view: An #ECalClientView object.
+ * @error: A #Gerror
+ *
+ * Starts a live query to the calendar/tasks backend.
+ **/
+void
+e_cal_client_view_start (ECalClientView *view, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+
+		if (e_gdbus_cal_view_call_start_sync (priv->gdbus_calview, NULL, &local_error))
+			priv->running = TRUE;
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot start view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_cal_client_view_stop:
+ * @view: An #ECalClientView object.
+ * @error: A #GError
+ *
+ * Stops a live query to the calendar/tasks backend.
+ */
+void
+e_cal_client_view_stop (ECalClientView *view, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+	priv->running = FALSE;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+
+		e_gdbus_cal_view_call_stop_sync (priv->gdbus_calview, NULL, &local_error);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot stop view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_cal_client_view_set_restriction:
+ * @view: An #ECalClientView object
+ * @only_fields: List of field names to restrict result on
+ * @error: A #GError
+ *
+ * Client can instruct server to which fields it is interested in only, thus
+ * the server can return less data over the wire. The server can still return
+ * complete objects, this is just a hint to it that the listef fields will
+ * be used only. The UID/RID fields are returned always. Initial views has
+ * no restriction, and using %NULL for @only_fields will unset any previous
+ * changes.
+ **/
+void
+e_cal_client_view_set_restriction (ECalClientView *view, const GSList *only_fields, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+		gchar **strv;
+
+		strv = e_client_util_slist_to_strv (only_fields);
+		e_gdbus_cal_view_call_set_restriction_sync (priv->gdbus_calview, (const gchar * const *) strv, NULL, &local_error);
+		g_strfreev (strv);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot set restriction, D-Bus proxy gone"));
+	}
+}
diff --git a/calendar/libecal/e-cal-client-view.h b/calendar/libecal/e-cal-client-view.h
new file mode 100644
index 0000000..811339a
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view.h
@@ -0,0 +1,68 @@
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Author: Federico Mena-Quintero <federico ximian com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CAL_CLIENT_VIEW_H
+#define E_CAL_CLIENT_VIEW_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_CLIENT_VIEW            (e_cal_client_view_get_type ())
+#define E_CAL_CLIENT_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_CLIENT_VIEW, ECalClientView))
+#define E_CAL_CLIENT_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_CLIENT_VIEW, ECalClientViewClass))
+#define E_IS_CAL_CLIENT_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_CLIENT_VIEW))
+#define E_IS_CAL_CLIENT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_CLIENT_VIEW))
+
+typedef struct _ECalClientView		ECalClientView;
+typedef struct _ECalClientViewClass	ECalClientViewClass;
+typedef struct _ECalClientViewPrivate	ECalClientViewPrivate;
+
+struct _ECalClient;
+
+struct _ECalClientView {
+	GObject object;
+
+	/*< private >*/
+	ECalClientViewPrivate *priv;
+};
+
+struct _ECalClientViewClass {
+	GObjectClass parent_class;
+
+	/* Notification signals */
+	void (* objects_added)		(ECalClientView *view, const GSList *objects);
+	void (* objects_modified)	(ECalClientView *view, const GSList *objects);
+	void (* objects_removed)	(ECalClientView *view, const GSList *uids);
+
+	void (* progress)		(ECalClientView *view, gint percent, const gchar *message);
+	void (* complete)		(ECalClientView *view, const GError *error);
+};
+
+GType			e_cal_client_view_get_type		(void);
+struct _ECalClient *	e_cal_client_view_get_client		(ECalClientView *view);
+gboolean		e_cal_client_view_is_running		(ECalClientView *view);
+void			e_cal_client_view_set_restriction	(ECalClientView *view, const GSList *only_fields, GError **error);
+void			e_cal_client_view_start			(ECalClientView *view, GError **error);
+void			e_cal_client_view_stop			(ECalClientView *view, GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_CLIENT_VIEW_H */
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 88c0baf..215e736 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -33,8 +33,8 @@
 #include "libedata-cal/e-data-cal-types.h"
 
 #include "e-cal-client.h"
+#include "e-cal-client-view-private.h"
 #include "e-cal-component.h"
-#include "e-cal-view-private.h"
 #include "e-cal-check-timezones.h"
 #include "e-cal-time-util.h"
 
@@ -140,17 +140,16 @@ e_cal_client_error_to_string (ECalClientError code)
 }
 
 /**
- * If the GError is a remote error, extract the ECalClientError embedded inside.
- * Otherwise return DBUS_ERROR.
+ * If the specified GError is a remote error, then create a new error
+ * representing the remote error.  If the error is anything else, then
+ * leave it alone.
  */
-static void
-get_client_error_from_gerror (GError *error, GError **client_error)
+static gboolean
+unwrap_dbus_error (GError *error, GError **client_error)
 {
 	#define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
-	static struct {
-		const gchar *name;
-		ECalClientError err_code;
-	} cal_errors[] = {
+	static struct EClientErrorsList
+	cal_errors[] = {
 		{ err ("Success",				-1) },
 		{ err ("ObjectNotFound",			E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) },
 		{ err ("InvalidObject",				E_CAL_CLIENT_ERROR_INVALID_OBJECT) },
@@ -180,79 +179,11 @@ get_client_error_from_gerror (GError *error, GError **client_error)
 	};
 	#undef err
 
-	g_return_if_fail (client_error != NULL);
-
-	if G_LIKELY (error == NULL)
-		return;
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
-		gchar *name;
-		gint i;
-
-		name = g_dbus_error_get_remote_error (error);
-
-		for (i = 0; i < G_N_ELEMENTS (cal_errors); i++) {
-			if (g_ascii_strcasecmp (cal_errors[i].name, name) == 0) {
-				g_free (name);
-				g_dbus_error_strip_remote_error (error);
-
-				*client_error = g_error_new_literal (E_CAL_CLIENT_ERROR, cal_errors[i].err_code, error->message);
-				return;
-			}
-		}
-
-		for (i = 0; i < G_N_ELEMENTS (cl_errors); i++) {
-			if (g_ascii_strcasecmp (cl_errors[i].name, name) == 0) {
-				g_free (name);
-				g_dbus_error_strip_remote_error (error);
-
-				*client_error = g_error_new_literal (E_CLIENT_ERROR, cl_errors[i].err_code, error->message);
-				return;
-			}
-		}
-
-		g_warning (G_STRLOC ": Unmatched error name %s", name);
-		g_free (name);
-
-		g_dbus_error_strip_remote_error (error);
-		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, error->message);
-	} else if (error->domain == E_CAL_CLIENT_ERROR || error->domain == E_CLIENT_ERROR) {
-		*client_error = g_error_copy (error);
-	} else {
-		/* In this case the error was caused by DBus. Dump the message to the
-		   console as otherwise we have no idea what the problem is. */
-		g_debug ("DBus error: %s", error->message);
-		g_dbus_error_strip_remote_error (error);
-
-		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, error->message);
-	}
-}
-
-/**
- * If the specified GError is a remote error, then create a new error
- * representing the remote error.  If the error is anything else, then
- * leave it alone.
- */
-static gboolean
-unwrap_dbus_error (GError *error, GError **client_error)
-{
 	if (error == NULL)
 		return TRUE;
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
-		if (client_error)
-			get_client_error_from_gerror (error, client_error);
-
-		g_error_free (error);
-	} else {
-		if (client_error) {
-			if (error->domain == G_DBUS_ERROR)
-				g_dbus_error_strip_remote_error (error);
-			*client_error = error;
-		} else {
-			g_error_free (error);
-		}
-	}
+	if (!e_client_util_unwrap_dbus_error (error, client_error, cal_errors, G_N_ELEMENTS (cal_errors), E_CAL_CLIENT_ERROR, TRUE))
+		e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
 
 	return FALSE;
 }
@@ -1376,7 +1307,7 @@ generate_instances (ECalClient *client, time_t start, time_t end, const gchar *u
 
  try_again:
 		if (!e_cal_client_get_objects_for_uid_sync (client, uid, &objects, NULL, &error)) {
-			if (error->code == E_CALENDAR_STATUS_BUSY && tries >= 10) {
+			if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries >= 10) {
 				tries++;
 				g_usleep (500);
 				g_clear_error (&error);
@@ -3424,7 +3355,7 @@ e_cal_client_get_attachment_uris_sync (ECalClient *client, const gchar *uid, con
  * @callback: callback to call when a result is ready
  * @user_data: user data for the @callback
  *
- * Query @client with @sexp, creating an #ECalView.
+ * Query @client with @sexp, creating an #ECalClientView.
  * The call is finished by e_cal_client_get_view_finish()
  * from the @callback.
  *
@@ -3445,9 +3376,9 @@ e_cal_client_get_view (ECalClient *client, const gchar *sexp, GCancellable *canc
 }
 
 static gboolean
-complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalView **cal_view, GError **error)
+complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalClientView **view, GError **error)
 {
-	g_return_val_if_fail (cal_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	if (view_path && res && cal_factory_proxy) {
 		EGdbusCalView *gdbus_calview;
@@ -3461,20 +3392,21 @@ complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalView
 								&local_error);
 
 		if (gdbus_calview) {
-			*cal_view = _e_cal_view_new (client, gdbus_calview);
+			*view = _e_cal_client_view_new (client, gdbus_calview);
+			g_object_unref (gdbus_calview);
 		} else {
-			*cal_view = NULL;
+			*view = NULL;
 			res = FALSE;
 		}
 
 		if (local_error)
 			unwrap_dbus_error (local_error, error);
 	} else {
-		*cal_view = NULL;
+		*view = NULL;
 		res = FALSE;
 	}
 
-	if (!*cal_view && error && !*error)
+	if (!*view && error && !*error)
 		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
 
 	g_free (view_path);
@@ -3486,11 +3418,11 @@ complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalView
  * e_cal_client_get_view_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @cal_view: (out) an #ECalView
+ * @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 @cal_view is set to newly allocated #ECalView,
+ * If successful, then the @view is set to newly allocated #ECalClientView,
  * which should be freed with g_object_unref().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -3498,28 +3430,28 @@ complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalView
  * Since: 3.2
  **/
 gboolean
-e_cal_client_get_view_finish (ECalClient *client, GAsyncResult *result, ECalView **cal_view, GError **error)
+e_cal_client_get_view_finish (ECalClient *client, GAsyncResult *result, ECalClientView **view, GError **error)
 {
 	gboolean res;
 	gchar *view_path = NULL;
 
-	g_return_val_if_fail (cal_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_cal_client_get_view);
 
-	return complete_get_view (client, res, view_path, cal_view, error);
+	return complete_get_view (client, res, view_path, view, error);
 }
 
 /**
  * e_cal_client_get_view_sync:
  * @client: an #ECalClient
  * @sexp: an S-expression representing the query.
- * @cal_view: (out) an #ECalView
+ * @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 #ECalView.
- * If successful, then the @cal_view is set to newly allocated #ECalView,
+ * Query @client with @sexp, creating an #ECalClientView.
+ * If successful, then the @view is set to newly allocated #ECalClientView,
  * which should be freed with g_object_unref().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -3527,7 +3459,7 @@ e_cal_client_get_view_finish (ECalClient *client, GAsyncResult *result, ECalView
  * Since: 3.2
  **/
 gboolean
-e_cal_client_get_view_sync (ECalClient *client, const gchar *sexp, ECalView **cal_view, GCancellable *cancellable, GError **error)
+e_cal_client_get_view_sync (ECalClient *client, const gchar *sexp, ECalClientView **view, GCancellable *cancellable, GError **error)
 {
 	gboolean res;
 	gchar *gdbus_sexp = NULL;
@@ -3537,7 +3469,7 @@ e_cal_client_get_view_sync (ECalClient *client, const gchar *sexp, ECalView **ca
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (client->priv != NULL, FALSE);
 	g_return_val_if_fail (sexp != NULL, FALSE);
-	g_return_val_if_fail (cal_view != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
 
 	if (!client->priv->gdbus_cal) {
 		set_proxy_gone_error (error);
@@ -3548,7 +3480,7 @@ e_cal_client_get_view_sync (ECalClient *client, const gchar *sexp, ECalView **ca
 
 	g_free (gdbus_sexp);
 
-	return complete_get_view (client, res, view_path, cal_view, error);
+	return complete_get_view (client, res, view_path, view, error);
 }
 
 static icaltimezone *
diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h
index 2dd7de6..53f9cfa 100644
--- a/calendar/libecal/e-cal-client.h
+++ b/calendar/libecal/e-cal-client.h
@@ -26,9 +26,9 @@
 #include <gio/gio.h>
 
 #include <libedataserver/e-client.h>
+#include <libecal/e-cal-client-view.h>
 #include <libecal/e-cal-recur.h>
 #include <libecal/e-cal-util.h>
-#include <libecal/e-cal-view.h>
 
 G_BEGIN_DECLS
 
@@ -174,8 +174,8 @@ gboolean	e_cal_client_get_attachment_uris_finish		(ECalClient *client, GAsyncRes
 gboolean	e_cal_client_get_attachment_uris_sync		(ECalClient *client, const gchar *uid, const gchar *rid, GSList **attachment_uris, GCancellable *cancellable, GError **error);
 
 void		e_cal_client_get_view				(ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean	e_cal_client_get_view_finish			(ECalClient *client, GAsyncResult *result, ECalView **view, GError **error);
-gboolean	e_cal_client_get_view_sync			(ECalClient *client, const gchar *sexp, ECalView **view, GCancellable *cancellable, GError **error);
+gboolean	e_cal_client_get_view_finish			(ECalClient *client, GAsyncResult *result, ECalClientView **view, GError **error);
+gboolean	e_cal_client_get_view_sync			(ECalClient *client, const gchar *sexp, ECalClientView **view, GCancellable *cancellable, GError **error);
 
 void		e_cal_client_get_timezone			(ECalClient *client, const gchar *tzid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean	e_cal_client_get_timezone_finish		(ECalClient *client, GAsyncResult *result, icaltimezone **zone, GError **error);
diff --git a/calendar/libecal/e-cal-view-private.h b/calendar/libecal/e-cal-view-private.h
index be63ba6..9aa39df 100644
--- a/calendar/libecal/e-cal-view-private.h
+++ b/calendar/libecal/e-cal-view-private.h
@@ -28,11 +28,7 @@ G_BEGIN_DECLS
 
 struct _EGdbusCalView;
 
-#ifndef E_CAL_DISABLE_DEPRECATED
-ECalView *_e_cal_view_new_for_ecal (struct _ECal *client,  struct _EGdbusCalView *gdbus_calview);
-#endif /* E_CAL_DISABLE_DEPRECATED */
-
-ECalView *_e_cal_view_new (struct _ECalClient *client,  struct _EGdbusCalView *gdbus_calview);
+ECalView *_e_cal_view_new (struct _ECal *client,  struct _EGdbusCalView *gdbus_calview);
 
 G_END_DECLS
 
diff --git a/calendar/libecal/e-cal-view.c b/calendar/libecal/e-cal-view.c
index 2c18254..3302198 100644
--- a/calendar/libecal/e-cal-view.c
+++ b/calendar/libecal/e-cal-view.c
@@ -27,10 +27,7 @@
 
 #include <string.h>
 #include "e-cal-marshal.h"
-#ifndef E_CAL_DISABLE_DEPRECATED
 #include "e-cal.h"
-#endif
-#include "e-cal-client.h"
 #include "e-cal-view.h"
 #include "e-cal-view-private.h"
 #include "e-gdbus-cal-view.h"
@@ -40,20 +37,14 @@ G_DEFINE_TYPE (ECalView, e_cal_view, G_TYPE_OBJECT);
 /* Private part of the ECalView structure */
 struct _ECalViewPrivate {
 	GDBusProxy *gdbus_calview;
-	#ifndef E_CAL_DISABLE_DEPRECATED
 	ECal *client;
-	#endif
-	ECalClient *cal_client;
 };
 
 /* Property IDs */
 enum props {
 	PROP_0,
 	PROP_VIEW,
-	#ifndef E_CAL_DISABLE_DEPRECATED
-	PROP_CLIENT,
-	#endif
-	PROP_CAL_CLIENT
+	PROP_CLIENT
 };
 
 /* Signal IDs */
@@ -128,7 +119,7 @@ objects_added_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, EC
 }
 
 static void
-objects_changed_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalView *view)
+objects_modified_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalView *view)
 {
 	GList *list;
 
@@ -172,15 +163,22 @@ progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message,
 }
 
 static void
-complete_cb (EGdbusCalView *gdbus_calview, /* ECalendarStatus */ guint status, const gchar *message, ECalView *view)
+complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalView *view)
 {
+	GError *error;
+
 	g_return_if_fail (E_IS_CAL_VIEW (view));
 
+	error = e_gdbus_cal_view_decode_error (arg_error);
+
 	#ifndef E_CAL_DISABLE_DEPRECATED
-	g_signal_emit (G_OBJECT (view), signals[VIEW_DONE], 0, status);
+	g_signal_emit (G_OBJECT (view), signals[VIEW_DONE], 0, error ? error->code : 0);
 	#endif
 
-	g_signal_emit (G_OBJECT (view), signals[VIEW_COMPLETE], 0, status, message);
+	g_signal_emit (G_OBJECT (view), signals[VIEW_COMPLETE], 0, error ? error->code : 0, error ? error->message : "");
+
+	if (error)
+		g_error_free (error);
 }
 
 /* Object initialization function for the calendar view */
@@ -207,19 +205,14 @@ e_cal_view_set_property (GObject *object, guint property_id, const GValue *value
 
 		priv->gdbus_calview = g_object_ref (g_value_get_pointer (value));
 		g_signal_connect (priv->gdbus_calview, "objects-added", G_CALLBACK (objects_added_cb), view);
-		g_signal_connect (priv->gdbus_calview, "objects-changed", G_CALLBACK (objects_changed_cb), view);
+		g_signal_connect (priv->gdbus_calview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
 		g_signal_connect (priv->gdbus_calview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
 		g_signal_connect (priv->gdbus_calview, "progress", G_CALLBACK (progress_cb), view);
 		g_signal_connect (priv->gdbus_calview, "complete", G_CALLBACK (complete_cb), view);
 		break;
-	case PROP_CAL_CLIENT:
-		priv->cal_client = E_CAL_CLIENT (g_value_dup_object (value));
-		break;
-	#ifndef E_CAL_DISABLE_DEPRECATED
 	case PROP_CLIENT:
 		priv->client = E_CAL (g_value_dup_object (value));
 		break;
-	#endif
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 		break;
@@ -239,14 +232,9 @@ e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GPar
 	case PROP_VIEW:
 		g_value_set_pointer (value, priv->gdbus_calview);
 		break;
-	case PROP_CAL_CLIENT:
-		g_value_set_object (value, priv->cal_client);
-		break;
-	#ifndef E_CAL_DISABLE_DEPRECATED
 	case PROP_CLIENT:
 		g_value_set_object (value, priv->client);
 		break;
-	#endif
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 		break;
@@ -280,17 +268,10 @@ e_cal_view_finalize (GObject *object)
 		}
 	}
 
-	#ifndef E_CAL_DISABLE_DEPRECATED
 	if (priv->client) {
 		g_object_unref (priv->client);
 		priv->client = NULL;
 	}
-	#endif
-
-	if (priv->cal_client) {
-		g_object_unref (priv->cal_client);
-		priv->cal_client = NULL;
-	}
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_cal_view_parent_class)->finalize (object);
@@ -314,15 +295,9 @@ e_cal_view_class_init (ECalViewClass *klass)
 		g_param_spec_pointer ("view", "The GDBus view proxy", NULL,
 				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 
-	#ifndef E_CAL_DISABLE_DEPRECATED
 	g_object_class_install_property (object_class, PROP_CLIENT,
 		g_param_spec_object ("client", "The e-cal for the view", NULL, E_TYPE_CAL,
 				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-	#endif
-
-	g_object_class_install_property (object_class, PROP_CAL_CLIENT,
-		g_param_spec_object ("cal-client", "The e-cal-client for the view", NULL, E_TYPE_CAL_CLIENT,
-				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
         /**
          * ECalView::objects-added:
          * @view:: self
@@ -393,48 +368,6 @@ e_cal_view_class_init (ECalViewClass *klass)
 }
 
 /**
- * _e_cal_view_new:
- * @client: An #ECalClient object.
- * @gdbuc_calview: The GDBus object for the view.
- *
- * Creates a new view object by issuing the view creation request to the
- * calendar server.
- *
- * Returns: A newly-created view object, or NULL if the request failed.
- **/
-ECalView *
-_e_cal_view_new (ECalClient *client, EGdbusCalView *gdbus_calview)
-{
-	ECalView *view;
-
-	view = g_object_new (E_TYPE_CAL_VIEW,
-		"cal-client", client,
-		"view", gdbus_calview,
-		NULL);
-
-	return view;
-}
-
-/**
- * e_cal_view_get_cal_client
- * @view: A #ECalView object.
- *
- * Get the #ECalClient associated with this view.
- *
- * Returns: the associated client.
- *
- * Since: 3.2
- */
-ECalClient *
-e_cal_view_get_cal_client (ECalView *view)
-{
-	g_return_val_if_fail (E_IS_CAL_VIEW (view), NULL);
-
-	return view->priv->cal_client;
-}
-
-#ifndef E_CAL_DISABLE_DEPRECATED
-/**
  * _e_cal_view_new_for_ecal:
  * @client: An #ECal object.
  * @gdbuc_calview: The GDBus object for the view.
@@ -443,9 +376,11 @@ e_cal_view_get_cal_client (ECalView *view)
  * calendar server.
  *
  * Returns: A newly-created view object, or NULL if the request failed.
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  **/
 ECalView *
-_e_cal_view_new_for_ecal (ECal *ecal, EGdbusCalView *gdbus_calview)
+_e_cal_view_new (ECal *ecal, EGdbusCalView *gdbus_calview)
 {
 	ECalView *view;
 
@@ -458,7 +393,7 @@ _e_cal_view_new_for_ecal (ECal *ecal, EGdbusCalView *gdbus_calview)
 }
 
 /**
- * e_cal_view_get_client_ecal
+ * e_cal_view_get_client
  * @view: A #ECalView object.
  *
  * Get the #ECal associated with this view.
@@ -467,7 +402,7 @@ _e_cal_view_new_for_ecal (ECal *ecal, EGdbusCalView *gdbus_calview)
  *
  * Since: 2.22
  *
- * Deprecated: 3.2: Use #ECalClient and e_cal_view_get_cal_client() instead
+ * Deprecated: 3.2: Use #ECalClientView
  */
 ECal *
 e_cal_view_get_client (ECalView *view)
@@ -476,7 +411,6 @@ e_cal_view_get_client (ECalView *view)
 
 	return view->priv->client;
 }
-#endif
 
 /**
  * e_cal_view_start:
@@ -485,6 +419,8 @@ e_cal_view_get_client (ECalView *view)
  * Starts a live query to the calendar/tasks backend.
  *
  * Since: 2.22
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  */
 void
 e_cal_view_start (ECalView *view)
@@ -521,6 +457,8 @@ e_cal_view_start (ECalView *view)
  * Stops a live query to the calendar/tasks backend.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  */
 void
 e_cal_view_stop (ECalView *view)
diff --git a/calendar/libecal/e-cal-view.h b/calendar/libecal/e-cal-view.h
index 347eac8..a090a1c 100644
--- a/calendar/libecal/e-cal-view.h
+++ b/calendar/libecal/e-cal-view.h
@@ -21,6 +21,8 @@
 #ifndef E_CAL_VIEW_H
 #define E_CAL_VIEW_H
 
+#ifndef E_CAL_DISABLE_DEPRECATED
+
 #include <glib-object.h>
 #include <libecal/e-cal-types.h>
 
@@ -36,12 +38,7 @@ typedef struct _ECalView ECalView;
 typedef struct _ECalViewClass ECalViewClass;
 typedef struct _ECalViewPrivate ECalViewPrivate;
 
-#ifndef E_CAL_DISABLE_DEPRECATED
 struct _ECal;
-#endif
-struct _ECalClient;
-
-struct _ECalClient;
 
 struct _ECalView {
 	GObject object;
@@ -66,15 +63,13 @@ struct _ECalViewClass {
 
 GType      e_cal_view_get_type (void);
 
-#ifndef E_CAL_DISABLE_DEPRECATED
 struct _ECal *e_cal_view_get_client (ECalView *view);
-#endif
-
-struct _ECalClient *e_cal_view_get_cal_client (ECalView *view);
 
 void e_cal_view_start (ECalView *view);
 void e_cal_view_stop (ECalView *view);
 
 G_END_DECLS
 
+#endif /* E_CAL_DISABLE_DEPRECATED */
+
 #endif
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index a93f7ca..cd6cf0b 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -4312,7 +4312,7 @@ e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error
 		*query = NULL;
 		status = E_CALENDAR_STATUS_OTHER_ERROR;
 	} else {
-		*query = _e_cal_view_new_for_ecal (ecal, gdbus_calview);
+		*query = _e_cal_view_new (ecal, gdbus_calview);
 		g_object_unref (gdbus_calview);
 	}
 
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 244fd79..5556d13 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -1228,7 +1228,10 @@ e_cal_backend_stop_view (ECalBackend *backend, EDataCalView *view)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->stop_view != NULL);
+
+	/* backward compatibility, do not force each backend define this function */
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
+		return;
 
 	(* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
 }
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 6688446..0fb7d52 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -61,6 +61,9 @@ struct _EDataCalViewPrivate {
 
 	GMutex *pending_mutex;
 	guint flush_id;
+
+	/* restriction which fields is listener interested in */
+	GHashTable *only_fields;
 };
 
 G_DEFINE_TYPE (EDataCalView, e_data_cal_view, G_TYPE_OBJECT);
@@ -102,6 +105,43 @@ e_data_cal_view_class_init (EDataCalViewClass *klass)
 }
 
 static guint
+str_ic_hash (gconstpointer key)
+{
+	guint32 hash = 5381;
+	const gchar *str = key;
+	gint ii;
+
+	if (!str)
+		return hash;
+
+	for (ii = 0; str[ii]; ii++) {
+		hash = hash * 33 + g_ascii_tolower (str[ii]);
+	}
+
+	return hash;
+}
+
+static gboolean
+str_ic_equal (gconstpointer a, gconstpointer b)
+{
+	const gchar *stra = a, *strb = b;
+	gint ii;
+
+	if (!stra && !strb)
+		return TRUE;
+
+	if (!stra || !strb)
+		return FALSE;
+
+	for (ii = 0; stra[ii] && strb[ii]; ii++) {
+		if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
+			return FALSE;
+	}
+
+	return stra[ii] == strb[ii];
+}
+
+static guint
 id_hash (gconstpointer key)
 {
 	const ECalComponentId *id = key;
@@ -177,7 +217,7 @@ send_pending_changes (EDataCalView *view)
 	if (priv->changes->len == 0)
 		return;
 
-	e_gdbus_cal_view_emit_objects_changed (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
+	e_gdbus_cal_view_emit_objects_modified (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
 	reset_array (priv->changes);
 }
 
@@ -289,15 +329,17 @@ notify_remove (EDataCalView *view, ECalComponentId *id)
 static void
 notify_complete (EDataCalView *view, const GError *error)
 {
-	gchar *gdbus_error_msg = NULL;
+	gchar **error_strv;
 
 	send_pending_adds (view);
 	send_pending_changes (view);
 	send_pending_removes (view);
 
-	e_gdbus_cal_view_emit_complete (view->priv->gdbus_object, error ? error->code : 0, e_util_ensure_gdbus_string (error ? error->message : "", &gdbus_error_msg));
+	error_strv = e_gdbus_cal_view_encode_error (error);
 
-	g_free (gdbus_error_msg);
+	e_gdbus_cal_view_emit_complete (view->priv->gdbus_object, (const gchar * const *) error_strv);
+
+	g_strfreev (error_strv);
 }
 
 static gboolean
@@ -328,6 +370,7 @@ impl_DataCalView_stop (EGdbusCalView *object, GDBusMethodInvocation *invocation,
 	priv->stopped = TRUE;
 
 	e_gdbus_cal_view_complete_stop (object, invocation, NULL);
+	e_cal_backend_stop_view (priv->backend, view);
 
 	return TRUE;
 }
@@ -337,11 +380,45 @@ impl_DataCalView_dispose (EGdbusCalView *object, GDBusMethodInvocation *invocati
 {
 	e_gdbus_cal_view_complete_dispose (object, invocation, NULL);
 
+	view->priv->stopped = TRUE;
+	e_cal_backend_stop_view (view->priv->backend, view);
+
 	g_object_unref (view);
 
 	return TRUE;
 }
 
+static gboolean
+impl_DataCalView_setRestriction (EGdbusCalView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields, EDataCalView *view)
+{
+	EDataCalViewPrivate *priv;
+	gint ii;
+
+	g_return_val_if_fail (in_only_fields != NULL, TRUE);
+
+	priv = view->priv;
+
+	if (priv->only_fields)
+		g_hash_table_destroy (priv->only_fields);
+	priv->only_fields = NULL;
+
+	for (ii = 0; in_only_fields[ii]; ii++) {
+		const gchar *field = in_only_fields[ii];
+
+		if (!*field)
+			continue;
+
+		if (!priv->only_fields)
+			priv->only_fields = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
+
+		g_hash_table_insert (priv->only_fields, g_strdup (field), GINT_TO_POINTER (1));
+	}
+
+	e_gdbus_cal_view_complete_set_restriction (object, invocation, NULL);
+
+	return TRUE;
+}
+
 static void
 e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 {
@@ -399,12 +476,14 @@ e_data_cal_view_init (EDataCalView *view)
 	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataCalView_start), view);
 	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataCalView_stop), view);
 	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataCalView_dispose), view);
+	g_signal_connect (priv->gdbus_object, "handle-set-restriction", G_CALLBACK (impl_DataCalView_setRestriction), view);
 
 	priv->backend = NULL;
 	priv->started = FALSE;
 	priv->stopped = FALSE;
 	priv->complete = FALSE;
 	priv->sexp = NULL;
+	priv->only_fields = NULL;
 
 	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
 	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
@@ -473,6 +552,9 @@ e_data_cal_view_finalize (GObject *object)
 
 	g_hash_table_destroy (priv->ids);
 
+	if (priv->only_fields)
+		g_hash_table_destroy (priv->only_fields);
+
 	g_mutex_free (priv->pending_mutex);
 
 	(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize) (object);
@@ -588,6 +670,26 @@ e_data_cal_view_is_completed (EDataCalView *view)
 }
 
 /**
+ * e_data_cal_view_get_restriction:
+ * @view: A view object.
+ *
+ * Returns: Hash table of field names which the listener is interested in.
+ * Backends can return fully populated objects, but the listener advertised
+ * that it will use only these. Returns %NULL for all available fields.
+ *
+ * Note: The data pointer in the hash table has no special meaning, it's
+ * only GINT_TO_POINTER(1) for easier checking. Also, field names are
+ * compared case insensitively.
+ **/
+/* const */ GHashTable *
+e_data_cal_view_get_restriction (EDataCalView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
+
+	return view->priv->only_fields;
+}
+
+/**
  * e_data_cal_view_notify_objects_added:
  * @view: A view object.
  * @objects: List of objects that have been added.
diff --git a/calendar/libedata-cal/e-data-cal-view.h b/calendar/libedata-cal/e-data-cal-view.h
index 81825cc..044ddec 100644
--- a/calendar/libedata-cal/e-data-cal-view.h
+++ b/calendar/libedata-cal/e-data-cal-view.h
@@ -57,6 +57,7 @@ gboolean		e_data_cal_view_object_matches			(EDataCalView *view, const gchar *obj
 gboolean		e_data_cal_view_is_started			(EDataCalView *view);
 gboolean		e_data_cal_view_is_completed			(EDataCalView *view);
 gboolean		e_data_cal_view_is_stopped			(EDataCalView *view);
+/* const */ GHashTable *e_data_cal_view_get_restriction			(EDataCalView *view);
 
 void			e_data_cal_view_notify_objects_added		(EDataCalView *view, const GSList *objects);
 void			e_data_cal_view_notify_objects_added_1		(EDataCalView *view, const gchar *object);
diff --git a/calendar/libegdbus/e-gdbus-cal-view.c b/calendar/libegdbus/e-gdbus-cal-view.c
index f9f1ad7..1497a98 100644
--- a/calendar/libegdbus/e-gdbus-cal-view.c
+++ b/calendar/libegdbus/e-gdbus-cal-view.c
@@ -36,13 +36,14 @@ enum
 {
 	_0_SIGNAL,
 	__OBJECTS_ADDED_SIGNAL,
-	__OBJECTS_CHANGED_SIGNAL,
+	__OBJECTS_MODIFIED_SIGNAL,
 	__OBJECTS_REMOVED_SIGNAL,
 	__PROGRESS_SIGNAL,
 	__COMPLETE_SIGNAL,
 	__START_METHOD,
 	__STOP_METHOD,
 	__DISPOSE_METHOD,
+	__SET_RESTRICTION_METHOD,
 	__LAST_SIGNAL
 };
 
@@ -84,10 +85,10 @@ lookup_signal_type_from_signal_name (const gchar *signal_name)
 /* ------------------------------------------------------------------------- */
 
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_added)
-E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_changed)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_modified)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_removed)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_CAL_VIEW_INTERFACE_NAME, progress)
-E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_CAL_VIEW_INTERFACE_NAME, complete)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, complete)
 
 static void
 e_gdbus_cal_view_default_init (EGdbusCalViewIface *iface)
@@ -101,18 +102,18 @@ e_gdbus_cal_view_default_init (EGdbusCalViewIface *iface)
 	
 	/* GObject signals definitions for D-Bus signals: */
 	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsAdded",	objects_added, __OBJECTS_ADDED_SIGNAL)
-	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsChanged",	objects_changed, __OBJECTS_CHANGED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsModified",	objects_modified, __OBJECTS_MODIFIED_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsRemoved",	objects_removed, __OBJECTS_REMOVED_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusCalViewIface, "Progress",	progress, __PROGRESS_SIGNAL)
-	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusCalViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
 
 	/* GObject signals definitions for D-Bus methods: */
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "start",		start, __START_METHOD)
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "stop",		stop, __STOP_METHOD)
 	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "dispose",		dispose, __DISPOSE_METHOD)
+	E_INIT_GDBUS_METHOD_STRV	(EGdbusCalViewIface, "setRestriction",	set_restriction, __SET_RESTRICTION_METHOD)
 }
 
-
 void
 e_gdbus_cal_view_call_start (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -168,15 +169,33 @@ e_gdbus_cal_view_call_dispose_sync (GDBusProxy *proxy, GCancellable *cancellable
 }
 
 void
+e_gdbus_cal_view_call_set_restriction (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("setRestriction", proxy, in_only_fields, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_view_call_set_restriction_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_view_call_set_restriction_sync (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("setRestriction", proxy, in_only_fields, cancellable, error);
+}
+
+void
 e_gdbus_cal_view_emit_objects_added (EGdbusCalView *object, const gchar * const *arg_objects)
 {
 	g_signal_emit (object, signals[__OBJECTS_ADDED_SIGNAL], 0, arg_objects);
 }
 
 void
-e_gdbus_cal_view_emit_objects_changed (EGdbusCalView *object, const gchar * const *arg_objects)
+e_gdbus_cal_view_emit_objects_modified (EGdbusCalView *object, const gchar * const *arg_objects)
 {
-	g_signal_emit (object, signals[__OBJECTS_CHANGED_SIGNAL], 0, arg_objects);
+	g_signal_emit (object, signals[__OBJECTS_MODIFIED_SIGNAL], 0, arg_objects);
 }
 
 void
@@ -191,34 +210,80 @@ e_gdbus_cal_view_emit_progress (EGdbusCalView *object, guint arg_percent, const
 	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
 }
 
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_view_encode_error (const GError *in_error)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+
+	if (!in_error) {
+		strv[0] = g_strdup ("");
+		strv[1] = g_strdup ("");
+	} else {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
+
+		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
+		strv[1] = e_util_utf8_make_valid (in_error->message);
+
+		g_free (dbus_error_name);
+	}
+
+	return strv;
+}
+
+/* free returned pointer with g_error_free(), of not NULL */
+GError *
+e_gdbus_cal_view_decode_error (const gchar * const *in_strv)
+{
+	GError *error = NULL;
+	const gchar *error_name, *error_message;
+
+	g_return_val_if_fail (in_strv != NULL, NULL);
+	g_return_val_if_fail (in_strv[0] != NULL, NULL);
+	g_return_val_if_fail (in_strv[1] != NULL, NULL);
+	g_return_val_if_fail (in_strv[2] == NULL, NULL);
+
+	error_name = in_strv[0];
+	error_message = in_strv[1];
+
+	if (error_name && *error_name && error_message)
+		error = g_dbus_error_new_for_dbus_error (error_name, error_message);
+
+	return error;
+}
+
 void
-e_gdbus_cal_view_emit_complete (EGdbusCalView *object, guint arg_status, const gchar *arg_message)
+e_gdbus_cal_view_emit_complete (EGdbusCalView *object, const gchar * const *arg_error)
 {
-	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_status, arg_message);
+	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_error);
 }
 
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsAdded, objects, "as")
-E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsChanged, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsModified, objects, "as")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsRemoved, uids, "as")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (cal_view, Progress, percent, "u", message, "s")
-E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (cal_view, Complete, status, "u", message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, Complete, error, "as")
 
 E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, start)
 E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, stop)
 E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, dispose)
+E_DECLARE_GDBUS_SYNC_METHOD_1	(cal_view, setRestriction, only_fields, "as")
 
 static const GDBusMethodInfo * const e_gdbus_cal_view_method_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, start),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, stop),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, dispose),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, setRestriction),
 	NULL
 };
 
 static const GDBusSignalInfo * const e_gdbus_cal_view_signal_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsAdded),
-	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsChanged),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsModified),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsRemoved),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, Progress),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, Complete),
diff --git a/calendar/libegdbus/e-gdbus-cal-view.h b/calendar/libegdbus/e-gdbus-cal-view.h
index 0c4bfb6..c5a646c 100644
--- a/calendar/libegdbus/e-gdbus-cal-view.h
+++ b/calendar/libegdbus/e-gdbus-cal-view.h
@@ -98,16 +98,17 @@ struct _EGdbusCalViewIface
 
 	/* Signal handlers for receiving D-Bus signals: */
 	void	(*objects_added)	(EGdbusCalView *object, const gchar * const *arg_objects);
-	void	(*objects_changed)	(EGdbusCalView *object, const gchar * const *arg_objects);
+	void	(*objects_modified)	(EGdbusCalView *object, const gchar * const *arg_objects);
 	void	(*objects_removed)	(EGdbusCalView *object, const gchar * const *arg_uids);
 
 	void	(*progress)		(EGdbusCalView *object, guint arg_percent, const gchar *arg_message);
 	void	(*complete)		(EGdbusCalView *object, guint arg_status, const gchar *arg_message);
 
 	/* Signal handlers for handling D-Bus method calls: */
-	gboolean (*handle_start)	(EGdbusCalView *object, GDBusMethodInvocation *invocation);
-	gboolean (*handle_stop)		(EGdbusCalView *object, GDBusMethodInvocation *invocation);
-	gboolean (*handle_dispose)	(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_start)		(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_stop)			(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_dispose)		(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_set_restriction)	(EGdbusCalView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields);
 };
 
 /* D-Bus Methods */
@@ -123,18 +124,26 @@ void		e_gdbus_cal_view_call_dispose		(GDBusProxy *proxy, GCancellable *cancellab
 gboolean	e_gdbus_cal_view_call_dispose_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_cal_view_call_dispose_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
 
+void		e_gdbus_cal_view_call_set_restriction		(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_view_call_set_restriction_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_view_call_set_restriction_sync	(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GError **error);
+
 /* D-Bus Methods Completion Helpers */
-#define e_gdbus_cal_view_complete_start		e_gdbus_complete_sync_method_void
-#define e_gdbus_cal_view_complete_stop		e_gdbus_complete_sync_method_void
-#define e_gdbus_cal_view_complete_dispose	e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_start			e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_stop			e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_dispose		e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_set_restriction	e_gdbus_complete_sync_method_void
 
 /* D-Bus Signal Emission Helpers */
 void e_gdbus_cal_view_emit_objects_added	(EGdbusCalView *object, const gchar * const *arg_objects);
-void e_gdbus_cal_view_emit_objects_changed	(EGdbusCalView *object, const gchar * const *arg_objects);
+void e_gdbus_cal_view_emit_objects_modified	(EGdbusCalView *object, const gchar * const *arg_objects);
 void e_gdbus_cal_view_emit_objects_removed	(EGdbusCalView *object, const gchar * const *arg_uids);
 
 void e_gdbus_cal_view_emit_progress		(EGdbusCalView *object, guint arg_percent, const gchar *arg_message);
-void e_gdbus_cal_view_emit_complete		(EGdbusCalView *object, guint arg_status, const gchar *arg_message);
+
+gchar **e_gdbus_cal_view_encode_error		(const GError *in_error);
+GError *e_gdbus_cal_view_decode_error		(const gchar * const *in_strv);
+void e_gdbus_cal_view_emit_complete		(EGdbusCalView *object, const gchar * const *arg_error);
 
 G_END_DECLS
 
diff --git a/libedataserver/e-client.c b/libedataserver/e-client.c
index 798d0b9..4e11710 100644
--- a/libedataserver/e-client.c
+++ b/libedataserver/e-client.c
@@ -1605,6 +1605,83 @@ e_client_unwrap_dbus_error (EClient *client, GError *dbus_error, GError **out_er
 	}
 }
 
+/**
+ * e_client_util_unwrap_dbus_error:
+ * @dbus_error: DBus #GError to unwrap
+ * @client_error: (out): Resulting #GError; can be %NULL
+ * @known_errors: List of known errors against which try to match
+ * @known_errors_count: How many items are stored in @known_errors
+ * @known_errors_domain: Error domain for @known_errors
+ * @fail_when_none_matched: Whether to fail when none of @known_errors matches
+ *
+ * The function takes a @dbus_error and tries to find a match in @known_errors for it,
+ * if it is a G_IO_ERROR, G_IO_ERROR_DBUS_ERROR. If it is anything else then the @dbus_error
+ * is moved to @client_error.
+ *
+ * The @fail_when_none_matched influences behaviour. If it's %TRUE, and none of @known_errors matches,
+ * or this is not a G_IO_ERROR_DBUS_ERROR, then %FALSE is returned and the @client_error
+ * is left without change. Otherwise, the @fail_when_none_matched is %FALSE, the error is always
+ * processed and will result in E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR if none of @known_error matches.
+ *
+ * Returns: Whether was @dbus_error processed into @client_error.
+ *
+ * Note: The @dbus_error is automatically freed if returned %TRUE.
+ **/
+gboolean
+e_client_util_unwrap_dbus_error (GError *dbus_error, GError **client_error, const struct EClientErrorsList *known_errors, guint known_errors_count, GQuark known_errors_domain, gboolean fail_when_none_matched)
+{
+	if (!client_error) {
+		if (dbus_error)
+			g_error_free (dbus_error);
+		return TRUE;
+	}
+
+	if (!dbus_error) {
+		*client_error = NULL;
+		return TRUE;
+	}
+
+	if (dbus_error->domain == known_errors_domain) {
+		*client_error = dbus_error;
+		return TRUE;
+	}
+
+	if (known_errors) {
+		if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
+			gchar *name;
+			gint ii;
+
+			name = g_dbus_error_get_remote_error (dbus_error);
+
+			for (ii = 0; ii < known_errors_count; ii++) {
+				if (g_ascii_strcasecmp (known_errors[ii].name, name) == 0) {
+					g_free (name);
+
+					g_dbus_error_strip_remote_error (dbus_error);
+					*client_error = g_error_new_literal (known_errors_domain, known_errors[ii].err_code, dbus_error->message);
+					g_error_free (dbus_error);
+					return TRUE;
+				}
+			}
+		}
+	}
+
+	if (fail_when_none_matched)
+		return FALSE;
+
+	if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
+		g_dbus_error_strip_remote_error (dbus_error);
+		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, dbus_error->message);
+		g_error_free (dbus_error);
+	} else {
+		if (dbus_error->domain == G_DBUS_ERROR)
+			g_dbus_error_strip_remote_error (dbus_error);
+		*client_error = dbus_error;
+	}
+
+	return TRUE;
+}
+
 typedef struct _EClientAsyncOpData
 {
 	EClient *client;
diff --git a/libedataserver/e-client.h b/libedataserver/e-client.h
index accdf91..b2ece72 100644
--- a/libedataserver/e-client.h
+++ b/libedataserver/e-client.h
@@ -144,6 +144,13 @@ void		e_client_util_free_string_slist		(GSList *strings);
 void		e_client_util_free_object_slist		(GSList *objects);
 GSList *	e_client_util_parse_comma_strings	(const gchar *capabilities);
 
+struct EClientErrorsList {
+	const gchar *name;
+	gint err_code;
+};
+
+gboolean	e_client_util_unwrap_dbus_error		(GError *dbus_error, GError **client_error, const struct EClientErrorsList *known_errors, guint known_errors_count, GQuark known_errors_domain, gboolean fail_when_none_matched);
+
 G_END_DECLS
 
 #endif /* E_CLIENT_H */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7d7694e..e96df5b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,6 +9,7 @@ addressbook/backends/vcf/e-book-backend-vcf.c
 addressbook/backends/webdav/e-book-backend-webdav.c
 addressbook/libebook/e-book.c
 addressbook/libebook/e-book-client.c
+addressbook/libebook/e-book-client-view.c
 addressbook/libebook/e-contact.c
 addressbook/libebook/e-destination.c
 addressbook/libedata-book/e-book-backend.c
@@ -22,6 +23,7 @@ calendar/backends/groupwise/e-cal-backend-groupwise.c
 calendar/backends/http/e-cal-backend-http.c
 calendar/backends/weather/e-cal-backend-weather.c
 calendar/libecal/e-cal-client.c
+calendar/libecal/e-cal-client-view.c
 calendar/libecal/e-cal-component.c
 calendar/libecal/e-cal-recur.c
 calendar/libecal/e-cal-util.c
diff --git a/tests/libebook/client/Makefile.am b/tests/libebook/client/Makefile.am
index 774cac3..327659b 100644
--- a/tests/libebook/client/Makefile.am
+++ b/tests/libebook/client/Makefile.am
@@ -23,7 +23,7 @@ TESTS =								\
 	test-client-examine					\
 	test-client-add-contact					\
 	test-client-get-contact					\
-	test-client-get-book-view				\
+	test-client-get-view					\
 	test-client-modify-contact				\
 	test-client-remove-contact				\
 	test-client-remove-contact-by-uid			\
@@ -63,10 +63,10 @@ test_client_add_contact_LDADD=$(TEST_LIBS)
 test_client_add_contact_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_examine_LDADD=$(TEST_LIBS)
 test_client_examine_CPPFLAGS=$(TEST_CPPFLAGS)
-test_client_get_book_view_LDADD=$(TEST_LIBS)
-test_client_get_book_view_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_get_contact_LDADD=$(TEST_LIBS)
 test_client_get_contact_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_view_LDADD=$(TEST_LIBS)
+test_client_get_view_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_modify_contact_LDADD=$(TEST_LIBS)
 test_client_modify_contact_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_remove_LDADD=$(TEST_LIBS)
diff --git a/tests/libebook/client/test-client-get-book-view.c b/tests/libebook/client/test-client-get-view.c
similarity index 71%
rename from tests/libebook/client/test-client-get-book-view.c
rename to tests/libebook/client/test-client-get-view.c
index 06d323b..4d2563a 100644
--- a/tests/libebook/client/test-client-get-book-view.c
+++ b/tests/libebook/client/test-client-get-view.c
@@ -7,52 +7,52 @@
 #include "client-test-utils.h"
 
 static void
-contacts_added (EBookView *book_view, const GList *contacts)
+objects_added (EBookClientView *view, const GSList *contacts)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)contacts; l; l = l->next) {
+	for (l = contacts; l; l = l->next) {
 		print_email (l->data);
 	}
 }
 
 static void
-contacts_removed (EBookView *book_view, const GList *ids)
+objects_removed (EBookClientView *view, const GSList *ids)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)ids; l; l = l->next) {
-		printf ("   Removed contact: %s\n", (gchar *)l->data);
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
 	}
 }
 
 static void
-view_complete (EBookView *book_view, EBookViewStatus status, const gchar *error_msg)
+complete (EBookClientView *view, const GError *error)
 {
-	e_book_view_stop (book_view);
-	g_object_unref (book_view);
+	e_book_client_view_stop (view, NULL);
+	g_object_unref (view);
 
 	stop_main_loop (0);
 }
 
 static void
-setup_and_start_view (EBookView *view)
+setup_and_start_view (EBookClientView *view)
 {
-	g_signal_connect (view, "contacts_added", G_CALLBACK (contacts_added), NULL);
-	g_signal_connect (view, "contacts_removed", G_CALLBACK (contacts_removed), NULL);
-	g_signal_connect (view, "view_complete", G_CALLBACK (view_complete), NULL);
+	g_signal_connect (view, "objects-added", G_CALLBACK (objects_added), NULL);
+	g_signal_connect (view, "objects-removed", G_CALLBACK (objects_removed), NULL);
+	g_signal_connect (view, "complete", G_CALLBACK (complete), NULL);
 
-	e_book_view_start (view);
+	e_book_client_view_start (view, NULL);
 }
 
 static void
-get_book_view_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+get_view_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
-	EBookView *view;
+	EBookClientView *view;
 	GError *error = NULL;
 
 	if (!e_book_client_get_view_finish (E_BOOK_CLIENT (source_object), result, &view, &error)) {
-		report_error ("get book view finish", &error);
+		report_error ("get view finish", &error);
 		stop_main_loop (1);
 
 		return;
@@ -88,7 +88,7 @@ setup_book (EBookClient **book_client)
 }
 
 static gpointer
-call_get_book_view (gpointer user_data)
+call_get_view (gpointer user_data)
 {
 	EBookQuery *query;
 	EBookClient *book_client = user_data;
@@ -101,7 +101,7 @@ call_get_book_view (gpointer user_data)
 	sexp = e_book_query_to_string (query);
 	e_book_query_unref (query);
 
-	e_book_client_get_view (book_client, sexp, NULL, get_book_view_cb, NULL);
+	e_book_client_get_view (book_client, sexp, NULL, get_view_cb, NULL);
 
 	g_free (sexp);
 
@@ -113,7 +113,7 @@ main (gint argc, gchar **argv)
 {
 	EBookClient *book_client;
 	EBookQuery *query;
-	EBookView *view;
+	EBookClientView *view;
 	gchar *sexp;
 	GError *error = NULL;
 
@@ -157,7 +157,7 @@ main (gint argc, gchar **argv)
 	if (!setup_book (&book_client))
 		return 1;
 
-	start_in_idle_with_main_loop (call_get_book_view, book_client);
+	start_in_idle_with_main_loop (call_get_view, book_client);
 
 	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
 		report_error ("client remove sync", &error);
diff --git a/tests/libebook/client/test-client-stress-views.c b/tests/libebook/client/test-client-stress-views.c
index 4628e56..e6638da 100644
--- a/tests/libebook/client/test-client-stress-views.c
+++ b/tests/libebook/client/test-client-stress-views.c
@@ -9,37 +9,37 @@
 #define NUM_VIEWS 200
 
 static void
-contacts_added (EBookView *book_view, const GList *contacts)
+objects_added (EBookClientView *view, const GSList *contacts)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)contacts; l; l = l->next) {
+	for (l = contacts; l; l = l->next) {
 		print_email (l->data);
 	}
 }
 
 static void
-contacts_removed (EBookView *book_view, const GList *ids)
+objects_removed (EBookClientView *view, const GSList *ids)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)ids; l; l = l->next) {
-		printf ("   Removed contact: %s\n", (gchar *)l->data);
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
 	}
 }
 
 static void
-view_complete (EBookView *book_view, EBookViewStatus status, const gchar *error_msg)
+complete (EBookClientView *view, const GError *error)
 {
-	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", status, error_msg ? "'" : "", error_msg ? error_msg : "NULL", error_msg ? "'" : "");
+	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", error ? error->code : 0, error ? "'" : "", error ? error->message : "NULL", error ? "'" : "");
 }
 
 static gint
 stress_book_views (EBookClient *book_client, gboolean in_thread)
 {
 	EBookQuery *query;
-	EBookView *view = NULL;
-	EBookView *new_view;
+	EBookClientView *view = NULL;
+	EBookClientView *new_view;
 	gchar *sexp;
 	gint i;
 
@@ -60,25 +60,25 @@ stress_book_views (EBookClient *book_client, gboolean in_thread)
 			return 1;
 		}
 
-		g_signal_connect (new_view, "contacts_added", G_CALLBACK (contacts_added), NULL);
-		g_signal_connect (new_view, "contacts_removed", G_CALLBACK (contacts_removed), NULL);
-		g_signal_connect (new_view, "view_complete", G_CALLBACK (view_complete), NULL);
+		g_signal_connect (new_view, "objects-added", G_CALLBACK (objects_added), NULL);
+		g_signal_connect (new_view, "objects-removed", G_CALLBACK (objects_removed), NULL);
+		g_signal_connect (new_view, "complete", G_CALLBACK (complete), NULL);
 
-		e_book_view_start (new_view);
+		e_book_client_view_start (new_view, NULL);
 
 		if (view) {
 			/* wait 100 ms when in a thread */
 			if (in_thread)
 				g_usleep (100000);
 
-			e_book_view_stop (view);
+			e_book_client_view_stop (view, NULL);
 			g_object_unref (view);
 		}
 
 		view = new_view;
 	}
 
-	e_book_view_stop (view);
+	e_book_client_view_stop (view, NULL);
 	g_object_unref (view);
 
 	g_free (sexp);
diff --git a/tests/libecal/client/test-client-get-view.c b/tests/libecal/client/test-client-get-view.c
index e85c597..4ce3456 100644
--- a/tests/libecal/client/test-client-get-view.c
+++ b/tests/libecal/client/test-client-get-view.c
@@ -32,9 +32,9 @@ subtest_passed (SubTestId id)
 }
 
 static void
-objects_added_cb (GObject *object, GList *objects, gpointer data)
+objects_added_cb (GObject *object, const GSList *objects, gpointer data)
 {
-	GList *l;
+	const GSList *l;
 
 	for (l = objects; l; l = l->next)
                 g_print ("Object added %s (%s)\n", icalcomponent_get_uid (l->data), icalcomponent_get_summary (l->data));
@@ -43,9 +43,9 @@ objects_added_cb (GObject *object, GList *objects, gpointer data)
 }
 
 static void
-objects_modified_cb (GObject *object, GList *objects, gpointer data)
+objects_modified_cb (GObject *object, const GSList *objects, gpointer data)
 {
-	GList *l;
+	const GSList *l;
 
 	for (l = objects; l; l = l->next)
                 g_print ("Object modified %s (%s)\n", icalcomponent_get_uid (l->data), icalcomponent_get_summary (l->data));
@@ -54,9 +54,9 @@ objects_modified_cb (GObject *object, GList *objects, gpointer data)
 }
 
 static void
-objects_removed_cb (GObject *object, GList *objects, gpointer data)
+objects_removed_cb (GObject *object, const GSList *objects, gpointer data)
 {
-	GList *l;
+	const GSList *l;
 
 	for (l = objects; l; l = l->next) {
 		ECalComponentId *id = l->data;
@@ -68,9 +68,9 @@ objects_removed_cb (GObject *object, GList *objects, gpointer data)
 }
 
 static void
-view_complete_cb (GObject *object, ECalendarStatus status, const gchar *error_msg, gpointer data)
+complete_cb (GObject *object, const GError *error, gpointer data)
 {
-        g_print ("View complete (status: %d, error_msg:%s)\n", status, error_msg ? error_msg : "NULL");
+        g_print ("View complete (status: %d, error_msg:%s)\n", error ? error->code : 0, error ? error->message : "NULL");
 
 	subtest_passed (SUBTEST_VIEW_DONE);
 }
@@ -128,7 +128,7 @@ static void
 async_get_view_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
 	ECalClient *cal_client = E_CAL_CLIENT (source_object);
-	ECalView *view = NULL;
+	ECalClientView *view = NULL;
 	GError *error = NULL;
 
 	g_return_if_fail (cal_client != NULL);
@@ -143,11 +143,11 @@ async_get_view_ready (GObject *source_object, GAsyncResult *result, gpointer use
 	g_signal_connect (view, "objects_added", G_CALLBACK (objects_added_cb), cal_client);
 	g_signal_connect (view, "objects_modified", G_CALLBACK (objects_modified_cb), cal_client);
 	g_signal_connect (view, "objects_removed", G_CALLBACK (objects_removed_cb), cal_client);
-	g_signal_connect (view, "view_complete", G_CALLBACK (view_complete_cb), cal_client);
+	g_signal_connect (view, "complete", G_CALLBACK (complete_cb), cal_client);
 
 	g_object_set_data_full (G_OBJECT (cal_client), "cal-view", view, g_object_unref);
 
-	e_cal_view_start (view);
+	e_cal_client_view_start (view, NULL);
 
 	alter_cal_client (cal_client);
 }
@@ -167,7 +167,7 @@ get_view_async (gpointer user_data)
 gint
 main (gint argc, gchar **argv)
 {
-	ECalView *view = NULL;
+	ECalClientView *view = NULL;
 	ECalClient *cal_client;
 	GError *error = NULL;
 
@@ -192,9 +192,9 @@ main (gint argc, gchar **argv)
 	g_signal_connect (view, "objects_added", G_CALLBACK (objects_added_cb), cal_client);
 	g_signal_connect (view, "objects_modified", G_CALLBACK (objects_modified_cb), cal_client);
 	g_signal_connect (view, "objects_removed", G_CALLBACK (objects_removed_cb), cal_client);
-	g_signal_connect (view, "view_complete", G_CALLBACK (view_complete_cb), cal_client);
+	g_signal_connect (view, "complete", G_CALLBACK (complete_cb), cal_client);
 
-	e_cal_view_start (view);
+	e_cal_client_view_start (view, NULL);
 
 	start_in_thread_with_main_loop (alter_cal_client, cal_client);
 
diff --git a/tests/libecal/client/test-client-stress-views.c b/tests/libecal/client/test-client-stress-views.c
index f564ea5..7086b76 100644
--- a/tests/libecal/client/test-client-stress-views.c
+++ b/tests/libecal/client/test-client-stress-views.c
@@ -8,36 +8,36 @@
 #define NUM_VIEWS 200
 
 static void
-objects_added (ECalView *cal_view, const GList *objects)
+objects_added (ECalClientView *cal_view, const GSList *objects)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)objects; l; l = l->next) {
+	for (l = objects; l; l = l->next) {
 		print_icomp (l->data);
 	}
 }
 
 static void
-objects_removed (ECalView *cal_view, const GList *ids)
+objects_removed (ECalClientView *view, const GSList *ids)
 {
-	GList *l;
+	const GSList *l;
 
-	for (l = (GList*)ids; l; l = l->next) {
-		printf ("   Removed contact: %s\n", (gchar *)l->data);
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
 	}
 }
 
 static void
-view_complete (ECalView *cal_view, ECalendarStatus status, const gchar *error_msg)
+complete (ECalClientView *view, const GError *error)
 {
-	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", status, error_msg ? "'" : "", error_msg ? error_msg : "NULL", error_msg ? "'" : "");
+	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", error ? error->code : 0, error ? "'" : "", error ? error->message : "NULL", error ? "'" : "");
 }
 
 static gint
 stress_cal_views (ECalClient *cal_client, gboolean in_thread)
 {
-	ECalView *view = NULL;
-	ECalView *new_view;
+	ECalClientView *view = NULL;
+	ECalClientView *new_view;
 	gint i;
 
 	g_return_val_if_fail (cal_client != NULL, -1);
@@ -54,23 +54,23 @@ stress_cal_views (ECalClient *cal_client, gboolean in_thread)
 
 		g_signal_connect (new_view, "objects_added", G_CALLBACK (objects_added), NULL);
 		g_signal_connect (new_view, "objects_removed", G_CALLBACK (objects_removed), NULL);
-		g_signal_connect (new_view, "view_complete", G_CALLBACK (view_complete), NULL);
+		g_signal_connect (new_view, "complete", G_CALLBACK (complete), NULL);
 
-		e_cal_view_start (new_view);
+		e_cal_client_view_start (new_view, NULL);
 
 		if (view) {
 			/* wait 100 ms when in a thread */
 			if (in_thread)
 				g_usleep (100000);
 
-			e_cal_view_stop (view);
+			e_cal_client_view_stop (view, NULL);
 			g_object_unref (view);
 		}
 
 		view = new_view;
 	}
 
-	e_cal_view_stop (view);
+	e_cal_client_view_stop (view, NULL);
 	g_object_unref (view);
 
 	return 0;



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