[evolution-mapi] Merge common parts of EBookBackend-s and make it more asynchronous



commit 25f4ad0c57f451a0655e0399ea71ce3ecffb642b
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jul 21 16:01:34 2010 +0200

    Merge common parts of EBookBackend-s and make it more asynchronous
    
    Make sure to delete
    $PREFIX/lib/evolution-data-server-1.2/extensions/libebookbackendmapigal.*
    as this one was removed, merged to libebookbackendmapi.*, so if not removed
    then e-addressbook-factory claims about two factories trying to register
    with the same name.

 src/addressbook/Makefile.am                       |   24 +-
 src/addressbook/e-book-backend-mapi-contacts.c    | 1202 +++++++++
 src/addressbook/e-book-backend-mapi-contacts.h    |   56 +
 src/addressbook/e-book-backend-mapi-factory.c     |   27 +-
 src/addressbook/e-book-backend-mapi-gal-factory.c |   51 -
 src/addressbook/e-book-backend-mapi-gal.c         |  906 +------
 src/addressbook/e-book-backend-mapi-gal.h         |   32 +-
 src/addressbook/e-book-backend-mapi-utils.c       |  465 ----
 src/addressbook/e-book-backend-mapi-utils.h       |   47 -
 src/addressbook/e-book-backend-mapi.c             | 2998 +++++++++++----------
 src/addressbook/e-book-backend-mapi.h             |   99 +-
 src/libexchangemapi/exchange-mapi-connection.c    |    6 +-
 src/libexchangemapi/exchange-mapi-connection.h    |    2 +-
 13 files changed, 3001 insertions(+), 2914 deletions(-)
---
diff --git a/src/addressbook/Makefile.am b/src/addressbook/Makefile.am
index ec55a5f..6a715f7 100644
--- a/src/addressbook/Makefile.am
+++ b/src/addressbook/Makefile.am
@@ -7,22 +7,16 @@ AM_CPPFLAGS =					\
 	$(LIBEDATABOOK_CFLAGS)			\
 	$(LIBMAPI_CFLAGS)
 
-extension_LTLIBRARIES = libebookbackendmapi.la \
-			libebookbackendmapigal.la
+extension_LTLIBRARIES = libebookbackendmapi.la
 
 libebookbackendmapi_la_SOURCES =		\
 	e-book-backend-mapi.c			\
 	e-book-backend-mapi.h			\
-	e-book-backend-mapi-utils.c		\
-	e-book-backend-mapi-utils.h		\
-	e-book-backend-mapi-factory.c
-
-libebookbackendmapigal_la_SOURCES =		\
+	e-book-backend-mapi-contacts.c		\
+	e-book-backend-mapi-contacts.h		\
 	e-book-backend-mapi-gal.c		\
 	e-book-backend-mapi-gal.h		\
-	e-book-backend-mapi-utils.c		\
-	e-book-backend-mapi-utils.h		\
-	e-book-backend-mapi-gal-factory.c
+	e-book-backend-mapi-factory.c
 
 libebookbackendmapi_la_LIBADD =			\
 	$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la \
@@ -31,17 +25,7 @@ libebookbackendmapi_la_LIBADD =			\
 	$(LIBEDATABOOK_LIBS)			\
 	$(LIBMAPI_LIBS)
 
-libebookbackendmapigal_la_LIBADD =			\
-	$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la \
-	$(LIBEBACKEND_LIBS)			\
-	$(LIBEBOOK_LIBS)			\
-	$(LIBEDATABOOK_LIBS)			\
-	$(LIBMAPI_LIBS)
-
 libebookbackendmapi_la_LDFLAGS =		\
 	-module -avoid-version $(NO_UNDEFINED)
 
-libebookbackendmapigal_la_LDFLAGS =		\
-	-module -avoid-version $(NO_UNDEFINED)
-
 -include $(top_srcdir)/git.mk
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
new file mode 100644
index 0000000..71a45eb
--- /dev/null
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -0,0 +1,1202 @@
+/* -*- 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/>
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include <sys/time.h>
+/*
+** #include <glib/gi18n-lib.h>
+*/
+
+#include <libedataserver/e-sexp.h>
+#include "libedataserver/e-flag.h"
+#include <libebook/e-contact.h>
+#include <camel/camel.h>
+
+#include <libedata-book/e-book-backend-sexp.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+#include <libedata-book/e-book-backend-cache.h>
+#include <libedata-book/e-book-backend-summary.h>
+
+#include "e-book-backend-mapi-contacts.h"
+
+G_DEFINE_TYPE (EBookBackendMAPIContacts, e_book_backend_mapi_contacts, E_TYPE_BOOK_BACKEND_MAPI)
+
+struct _EBookBackendMAPIContactsPrivate
+{
+	mapi_id_t fid;
+	gboolean is_public_folder;
+};
+
+static gboolean
+build_restriction_emails_contains (struct mapi_SRestriction *res, const gchar *query)
+{
+	gchar *email=NULL, *tmp, *tmp1;
+
+	/* This currently supports "email foo bar soo" */
+	tmp = strdup (query);
+
+	tmp = strstr (tmp, "email");
+	if (tmp ) {
+		tmp = strchr (tmp, '\"');
+		if (tmp && ++tmp) {
+			tmp = strchr (tmp, '\"');
+			if (tmp && ++tmp) {
+				tmp1 = tmp;
+				tmp1 = strchr (tmp1, '\"');
+				if (tmp1) {
+					*tmp1 = 0;
+					email = tmp;
+				}
+			}
+		}
+	}
+
+	if (email==NULL || !strchr (email, '@'))
+		return FALSE;
+
+	res->rt = RES_PROPERTY;
+	res->res.resProperty.relop = RES_PROPERTY;
+	res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
+	res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
+	res->res.resProperty.lpProp.value.lpszA = email;
+
+	return TRUE;
+}
+
+#if 0
+static gboolean
+build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
+					    struct mapi_SRestriction_or *or_res,
+					    const gchar *query, gchar **to_free)
+{
+	gchar *email=NULL, *tmp, *tmp1;
+	//Number of restriction to apply
+	guint res_count = 6;
+
+	g_return_val_if_fail (to_free != NULL, FALSE);
+
+	/* This currently supports "email foo bar soo" */
+	*to_free = strdup (query);
+
+	tmp = strstr (*to_free, "email");
+	if (tmp ) {
+		tmp = strchr (tmp, '\"');
+		if (tmp && ++tmp) {
+			tmp = strchr (tmp, '\"');
+			if (tmp && ++tmp) {
+				tmp1 = tmp;
+				tmp1 = strchr (tmp1, '\"');
+				if (tmp1) {
+					*tmp1 = 0;
+					email = tmp;
+				}
+			}
+		}
+	}
+
+	if (email==NULL || !strchr (email, '@')) {
+		g_free (*to_free);
+		*to_free = NULL;
+
+		return FALSE;
+	}
+
+	or_res[0].rt = RES_CONTENT;
+	or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
+	or_res[0].res.resContent.lpProp.value.lpszA = email;
+
+	or_res[1].rt = RES_CONTENT;
+	or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
+	or_res[1].res.resContent.lpProp.value.lpszA = email;
+
+	or_res[2].rt = RES_CONTENT;
+	or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
+	or_res[2].res.resContent.lpProp.value.lpszA = email;
+
+	or_res[3].rt = RES_CONTENT;
+	or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[3].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail1OriginalDisplayName, NULL);
+	or_res[3].res.resContent.lpProp.value.lpszA = email;
+
+	or_res[4].rt = RES_CONTENT;
+	or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[4].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail2OriginalDisplayName, NULL);
+	or_res[4].res.resContent.lpProp.value.lpszA = email;
+
+	or_res[5].rt = RES_CONTENT;
+	or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+	or_res[5].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail3OriginalDisplayName, NULL);
+	or_res[5].res.resContent.lpProp.value.lpszA = email;
+
+	res = g_new0 (struct mapi_SRestriction, 1);
+
+	res->rt = RES_OR;
+	res->res.resOr.cRes = res_count;
+	res->res.resOr.res = or_res;
+
+	return TRUE;
+}
+#endif
+
+static uint32_t
+string_to_bin (TALLOC_CTX *mem_ctx, const gchar *str, uint8_t **lpb)
+{
+	uint32_t len, i;
+
+	g_return_val_if_fail (str != NULL, 0);
+	g_return_val_if_fail (lpb != NULL, 0);
+
+	len = strlen (str);
+	g_return_val_if_fail ((len & 1) == 0, 0);
+
+	len = len / 2;
+	*lpb = talloc_zero_array (mem_ctx, uint8_t, len);
+
+	i = 0;
+	while (*str && i < len) {
+		gchar c1 = str[0], c2 = str[1];
+		str += 2;
+
+		g_return_val_if_fail ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f') || (c1 >= 'A' && c1 <= 'F'), 0);
+		g_return_val_if_fail ((c2 >= '0' && c2 <= '9') || (c2 >= 'a' && c2 <= 'f') || (c2 >= 'A' && c2 <= 'F'), 0);
+
+		#define deHex(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : (((x) >= 'a' && (x) <= 'f') ? (x) - 'a' + 10 : (x) - 'A' + 10))
+		(*lpb)[i] = (deHex (c1) << 4) | (deHex (c2));
+		#undef deHex
+		i++;
+	}
+
+	return len;
+}
+
+static gint
+cmp_member_id (gconstpointer a, gconstpointer b, gpointer ht)
+{
+	gchar *va, *vb;
+	gint res;
+
+	if (!a)
+		return b ? -1 : 0;
+	if (!b)
+		return 1;
+
+	va = e_vcard_attribute_get_value ((EVCardAttribute *) a);
+	vb = e_vcard_attribute_get_value ((EVCardAttribute *) b);
+
+	res = GPOINTER_TO_INT (g_hash_table_lookup (ht, va)) - GPOINTER_TO_INT (g_hash_table_lookup (ht, vb));
+
+	g_free (va);
+	g_free (vb);
+
+	return res;
+}
+
+typedef struct {
+	EContact *contact;
+	EBookBackendCache *cache;
+} MapiCreateitemData;
+
+static gboolean
+mapi_book_write_props (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropValue **values, uint32_t *n_values, gpointer data)
+{
+	/* Do not make this array static, below function modifies it.
+	   The array is used to just ensure named ids are known later. */
+	ResolveNamedIDsData nids[] = {
+		{ PidLidDistributionListName, 0 },
+		{ PidLidDistributionListOneOffMembers, 0 },
+		{ PidLidDistributionListMembers, 0 },
+		{ PidLidDistributionListChecksum, 0 },
+		{ PidLidFileUnder, 0 },
+		{ PidLidFileUnderId, 0 },
+		{ PidLidEmail1OriginalDisplayName, 0 },
+		{ PidLidEmail1EmailAddress, 0 },
+		{ PidLidEmail2EmailAddress, 0 },
+		{ PidLidEmail3EmailAddress, 0 },
+		{ PidLidHtml, 0 },
+		{ PidLidInstantMessagingAddress, 0 },
+		{ PidLidHomeAddress, 0 },
+		{ PidLidWorkAddress, 0 },
+		{ PidLidEmail2OriginalDisplayName, 0 },
+		{ PidLidEmail3OriginalDisplayName, 0 }
+	};
+
+	MapiCreateitemData *mcd = data;
+
+	#define set_str_value(hex, val) G_STMT_START { \
+		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, hex, val ? val : "")) \
+			return FALSE;	\
+		} G_STMT_END
+
+	#define set_str_named_value(named_id, val) G_STMT_START { \
+		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, named_id, val ? val : "")) \
+			return FALSE;	\
+		} G_STMT_END
+
+	#define set_str_con_value(hex, field_id) G_STMT_START { \
+		if (e_contact_get (mcd->contact, field_id)) { \
+			set_str_value (hex, e_contact_get (mcd->contact, field_id)); \
+		} } G_STMT_END
+
+	#define set_str_named_con_value(named_id, field_id) G_STMT_START { \
+		if (e_contact_get (mcd->contact, field_id)) { \
+			set_str_named_value (named_id, e_contact_get (mcd->contact, field_id)); \
+		} } G_STMT_END
+
+	g_return_val_if_fail (mcd != NULL, FALSE);
+	g_return_val_if_fail (mcd->contact != NULL, FALSE);
+	g_return_val_if_fail (conn != NULL, FALSE);
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+	g_return_val_if_fail (values != NULL, FALSE);
+	g_return_val_if_fail (n_values != NULL, FALSE);
+
+	if (!exchange_mapi_connection_resolve_named_props (conn, fid, nids, G_N_ELEMENTS (nids), NULL))
+		return FALSE;
+
+	if (GPOINTER_TO_INT (e_contact_get (mcd->contact, E_CONTACT_IS_LIST))) {
+		EContact *old_contact;
+		GList *local, *l;
+		struct BinaryArray_r *members, *oneoff_members;
+		uint32_t list_size = 0, u32, crc32 = 0;
+		GHashTable *member_values = NULL, *member_ids = NULL;
+
+		old_contact = e_contact_get_const (mcd->contact, E_CONTACT_UID) ? e_book_backend_cache_get_contact (mcd->cache, e_contact_get_const (mcd->contact, E_CONTACT_UID)) : NULL;
+		if (old_contact) {
+			member_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+			member_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+			local = e_contact_get_attributes (old_contact, E_CONTACT_EMAIL);
+			for (l = local; l; l = l->next) {
+				EVCardAttribute *attr = l->data;
+				GList *param;
+
+				if (!attr)
+					continue;
+
+				param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERVALUE);
+				if (param && param->data && !param->next) {
+					g_hash_table_insert (member_values, e_vcard_attribute_get_value (attr), g_strdup (param->data));
+				}
+
+				param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERID);
+				if (param && param->data && !param->next) {
+					g_hash_table_insert (member_ids, e_vcard_attribute_get_value (attr), GINT_TO_POINTER (atoi (param->data)));
+				}
+			}
+
+			g_object_unref (old_contact);
+			g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
+			g_list_free (local);
+		}
+
+		set_str_value (PR_MESSAGE_CLASS, IPM_DISTLIST);
+		u32 = 0xFFFFFFFF;
+		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, PidLidFileUnderId, &u32))
+			return FALSE;
+		set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
+		set_str_named_con_value (PidLidDistributionListName, E_CONTACT_FILE_AS);
+		set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FILE_AS);
+		set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
+
+
+		local = e_contact_get_attributes (mcd->contact, E_CONTACT_EMAIL);
+		if (member_ids)
+			local = g_list_sort_with_data (local, cmp_member_id, member_ids);
+
+		members = talloc_zero (mem_ctx, struct BinaryArray_r);
+		members->cValues = 0;
+		members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
+
+		oneoff_members = talloc_zero (mem_ctx, struct BinaryArray_r);
+		oneoff_members->cValues = 0;
+		oneoff_members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
+
+		for (l = local; l; l = l->next) {
+			EVCardAttribute *attr = (EVCardAttribute *) l->data;
+			gchar *raw;
+			CamelInternetAddress *addr;
+
+			if (!attr)
+				continue;
+
+			raw = e_vcard_attribute_get_value (attr);
+			if (!raw)
+				continue;
+
+			addr = camel_internet_address_new ();
+			if (camel_address_decode (CAMEL_ADDRESS (addr), raw) > 0) {
+				const gchar *nm = NULL, *eml = NULL;
+
+				camel_internet_address_get (addr, 0, &nm, &eml);
+				if (eml) {
+					/* keep both lists in sync */
+					if (member_values && g_hash_table_lookup (member_values, raw)) {
+						/* stored ListMembers values when contact's value didn't change */
+						members->lpbin[members->cValues].cb = string_to_bin (mem_ctx, g_hash_table_lookup (member_values, raw), &members->lpbin[members->cValues].lpb);
+						members->cValues++;
+					} else {
+						exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &members->lpbin[members->cValues], nm ? nm : "", eml);
+						members->cValues++;
+					}
+
+					exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &oneoff_members->lpbin[oneoff_members->cValues], nm ? nm : "", eml);
+					oneoff_members->cValues++;
+
+					list_size += MAX (oneoff_members->lpbin[oneoff_members->cValues - 1].cb, members->lpbin[members->cValues - 1].cb);
+					crc32 = exchange_mapi_utils_push_crc32 (crc32, members->lpbin[members->cValues - 1].lpb, members->lpbin[members->cValues - 1].cb);
+				}
+			}
+
+			g_object_unref (addr);
+			g_free (raw);
+		}
+
+		if (member_values)
+			g_hash_table_destroy (member_values);
+		if (member_ids)
+			g_hash_table_destroy (member_ids);
+		g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
+		g_list_free (local);
+
+		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+			PidLidDistributionListOneOffMembers, oneoff_members))
+			return FALSE;
+
+		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+			PidLidDistributionListMembers, members))
+			return FALSE;
+
+		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+			PidLidDistributionListChecksum, &crc32))
+			return FALSE;
+
+		/* list_size shouldn't exceed 15000 bytes, is so, use a stream instead of those properties above, but for now... */
+		if (list_size > 15000)
+			return FALSE;
+
+		return TRUE;
+	}
+
+	set_str_value (PR_MESSAGE_CLASS, IPM_CONTACT);
+	set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
+
+	set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FULL_NAME);
+	set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
+	set_str_named_con_value (PidLidEmail1OriginalDisplayName, E_CONTACT_EMAIL_1);
+	/*set_str_named_con_value (PidLidEmail1EmailAddress, E_CONTACT_EMAIL_1);*/
+
+	/*set_str_con_value (0x8083001e, E_CONTACT_EMAIL_1);*/
+	set_str_named_con_value (PidLidEmail2EmailAddress, E_CONTACT_EMAIL_2);
+
+	set_str_named_con_value (PidLidEmail3EmailAddress, E_CONTACT_EMAIL_3);
+	/*set_str_named_con_value (PidLidEmail3OriginalDisplayName, E_CONTACT_EMAIL_3);*/
+
+	set_str_named_con_value (PidLidHtml, E_CONTACT_HOMEPAGE_URL);
+	set_str_named_con_value (PidLidFreeBusyLocation, E_CONTACT_FREEBUSY_URL);
+
+	set_str_con_value (PR_OFFICE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS);
+	set_str_con_value (PR_HOME_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_HOME);
+	set_str_con_value (PR_MOBILE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_MOBILE);
+	set_str_con_value (PR_HOME_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_HOME_FAX);
+	set_str_con_value (PR_BUSINESS_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS_FAX);
+	set_str_con_value (PR_PAGER_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_PAGER);
+	set_str_con_value (PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_ASSISTANT);
+	set_str_con_value (PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, E_CONTACT_PHONE_COMPANY);
+
+	set_str_con_value (PR_MANAGER_NAME_UNICODE, E_CONTACT_MANAGER);
+	set_str_con_value (PR_ASSISTANT_UNICODE, E_CONTACT_ASSISTANT);
+	set_str_con_value (PR_COMPANY_NAME_UNICODE, E_CONTACT_ORG);
+	set_str_con_value (PR_DEPARTMENT_NAME_UNICODE, E_CONTACT_ORG_UNIT);
+	set_str_con_value (PR_PROFESSION_UNICODE, E_CONTACT_ROLE);
+	set_str_con_value (PR_TITLE_UNICODE, E_CONTACT_TITLE);
+
+	set_str_con_value (PR_OFFICE_LOCATION_UNICODE, E_CONTACT_OFFICE);
+	set_str_con_value (PR_SPOUSE_NAME_UNICODE, E_CONTACT_SPOUSE);
+
+	set_str_con_value (PR_BODY_UNICODE, E_CONTACT_NOTE);
+	set_str_con_value (PR_NICKNAME_UNICODE, E_CONTACT_NICKNAME);
+
+	/* BDAY AND ANNV */
+	if (e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE)) {
+		EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE);
+		struct tm tmtime;
+		time_t lt;
+		NTTIME nt;
+		struct FILETIME t;
+
+		tmtime.tm_mday = date->day;
+		tmtime.tm_mon = date->month - 1;
+		tmtime.tm_year = date->year - 1900;
+
+		lt = mktime (&tmtime);
+		unix_to_nt_time (&nt, lt);
+		t.dwLowDateTime = (nt << 32) >> 32;
+		t.dwHighDateTime = (nt >> 32);
+
+		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_BIRTHDAY, &t))
+			return FALSE;
+	}
+
+	if (e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY)) {
+		EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY);
+		struct tm tmtime;
+		time_t lt;
+		NTTIME nt;
+		struct FILETIME t;
+
+		tmtime.tm_mday = date->day;
+		tmtime.tm_mon = date->month - 1;
+		tmtime.tm_year = date->year - 1900;
+
+		lt = mktime (&tmtime);
+		unix_to_nt_time (&nt, lt);
+		t.dwLowDateTime = (nt << 32) >> 32;
+		t.dwHighDateTime = (nt >> 32);
+
+		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_WEDDING_ANNIVERSARY, &t))
+			return FALSE;
+	}
+
+	/* Home and Office address */
+	if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME)) {
+		EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME);
+
+		set_str_named_value (PidLidHomeAddress, contact_addr->street);
+		set_str_value (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
+		set_str_value (PR_HOME_ADDRESS_CITY_UNICODE, contact_addr->locality);
+		set_str_value (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
+		set_str_value (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE, contact_addr->code);
+		set_str_value (PR_HOME_ADDRESS_COUNTRY_UNICODE, contact_addr->country);
+	}
+
+	if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK)) {
+		EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK);
+
+		set_str_named_value (PidLidWorkAddress, contact_addr->street);
+		set_str_value (PR_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
+		set_str_value (PR_LOCALITY_UNICODE, contact_addr->locality);
+		set_str_value (PR_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
+		set_str_value (PR_POSTAL_CODE_UNICODE, contact_addr->code);
+		set_str_value (PR_COUNTRY_UNICODE, contact_addr->country);
+	}
+
+	if (e_contact_get (mcd->contact, E_CONTACT_IM_AIM)) {
+		GList *l = e_contact_get (mcd->contact, E_CONTACT_IM_AIM);
+		set_str_named_value (PidLidInstantMessagingAddress, l->data);
+	}
+
+	return TRUE;
+}
+
+struct FetchContactItemData
+{
+	EBookBackendMAPI *ebma;
+	EContact *contact; /* out */
+};
+
+static gboolean
+fetch_contact_item_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct FetchContactItemData *fcid = data;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (fcid->ebma != NULL, FALSE);
+
+	fcid->contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcid->ebma), item_data->properties, NULL);
+
+	if (fcid->contact) {
+		gchar *suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		e_contact_set (fcid->contact, E_CONTACT_UID, suid);
+
+		if (!e_book_backend_mapi_notify_contact_update (fcid->ebma, NULL, fcid->contact, NULL, item_data->index, item_data->total, NULL)) {
+			g_free (suid);
+			return FALSE;
+		}
+
+		g_free (suid);
+	}
+
+	return TRUE;
+}
+
+struct CreateContactListData
+{
+	EBookBackendMAPI *ebma;
+	GList **vCards;
+};
+
+static gboolean
+create_contact_list_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct CreateContactListData *ccld = data;
+	EContact *contact;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (ccld->ebma != NULL, FALSE);
+	g_return_val_if_fail (ccld->vCards != NULL, FALSE);
+
+	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (ccld->ebma), item_data->properties, NULL);
+	if (contact) {
+		gchar *suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+
+		e_contact_set (contact, E_CONTACT_UID, suid);
+
+		*ccld->vCards = g_list_prepend (*ccld->vCards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
+
+		e_book_backend_mapi_notify_contact_update (ccld->ebma, NULL, contact, NULL, -1, -1, NULL);
+
+		g_object_unref (contact);
+		g_free (suid);
+	}
+
+	return TRUE;
+}
+
+struct FetchContactsData
+{
+	EBookBackendMAPI *ebma;
+	EDataBookView *book_view;
+	gpointer notify_contact_data;
+};
+
+static gboolean
+fetch_contacts_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct FetchContactsData *fcd = data;
+	EContact *contact;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (fcd->ebma != NULL, FALSE);
+	g_return_val_if_fail (fcd->ebma->priv != NULL, FALSE);
+
+	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcd->ebma), item_data->properties, NULL);
+
+	if (contact) {
+		gchar *suid;
+		struct timeval *last_modification = NULL, tv = { 0 };
+
+		suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+		e_contact_set (contact, E_CONTACT_UID, suid);
+		g_free (suid);
+
+		if (get_mapi_SPropValue_array_date_timeval (&tv, item_data->properties, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS)
+			last_modification = &tv;
+
+		if (!e_book_backend_mapi_notify_contact_update (fcd->ebma, fcd->book_view, contact, last_modification, item_data->index, item_data->total, fcd->notify_contact_data)) {
+			g_object_unref (contact);
+			return FALSE;
+		}
+
+		g_object_unref (contact);
+	}
+
+	return TRUE;
+}
+
+struct FetchContactsUidsData
+{
+	GCancellable *cancelled;
+	GHashTable *uids;
+};
+
+static gboolean
+fetch_contacts_uids_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct FetchContactsUidsData *fcud = data;
+	gchar *suid;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+	
+	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	if (suid)
+		g_hash_table_insert (fcud->uids, suid, GINT_TO_POINTER (1));
+
+	return !g_cancellable_is_cancelled (fcud->cancelled);
+}
+
+static void
+ebbm_contacts_load_source (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **perror)
+{
+	EBookBackendMAPIContactsPrivate *priv = ((EBookBackendMAPIContacts *) ebma)->priv;
+	GError *err = NULL;
+
+	if (e_book_backend_is_loaded (E_BOOK_BACKEND (ebma)))
+		return /* Success */;
+
+	priv->fid = 0;
+	priv->is_public_folder = e_source_get_property (source, "public") && g_str_equal (e_source_get_property (source, "public"), "yes");
+
+	exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+
+	/* Chain up to parent's op_load_source() method. */
+	if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_load_source)
+		E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_load_source (ebma, source, only_if_exists, &err);
+
+	if (err)
+		g_propagate_error (perror, err);
+}
+
+static void
+ebbm_contacts_connection_status_changed (EBookBackendMAPI *ebma, gboolean is_online)
+{
+	e_book_backend_set_is_writable (E_BOOK_BACKEND (ebma), is_online);
+	e_book_backend_notify_writable (E_BOOK_BACKEND (ebma), is_online);
+}
+
+static void
+ebbm_contacts_remove (EBookBackendMAPI *ebma, GError **error)
+{
+	EBookBackendMAPIContactsPrivate *priv;
+	GError *mapi_error = NULL;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = E_BOOK_BACKEND_MAPI_CONTACTS (ebma)->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	if (E_BOOK_BACKEND_MAPI_GET_CLASS (ebma)->op_remove)
+		E_BOOK_BACKEND_MAPI_GET_CLASS (ebma)->op_remove (ebma, &mapi_error);
+
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
+		g_error_free (mapi_error);
+		return;
+	}
+
+	if (priv->is_public_folder) {
+		ExchangeMapiConnection *conn;
+
+		e_book_backend_mapi_lock_connection (ebma);
+
+		conn = e_book_backend_mapi_get_connection (ebma);
+		if (!conn) {
+			g_propagate_error (error, EDB_ERROR (OFFLINE_UNAVAILABLE));
+		} else {
+			exchange_mapi_connection_remove_folder (conn, priv->fid, MAPI_OPTIONS_USE_PFSTORE, &mapi_error);
+
+			if (mapi_error) {
+				mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder"));
+				g_error_free (mapi_error);
+			}
+		}
+
+		e_book_backend_mapi_unlock_connection (ebma);
+	}
+}
+
+static void
+ebbm_contacts_create_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	MapiCreateitemData mcd;
+	GError *mapi_error = NULL;
+	mapi_id_t mid;
+	gchar *id;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (contact != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	*contact = e_contact_new_from_vcard (vcard);
+	if (!*contact) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	e_book_backend_mapi_get_summary_and_cache (ebma, NULL, &mcd.cache);
+	mcd.contact = *contact;
+
+	mid = exchange_mapi_connection_create_item (conn, olFolderContacts, priv->fid,
+		mapi_book_write_props, &mcd,
+		NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, &mapi_error);
+
+	e_book_backend_mapi_unlock_connection (ebma);
+
+	if (!mid) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server"));
+
+		if (mapi_error)
+			g_error_free (mapi_error);
+
+		g_object_unref (*contact);
+		*contact = NULL;
+		return;
+	}
+
+	id = exchange_mapi_util_mapi_ids_to_uid (priv->fid, mid);
+
+	/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+	e_contact_set (*contact, E_CONTACT_UID, id);
+	e_contact_set (*contact, E_CONTACT_BOOK_URI, e_book_backend_mapi_get_book_uri (ebma));
+
+	g_free (id);
+}
+
+static void
+ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, const GList *id_list, GList **removed_ids, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	GError *mapi_error = NULL;
+	GSList *to_remove;
+	const GList *l;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (id_list != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (removed_ids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	to_remove = NULL;
+	for (l = id_list; l; l = l->next) {
+		mapi_id_t mid, fid;
+		const gchar *uid = l->data;
+		struct id_list *idl = g_new0 (struct id_list, 1);
+
+		exchange_mapi_util_mapi_ids_from_uid (uid, &fid, &mid);
+
+		idl->id = mid;
+		to_remove = g_slist_prepend (to_remove, idl);
+
+		*removed_ids = g_list_prepend (*removed_ids, g_strdup (uid));
+	}
+
+	exchange_mapi_connection_remove_items (conn, olFolderContacts, priv->fid, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, to_remove, &mapi_error);
+
+	e_book_backend_mapi_unlock_connection (ebma);
+
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
+
+		g_error_free (mapi_error);
+
+		g_list_foreach (*removed_ids, (GFunc) g_free, NULL);
+		g_list_free (*removed_ids);
+		*removed_ids = NULL;
+	}
+
+	g_slist_foreach (to_remove, (GFunc) g_free, NULL);
+	g_slist_free (to_remove);
+}
+
+static void
+ebbm_contacts_modify_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	MapiCreateitemData mcd;
+	GError *mapi_error = NULL;
+	mapi_id_t fid, mid;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (contact != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	*contact = e_contact_new_from_vcard (vcard);
+	if (!*contact) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	e_book_backend_mapi_get_summary_and_cache (ebma, NULL, &mcd.cache);
+	mcd.contact = *contact;
+
+	exchange_mapi_util_mapi_ids_from_uid (e_contact_get_const (*contact, E_CONTACT_UID), &fid, &mid);
+
+	if (!exchange_mapi_connection_modify_item (conn, olFolderContacts, priv->fid, mid,
+		mapi_book_write_props, &mcd, NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, &mapi_error)) {
+
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
+		if (mapi_error)
+			g_error_free (mapi_error);
+
+		g_object_unref (*contact);
+		*contact = NULL;
+	}
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_get_contact (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	mapi_id_t fid, mid;
+	guint32 options;
+	struct FetchContactItemData fcid = { 0 };
+	GError *mapi_error = NULL;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (id != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact)
+		E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact (ebma, id, vcard, &mapi_error);
+
+	if (mapi_error) {
+		g_propagate_error (error, mapi_error);
+		return;
+	}
+
+	/* found in a cache */
+	if (*vcard)
+		return;
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		e_book_backend_mapi_unlock_connection (ebma);
+		return;
+	}
+
+	options = MAPI_OPTIONS_FETCH_ALL;
+	if (priv->is_public_folder)
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+
+	fcid.ebma = ebma;
+	fcid.contact = NULL;
+	exchange_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
+
+	exchange_mapi_connection_fetch_item (conn, priv->fid, mid,
+		priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+		fetch_contact_item_cb, &fcid,
+		options, &mapi_error);
+
+	if (fcid.contact) {
+		*vcard =  e_vcard_to_string (E_VCARD (fcid.contact), EVC_FORMAT_VCARD_30);
+		g_object_unref (fcid.contact);
+	} else {
+		if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
+			g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
+		} else {
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL);
+		}
+
+		if (mapi_error)
+			g_error_free (mapi_error);
+	}
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	guint32 options;
+	struct CreateContactListData ccld = { 0 };
+	GError *mapi_error = NULL;
+	struct mapi_SRestriction res;
+	gboolean get_all;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (query != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (vCards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list)
+		E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list (ebma, query, vCards, &mapi_error);
+
+	if (mapi_error) {
+		g_propagate_error (error, mapi_error);
+		return;
+	}
+
+	/* found some in cache, thus use them */
+	if (*vCards)
+		return;
+
+	options = MAPI_OPTIONS_FETCH_ALL;
+	if (priv->is_public_folder)
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		return;
+	}
+
+	ccld.ebma = ebma;
+	ccld.vCards = vCards;
+
+	get_all = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
+	if (!get_all && !build_restriction_emails_contains (&res, query)) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (OTHER_ERROR));
+
+		return;
+	}
+
+	if (!exchange_mapi_connection_fetch_items (conn, priv->fid, get_all ? NULL : &res, NULL,
+		priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+		create_contact_list_cb, &ccld, options, &mapi_error)) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+		if (mapi_error)
+			g_error_free (mapi_error);
+	}
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static gchar *
+ebbm_contacts_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
+{
+	if (index <= 0)
+		return NULL;
+
+	return g_strdup_printf (
+		total <= 0 ?
+			/* Translators : This is used to cache the downloaded contacts from a server.
+			   %d is an index of the contact. */
+			_("Caching contact %d") :
+			/* Translators : This is used to cache the downloaded contacts from a server.
+			   The first %d is an index of the contact,
+			   the second %d is total count of conacts on the server. */
+			_("Caching contact %d/%d"),
+		index, total);
+}
+
+static void
+ebbm_contacts_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	guint32 options;
+	struct FetchContactsData fcd = { 0 };
+	GError *mapi_error = NULL;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+	e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		return;
+	}
+
+	fcd.ebma = ebma;
+	fcd.book_view = book_view;
+	fcd.notify_contact_data = notify_contact_data;
+
+	options = MAPI_OPTIONS_FETCH_ALL;
+	if (priv->is_public_folder)
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+
+	if (!exchange_mapi_connection_fetch_items (conn, priv->fid, restriction, NULL,
+		mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+		fetch_contacts_cb, &fcd, options, &mapi_error)) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+
+		if (mapi_error)
+			g_error_free (mapi_error);
+	}
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error)
+{
+	EBookBackendMAPIContacts *ebmac;
+	EBookBackendMAPIContactsPrivate *priv;
+	ExchangeMapiConnection *conn;
+	GError *mapi_error = NULL;
+	struct FetchContactsUidsData fcud = { 0 };
+	guint32 options;
+
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (cancelled != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (uids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+	e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebmac->priv;
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		return;
+	}
+
+	options = MAPI_OPTIONS_DONT_OPEN_MESSAGE;
+	if (priv->is_public_folder)
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+
+	fcud.cancelled = cancelled;
+	fcud.uids = uids;
+
+	exchange_mapi_connection_fetch_items (conn, priv->fid, NULL, NULL,
+		mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
+		fetch_contacts_uids_cb, &fcud, options, &mapi_error);
+
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+		g_error_free (mapi_error);
+	}
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+e_book_backend_mapi_contacts_init (EBookBackendMAPIContacts *backend)
+{
+	backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsPrivate);
+}
+
+static void
+e_book_backend_mapi_contacts_class_init (EBookBackendMAPIContactsClass *klass)
+{
+	EBookBackendMAPIClass *parent_class;
+
+	g_type_class_add_private (klass, sizeof (EBookBackendMAPIContactsPrivate));
+
+	parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
+
+	/* Set the virtual methods. */
+	parent_class->op_load_source			= ebbm_contacts_load_source;
+	parent_class->op_remove				= ebbm_contacts_remove;
+	parent_class->op_create_contact			= ebbm_contacts_create_contact;
+	parent_class->op_remove_contacts		= ebbm_contacts_remove_contacts;
+	parent_class->op_modify_contact			= ebbm_contacts_modify_contact;
+	parent_class->op_get_contact			= ebbm_contacts_get_contact;
+	parent_class->op_get_contact_list		= ebbm_contacts_get_contact_list;
+
+	parent_class->op_connection_status_changed	= ebbm_contacts_connection_status_changed;
+	parent_class->op_get_status_message     	= ebbm_contacts_get_status_message;
+	parent_class->op_fetch_contacts			= ebbm_contacts_fetch_contacts;
+	parent_class->op_fetch_known_uids		= ebbm_contacts_fetch_known_uids;
+}
+
+EBookBackend *
+e_book_backend_mapi_contacts_new (void)
+{
+	return g_object_new (E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, NULL);
+}
diff --git a/src/addressbook/e-book-backend-mapi-contacts.h b/src/addressbook/e-book-backend-mapi-contacts.h
new file mode 100644
index 0000000..c09723c
--- /dev/null
+++ b/src/addressbook/e-book-backend-mapi-contacts.h
@@ -0,0 +1,56 @@
+/* -*- 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/>
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E_BOOK_BACKEND_MAPI_CONTACTS_H__
+#define __E_BOOK_BACKEND_MAPI_CONTACTS_H__
+
+#include "e-book-backend-mapi.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BOOK_BACKEND_MAPI_CONTACTS         (e_book_backend_mapi_contacts_get_type ())
+#define E_BOOK_BACKEND_MAPI_CONTACTS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContacts))
+#define E_BOOK_BACKEND_MAPI_CONTACTS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsClass))
+#define E_IS_BOOK_BACKEND_MAPI_CONTACTS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS))
+#define E_IS_BOOK_BACKEND_MAPI_CONTACTS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS))
+#define E_BOOK_BACKEND_MAPI_CONTACTS_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsClass))
+
+typedef struct _EBookBackendMAPIContactsPrivate EBookBackendMAPIContactsPrivate;
+
+typedef struct
+{
+	EBookBackendMAPI                 parent_object;
+	EBookBackendMAPIContactsPrivate *priv;
+} EBookBackendMAPIContacts;
+
+typedef struct
+{
+	EBookBackendMAPIClass parent_class;
+} EBookBackendMAPIContactsClass;
+
+EBookBackend *e_book_backend_mapi_contacts_new      (void);
+GType         e_book_backend_mapi_contacts_get_type (void);
+
+G_END_DECLS
+
+#endif /* __E_BOOK_BACKEND_MAPI_CONTACTS_H__ */
diff --git a/src/addressbook/e-book-backend-mapi-factory.c b/src/addressbook/e-book-backend-mapi-factory.c
index b7f4eca..18fec2c 100644
--- a/src/addressbook/e-book-backend-mapi-factory.c
+++ b/src/addressbook/e-book-backend-mapi-factory.c
@@ -27,25 +27,30 @@
 
 #include <libebackend/e-data-server-module.h>
 #include <libedata-book/e-book-backend-factory.h>
-#include "e-book-backend-mapi.h"
 
-E_BOOK_BACKEND_FACTORY_SIMPLE (mapi,
-			       MAPI,
-			       e_book_backend_mapi_new)
+#include "e-book-backend-mapi-contacts.h"
+#include "e-book-backend-mapi-gal.h"
 
-static GType mapi_type;
+E_BOOK_BACKEND_FACTORY_SIMPLE (mapi,    MAPI,    e_book_backend_mapi_contacts_new)
+E_BOOK_BACKEND_FACTORY_SIMPLE (mapigal, MAPIGAL, e_book_backend_mapi_gal_new)
 
-void	eds_module_initialize (GTypeModule *module)
+static GType mapi_type[2];
+
+void
+eds_module_initialize (GTypeModule *module)
 {
-	mapi_type = _mapi_factory_get_type (module);
+	mapi_type[0] = _mapi_factory_get_type (module);
+	mapi_type[1] = _mapigal_factory_get_type (module);
 }
 
-void	eds_module_shutdown   (void)
+void
+eds_module_shutdown (void)
 {
 }
 
-void	eds_module_list_types (const GType **types, gint *num_types)
+void
+eds_module_list_types (const GType **types, gint *num_types)
 {
-	*types = &mapi_type;
-	*num_types = 1;
+	*types = mapi_type;
+	*num_types = G_N_ELEMENTS (mapi_type);
 }
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index b514e4d..b85a439 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -22,160 +22,50 @@
 #include <libedata-book/e-book-backend-summary.h>
 
 #include "e-book-backend-mapi-gal.h"
-#include "e-book-backend-mapi-utils.h"
 
-G_DEFINE_TYPE (EBookBackendMAPIGAL, e_book_backend_mapi_gal, E_TYPE_BOOK_BACKEND)
-
-static gboolean enable_debug = TRUE;
+G_DEFINE_TYPE (EBookBackendMAPIGAL, e_book_backend_mapi_gal, E_TYPE_BOOK_BACKEND_MAPI)
 
 struct _EBookBackendMAPIGALPrivate
 {
-	gchar *profile;
-	ExchangeMapiConnection *conn;
+	/* nothing to store locally at the moment,
+	   but keep it ready for any later need */
 
-	mapi_id_t fid;
-	gint mode;
-	gboolean marked_for_offline;
-	GThread *build_cache_thread;
-	gboolean kill_cache_build;
-	gboolean is_cache_ready;
-	gboolean is_summary_ready;
-	gboolean is_writable;
-	gchar *uri;
-
-	GMutex *lock;
-	gchar *summary_file_name;
-	EBookBackendSummary *summary;
-	EBookBackendCache *cache;
-
-	GStaticMutex running_mutex;
-	GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
+	gint32 unused;
 };
 
-#define SUMMARY_FLUSH_TIMEOUT 5000
-
-static gchar *
-e_book_backend_mapi_gal_get_static_capabilities (EBookBackend *backend)
-{
-	if (enable_debug)
-		printf("mapi get_static_capabilities\n");
-	//FIXME: Implement this.
-
-	return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
-}
-
-static EDataBookView *
-find_book_view (EBookBackendMAPIGAL *ebmapi)
-{
-	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebmapi));
-	EIterator *iter;
-	EDataBookView *rv = NULL;
-	gint test;
-
-	if (!views)
-		return NULL;
-
-	test = e_list_length (views);
-
-	iter = e_list_get_iterator (views);
-
-	if (!iter) {
-		g_object_unref (views);
-		return NULL;
-	}
-
-	if (e_iterator_is_valid (iter)) {
-		/* just always use the first book view */
-		EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
-		if (v)
-			rv = v;
-	}
-
-	g_object_unref (iter);
-	g_object_unref (views);
-
-	return rv;
-}
-
-static void
-book_view_notify_status (EDataBookView *view, const gchar *status)
+struct FetchGalData
 {
-	if (!view)
-		return;
-	e_data_book_view_notify_status_message (view, status);
-}
-
-static guint32
-current_time_ms (void)
-{
-	GTimeVal tv;
-
-	g_get_current_time (&tv);
-
-	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-struct fetch_gal_data
-{
-	EBookBackendMAPIGAL *ebmapi;
+	EBookBackendMAPI *ebma;
 	EDataBookView *book_view;
+	gpointer notify_contact_data;
 	mapi_id_t fid; /* folder ID of contacts, for named IDs */
-	guint32 last_update; /* when in micro-seconds was done last notification about progress */
 };
 
 static gboolean
 fetch_gal_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows, struct SRow *aRow, gpointer data)
 {
-	EBookBackendMAPIGALPrivate *priv;
-	struct fetch_gal_data *fgd = data;
+	struct FetchGalData *fgd = data;
+	struct timeval *last_modification = NULL, tv = { 0 };
+	struct SPropValue *spropval;
 	EContact *contact;
-	gchar *uid;
-	guint32 current_time;
 
 	g_return_val_if_fail (conn != NULL, FALSE);
 	g_return_val_if_fail (aRow != NULL, FALSE);
 	g_return_val_if_fail (data != NULL, FALSE);
 
-	priv = fgd->ebmapi->priv;
-	if (priv->kill_cache_build)
-		return FALSE;
-
-	contact = mapi_book_utils_contact_from_props (conn, fgd->fid, NULL, aRow);
+	contact = mapi_book_utils_contact_from_props (conn, fgd->fid, e_book_backend_mapi_get_book_uri (fgd->ebma), NULL, aRow);
 	if (!contact) {
 		/* just ignore them */
 		return TRUE;
 	}
 
-	uid = g_strdup_printf ("%d", row_index);
-	e_contact_set (contact, E_CONTACT_UID, uid);
-	g_free (uid);
-
-	e_book_backend_cache_add_contact (priv->cache, contact);
-	e_book_backend_summary_add_contact (priv->summary, contact);
-
-	if (!fgd->book_view)
-		fgd->book_view = find_book_view (fgd->ebmapi);
+	spropval = get_SPropValue_SRow (aRow, PR_LAST_MODIFICATION_TIME);
+	if (spropval && get_mapi_SPropValue_date_timeval (&tv, *spropval) == MAPI_E_SUCCESS)
+		last_modification = &tv;
 
-	if (fgd->book_view)
-		e_data_book_view_notify_update (fgd->book_view, contact);
-
-	current_time = current_time_ms ();
-	if (fgd->book_view && current_time - fgd->last_update >= 333) {
-		gchar *status_msg;
-
-		if (n_rows > 0) {
-			/* To translators : This is used to cache the downloaded contacts from GAL.
-			   The first %d is an index of the GAL entry,
-			   the second %d is total count of entries in GAL. */
-			status_msg = g_strdup_printf (_("Caching GAL entry %d/%d"), row_index, n_rows);
-		} else {
-			/* To translators : This is used to cache the downloaded contacts from GAL.
-			   %d is an index of the GAL entry. */
-			status_msg = g_strdup_printf (_("Caching GAL entry %d"), row_index);
-		}
-		book_view_notify_status (fgd->book_view, status_msg);
-		g_free (status_msg);
-		fgd->last_update = current_time;
+	if (!e_book_backend_mapi_notify_contact_update (fgd->ebma, fgd->book_view, contact, last_modification, row_index, n_rows, fgd->notify_contact_data)) {
+		g_object_unref (contact);
+		return FALSE;
 	}
 
 	g_object_unref (contact);
@@ -183,736 +73,157 @@ fetch_gal_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows,
 	return TRUE;
 }
 
-static gpointer
-build_cache (EBookBackendMAPIGAL *ebmapi)
+struct FetchGalUidsData
 {
-	EBookBackendMAPIGALPrivate *priv = ebmapi->priv;
-	GError *mapi_error = NULL;
-	gchar *tmp;
-	struct fetch_gal_data fgd = { 0 };
-
-	//FIXME: What if book view is NULL? Can it be? Check that.
-	if (!priv->cache) {
-		printf("Caching for the first time\n");
-		priv->cache = e_book_backend_cache_new (priv->uri);
-	}
-
-	fgd.ebmapi = ebmapi;
-	fgd.book_view = find_book_view (ebmapi);
-	fgd.fid = exchange_mapi_connection_get_default_folder_id (priv->conn, olFolderContacts, NULL);
-	fgd.last_update = current_time_ms ();
-
-	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
-	exchange_mapi_connection_fetch_gal (priv->conn,
-					mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-					fetch_gal_cb, &fgd, &mapi_error);
-
-	if (fgd.book_view) {
-		GError *error = NULL;
-
-		if (mapi_error) {
-			mapi_error_to_edb_error (&error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
-			g_error_free (mapi_error);
-		}
-
-		e_data_book_view_notify_complete (fgd.book_view, error);
-		e_data_book_view_unref (fgd.book_view);
-
-		if (error)
-			g_error_free (error);
-	}
-
-	tmp = g_strdup_printf("%d", priv->kill_cache_build ? 0 : (gint)time (NULL));
-	e_book_backend_cache_set_time (priv->cache, tmp);
-	printf("setting time  %s\n", tmp);
-	g_free (tmp);
+	GCancellable *cancelled;
+	GHashTable *uids;
+};
 
-	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+static gboolean
+fetch_gal_uids_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows, struct SRow *aRow, gpointer data)
+{
+	const gchar *uid;
+	struct FetchGalUidsData *fgud = data;
 
-	e_book_backend_summary_save (priv->summary);
+	g_return_val_if_fail (conn != NULL, FALSE);
+	g_return_val_if_fail (aRow != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	priv->is_cache_ready = !priv->kill_cache_build;
-	priv->is_summary_ready = !priv->kill_cache_build;
+	uid = exchange_mapi_util_find_row_propval (aRow, PR_EMAIL_ADDRESS_UNICODE);
+	if (uid)
+		g_hash_table_insert (fgud->uids, g_strdup (uid), GINT_TO_POINTER (1));
 
-	return NULL;
+	return !g_cancellable_is_cancelled (fgud->cancelled);
 }
 
 static void
-e_book_backend_mapi_gal_get_supported_fields (EBookBackend *backend,
-		      EDataBook    *book,
-		      guint32	    opid)
-
+ebbm_gal_create_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
 {
-	GList *fields;
-
-	fields = mapi_book_utils_get_supported_fields ();
-	e_data_book_respond_get_supported_fields (book,
-						  opid,
-						  NULL /* Success */,
-						  fields);
-	g_list_free (fields);
+	g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
 }
 
 static void
-e_book_backend_mapi_gal_get_required_fields (EBookBackend *backend,
-		     EDataBook *book,
-		     guint32 opid)
+ebbm_gal_remove_contacts (EBookBackendMAPI *ebma, const GList *ids, GList **removed_ids, GError **error)
 {
-	GList *fields = NULL;
-
-	fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
-	e_data_book_respond_get_required_fields (book,
-						  opid,
-						  NULL /* Success */,
-						  fields);
-	g_list_free (fields);
+	g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
 }
 
 static void
-e_book_backend_mapi_gal_authenticate_user (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid,
-					    const gchar *user,
-					    const gchar *passwd,
-					    const gchar *auth_method)
+ebbm_gal_modify_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
 {
-	EBookBackendMAPIGAL *ebmapi = (EBookBackendMAPIGAL *) backend;
-	EBookBackendMAPIGALPrivate *priv = ebmapi->priv;
-	GError *mapi_error = NULL;
-
-	if (enable_debug) {
-		printf ("mapi: authenticate user\n");
-	}
-
-	switch (priv->mode) {
-	case E_DATA_BOOK_MODE_LOCAL:
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_set_is_writable (E_BOOK_BACKEND(backend), FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
-		return;
-
-	case E_DATA_BOOK_MODE_REMOTE:
-		g_static_mutex_lock (&priv->running_mutex);
-
-		/* rather reuse already established connection */
-		priv->conn = exchange_mapi_connection_find (priv->profile);
-		if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
-			exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
-		else if (!priv->conn)
-			priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
-
-		if (!priv->conn || mapi_error) {
-			GError *err = NULL;
-
-			if (priv->conn) {
-				g_object_unref (priv->conn);
-				priv->conn = NULL;
-			}
-				
-			mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
-			e_data_book_respond_authenticate_user (book, opid, err);
-			g_static_mutex_unlock (&priv->running_mutex);
-
-			if (mapi_error)
-				g_error_free (mapi_error);
-			return;
-		}
-
-		if (priv->cache && priv->is_cache_ready) {
-			printf("FIXME: Should check for an update in the cache\n");
-//			g_thread_create ((GThreadFunc) update_cache,
-	//					  backend, FALSE, backend);
-		} else if (priv->marked_for_offline && !priv->is_cache_ready) {
-			if (!priv->build_cache_thread) {
-				/* Means we dont have a cache. Lets build that first */
-				printf("Preparing to build cache\n");
-				priv->kill_cache_build = FALSE;
-				priv->build_cache_thread = g_thread_create ((GThreadFunc) build_cache, ebmapi, TRUE, NULL);
-			}
-		}
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
-		g_static_mutex_unlock (&priv->running_mutex);
-		return;
-
-	default :
-		break;
-	}
+	g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
 }
 
 static gchar *
-get_filename_from_uri (const gchar *uri, const gchar *file)
-{
-	gchar *mangled_uri, *filename;
-	gint i;
-
-	/* mangle the URI to not contain invalid characters */
-	mangled_uri = g_strdup (uri);
-	for (i = 0; i < strlen (mangled_uri); i++) {
-		switch (mangled_uri[i]) {
-		case ':' :
-		case '/' :
-			mangled_uri[i] = '_';
-		}
-	}
-
-	/* generate the file name */
-	filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
-				     mangled_uri, file, NULL);
-
-	/* free memory */
-	g_free (mangled_uri);
-
-	return filename;
-}
-
-static void
-e_book_backend_mapi_gal_create_contact (EBookBackend *backend,
-		EDataBook    *book,
-		guint32       opid,
-		const gchar   *vcard)
+ebbm_gal_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
 {
-	e_data_book_respond_create (book, opid,
-				    EDB_ERROR (PERMISSION_DENIED),
-				    NULL);
-}
-
-static void
-e_book_backend_mapi_gal_remove_contacts (EBookBackend *backend,
-		 EDataBook    *book,
-		 guint32       opid,
-		 GList        *ids)
-{
-	e_data_book_respond_remove_contacts (book, opid,
-					     EDB_ERROR (PERMISSION_DENIED),
-					     NULL);
-}
+	if (index <= 0)
+		return NULL;
 
-static void
-e_book_backend_mapi_gal_modify_contact (EBookBackend *backend,
-		EDataBook    *book,
-		guint32       opid,
-		const gchar   *vcard)
-{
-	e_data_book_respond_modify (book, opid,
-				    EDB_ERROR (PERMISSION_DENIED),
-				    NULL);
+	return g_strdup_printf (
+		total <= 0 ?
+			/* Translators : This is used to cache the downloaded contacts from GAL.
+			   %d is an index of the GAL entry. */
+			_("Caching GAL contact %d") :
+			/* Translators : This is used to cache the downloaded contacts from GAL.
+			   The first %d is an index of the GAL entry,
+			   the second %d is total count of entries in GAL. */
+			_("Caching GAL contact %d/%d"),
+		index, total);
 }
 
 static void
-e_book_backend_mapi_gal_load_source (EBookBackend *backend,
-				 ESource      *source,
-				 gboolean     only_if_exists,
-				 GError **perror)
+ebbm_gal_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
 {
-	EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;
-	const gchar *offline, *tmp;
-
-	if (enable_debug)
-		printf("MAPI load source\n");
-
-	if (e_book_backend_is_loaded (backend))
-		return /* Success */;
-
-	offline = e_source_get_property (source, "offline_sync");
-	if (offline  && g_str_equal (offline, "1"))
-		priv->marked_for_offline = TRUE;
+	GError *mapi_error = NULL;
+	struct FetchGalData fgd = { 0 };
+	ExchangeMapiConnection *conn;
 
-	/* Either we are in Online mode or this is marked for offline */
+	e_book_backend_mapi_lock_connection (ebma);
 
-	priv->uri = e_source_get_uri (source);
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
 
-	if (priv->mode ==  E_DATA_BOOK_MODE_LOCAL &&
-	    !priv->marked_for_offline ) {
-		g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
 		return;
 	}
 
-	g_free (priv->summary_file_name);
-	priv->summary_file_name = get_filename_from_uri (priv->uri, "cache.summary");
-	if (priv->summary) g_object_unref (priv->summary);
-	priv->summary = e_book_backend_summary_new (priv->summary_file_name, SUMMARY_FLUSH_TIMEOUT);
-
-	if (priv->marked_for_offline) {
-		if (g_file_test (priv->summary_file_name, G_FILE_TEST_EXISTS)) {
-			e_book_backend_summary_load (priv->summary);
-			priv->is_summary_ready = TRUE;
-		}
-
-		/* Load the cache as well.*/
-		if (e_book_backend_cache_exists (priv->uri)) {
-			gchar *last_time;
-
-			priv->cache = e_book_backend_cache_new (priv->uri);
-
-			last_time = e_book_backend_cache_get_time (priv->cache);
-			priv->is_cache_ready = last_time && !g_str_equal (last_time, "0");
-			g_free (last_time);
-		}
-		//FIXME: We may have to do a time based reload. Or deltas should upload.
-	}
-
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_set_is_writable (backend, FALSE);
-	if (priv->mode ==  E_DATA_BOOK_MODE_LOCAL) {
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		if (!priv->cache) {
-			printf("Unfortunately the cache is not yet created\n");
-			g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
-			return;
-		}
-	} else {
-		e_book_backend_notify_connection_status (backend, TRUE);
-	}
-
-	priv->profile = g_strdup (e_source_get_property (source, "profile"));
-	exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+	fgd.ebma = ebma;
+	fgd.book_view = book_view;
+	fgd.notify_contact_data = notify_contact_data;
+	fgd.fid = exchange_mapi_connection_get_default_folder_id (conn, olFolderContacts, NULL);
 
-	tmp = e_source_get_property (source, "folder-id");
+	exchange_mapi_connection_fetch_gal (conn, restriction,
+		mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+		fetch_gal_cb, &fgd, &mapi_error);
 
-	/* Once aunthentication in address book works this can be removed */
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
-		return /* Success */;
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
+		g_error_free (mapi_error);
 	}
 
-	// writable property will be set in authenticate_user callback
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
-
-	if (enable_debug)
-		printf("For profile %s and folder %s - %016" G_GINT64_MODIFIER "X\n", priv->profile, tmp, priv->fid);
-}
-
-static void
-e_book_backend_mapi_gal_set_mode (EBookBackend *backend, EDataBookMode mode)
-{
-	EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;
-
-	if (enable_debug)
-		printf("mapi: set_mode \n");
-
-	priv->mode = mode;
-	if (e_book_backend_is_loaded (backend)) {
-		if (mode == E_DATA_BOOK_MODE_LOCAL) {
-			e_book_backend_notify_writable (backend, FALSE);
-			e_book_backend_set_is_writable (backend, FALSE);
-			e_book_backend_notify_connection_status (backend, FALSE);
-			/* FIXME: Uninitialize mapi here. may be.*/
-		}
-		else if (mode == E_DATA_BOOK_MODE_REMOTE) {
-			e_book_backend_notify_writable (backend, FALSE);
-			e_book_backend_set_is_writable (backend, FALSE);
-			e_book_backend_notify_connection_status (backend, TRUE);
-//			e_book_backend_notify_auth_required (backend); //FIXME: WTH is this required.
-		}
-	}
-}
-
-typedef struct {
-	EBookBackendMAPIGAL *bg;
-	EDataBookView *book_view;
-	gboolean stop;
-} BESearchClosure;
-
-static BESearchClosure*
-init_closure (EDataBookView *book_view, EBookBackendMAPIGAL *bg)
-{
-	BESearchClosure *closure;
-
-	g_return_val_if_fail (bg != NULL, NULL);
-	g_return_val_if_fail (bg->priv != NULL, NULL);
-	g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
-	
-	closure = g_new0 (BESearchClosure, 1);
-	closure->bg = bg;
-	closure->book_view = book_view;
-	closure->stop = FALSE;
-
-	g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
-
-	return closure;
+	e_book_backend_mapi_unlock_connection (ebma);
 }
 
 static void
-destroy_closure (BESearchClosure *closure)
+ebbm_gal_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error)
 {
-	g_return_if_fail (closure != NULL);
-
-	if (closure->book_view)
-		g_object_unref (closure->book_view);
-	g_free (closure);
-}
-
-static void
-stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPIGAL *mapi_backend)
-{
-	g_return_if_fail (closure != NULL);
-
-	closure->stop = TRUE;
-}
-
-static void
-untrack_book_view (EBookBackendMAPIGAL *mapi_backend, EDataBookView *book_view)
-{
-	g_return_if_fail (mapi_backend != NULL);
-	g_return_if_fail (mapi_backend->priv != NULL);
-	g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
-	g_return_if_fail (book_view != NULL);
-
-	g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
-}
-
-static void
-get_contacts_from_cache (EBookBackendMAPIGAL *ebmapi,
-			 const gchar *query,
-			 GPtrArray *ids,
-			 EDataBookView *book_view,
-			 BESearchClosure *closure)
-{
-	gint i;
+	ExchangeMapiConnection *conn;
+	GError *mapi_error = NULL;
+	struct FetchGalUidsData fgud = { 0 };
 
-	for (i = 0; i < ids->len; i ++) {
-		gchar *uid;
-		EContact *contact;
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (cancelled != NULL);
+	g_return_if_fail (uids != NULL);
 
-                if (closure->stop)
-                        break;
+	e_book_backend_mapi_lock_connection (ebma);
 
-		uid = g_ptr_array_index (ids, i);
-		contact = e_book_backend_cache_get_contact (ebmapi->priv->cache, uid);
-		if (contact) {
-			e_data_book_view_notify_update (book_view, contact);
-			g_object_unref (contact);
-		}
-	}
-}
-#if 0
-static gboolean
-build_restriction_emails_contains (struct mapi_SRestriction *res,
-				   const gchar *query)
-{
-	gchar *email=NULL, *tmp, *tmp1;
-
-	/* This currently supports "email foo bar soo" */
-	tmp = strdup (query);
-
-	tmp = strstr (tmp, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
+	conn = e_book_backend_mapi_get_connection (ebma);
+	if (!conn) {
+		e_book_backend_mapi_unlock_connection (ebma);
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		return;
 	}
 
-	if (email==NULL || !strchr (email, '@'))
-		return FALSE;
+	fgud.cancelled = cancelled;
+	fgud.uids = uids;
 
-	res->rt = RES_PROPERTY;
-	res->res.resProperty.relop = RES_PROPERTY;
-	res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
-	res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
-	res->res.resProperty.lpProp.value.lpszA = email;
+	exchange_mapi_connection_fetch_gal (conn, NULL,
+		mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
+		fetch_gal_uids_cb, &fgud, &mapi_error);
 
-	return TRUE;
-}
-#endif
-
-static void
-book_view_thread (gpointer data)
-{
-	BESearchClosure *closure = data;
-	EDataBookView *book_view = closure->book_view;
-	EBookBackendMAPIGAL *backend = closure->bg;
-	EBookBackendMAPIGALPrivate *priv = backend->priv;
-	const gchar *query = NULL;
-	GPtrArray *ids = NULL;
-	GList *contacts = NULL, *temp_list = NULL;
-
-	if (enable_debug)
-		printf("mapi: book view\n");
-
-	book_view_notify_status (book_view, _("Searching"));
-	query = e_data_book_view_get_card_query (book_view);
-
-	if (!find_book_view (backend))
-		e_book_backend_add_book_view (E_BOOK_BACKEND (backend), book_view);
-
-	switch (priv->mode) {
-		case E_DATA_BOOK_MODE_REMOTE:
-			if (!priv->conn) {
-				GError *err = EDB_ERROR (AUTHENTICATION_REQUIRED);
-				e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
-				e_data_book_view_notify_complete (book_view, err);
-				g_error_free (err);
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
-				return;
-			}
-
-			if (priv->marked_for_offline && !priv->is_cache_ready) {
-				/* To translators : Here Evolution MAPI downloads the entries from the GAL server */
-				book_view_notify_status (book_view, _("Downloading GAL entries from serverâ?¦"));
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
-				return;
-			}
-
-			if (priv->marked_for_offline && priv->cache && priv->is_cache_ready) {
-				if (priv->is_summary_ready &&
-				    e_book_backend_summary_is_summary_query (priv->summary, query)) {
-					if (enable_debug)
-						printf ("reading the contacts from summary \n");
-					ids = e_book_backend_summary_search (priv->summary, query);
-					if (ids && ids->len > 0)
-						get_contacts_from_cache (backend, query, ids, book_view, closure);
-					if (ids)
-						g_ptr_array_free (ids, TRUE);
-					break;
-				}
-
-				printf("Summary seems to be not there or not a summary query, lets fetch from cache directly\n");
-
-				/* We are already cached. Lets return from there. */
-				contacts = e_book_backend_cache_get_contacts (priv->cache,
-								      query);
-				temp_list = contacts;
-				for (; contacts != NULL; contacts = g_list_next(contacts)) {
-					if (closure->stop) {
-						for (;contacts != NULL; contacts = g_list_next (contacts))
-							g_object_unref (contacts->data);
-						break;
-					}
-					e_data_book_view_notify_update (book_view,
-									E_CONTACT(contacts->data));
-					g_object_unref (contacts->data);
-				}
-				if (temp_list)
-					g_list_free (temp_list);
-				break;
-			}
-
-			if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
-				ids = e_book_backend_summary_search (priv->summary, query);
-				if (ids && ids->len > 0)
-					get_contacts_from_cache (backend, query, ids, book_view, closure);
-				if (ids)
-					g_ptr_array_free (ids, TRUE);
-				break;
-			}
-
-			break;
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
+		g_error_free (mapi_error);
 	}
 
-	e_data_book_view_notify_complete (book_view, NULL /* Success */);
-	untrack_book_view (backend, book_view);
-	destroy_closure (closure);
-}
-
-static void
-e_book_backend_mapi_gal_get_contact (EBookBackend *backend,
-				     EDataBook    *book,
-				     guint32       opid,
-				     const gchar   *id)
-{
-	if (enable_debug)
-		printf ("mapi: get contact %s\n", id);
-
-	e_data_book_respond_get_contact (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_get_contact_list (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid,
-					    const gchar   *query )
-{
-	/*EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;*/
-
-	if (enable_debug)
-		printf("mapi: get contact list %s\n", query);
-
-	e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_start_book_view (EBookBackend  *backend,
-					   EDataBookView *book_view)
-{
-	BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPIGAL (backend));
-
-	g_return_if_fail (closure != NULL);
-
-	if (enable_debug)
-		printf ("mapi: start_book_view...\n");
-
-	g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
-}
-
-static void
-e_book_backend_mapi_gal_stop_book_view (EBookBackend  *backend,
-					  EDataBookView *book_view)
-{
-	if (enable_debug)
-		printf("mapi: stop book view\n");
-
-	untrack_book_view (E_BOOK_BACKEND_MAPIGAL (backend), book_view);
-}
-
-static void
-e_book_backend_mapi_gal_get_changes (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *change_id)
-{
-	if (enable_debug)
-		printf ("mapi: get changes\n");
-
-	e_data_book_respond_get_changes (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	GList *auth_methods = NULL;
-	gchar *auth_method;
-
-	if (enable_debug)
-		printf ("mapi get_supported_auth_methods...\n");
-
-	auth_method =  g_strdup_printf ("plain/password");
-	auth_methods = g_list_append (auth_methods, auth_method);
-	e_data_book_respond_get_supported_auth_methods (book,
-							opid,
-							NULL /* Success */,
-							auth_methods);
-	g_free (auth_method);
-	g_list_free (auth_methods);
-}
-
-static void
-e_book_backend_mapi_gal_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
-	if (enable_debug)
-		printf ("mapi cancel_operation...\n");
-	g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
-}
-
-static void
-e_book_backend_mapi_gal_remove (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	e_data_book_respond_remove (book, opid, EDB_ERROR (PERMISSION_DENIED));
+	e_book_backend_mapi_unlock_connection (ebma);
 }
 
 static void
 e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *backend)
 {
-	EBookBackendMAPIGALPrivate *priv;
-
-	priv = g_new0 (EBookBackendMAPIGALPrivate, 1);
-	/* Priv Struct init */
-	backend->priv = priv;
-
-	priv->build_cache_thread = NULL;
-	priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
-	g_static_mutex_init (&priv->running_mutex);
-
-/*	priv->marked_for_offline = FALSE;
-	priv->uri = NULL;
-	priv->cache = NULL;
-	priv->is_summary_ready = FALSE;
-	priv->is_cache_ready = FALSE;
-
-*/	if (g_getenv ("MAPI_DEBUG"))
-		enable_debug = TRUE;
-	else
-		enable_debug = FALSE;
-}
-
-static void
-e_book_backend_mapi_gal_dispose (GObject *object)
-{
-	EBookBackendMAPIGAL *mapi_backend = E_BOOK_BACKEND_MAPIGAL (object);
-	EBookBackendMAPIGALPrivate *priv = mapi_backend->priv;
-
-	if (priv) {
-		if (priv->view_to_closure_hash) {
-			g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
-			g_hash_table_destroy (priv->view_to_closure_hash);
-			priv->view_to_closure_hash = NULL;
-		}
-
-		if (priv->build_cache_thread) {
-			priv->kill_cache_build = TRUE;
-			g_thread_join (priv->build_cache_thread);
-			priv->build_cache_thread = NULL;
-		}
-
-		#define FREE(x) if (x) { g_free (x); x = NULL; }
-		#define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
-
-		/* this will also ensure any pending authentication
-		   request is finished and it's safe to free memory */
-		g_static_mutex_lock (&priv->running_mutex);
-
-		UNREF (priv->conn);
-		UNREF (priv->cache);
-		UNREF (priv->summary);
-
-		FREE (priv->profile);
-		FREE (priv->uri);
-		FREE (priv->summary_file_name);
-
-		g_static_mutex_unlock (&priv->running_mutex);
-		g_static_mutex_free (&priv->running_mutex);
-
-		FREE (mapi_backend->priv);
-
-		#undef UNREF
-		#undef FREE
-	}
-
-	/* Chain up to parent's dispose() method. */
-	if (G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose)
-		G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose (object);
+	backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGALPrivate);
 }
 
 static void
 e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
 {
-	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
-	EBookBackendClass *parent_class;
+	EBookBackendMAPIClass *parent_class;
 
-	parent_class = E_BOOK_BACKEND_CLASS (klass);
+	g_type_class_add_private (klass, sizeof (EBookBackendMAPIGALPrivate));
+
+	parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
 
 	/* Set the virtual methods. */
-	parent_class->create_contact		 = e_book_backend_mapi_gal_create_contact;
-	parent_class->remove_contacts		 = e_book_backend_mapi_gal_remove_contacts;
-	parent_class->modify_contact		 = e_book_backend_mapi_gal_modify_contact;
-	parent_class->load_source		 = e_book_backend_mapi_gal_load_source;
-	parent_class->get_static_capabilities    = e_book_backend_mapi_gal_get_static_capabilities;
-
-	parent_class->get_contact                = e_book_backend_mapi_gal_get_contact;
-	parent_class->get_contact_list           = e_book_backend_mapi_gal_get_contact_list;
-	parent_class->start_book_view            = e_book_backend_mapi_gal_start_book_view;
-	parent_class->stop_book_view             = e_book_backend_mapi_gal_stop_book_view;
-	parent_class->get_changes                = e_book_backend_mapi_gal_get_changes;
-	parent_class->authenticate_user          = e_book_backend_mapi_gal_authenticate_user;
-	parent_class->get_supported_fields	 = e_book_backend_mapi_gal_get_supported_fields;
-	parent_class->get_required_fields	 = e_book_backend_mapi_gal_get_required_fields;
-	parent_class->get_supported_auth_methods = e_book_backend_mapi_gal_get_supported_auth_methods;
-	parent_class->cancel_operation		 = e_book_backend_mapi_gal_cancel_operation;
-	parent_class->set_mode                   = e_book_backend_mapi_gal_set_mode;
-	parent_class->remove			 = e_book_backend_mapi_gal_remove;
-
-	object_class->dispose                    = e_book_backend_mapi_gal_dispose;
+	parent_class->op_create_contact		= ebbm_gal_create_contact;
+	parent_class->op_remove_contacts	= ebbm_gal_remove_contacts;
+	parent_class->op_modify_contact		= ebbm_gal_modify_contact;
+
+	parent_class->op_get_status_message	= ebbm_gal_get_status_message;
+	parent_class->op_fetch_contacts		= ebbm_gal_fetch_contacts;
+	parent_class->op_fetch_known_uids	= ebbm_gal_fetch_known_uids;
 }
 
 /**
@@ -923,10 +234,7 @@ e_book_backend_mapi_gal_new (void)
 {
 	EBookBackendMAPIGAL *backend;
 
-	if (enable_debug)
-		printf ("\ne_book_backend_mapi_gal_new...\n");
-
-	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPIGAL, NULL);
+	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI_GAL, NULL);
 
 	return E_BOOK_BACKEND (backend);
 }
diff --git a/src/addressbook/e-book-backend-mapi-gal.h b/src/addressbook/e-book-backend-mapi-gal.h
index c6c00f7..e9f1e82 100644
--- a/src/addressbook/e-book-backend-mapi-gal.h
+++ b/src/addressbook/e-book-backend-mapi-gal.h
@@ -21,34 +21,34 @@
  *
  */
 
-#ifndef __E_BOOK_BACKEND_MAPIGAL_H__
-#define __E_BOOK_BACKEND_MAPIGAL_H__
+#ifndef __E_BOOK_BACKEND_MAPI_GAL_H__
+#define __E_BOOK_BACKEND_MAPI_GAL_H__
 
-#include <libedata-book/e-book-backend.h>
-#include <libedata-book/e-book-backend-sync.h>
-#include "exchange-mapi-connection.h"
-#include "exchange-mapi-defs.h"
-#include "exchange-mapi-utils.h"
+#include "e-book-backend-mapi.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BOOK_BACKEND_MAPI_GAL        (e_book_backend_mapi_gal_get_type ())
+#define E_BOOK_BACKEND_MAPI_GAL(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGAL))
+#define E_BOOK_BACKEND_MAPI_GAL_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGALClass))
+#define E_IS_BOOK_BACKEND_MAPI_GAL(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI_GAL))
+#define E_IS_BOOK_BACKEND_MAPI_GAL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI_GAL))
 
 typedef struct _EBookBackendMAPIGALPrivate EBookBackendMAPIGALPrivate;
 
 typedef struct {
-	EBookBackend             parent_object;
+	EBookBackendMAPI            parent_object;
 	EBookBackendMAPIGALPrivate *priv;
 } EBookBackendMAPIGAL;
 
 typedef struct {
-	EBookBackendClass parent_class;
+	EBookBackendMAPIClass parent_class;
 } EBookBackendMAPIGALClass;
 
 EBookBackend *e_book_backend_mapi_gal_new      (void);
-GType       e_book_backend_mapi_gal_get_type (void);
+GType         e_book_backend_mapi_gal_get_type (void);
 
-#define E_TYPE_BOOK_BACKEND_MAPIGAL        (e_book_backend_mapi_gal_get_type ())
-#define E_BOOK_BACKEND_MAPIGAL(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPIGAL, EBookBackendMAPIGAL))
-#define E_BOOK_BACKEND_MAPIGAL_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_BACKEND_MAPIGAL, EBookBackendMAPIGALClass))
-#define E_IS_BOOK_BACKEND_MAPIGAL(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPIGAL))
-#define E_IS_BOOK_BACKEND_MAPIGAL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPIGAL))
+G_END_DECLS
 
-#endif /* __E_BOOK_BACKEND_MAPIGAL_H__ */
+#endif /* __E_BOOK_BACKEND_MAPI_GAL_H__ */
 
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index 582a269..528114f 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -32,198 +32,102 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
-#include <sys/time.h>
-/*
-** #include <glib/gi18n-lib.h>
-*/
-
-#include <libedataserver/e-sexp.h>
-#include "libedataserver/e-flag.h"
 #include <libebook/e-contact.h>
 #include <camel/camel.h>
 
-#include <libedata-book/e-book-backend-sexp.h>
-#include <libedata-book/e-data-book.h>
-#include <libedata-book/e-data-book-view.h>
-#include <libedata-book/e-book-backend-cache.h>
-#include <libedata-book/e-book-backend-summary.h>
+#include <em-operation-queue.h>
+
+#include "exchange-mapi-utils.h"
+#include "exchange-mapi-defs.h"
+
 #include "e-book-backend-mapi.h"
-#include "e-book-backend-mapi-utils.h"
 
 G_DEFINE_TYPE (EBookBackendMAPI, e_book_backend_mapi, E_TYPE_BOOK_BACKEND)
 
-static gboolean enable_debug = TRUE;
-
 struct _EBookBackendMAPIPrivate
 {
-	gchar *profile;
-	ExchangeMapiConnection *conn;
+	EMOperationQueue *op_queue;
 
-	mapi_id_t fid;
-	gint mode;
+	GMutex *conn_lock;
+	ExchangeMapiConnection *conn;
+	gchar *profile;
+	gchar *book_uri;
+	EDataBookMode mode;
 	gboolean marked_for_offline;
-	gboolean is_cache_ready;
-	gboolean is_summary_ready;
-	gboolean is_writable;
-	gchar *uri;
 
-	gchar *summary_file_name;
+	GThread *update_cache_thread;
+	GCancellable *update_cache;
+
 	EBookBackendSummary *summary;
 	EBookBackendCache *cache;
-
-	GStaticMutex running_mutex;
-	GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
+	GHashTable *running_book_views;
 };
 
-#define SUMMARY_FLUSH_TIMEOUT 5000
-
-#if 0
-static EDataBookView *
-find_book_view (EBookBackendMAPI *ebmapi)
-{
-	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebmapi));
-	EIterator *iter;
-	EDataBookView *rv = NULL;
-
-	if (!views)
-		return NULL;
-
-	iter = e_list_get_iterator (views);
-
-	if (!iter) {
-		g_object_unref (views);
-		return NULL;
-	}
-
-	if (e_iterator_is_valid (iter)) {
-		/* just always use the first book view */
-		EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
-		if (v)
-			rv = v;
-	}
-
-	g_object_unref (iter);
-	g_object_unref (views);
-
-	return rv;
-}
-#endif
-
-static gboolean
-build_restriction_emails_contains (struct mapi_SRestriction *res,
-				   const gchar *query)
-{
-	gchar *email=NULL, *tmp, *tmp1;
-
-	/* This currently supports "email foo bar soo" */
-	tmp = strdup (query);
-
-	tmp = strstr (tmp, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
-	}
-
-	if (email==NULL || !strchr (email, '@'))
-		return FALSE;
+#define SUMMARY_FLUSH_TIMEOUT_SECS 60
 
-	res->rt = RES_PROPERTY;
-	res->res.resProperty.relop = RES_PROPERTY;
-	res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
-	res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
-	res->res.resProperty.lpProp.value.lpszA = email;
+#define ELEMENT_TYPE_MASK   0xF /* mask where the real type of the element is stored */
 
-	return TRUE;
-}
+#define ELEMENT_TYPE_SIMPLE 0x01
+#define ELEMENT_TYPE_COMPLEX 0x02
 
-static gboolean
-build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
-					    struct mapi_SRestriction_or *or_res,
-					    const gchar *query, gchar **to_free)
-{
-	gchar *email=NULL, *tmp, *tmp1;
-	//Number of restriction to apply
-	guint res_count = 6;
-
-	g_return_val_if_fail (to_free != NULL, FALSE);
-
-	/* This currently supports "email foo bar soo" */
-	*to_free = strdup (query);
-
-	tmp = strstr (*to_free, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
-	}
+#define ELEMENT_TYPE_NAMEDID 0x10
 
-	if (email==NULL || !strchr (email, '@')) {
-		g_free (*to_free);
-		*to_free = NULL;
+static const struct field_element_mapping {
+		EContactField field_id;
+		gint element_type;
+		gint mapi_id;
+		gint contact_type;
+	} mappings [] = {
 
-		return FALSE;
-	}
+	{ E_CONTACT_UID, PT_UNICODE, PR_EMAIL_ADDRESS_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_REV, PT_SYSTIME, PR_LAST_MODIFICATION_TIME, ELEMENT_TYPE_SIMPLE},
 
-	or_res[0].rt = RES_CONTENT;
-	or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
-	or_res[0].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_FILE_AS, PT_UNICODE, PidLidFileUnder, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_FULL_NAME, PT_UNICODE, PR_DISPLAY_NAME_UNICODE, ELEMENT_TYPE_SIMPLE },
+	{ E_CONTACT_GIVEN_NAME, PT_UNICODE, PR_GIVEN_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_FAMILY_NAME, PT_UNICODE, PR_SURNAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_NICKNAME, PT_UNICODE, PR_NICKNAME_UNICODE, ELEMENT_TYPE_SIMPLE },
 
-	or_res[1].rt = RES_CONTENT;
-	or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
-	or_res[1].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_EMAIL_1, PT_UNICODE, PidLidEmail1OriginalDisplayName, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_EMAIL_2, PT_UNICODE, PidLidEmail2EmailAddress, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_EMAIL_3, PT_UNICODE, PidLidEmail3EmailAddress, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_IM_AIM,  PT_UNICODE, PidLidInstantMessagingAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID},
 
-	or_res[2].rt = RES_CONTENT;
-	or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
-	or_res[2].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_PHONE_BUSINESS, PT_UNICODE, PR_OFFICE_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_HOME, PT_UNICODE, PR_HOME_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_MOBILE, PT_UNICODE, PR_MOBILE_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_HOME_FAX, PT_UNICODE, PR_HOME_FAX_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_BUSINESS_FAX, PT_UNICODE, PR_BUSINESS_FAX_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_PAGER, PT_UNICODE, PR_PAGER_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_ASSISTANT, PT_UNICODE, PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_COMPANY, PT_UNICODE, PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
 
-	or_res[3].rt = RES_CONTENT;
-	or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[3].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail1OriginalDisplayName, NULL);
-	or_res[3].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_HOMEPAGE_URL, PT_UNICODE, PidLidHtml, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_FREEBUSY_URL, PT_UNICODE, PidLidFreeBusyLocation, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
 
-	or_res[4].rt = RES_CONTENT;
-	or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[4].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail2OriginalDisplayName, NULL);
-	or_res[4].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_ROLE, PT_UNICODE, PR_PROFESSION_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_TITLE, PT_UNICODE, PR_TITLE_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ORG, PT_UNICODE, PR_COMPANY_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ORG_UNIT, PT_UNICODE, PR_DEPARTMENT_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_MANAGER, PT_UNICODE, PR_MANAGER_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ASSISTANT, PT_UNICODE, PR_ASSISTANT_UNICODE, ELEMENT_TYPE_SIMPLE},
 
-	or_res[5].rt = RES_CONTENT;
-	or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[5].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail3OriginalDisplayName, NULL);
-	or_res[5].res.resContent.lpProp.value.lpszA = email;
+	{ E_CONTACT_OFFICE, PT_UNICODE, PR_OFFICE_LOCATION_UNICODE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_SPOUSE, PT_UNICODE, PR_SPOUSE_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
 
-	res = g_new0 (struct mapi_SRestriction, 1);
+	{ E_CONTACT_BIRTH_DATE,  PT_SYSTIME, PR_BIRTHDAY, ELEMENT_TYPE_COMPLEX},
+	{ E_CONTACT_ANNIVERSARY, PT_SYSTIME, PR_WEDDING_ANNIVERSARY, ELEMENT_TYPE_COMPLEX},
 
-	res->rt = RES_OR;
-	res->res.resOr.cRes = res_count;
-	res->res.resOr.res = or_res;
+	{ E_CONTACT_NOTE, PT_UNICODE, PR_BODY_UNICODE, ELEMENT_TYPE_SIMPLE},
 
-	return TRUE;
-}
+	{ E_CONTACT_ADDRESS_HOME, PT_UNICODE, PidLidHomeAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID},
+	{ E_CONTACT_ADDRESS_WORK, PT_UNICODE, PidLidOtherAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID}
+	/* { E_CONTACT_BOOK_URI, ELEMENT_TYPE_SIMPLE, "book_uri"}, */
+	/* { E_CONTACT_CATEGORIES, } */
+	};
 
 static gchar *
-get_filename_from_uri (const gchar *uri, const gchar *file)
+ebbm_get_filename_from_uri (const gchar *uri, const gchar *file)
 {
 	gchar *mangled_uri, *filename;
 	gint i;
@@ -239,7 +143,7 @@ get_filename_from_uri (const gchar *uri, const gchar *file)
 	}
 
 	/* generate the file name */
-	filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
+	filename = g_build_filename (g_get_home_dir (), ".evolution", "cache", "addressbook",
 				     mangled_uri, file, NULL);
 
 	/* free memory */
@@ -248,1692 +152,1810 @@ get_filename_from_uri (const gchar *uri, const gchar *file)
 	return filename;
 }
 
-static void
-e_book_backend_mapi_load_source (EBookBackend *backend,
-				 ESource      *source,
-				 gboolean     only_if_exists,
-				 GError **perror)
+static gboolean
+ebbm_get_cache_time (EBookBackendMAPI *ebma, glong *cache_seconds)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	const gchar *offline, *tmp;
+	GTimeVal tv = { 0 };
+	gchar *last_update;
 
-	if (enable_debug)
-		printf("MAPI load source\n");
+	g_return_val_if_fail (ebma != NULL, FALSE);
+	g_return_val_if_fail (ebma->priv != NULL, FALSE);
+	g_return_val_if_fail (ebma->priv->cache != NULL, FALSE);
+	g_return_val_if_fail (cache_seconds != NULL, FALSE);
 
-	if (e_book_backend_is_loaded (backend))
-		return /* Success */;
+	last_update = e_book_backend_cache_get_time (ebma->priv->cache);
+	if (!last_update || !g_time_val_from_iso8601 (last_update, &tv)) {
+		g_free (last_update);
+		return FALSE;
+	}
 
-	offline = e_source_get_property (source, "offline_sync");
-	if (offline  && g_str_equal (offline, "1"))
-		priv->marked_for_offline = TRUE;
+	g_free (last_update);
 
-	/* Either we are in Online mode or this is marked for offline */
+	*cache_seconds = tv.tv_sec;
 
-	priv->uri = e_source_get_uri (source);
+	return TRUE;
+}
 
-	if (priv->mode ==  E_DATA_BOOK_MODE_LOCAL &&
-	    !priv->marked_for_offline ) {
-		g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
-		return;
-	}
+static void
+ebbm_set_cache_time (EBookBackendMAPI *ebma, glong cache_seconds)
+{
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (ebma->priv != NULL);
+	g_return_if_fail (ebma->priv->cache != NULL);
 
-	g_free (priv->summary_file_name);
-	priv->summary_file_name = get_filename_from_uri (priv->uri, "cache.summary");
-	if (priv->summary) g_object_unref (priv->summary);
-	priv->summary = e_book_backend_summary_new (priv->summary_file_name, SUMMARY_FLUSH_TIMEOUT);
+	if (cache_seconds > 0) {
+		gchar *iso_time;
+		GTimeVal tv = { 0 };
 
-	if (priv->marked_for_offline) {
-		if (g_file_test (priv->summary_file_name, G_FILE_TEST_EXISTS)) {
-			e_book_backend_summary_load (priv->summary);
-			priv->is_summary_ready = TRUE;
-		}
+		tv.tv_sec = cache_seconds;
+		iso_time = g_time_val_to_iso8601 (&tv);
 
-		/* Load the cache as well.*/
-		if (e_book_backend_cache_exists (priv->uri)) {
-			priv->cache = e_book_backend_cache_new (priv->uri);
-			priv->is_cache_ready = TRUE;
-		}
-		//FIXME: We may have to do a time based reload. Or deltas should upload.
-	} else {
-		priv->cache = e_book_backend_cache_new (priv->uri);
-	}
+		e_book_backend_cache_set_time (ebma->priv->cache, iso_time ? iso_time : "0");
 
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_set_is_writable (backend, TRUE);
-	if (priv->mode ==  E_DATA_BOOK_MODE_LOCAL) {
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		if (!priv->cache) {
-			printf("Unfortunately the cache is not yet created\n");
-			g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
-			return;
-		}
+		g_free (iso_time);
 	} else {
-		e_book_backend_notify_connection_status (backend, TRUE);
+		e_book_backend_cache_set_time (ebma->priv->cache, "0");
 	}
+}
 
-	priv->profile = g_strdup (e_source_get_property (source, "profile"));
-	exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+static EDataBookView *
+ebbm_pick_book_view (EBookBackendMAPI *ebma)
+{
+	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebma));
+	EIterator *iter;
+	EDataBookView *rv = NULL;
+	gint test;
+
+	if (!views)
+		return NULL;
 
-	tmp = e_source_get_property (source, "folder-id");
-	printf("Folder is %s %016" G_GINT64_MODIFIER "X\n", tmp, priv->fid);
+	test = e_list_length (views);
 
-	/* Once aunthentication in address book works this can be removed */
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
-		return /* Success */;
+	iter = e_list_get_iterator (views);
+
+	if (!iter) {
+		g_object_unref (views);
+		return NULL;
 	}
 
-	// writable property will be set in authenticate_user callback
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
+	if (e_iterator_is_valid (iter)) {
+		/* just always use the first book view */
+		EDataBookView *v = (EDataBookView *) e_iterator_get (iter);
+		if (v)
+			rv = v;
+	}
+
+	g_object_unref (iter);
+	g_object_unref (views);
 
-	if (enable_debug)
-		printf("For profile %s and folder %s - %016" G_GINT64_MODIFIER "X\n", priv->profile, tmp, priv->fid);
+	return rv;
 }
 
-static gchar *
-e_book_backend_mapi_get_static_capabilities (EBookBackend *backend)
+struct FetchContactsData
 {
-	if (enable_debug)
-		printf("mapi get_static_capabilities\n");
-	//FIXME: Implement this.
-
-	return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
-}
+	glong last_notification;
+	glong last_modification;
+};
 
-static uint32_t
-string_to_bin (TALLOC_CTX *mem_ctx, const gchar *str, uint8_t **lpb)
+static void
+ebbm_notify_connection_status (EBookBackendMAPI *ebma, gboolean is_online)
 {
-	uint32_t len, i;
+	EBookBackendMAPIClass *ebmac;
+
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
 
-	g_return_val_if_fail (str != NULL, 0);
-	g_return_val_if_fail (lpb != NULL, 0);
+	e_book_backend_notify_connection_status (E_BOOK_BACKEND (ebma), is_online);
 
-	len = strlen (str);
-	g_return_val_if_fail ((len & 1) == 0, 0);
+	ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+	g_return_if_fail (ebmac != NULL);
 
-	len = len / 2;
-	*lpb = talloc_zero_array (mem_ctx, uint8_t, len);
+	if (ebmac->op_connection_status_changed)
+		ebmac->op_connection_status_changed (ebma, is_online);
+}
 
-	i = 0;
-	while (*str && i < len) {
-		gchar c1 = str[0], c2 = str[1];
-		str += 2;
+static void
+ebbm_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, glong *last_modification_secs, GError **error)
+{
+	EBookBackendMAPIClass *ebmac;
+	struct FetchContactsData notify_data = { 0 };
 
-		g_return_val_if_fail ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f') || (c1 >= 'A' && c1 <= 'F'), 0);
-		g_return_val_if_fail ((c2 >= '0' && c2 <= '9') || (c2 >= 'a' && c2 <= 'f') || (c2 >= 'A' && c2 <= 'F'), 0);
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (ebma->priv != NULL);
+	g_return_if_fail (ebma->priv->conn != NULL);
 
-		#define deHex(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : (((x) >= 'a' && (x) <= 'f') ? (x) - 'a' + 10 : (x) - 'A' + 10))
-		(*lpb)[i] = (deHex (c1) << 4) | (deHex (c2));
-		#undef deHex
-		i++;
-	}
+	ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+	g_return_if_fail (ebmac != NULL);
+	g_return_if_fail (ebmac->op_fetch_contacts != NULL);
 
-	return len;
+	ebmac->op_fetch_contacts (ebma, restriction, book_view, &notify_data, error);
+
+	if (last_modification_secs && *last_modification_secs < notify_data.last_modification)
+		*last_modification_secs = notify_data.last_modification;
 }
 
-static gint
-cmp_member_id (gconstpointer a, gconstpointer b, gpointer ht)
+static struct mapi_SRestriction *
+ebbm_build_cache_update_restriction (EBookBackendMAPI *ebma, TALLOC_CTX *mem_ctx)
 {
-	gchar *va, *vb;
-	gint res;
+	struct mapi_SRestriction *restriction;
+	EBookBackendMAPIPrivate *priv;
+	struct SPropValue sprop;
+	struct timeval t = { 0 };
+	glong last_update_secs = 0;
 
-	if (!a)
-		return b ? -1 : 0;
-	if (!b)
-		return 1;
+	g_return_val_if_fail (ebma != NULL, NULL);
+	g_return_val_if_fail (mem_ctx != NULL, NULL);
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
 
-	va = e_vcard_attribute_get_value ((EVCardAttribute *) a);
-	vb = e_vcard_attribute_get_value ((EVCardAttribute *) b);
+	priv = ebma->priv;
+	g_return_val_if_fail (priv != NULL, NULL);
+	g_return_val_if_fail (priv->cache != NULL, NULL);
 
-	res = GPOINTER_TO_INT (g_hash_table_lookup (ht, va)) - GPOINTER_TO_INT (g_hash_table_lookup (ht, vb));
+	if (!ebbm_get_cache_time (ebma, &last_update_secs) || last_update_secs <= 0)
+		return NULL;
 
-	g_free (va);
-	g_free (vb);
+	restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
+	g_assert (restriction != NULL);
 
-	return res;
-}
+	restriction->rt = RES_PROPERTY;
+	restriction->res.resProperty.relop = RELOP_GE;
+	restriction->res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
 
-typedef struct {
-	EContact *contact;
-	EBookBackendCache *cache;
-} MapiCreateitemData;
+	t.tv_sec = last_update_secs;
+	t.tv_usec = 0;
 
-static gboolean
-mapi_book_write_props (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropValue **values, uint32_t *n_values, gpointer data)
+	set_SPropValue_proptag_date_timeval (&sprop, PR_LAST_MODIFICATION_TIME, &t);
+
+	cast_mapi_SPropValue (
+		#ifdef HAVE_MEMCTX_ON_CAST_MAPI_SPROPVALUE
+		mem_ctx,
+		#endif
+		&(restriction->res.resProperty.lpProp), &sprop);
+
+	return restriction;
+}
+
+static gpointer
+ebbm_update_cache_cb (gpointer data)
 {
-	/* Do not make this array static, below function modifies it.
-	   The array is used to just ensure named ids are known later. */
-	ResolveNamedIDsData nids[] = {
-		{ PidLidDistributionListName, 0 },
-		{ PidLidDistributionListOneOffMembers, 0 },
-		{ PidLidDistributionListMembers, 0 },
-		{ PidLidDistributionListChecksum, 0 },
-		{ PidLidFileUnder, 0 },
-		{ PidLidFileUnderId, 0 },
-		{ PidLidEmail1OriginalDisplayName, 0 },
-		{ PidLidEmail1EmailAddress, 0 },
-		{ PidLidEmail2EmailAddress, 0 },
-		{ PidLidEmail3EmailAddress, 0 },
-		{ PidLidHtml, 0 },
-		{ PidLidInstantMessagingAddress, 0 },
-		{ PidLidHomeAddress, 0 },
-		{ PidLidWorkAddress, 0 },
-		{ PidLidEmail2OriginalDisplayName, 0 },
-		{ PidLidEmail3OriginalDisplayName, 0 }
-	};
+	EBookBackendMAPI *ebma = (EBookBackendMAPI *) data;
+	EBookBackendMAPIPrivate *priv;
+	EBookBackendMAPIClass *ebmac;
+	glong last_modification_secs = 0;
+	EDataBookView *book_view;
 
-	MapiCreateitemData *mcd = data;
+	g_return_val_if_fail (ebma != NULL, NULL);
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
 
-	#define set_str_value(hex, val) G_STMT_START { \
-		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, hex, val ? val : "")) \
-			return FALSE;	\
-		} G_STMT_END
+	priv = ebma->priv;
+	g_return_val_if_fail (priv != NULL, NULL);
+	g_return_val_if_fail (priv->cache != NULL, NULL);
+	g_return_val_if_fail (priv->conn != NULL, NULL);
 
-	#define set_str_named_value(named_id, val) G_STMT_START { \
-		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, named_id, val ? val : "")) \
-			return FALSE;	\
-		} G_STMT_END
+	ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+	g_return_val_if_fail (ebmac != NULL, NULL);
 
-	#define set_str_con_value(hex, field_id) G_STMT_START { \
-		if (e_contact_get (mcd->contact, field_id)) { \
-			set_str_value (hex, e_contact_get (mcd->contact, field_id)); \
-		} } G_STMT_END
+	g_cancellable_reset (priv->update_cache);
 
-	#define set_str_named_con_value(named_id, field_id) G_STMT_START { \
-		if (e_contact_get (mcd->contact, field_id)) { \
-			set_str_named_value (named_id, e_contact_get (mcd->contact, field_id)); \
-		} } G_STMT_END
+	if (!g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_contacts) {
+		TALLOC_CTX *mem_ctx;
+		struct mapi_SRestriction *restriction;
 
-	g_return_val_if_fail (mcd != NULL, FALSE);
-	g_return_val_if_fail (mcd->contact != NULL, FALSE);
-	g_return_val_if_fail (conn != NULL, FALSE);
-	g_return_val_if_fail (mem_ctx != NULL, FALSE);
-	g_return_val_if_fail (values != NULL, FALSE);
-	g_return_val_if_fail (n_values != NULL, FALSE);
+		mem_ctx = talloc_init (G_STRFUNC);
+		restriction = ebbm_build_cache_update_restriction (ebma, mem_ctx);
 
-	if (!exchange_mapi_connection_resolve_named_props (conn, fid, nids, G_N_ELEMENTS (nids), NULL))
-		return FALSE;
+		/* get time stored in a cache, to always use the latest last modification time */
+		if (!ebbm_get_cache_time (ebma, &last_modification_secs))
+			last_modification_secs = 0;
 
-	if (GPOINTER_TO_INT (e_contact_get (mcd->contact, E_CONTACT_IS_LIST))) {
-		EContact *old_contact;
-		GList *local, *l;
-		struct BinaryArray_r *members, *oneoff_members;
-		uint32_t list_size = 0, u32, crc32 = 0;
-		GHashTable *member_values = NULL, *member_ids = NULL;
+		ebbm_fetch_contacts (ebma, restriction, NULL, &last_modification_secs, NULL);
 
-		old_contact = e_contact_get (mcd->contact, E_CONTACT_UID) ? e_book_backend_cache_get_contact (mcd->cache, e_contact_get (mcd->contact, E_CONTACT_UID)) : NULL;
-		if (old_contact) {
-			member_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-			member_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+		talloc_free (mem_ctx);
+	}
+
+	if (!g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_known_uids) {
+		GHashTable *uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+		GError *error = NULL;
+
+		ebmac->op_fetch_known_uids (ebma, priv->update_cache, uids, &error);
 
-			local = e_contact_get_attributes (old_contact, E_CONTACT_EMAIL);
-			for (l = local; l; l = l->next) {
-				EVCardAttribute *attr = l->data;
-				GList *param;
+		if (!error && !g_cancellable_is_cancelled (priv->update_cache)) {
+			GSList *cache_keys, *c;
 
-				if (!attr)
+			e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+			cache_keys = e_file_cache_get_keys (E_FILE_CACHE (priv->cache));
+
+			for (c = cache_keys; c; c = c->next) {
+				const gchar *uid = c->data;
+				gchar *uid_str;
+
+				if (!uid || g_hash_table_lookup (uids, uid)
+				    || g_str_equal (uid, "populated")
+				    || g_str_equal (uid, "last_update_time"))
 					continue;
 
-				param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERVALUE);
-				if (param && param->data && !param->next) {
-					g_hash_table_insert (member_values, e_vcard_attribute_get_value (attr), g_strdup (param->data));
-				}
+				/* uid is hold by a cache, thus make a copy before remove */
+				uid_str = g_strdup (uid);
 
-				param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERID);
-				if (param && param->data && !param->next) {
-					g_hash_table_insert (member_ids, e_vcard_attribute_get_value (attr), GINT_TO_POINTER (atoi (param->data)));
-				}
+				e_book_backend_mapi_notify_contact_removed (ebma, uid_str);
+
+				g_free (uid_str);
 			}
 
-			g_object_unref (old_contact);
-			g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
-			g_list_free (local);
+			ebbm_set_cache_time (ebma, last_modification_secs);
+			e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+			e_book_backend_summary_save (priv->summary);
+
+			g_slist_free (cache_keys);
 		}
 
-		set_str_value (PR_MESSAGE_CLASS, IPM_DISTLIST);
-		u32 = 0xFFFFFFFF;
-		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, PidLidFileUnderId, &u32))
-			return FALSE;
-		set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
-		set_str_named_con_value (PidLidDistributionListName, E_CONTACT_FILE_AS);
-		set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FILE_AS);
-		set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
-
-
-		local = e_contact_get_attributes (mcd->contact, E_CONTACT_EMAIL);
-		if (member_ids)
-			local = g_list_sort_with_data (local, cmp_member_id, member_ids);
-
-		members = talloc_zero (mem_ctx, struct BinaryArray_r);
-		members->cValues = 0;
-		members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
-
-		oneoff_members = talloc_zero (mem_ctx, struct BinaryArray_r);
-		oneoff_members->cValues = 0;
-		oneoff_members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
-
-		for (l = local; l; l = l->next) {
-			EVCardAttribute *attr = (EVCardAttribute *) l->data;
-			gchar *raw;
-			CamelInternetAddress *addr;
-
-			if (!attr)
-				continue;
-
-			raw = e_vcard_attribute_get_value (attr);
-			if (!raw)
-				continue;
-
-			addr = camel_internet_address_new ();
-			if (camel_address_decode (CAMEL_ADDRESS (addr), raw) > 0) {
-				const gchar *nm = NULL, *eml = NULL;
-
-				camel_internet_address_get (addr, 0, &nm, &eml);
-				if (eml) {
-					/* keep both lists in sync */
-					if (member_values && g_hash_table_lookup (member_values, raw)) {
-						/* stored ListMembers values when contact's value didn't change */
-						members->lpbin[members->cValues].cb = string_to_bin (mem_ctx, g_hash_table_lookup (member_values, raw), &members->lpbin[members->cValues].lpb);
-						members->cValues++;
-					} else {
-						exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &members->lpbin[members->cValues], nm ? nm : "", eml);
-						members->cValues++;
-					}
-
-					exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &oneoff_members->lpbin[oneoff_members->cValues], nm ? nm : "", eml);
-					oneoff_members->cValues++;
-
-					list_size += MAX (oneoff_members->lpbin[oneoff_members->cValues - 1].cb, members->lpbin[members->cValues - 1].cb);
-					crc32 = exchange_mapi_utils_push_crc32 (crc32, members->lpbin[members->cValues - 1].lpb, members->lpbin[members->cValues - 1].cb);
-				}
-			}
+		g_hash_table_destroy (uids);
+		if (error)
+			g_error_free (error);
+	}
 
-			g_object_unref (addr);
-			g_free (raw);
-		}
+	book_view = ebbm_pick_book_view (ebma);
+	if (book_view)
+		e_data_book_view_notify_complete (book_view, NULL);
 
-		if (member_values)
-			g_hash_table_destroy (member_values);
-		if (member_ids)
-			g_hash_table_destroy (member_ids);
-		g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
-		g_list_free (local);
+	return NULL;
+}
 
-		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
-			PidLidDistributionListOneOffMembers, oneoff_members))
-			return FALSE;
+static void
+ebbm_load_source (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **perror)
+{
+	EBookBackendMAPIPrivate *priv = ebma->priv;
+	const gchar *offline;
+	gchar *summary_file_name;
 
-		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
-			PidLidDistributionListMembers, members))
-			return FALSE;
+	if (e_book_backend_is_loaded (E_BOOK_BACKEND (ebma)))
+		return /* Success */;
 
-		if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
-			PidLidDistributionListChecksum, &crc32))
-			return FALSE;
+	offline = e_source_get_property (source, "offline_sync");
+	priv->marked_for_offline = offline  && g_str_equal (offline, "1");
 
-		/* list_size shouldn't exceed 15000 bytes, is so, use a stream instead of those properties above, but for now... */
-		if (list_size > 15000)
-			return FALSE;
+	if (priv->book_uri)
+		g_free (priv->book_uri);
+	priv->book_uri = e_source_get_uri (source);
 
-		return TRUE;
-	}
+	g_free (priv->profile);
+	priv->profile = g_strdup (e_source_get_property (source, "profile"));
 
-	set_str_value (PR_MESSAGE_CLASS, IPM_CONTACT);
-	set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
-
-	set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FULL_NAME);
-	set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
-	set_str_named_con_value (PidLidEmail1OriginalDisplayName, E_CONTACT_EMAIL_1);
-	/*set_str_named_con_value (PidLidEmail1EmailAddress, E_CONTACT_EMAIL_1);*/
-
-	/*set_str_con_value (0x8083001e, E_CONTACT_EMAIL_1);*/
-	set_str_named_con_value (PidLidEmail2EmailAddress, E_CONTACT_EMAIL_2);
-
-	set_str_named_con_value (PidLidEmail3EmailAddress, E_CONTACT_EMAIL_3);
-	/*set_str_named_con_value (PidLidEmail3OriginalDisplayName, E_CONTACT_EMAIL_3);*/
-
-	set_str_named_con_value (PidLidHtml, E_CONTACT_HOMEPAGE_URL);
-	set_str_named_con_value (PidLidFreeBusyLocation, E_CONTACT_FREEBUSY_URL);
-
-	set_str_con_value (PR_OFFICE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS);
-	set_str_con_value (PR_HOME_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_HOME);
-	set_str_con_value (PR_MOBILE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_MOBILE);
-	set_str_con_value (PR_HOME_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_HOME_FAX);
-	set_str_con_value (PR_BUSINESS_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS_FAX);
-	set_str_con_value (PR_PAGER_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_PAGER);
-	set_str_con_value (PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_ASSISTANT);
-	set_str_con_value (PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, E_CONTACT_PHONE_COMPANY);
-
-	set_str_con_value (PR_MANAGER_NAME_UNICODE, E_CONTACT_MANAGER);
-	set_str_con_value (PR_ASSISTANT_UNICODE, E_CONTACT_ASSISTANT);
-	set_str_con_value (PR_COMPANY_NAME_UNICODE, E_CONTACT_ORG);
-	set_str_con_value (PR_DEPARTMENT_NAME_UNICODE, E_CONTACT_ORG_UNIT);
-	set_str_con_value (PR_PROFESSION_UNICODE, E_CONTACT_ROLE);
-	set_str_con_value (PR_TITLE_UNICODE, E_CONTACT_TITLE);
-
-	set_str_con_value (PR_OFFICE_LOCATION_UNICODE, E_CONTACT_OFFICE);
-	set_str_con_value (PR_SPOUSE_NAME_UNICODE, E_CONTACT_SPOUSE);
-
-	set_str_con_value (PR_BODY_UNICODE, E_CONTACT_NOTE);
-	set_str_con_value (PR_NICKNAME_UNICODE, E_CONTACT_NICKNAME);
-
-	/* BDAY AND ANNV */
-	if (e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE)) {
-		EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE);
-		struct tm tmtime;
-		time_t lt;
-		NTTIME nt;
-		struct FILETIME t;
-
-		tmtime.tm_mday = date->day;
-		tmtime.tm_mon = date->month - 1;
-		tmtime.tm_year = date->year - 1900;
-
-		lt = mktime (&tmtime);
-		unix_to_nt_time (&nt, lt);
-		t.dwLowDateTime = (nt << 32) >> 32;
-		t.dwHighDateTime = (nt >> 32);
-
-		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_BIRTHDAY, &t))
-			return FALSE;
+	summary_file_name = ebbm_get_filename_from_uri (priv->book_uri, "cache.summary");
+	if (priv->summary)
+		g_object_unref (priv->summary);
+	priv->summary = e_book_backend_summary_new (summary_file_name, SUMMARY_FLUSH_TIMEOUT_SECS * 1000);
+
+	if (g_file_test (summary_file_name, G_FILE_TEST_EXISTS)) {
+		e_book_backend_summary_load (priv->summary);
 	}
 
-	if (e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY)) {
-		EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY);
-		struct tm tmtime;
-		time_t lt;
-		NTTIME nt;
-		struct FILETIME t;
+	if (priv->cache)
+		g_object_unref (priv->cache);
+	priv->cache = e_book_backend_cache_new (priv->book_uri);
 
-		tmtime.tm_mday = date->day;
-		tmtime.tm_mon = date->month - 1;
-		tmtime.tm_year = date->year - 1900;
+	g_free (summary_file_name);
 
-		lt = mktime (&tmtime);
-		unix_to_nt_time (&nt, lt);
-		t.dwLowDateTime = (nt << 32) >> 32;
-		t.dwHighDateTime = (nt >> 32);
+	e_book_backend_set_is_loaded (E_BOOK_BACKEND (ebma), TRUE);
+	e_book_backend_set_is_writable (E_BOOK_BACKEND (ebma), FALSE);
+	e_book_backend_notify_writable (E_BOOK_BACKEND (ebma), FALSE);
 
-		if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_WEDDING_ANNIVERSARY, &t))
-			return FALSE;
-	}
+	ebbm_notify_connection_status (ebma, priv->mode != E_DATA_BOOK_MODE_LOCAL);
 
-	/* Home and Office address */
-	if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME)) {
-		EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME);
+	/* Either we are in Online mode or this is marked for offline */
+	if (priv->mode == E_DATA_BOOK_MODE_LOCAL &&
+	    !priv->marked_for_offline) {
+		g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
+		return;
+	}
 
-		set_str_named_value (PidLidHomeAddress, contact_addr->street);
-		set_str_value (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
-		set_str_value (PR_HOME_ADDRESS_CITY_UNICODE, contact_addr->locality);
-		set_str_value (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
-		set_str_value (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE, contact_addr->code);
-		set_str_value (PR_HOME_ADDRESS_COUNTRY_UNICODE, contact_addr->country);
+	/* Once aunthentication in address book works this can be removed */
+	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+		return /* Success */;
 	}
+}
 
-	if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK)) {
-		EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK);
+static void
+ebbm_remove (EBookBackendMAPI *ebma, GError **error)
+{
+	EBookBackendMAPIPrivate *priv;
+	gchar *filename;
 
-		set_str_named_value (PidLidWorkAddress, contact_addr->street);
-		set_str_value (PR_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
-		set_str_value (PR_LOCALITY_UNICODE, contact_addr->locality);
-		set_str_value (PR_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
-		set_str_value (PR_POSTAL_CODE_UNICODE, contact_addr->code);
-		set_str_value (PR_COUNTRY_UNICODE, contact_addr->country);
+	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (ebma->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+	priv = ebma->priv;
+
+	if (!priv->book_uri)
+		return;
+
+	e_book_backend_mapi_lock_connection (ebma);
+
+	if (priv->summary) {
+		g_object_unref (priv->summary);
+		priv->summary = NULL;
 	}
 
-	if (e_contact_get (mcd->contact, E_CONTACT_IM_AIM)) {
-		GList *l = e_contact_get (mcd->contact, E_CONTACT_IM_AIM);
-		set_str_named_value (PidLidInstantMessagingAddress, l->data);
+	if (priv->cache) {
+		g_object_unref (priv->cache);
+		priv->cache = NULL;
 	}
 
-	return TRUE;
+	filename = ebbm_get_filename_from_uri (priv->book_uri, "cache.summary");
+	if (g_file_test (filename, G_FILE_TEST_EXISTS))
+			g_unlink (filename);
+	g_free (filename);
+
+	filename = ebbm_get_filename_from_uri (priv->book_uri, "cache.xml");
+	if (g_file_test (filename, G_FILE_TEST_EXISTS))
+			g_unlink (filename);
+	g_free (filename);
+
+	e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static gchar *
+ebbm_get_static_capabilities (EBookBackend *backend)
+{
+	return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
 }
 
 static void
-e_book_backend_mapi_create_contact (EBookBackend *backend,
-					  EDataBook *book,
-					  guint32 opid,
-					  const gchar *vcard )
+ebbm_get_required_fields (EBookBackendMAPI *ebma, GList **fields, GError **error)
 {
-	EContact *contact;
-	gchar *id;
-	mapi_id_t status;
-	MapiCreateitemData mcd;
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	GError *mapi_error = NULL;
+	*fields = g_list_append (*fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
+}
 
-	if (enable_debug)
-		printf("mapi create_contact \n");
+static void
+ebbm_get_supported_fields (EBookBackendMAPI *ebma, GList **fields, GError **error)
+{
+	gint i;
 
-	switch (priv->mode) {
+	for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+		*fields = g_list_append (*fields, (gchar *)e_contact_field_name (mappings[i].field_id));
+	}
+
+	*fields = g_list_append (*fields, (gpointer) e_contact_field_name (E_CONTACT_BOOK_URI));
+}
+
+static void
+ebbm_authenticate_user (EBookBackendMAPI *ebma, const gchar *user, const gchar *passwd, const gchar *auth_method, GError **error)
+{
+	EBookBackendMAPIPrivate *priv = ebma->priv;
+	GError *mapi_error = NULL;
 
+	switch (priv->mode) {
 	case E_DATA_BOOK_MODE_LOCAL:
-		e_data_book_respond_create(book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-		break;
+		ebbm_notify_connection_status (ebma, FALSE);
+		return;
 
 	case E_DATA_BOOK_MODE_REMOTE:
-		contact = e_contact_new_from_vcard(vcard);
-		mcd.contact = contact;
-		mcd.cache = priv->cache;
-		status = exchange_mapi_connection_create_item (priv->conn, olFolderContacts, priv->fid,
-				mapi_book_write_props, &mcd,
-				NULL, NULL, NULL, 0, &mapi_error);
-		if (!status) {
-			GError *error = NULL;
+		if (priv->update_cache_thread) {
+			g_cancellable_cancel (priv->update_cache);
+			g_thread_join (priv->update_cache_thread);
+			priv->update_cache_thread = NULL;
+		}
+
+		e_book_backend_mapi_lock_connection (ebma);
+
+		if (priv->conn) {
+			g_object_unref (priv->conn);
+			priv->conn = NULL;
+		}
+
+		/* rather reuse already established connection */
+		priv->conn = exchange_mapi_connection_find (priv->profile);
+		if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
+			exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
+		else if (!priv->conn)
+			priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
 
-			mapi_error_to_edb_error (&error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server"));
+		if (!priv->conn || mapi_error) {
+			if (priv->conn) {
+				g_object_unref (priv->conn);
+				priv->conn = NULL;
+			}
 
-			e_data_book_respond_create (book, opid, error, NULL);
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
+			e_book_backend_mapi_unlock_connection (ebma);
 
 			if (mapi_error)
 				g_error_free (mapi_error);
+
+			ebbm_notify_connection_status (ebma, FALSE);
 			return;
 		}
-		id = exchange_mapi_util_mapi_ids_to_uid (priv->fid, status);
 
-		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-		e_contact_set (contact, E_CONTACT_UID, id);
-		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+		e_book_backend_mapi_unlock_connection (ebma);
 
-		//somehow get the mid.
-		//add to summary and cache.
-		if (priv->marked_for_offline && priv->is_cache_ready)
-			e_book_backend_cache_add_contact (priv->cache, contact);
+		ebbm_notify_connection_status (ebma, TRUE);
 
-		if (priv->marked_for_offline && priv->is_summary_ready)
-			e_book_backend_summary_add_contact (priv->summary, contact);
+		/* if (priv->marked_for_offline) */
+			priv->update_cache_thread = g_thread_create (ebbm_update_cache_cb, ebma, TRUE, NULL);
+		break;
 
-		e_data_book_respond_create(book, opid, NULL /* Success */, contact);
+	default:
 		break;
 	}
 }
 
 static void
-e_book_backend_mapi_remove_contacts (EBookBackend *backend,
-					   EDataBook    *book,
-					   guint32 opid,
-					   GList *id_list)
+ebbm_get_supported_auth_methods (EBookBackendMAPI *ebma, GList **auth_methods, GError **error)
 {
-	GSList *list=NULL;
-	GList *tmp = id_list;
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	mapi_id_t fid, mid;
-	GError *err = NULL;
+	*auth_methods = g_list_append (*auth_methods, g_strdup ("plain/password"));
+}
 
-	if (enable_debug)
-		printf("mapi: remove_contacts\n");
+static void
+ebbm_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
+{
+	EBookBackendMAPI *ebbm = E_BOOK_BACKEND_MAPI (backend);
 
-	switch (priv->mode) {
+	if (!ebbm || !ebbm->priv || !ebbm->priv->op_queue || !em_operation_queue_cancel_all (ebbm->priv->op_queue))
+		g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
+}
 
-	case E_DATA_BOOK_MODE_LOCAL:
-		e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-		break;
+static void
+ebbm_set_mode (EBookBackend *backend, EDataBookMode mode)
+{
+	EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (backend);
+	EBookBackendMAPIPrivate *priv = ebma->priv;
 
-	case E_DATA_BOOK_MODE_REMOTE:
-		while (tmp) {
-			struct id_list *data = g_new (struct id_list, 1);
-			exchange_mapi_util_mapi_ids_from_uid (tmp->data, &fid, &mid);
-			data->id = mid;
-			list = g_slist_prepend (list, (gpointer) data);
-			tmp = tmp->next;
-		}
+	priv->mode = mode;
+	if (e_book_backend_is_loaded (backend)) {
+		e_book_backend_mapi_lock_connection (ebma);
 
-		exchange_mapi_connection_remove_items (priv->conn, olFolderContacts, priv->fid, 0, list, &err);
-		if (priv->marked_for_offline && priv->is_cache_ready) {
-			tmp = id_list;
-			while (tmp) {
-				e_book_backend_cache_remove_contact (priv->cache, tmp->data);
-				tmp = tmp->next;
-			}
-		}
+		if (mode == E_DATA_BOOK_MODE_LOCAL) {
+			e_book_backend_notify_writable (backend, FALSE);
+			e_book_backend_set_is_writable (backend, FALSE);
+			ebbm_notify_connection_status (ebma, FALSE);
 
-		if (priv->marked_for_offline && priv->is_summary_ready) {
-			tmp = id_list;
-			while (tmp) {
-				e_book_backend_summary_remove_contact (priv->summary, tmp->data);
-				tmp = tmp->next;
+			if (priv->conn) {
+				g_object_unref (priv->conn);
+				priv->conn = NULL;
 			}
+		} else if (mode == E_DATA_BOOK_MODE_REMOTE) {
+			ebbm_notify_connection_status (ebma, TRUE);
+			if (!priv->conn)
+				e_book_backend_notify_auth_required (backend);
 		}
 
-		g_slist_free (list);
-
-		if (err) {
-			GError *mapi_err = err;
-
-			err = NULL;
-			mapi_error_to_edb_error (&err, mapi_err, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
-
-			g_error_free (mapi_err);
-		}
-
-		e_data_book_respond_remove_contacts (book, opid, err, id_list);
-		break;
-	default:
-		break;
+		e_book_backend_mapi_unlock_connection (ebma);
 	}
 }
 
 static void
-e_book_backend_mapi_modify_contact (EBookBackend *backend,
-					  EDataBook    *book,
-					  guint32       opid,
-					  const gchar   *vcard)
+ebbm_get_contact (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	MapiCreateitemData mcd;
+	EBookBackendMAPIPrivate *priv;
 	EContact *contact;
-	mapi_id_t fid, mid;
-	gboolean status;
-	gchar *tmp;
-	GError *mapi_error = NULL;
 
-	if (enable_debug)
-		printf("mapi: modify_contacts\n");
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (vcard != NULL);
 
-	switch (priv->mode) {
+	priv = ebma->priv;
+	g_return_if_fail (priv != NULL);
 
-	case E_DATA_BOOK_MODE_LOCAL:
-		e_data_book_respond_modify (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-		break;
-	case E_DATA_BOOK_MODE_REMOTE:
-		contact = e_contact_new_from_vcard(vcard);
-		tmp = e_contact_get (contact, E_CONTACT_UID);
-		exchange_mapi_util_mapi_ids_from_uid (tmp, &fid, &mid);
-		printf("modify id %s\n", tmp);
-
-		mcd.contact = contact;
-		mcd.cache = priv->cache;
-		status = exchange_mapi_connection_modify_item (priv->conn, olFolderContacts, priv->fid, mid,
-				mapi_book_write_props, &mcd,
-				NULL, NULL, NULL, 0, &mapi_error);
-		printf("getting %d\n", status);
-		if (!status) {
-			GError *perror = NULL;
-
-			mapi_error_to_edb_error (&perror, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
-			e_data_book_respond_modify (book, opid, perror, NULL);
-			if (mapi_error)
-				g_error_free (mapi_error);
-			break;
-		}
+	if (!priv->cache) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		return;
+	}
 
-		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+	contact = e_book_backend_cache_get_contact (priv->cache, id);
+	if (contact) {
+		*vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+		g_object_unref (contact);
+	} else {
+		g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
+	}
+}
 
-		//FIXME: Write it cleanly
-		if (priv->marked_for_offline && priv->is_cache_ready)
-			printf("delete cache %d\n", e_book_backend_cache_remove_contact (priv->cache, tmp));
+static void
+ebbm_get_contact_list (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error)
+{
+	EBookBackendMAPIPrivate *priv;
+	GList *contacts, *l;
 
-		if (priv->marked_for_offline && priv->is_summary_ready)
-				e_book_backend_summary_remove_contact (priv->summary, tmp);
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (query != NULL);
+	g_return_if_fail (vCards != NULL);
 
-		if (priv->marked_for_offline && priv->is_cache_ready)
-			e_book_backend_cache_add_contact (priv->cache, contact);
+	priv = ebma->priv;
+	g_return_if_fail (priv != NULL);
 
-		if (priv->marked_for_offline && priv->is_summary_ready)
-			e_book_backend_summary_add_contact (priv->summary, contact);
+	if (!priv->cache) {
+		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		return;
+	}
+
+	contacts = e_book_backend_cache_get_contacts (priv->cache, query);
 
-		e_data_book_respond_modify (book, opid, NULL /* Success */, contact);
+	for (l = contacts; l; l = g_list_next (l)) {
+		EContact *contact = l->data;
 
+		*vCards = g_list_prepend (*vCards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
+
+		g_object_unref (contact);
 	}
+
+	g_list_free (contacts);
 }
 
-static gboolean
-create_contact_item (FetchItemsCallbackData *item_data, gpointer data)
+struct BookViewThreadData
 {
-	EContact *contact;
-	gchar *suid;
+	EBookBackendMAPI *ebma;
+	EDataBookView *book_view;
+};
 
-	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
-	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
-	printf("got contact %s\n", suid);
-	if (contact) {
-		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-		e_contact_set (contact, E_CONTACT_UID, suid);
-		data = contact;
+static gpointer
+ebbm_book_view_thread (gpointer data)
+{
+	struct BookViewThreadData *bvtd = data;
+	EBookBackendMAPIPrivate *priv;
+	GError *error = NULL;
+
+	g_return_val_if_fail (bvtd != NULL, NULL);
+	g_return_val_if_fail (bvtd->ebma != NULL, NULL);
+	g_return_val_if_fail (bvtd->book_view != NULL, NULL);
+
+	priv = bvtd->ebma->priv;
+
+	e_data_book_view_notify_status_message (bvtd->book_view, _("Searching"));
+
+	e_book_backend_mapi_update_view_by_cache (bvtd->ebma, bvtd->book_view, &error);
+
+	if (!error && priv && priv->conn && !priv->update_cache_thread
+	    && e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)) {
+		EBookBackendMAPIClass *ebmac;
+
+		ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (bvtd->ebma);
+		if (ebmac && ebmac->op_book_view_thread)
+			ebmac->op_book_view_thread (bvtd->ebma, bvtd->book_view, &error);
+
+		if (!error && !priv->marked_for_offline) {
+			/* todo: create restriction based on the book_view */
+			ebbm_fetch_contacts (bvtd->ebma, NULL, bvtd->book_view, NULL, &error);
+		}
 	}
 
-	g_free (suid);
+	/* do not stop book view when filling cache */
+	if (e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)
+	    && (!priv->update_cache_thread || g_cancellable_is_cancelled (priv->update_cache)))
+		e_data_book_view_notify_complete (bvtd->book_view, error);
 
-	return TRUE;
+	if (error)
+		g_error_free (error);
+
+	g_object_unref (bvtd->book_view);
+	g_object_unref (bvtd->ebma);
+	g_free (bvtd);
+
+	return NULL;
 }
 
 static void
-e_book_backend_mapi_get_contact (EBookBackend *backend,
-				       EDataBook    *book,
-				       guint32       opid,
-				       const gchar   *id)
+free_data_book_change (EDataBookChange *change)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	EContact *contact = NULL;
-	gchar *vcard;
-	ESource *source;
-	guint32 options = MAPI_OPTIONS_FETCH_ALL; 
-	gboolean is_public = FALSE; 
-	
-	source = e_book_backend_get_source(backend);
-	if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
-		options |= MAPI_OPTIONS_USE_PFSTORE;
-		is_public = TRUE;
+	if (change) {
+		g_free (change->vcard);
+		g_free (change);
 	}
+}
 
-	if (enable_debug)
-		printf("mapi: get_contact %s\n", id);
+/* Async OP functions, data structures and so on */
+
+typedef enum {
+	/* OP_LOAD_SOURCE, */
+	OP_REMOVE,
+
+	OP_CREATE_CONTACT,
+	OP_REMOVE_CONTACTS,
+	OP_MODIFY_CONTACT,
+	OP_GET_CONTACT,
+	OP_GET_CONTACT_LIST,
+	OP_START_BOOK_VIEW,
+	OP_STOP_BOOK_VIEW,
+	OP_GET_CHANGES,
+	OP_AUTHENTICATE_USER,
+	OP_GET_REQUIRED_FIELDS,
+	OP_GET_SUPPORTED_FIELDS,
+	OP_GET_SUPPORTED_AUTH_METHODS,
+} OperationType;
 
-	switch (priv->mode) {
+typedef struct {
+	OperationType ot;
 
-	case E_DATA_BOOK_MODE_LOCAL:
-		contact = e_book_backend_cache_get_contact (priv->cache,
-							    id);
-		if (contact) {
-			vcard =  e_vcard_to_string (E_VCARD (contact),
-						     EVC_FORMAT_VCARD_30);
-			e_data_book_respond_get_contact (book,
-							 opid,
-							 NULL /* Success */,
-							 vcard);
-			g_free (vcard);
-			g_object_unref (contact);
-			return;
+	EDataBook *book;
+	guint32 opid;
+} OperationBase;
+
+/* typedef struct {
+	OperationBase base;
+
+	ESource *source;
+	gboolean only_if_exists;
+} OperationLoadSource; */
+
+typedef struct {
+	OperationBase base;
+
+	gchar *user;
+	gchar *passwd;
+	gchar *auth_method;
+} OperationAuthenticateUser;
+
+typedef struct {
+	OperationBase base;
+
+	gchar *str;
+} OperationStr;
+
+typedef struct {
+	OperationBase base;
+
+	GList *id_list;
+} OperationIDList;
+
+typedef struct {
+	OperationBase base;
+
+	EDataBookView *book_view;
+} OperationBookView;
+
+static void
+ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
+{
+	EBookBackendMAPI *ebma;
+	EBookBackendMAPIClass *ebmac;
+	GError *error = NULL;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (op != NULL);
+
+	ebma = E_BOOK_BACKEND_MAPI (backend);
+	g_return_if_fail (ebma != NULL);
+
+	ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+	g_return_if_fail (ebmac != NULL);
+
+	switch (op->ot) {
+	/* it's a sync op by e_book_backend_open
+	case OP_LOAD_SOURCE: {
+		OperationLoadSource *opls = (OperationLoadSource *) op;
+
+		if (!cancelled) {
+			if (ebmac->op_load_source)
+				ebmac->op_load_source (ebma, opls->source, opls->only_if_exists, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
+
+			e_data_book_respond_open (op->book, op->opid, error);
 		}
-		else {
-			e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), "");
-			return;
+
+		g_object_unref (opls->source);
+	} break; */
+	case OP_REMOVE: {
+		if (!cancelled) {
+			if (ebmac->op_remove)
+				ebmac->op_remove (ebma, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
+
+			e_data_book_respond_remove (op->book, op->opid, error);
 		}
+	} break;
+	case OP_CREATE_CONTACT: {
+		OperationStr *ops = (OperationStr *) op;
+		const gchar *vcard = ops->str;
 
-	case E_DATA_BOOK_MODE_REMOTE:
+		if (!cancelled) {
+			EContact *contact = NULL;
 
-		if (priv->marked_for_offline && e_book_backend_cache_is_populated (priv->cache)) {
-			contact = e_book_backend_cache_get_contact (priv->cache,
-								    id);
-			if (contact) {
-				vcard =  e_vcard_to_string (E_VCARD (contact),
-							     EVC_FORMAT_VCARD_30);
-				e_data_book_respond_get_contact (book,
-								 opid,
-								 NULL /* Success */,
-								 vcard);
-				g_free (vcard);
-				g_object_unref (contact);
-				return;
-			}
-			else {
-				e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), "");
-				return;
-			}
+			if (ebmac->op_create_contact)
+				ebmac->op_create_contact (ebma, vcard, &contact, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-		} else {
-			mapi_id_t fid, mid;
-			GError *mapi_error = NULL;
-
-			exchange_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
-			exchange_mapi_connection_fetch_item (priv->conn, priv->fid, mid,
-							is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-							create_contact_item, contact,
-							options, &mapi_error);
-
-			if (contact) {
-				e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
-				vcard =  e_vcard_to_string (E_VCARD (contact),
-							     EVC_FORMAT_VCARD_30);
-				e_data_book_respond_get_contact (book,
-								 opid,
-								 NULL /* Success */,
-								 vcard);
-				g_free (vcard);
+			if (contact && !error)
+				e_book_backend_mapi_notify_contact_update (ebma, NULL, contact, NULL, -1, -1, NULL);
+
+			e_data_book_respond_create (op->book, op->opid, error, contact);
+
+			if (contact)
 				g_object_unref (contact);
-				return;
+		}
 
-			} else {
-				GError *err = NULL;
+		g_free (ops->str);
+	} break;
+	case OP_REMOVE_CONTACTS: {
+		OperationIDList *opil = (OperationIDList *) op;
 
-				if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
-					err = EDB_ERROR (CONTACT_NOT_FOUND);
-				} else {
-					mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL);
-				}
+		if (!cancelled) {
+			GList *removed_ids = NULL;
 
-				e_data_book_respond_get_contact (book, opid, err, "");
+			if (ebmac->op_remove_contacts)
+				ebmac->op_remove_contacts (ebma, opil->id_list, &removed_ids, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-				if (mapi_error)
-					g_error_free (mapi_error);
+			if (!error) {
+				GList *r;
 
-				return;
+				for (r = removed_ids; r; r = r->next) {
+					const gchar *uid = r->data;
+
+					if (uid)
+						e_book_backend_mapi_notify_contact_removed (ebma, uid);
+				}
 			}
+
+			e_data_book_respond_remove_contacts (op->book, op->opid, error, removed_ids);
+
+			g_list_foreach (removed_ids, (GFunc) g_free, NULL);
+			g_list_free (removed_ids);
 		}
 
-	default:
-		break;
-	}
+		g_list_foreach (opil->id_list, (GFunc) g_free, NULL);
+		g_list_free (opil->id_list);
+	} break;
+	case OP_MODIFY_CONTACT: {
+		OperationStr *ops = (OperationStr *) op;
+		const gchar *vcard = ops->str;
 
-	return;
+		if (!cancelled) {
+			EContact *contact = NULL;
 
-}
+			if (ebmac->op_modify_contact)
+				ebmac->op_modify_contact (ebma, vcard, &contact, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-static gboolean
-create_contact_list_cb (FetchItemsCallbackData *item_data, gpointer data)
-{
-	struct mapi_SPropValue_array *array = item_data->properties;
-	const mapi_id_t fid = item_data->fid;
-	const mapi_id_t mid = item_data->mid;
+			if (contact && !error)
+				e_book_backend_mapi_notify_contact_update (ebma, NULL, contact, NULL, -1, -1, NULL);
 
-	GList **listptr = data;
-	EContact *contact;
-	gchar *suid;
+			e_data_book_respond_modify (op->book, op->opid, error, contact);
 
-	contact = mapi_book_utils_contact_from_props (item_data->conn, fid, array, NULL);
-	suid = exchange_mapi_util_mapi_ids_to_uid (fid, mid);
+			if (contact)
+				g_object_unref (contact);
+		}
 
-	if (contact) {
-		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-		printf("Contact added %s\n", suid);
-		e_contact_set (contact, E_CONTACT_UID, suid);
-//		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
-		//FIXME: Should we set this? How can we get this first?
-		*listptr = g_list_prepend (*listptr, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
-		g_object_unref (contact);
-	}
+		g_free (ops->str);
+	} break;
+	case OP_GET_CONTACT: {
+		OperationStr *ops = (OperationStr *) op;
+		const gchar *id = ops->str;
 
-	g_free (suid);
-	return TRUE;
-}
+		if (!cancelled) {
+			gchar *vcard = NULL;
 
-static void
-e_book_backend_mapi_get_contact_list (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid,
-					    const gchar   *query )
-{
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	ESource *source;
-	guint32 options = MAPI_OPTIONS_FETCH_ALL; 
-	gboolean is_public = FALSE; 	
-	source = e_book_backend_get_source(backend);
-	if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
-		options |= MAPI_OPTIONS_USE_PFSTORE;
-		is_public = TRUE;
-	}
+			if (ebmac->op_get_contact)
+				ebmac->op_get_contact (ebma, id, &vcard, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-	printf("mapi: get contact list %s\n", query);
-	switch (priv->mode) {
-	case E_DATA_BOOK_MODE_LOCAL:
-		if (priv->marked_for_offline && priv->cache) {
-			GList *contacts;
-			GList *vcard_strings = NULL;
-			GList *l;
+			e_data_book_respond_get_contact (op->book, op->opid, error, vcard);
 
-			contacts = e_book_backend_cache_get_contacts (priv->cache, query);
+			g_free (vcard);
+		}
 
-			for (l = contacts; l; l = g_list_next (l)) {
-				EContact *contact = l->data;
-				vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
-								EVC_FORMAT_VCARD_30));
-				g_object_unref (contact);
-			}
+		g_free (ops->str);
+	} break;
+	case OP_GET_CONTACT_LIST: {
+		OperationStr *ops = (OperationStr *) op;
+		const gchar *query = ops->str;
 
-			g_list_free (contacts);
-			printf("get_contact_list in  %s returning %d contacts\n", priv->uri, g_list_length (vcard_strings));
-			e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_strings);
-			return;
+		if (!cancelled) {
+			GList *vCards = NULL;
+
+			if (ebmac->op_get_contact_list)
+				ebmac->op_get_contact_list (ebma, query, &vCards, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
+
+			e_data_book_respond_get_contact_list (op->book, op->opid, error, vCards);
+
+			/* respond freed them */
+			/* g_list_foreach (vCards, (GFunc) g_free, NULL); */
+			g_list_free (vCards);
 		}
-		e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (REPOSITORY_OFFLINE),
-						      NULL);
-		return;
 
-	case E_DATA_BOOK_MODE_REMOTE:
-		printf("Mode : Remote\n");
-		if (priv->marked_for_offline && priv->cache) {
-			GList *contacts;
-			GList *vcard_strings = NULL;
-			GList *l;
-
-			contacts = e_book_backend_cache_get_contacts (priv->cache, query);
-
-			for (l = contacts; l;l = g_list_next (l)) {
-				EContact *contact = l->data;
-				vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
-								EVC_FORMAT_VCARD_30));
-				g_object_unref (contact);
+		g_free (ops->str);
+	} break;
+	case OP_START_BOOK_VIEW: {
+		OperationBookView *opbv = (OperationBookView *) op;
+
+		if (!cancelled && e_book_backend_mapi_book_view_is_running (ebma, opbv->book_view)) {
+			GError *err = NULL;
+			struct BookViewThreadData *bvtd = g_new0 (struct BookViewThreadData, 1);
+
+			bvtd->ebma = g_object_ref (ebma);
+			bvtd->book_view = g_object_ref (opbv->book_view);
+
+			g_thread_create (ebbm_book_view_thread, bvtd, FALSE, &err);
+
+			if (err) {
+				error = EDB_ERROR_EX (OTHER_ERROR, err->message);
+				e_data_book_view_notify_complete (opbv->book_view, error);
+				g_error_free (error);
+				g_error_free (err);
 			}
+		}
 
-			g_list_free (contacts);
-			printf("get_contact_list in %s  returning %d contacts\n", priv->uri, g_list_length (vcard_strings));
-			e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_strings);
-			return;
+		g_object_unref (opbv->book_view);
+	} break;
+	case OP_STOP_BOOK_VIEW: {
+		OperationBookView *opbv = (OperationBookView *) op;
+
+		if (!cancelled) {
+			e_data_book_view_notify_complete (opbv->book_view, NULL);
 		}
-		else {
-			GError *mapi_error = NULL;
-			struct mapi_SRestriction res;
-			GList *vcard_str = NULL;
-			gboolean no_summary_search = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
-
-			printf("Not marked for cache\n");
-
-			/* Unfortunately MAPI Doesn't support searching well, we do allow only online search for emails rest all are returned as error. */
-			if (!no_summary_search && !build_restriction_emails_contains (&res, query)) {
-				e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (OTHER_ERROR), NULL);
-				return;
-			}
 
-			if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, no_summary_search ? NULL : &res, NULL,
-								is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-								create_contact_list_cb, &vcard_str,
-								options, &mapi_error)) {
-				GError *err = NULL;
+		g_object_unref (opbv->book_view);
+	} break;
+	case OP_GET_CHANGES: {
+		OperationStr *ops = (OperationStr *) op;
+		const gchar *change_id = ops->str;
 
-				mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
-				e_data_book_respond_get_contact_list (book, opid, err, NULL);
+		if (!cancelled) {
+			GList *changes = NULL;
 
-				if (mapi_error)
-					g_error_free (mapi_error);
+			if (ebmac->op_get_changes)
+				ebmac->op_get_changes (ebma, change_id, &changes, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-				return;
-			}
-			printf("get_contact_list in %s returning %d contacts\n", priv->uri, g_list_length (vcard_str));
-			e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_str);
-			return;
+			e_data_book_respond_get_changes (op->book, op->opid, error, changes);
 
+			g_list_foreach (changes, (GFunc) free_data_book_change, NULL);
+			g_list_free (changes);
 		}
-	}
-}
 
-typedef struct {
-	EBookBackendMAPI *bg;
-	EDataBookView *book_view;
-	gboolean stop;
-} BESearchClosure;
+		g_free (ops->str);
+	} break;
+	case OP_AUTHENTICATE_USER: {
+		OperationAuthenticateUser *opau = (OperationAuthenticateUser *) op;
 
-static BESearchClosure*
-init_closure (EDataBookView *book_view, EBookBackendMAPI *bg)
-{
-	BESearchClosure *closure;
+		if (!cancelled) {
+			if (ebmac->op_authenticate_user)
+				ebmac->op_authenticate_user (ebma, opau->user, opau->passwd, opau->auth_method, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-	g_return_val_if_fail (bg != NULL, NULL);
-	g_return_val_if_fail (bg->priv != NULL, NULL);
-	g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
-	
-	closure = g_new0 (BESearchClosure, 1);
-	closure->bg = bg;
-	closure->book_view = book_view;
-	closure->stop = FALSE;
+			e_data_book_respond_authenticate_user (op->book, op->opid, error);
+		}
+
+		if (opau->passwd)
+			memset (opau->passwd, 0, strlen (opau->passwd));
+
+		g_free (opau->user);
+		g_free (opau->passwd);
+		g_free (opau->auth_method);
+	} break;
+	case OP_GET_REQUIRED_FIELDS: {
+		if (!cancelled) {
+			GList *fields = NULL;
+
+			if (ebmac->op_get_required_fields)
+				ebmac->op_get_required_fields (ebma, &fields, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
 
-	g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
+			e_data_book_respond_get_required_fields (op->book, op->opid, error, fields);
+
+			/* do not free list data, only list itself */
+			g_list_free (fields);
+		}
+	} break;
+	case OP_GET_SUPPORTED_FIELDS: {
+		if (!cancelled) {
+			GList *fields = NULL;
+
+			if (ebmac->op_get_supported_fields)
+				ebmac->op_get_supported_fields (ebma, &fields, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
+
+			e_data_book_respond_get_supported_fields (op->book, op->opid, error, fields);
+
+			/* do not free list data, only list itself */
+			g_list_free (fields);
+		}
+	} break;
+	case OP_GET_SUPPORTED_AUTH_METHODS: {
+		if (!cancelled) {
+			GList *methods = NULL;
+
+			if (ebmac->op_get_supported_auth_methods)
+				ebmac->op_get_supported_auth_methods (ebma, &methods, &error);
+			else
+				error = EDB_ERROR (NOT_SUPPORTED);
+
+			e_data_book_respond_get_supported_auth_methods (op->book, op->opid, error, methods);
+
+			g_list_foreach (methods, (GFunc) g_free, NULL);
+			g_list_free (methods);
+		}
+	} break;
+	}
 
-	return closure;
+	g_free (op);
 }
 
 static void
-destroy_closure (BESearchClosure *closure)
+base_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, OperationType ot)
 {
-	g_return_if_fail (closure != NULL);
+	OperationBase *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-	if (closure->book_view)
-		g_object_unref (closure->book_view);
-	g_free (closure);
+	op = g_new0 (OperationBase, 1);
+	op->ot = ot;
+	op->book = book;
+	op->opid = opid;
+
+	em_operation_queue_push (priv->op_queue, op);
 }
 
 static void
-stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPI *mapi_backend)
+str_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *str, OperationType ot)
 {
-	g_return_if_fail (closure != NULL);
+	OperationStr *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
+
+	op = g_new0 (OperationStr, 1);
+	op->base.ot = ot;
+	op->base.book = book;
+	op->base.opid = opid;
+	op->str = g_strdup (str);
+
+	em_operation_queue_push (priv->op_queue, op);
+}
+
+#define BASE_OP_DEF(_func, _ot)					\
+static void							\
+_func (EBookBackend *backend, EDataBook *book, guint32 opid)	\
+{								\
+	base_op_abstract (backend, book, opid, _ot);		\
+}
 
-	closure->stop = TRUE;
+#define STR_OP_DEF(_func, _ot)							\
+static void									\
+_func (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *str)	\
+{										\
+	str_op_abstract (backend, book, opid, str, _ot);			\
 }
 
+BASE_OP_DEF (ebbm_op_remove, OP_REMOVE)
+STR_OP_DEF  (ebbm_op_create_contact, OP_CREATE_CONTACT)
+STR_OP_DEF  (ebbm_op_modify_contact, OP_MODIFY_CONTACT)
+STR_OP_DEF  (ebbm_op_get_contact, OP_GET_CONTACT)
+STR_OP_DEF  (ebbm_op_get_contact_list, OP_GET_CONTACT_LIST)
+STR_OP_DEF  (ebbm_op_get_changes, OP_GET_CHANGES)
+BASE_OP_DEF (ebbm_op_get_required_fields, OP_GET_REQUIRED_FIELDS)
+BASE_OP_DEF (ebbm_op_get_supported_fields, OP_GET_SUPPORTED_FIELDS)
+BASE_OP_DEF (ebbm_op_get_supported_auth_methods, OP_GET_SUPPORTED_AUTH_METHODS)
+
 static void
-untrack_book_view (EBookBackendMAPI *mapi_backend, EDataBookView *book_view)
+ebbm_op_load_source (EBookBackend *backend, ESource *source, gboolean only_if_exists, GError **error)
 {
-	g_return_if_fail (mapi_backend != NULL);
-	g_return_if_fail (mapi_backend->priv != NULL);
-	g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
-	g_return_if_fail (book_view != NULL);
+	/*OperationLoadSource *op;*/
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
+	EBookBackendMAPIClass *ebmac;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+	g_return_if_fail (source != NULL);
+
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-	g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
+	ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebbm);
+	g_return_if_fail (ebmac != NULL);
+
+	/* it's a sync op by e_book_backend_open 
+	op = g_new0 (OperationLoadSource, 1);
+	op->base.ot = OP_LOAD_SOURCE;
+	op->base.book = book;
+	op->base.opid = opid;
+	op->source = g_object_ref (source);
+	op->only_if_exists = only_if_exists;
+
+	em_operation_queue_push (priv->op_queue, op);
+	*/
+
+	if (ebmac->op_load_source)
+		ebmac->op_load_source (ebbm, source, only_if_exists, error);
+	else
+		g_propagate_error (error, EDB_ERROR (NOT_SUPPORTED));
 }
 
 static void
-get_contacts_from_cache (EBookBackendMAPI *ebmapi,
-			 const gchar *query,
-			 GPtrArray *ids,
-			 EDataBookView *book_view,
-			 BESearchClosure *closure)
+ebbm_op_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GList *id_list)
 {
-	gint i;
+	OperationIDList *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
+	GList *l;
 
-	if (enable_debug)
-		printf ("\nread contacts from cache for the ids found in summary\n");
-	for (i = 0; i < ids->len; i ++) {
-		gchar *uid;
-		EContact *contact;
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+	g_return_if_fail (id_list != NULL);
 
-                if (closure->stop)
-                        break;
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-		uid = g_ptr_array_index (ids, i);
-		contact = e_book_backend_cache_get_contact (ebmapi->priv->cache, uid);
-		if (contact) {
-			e_data_book_view_notify_update (book_view, contact);
-			g_object_unref (contact);
-		}
+	op = g_new0 (OperationIDList, 1);
+	op->base.ot = OP_REMOVE_CONTACTS;
+	op->base.book = book;
+	op->base.opid = opid;
+	op->id_list = g_list_copy (id_list);
+
+	for (l = op->id_list; l; l = l->next) {
+		l->data = g_strdup (l->data);
 	}
+
+	em_operation_queue_push (priv->op_queue, op);
 }
 
-static gboolean
-create_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+static void
+ebbm_op_start_book_view (EBookBackend *backend, EDataBookView *book_view)
 {
-	BESearchClosure *closure = data;
-	EDataBookView *book_view = closure->book_view;
-	EBookBackendMAPI *be = closure->bg;
-	EContact *contact;
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
-	gchar *suid;
+	OperationBookView *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
 
-	if (closure->stop)
-		return FALSE;
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+	g_return_if_fail (book_view != NULL);
 
-	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
-	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-	if (contact) {
-		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-		e_contact_set (contact, E_CONTACT_UID, suid);
-		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
-		if (priv->cache)
-			e_book_backend_cache_add_contact (priv->cache, contact);
-		e_data_book_view_notify_update (book_view, contact);
-		g_object_unref(contact);
-	}
+	op = g_new0 (OperationBookView, 1);
+	op->base.ot = OP_START_BOOK_VIEW;
+	op->base.book = NULL;
+	op->base.opid = 0;
+	op->book_view = g_object_ref (book_view);
 
-	g_free (suid);
-	return TRUE;
+	g_hash_table_insert (priv->running_book_views, book_view, GINT_TO_POINTER(1));
+
+	em_operation_queue_push (priv->op_queue, op);
 }
 
 static void
-book_view_thread (gpointer data)
+ebbm_op_stop_book_view (EBookBackend *backend, EDataBookView *book_view)
 {
-	struct mapi_SRestriction res;
-	struct mapi_SRestriction_or *or_res = NULL;
-	BESearchClosure *closure = data;
-	EDataBookView *book_view = closure->book_view;
-	EBookBackendMAPI *backend = closure->bg;
-	EBookBackendMAPIPrivate *priv = backend->priv;
-	const gchar *query = NULL;
-	GPtrArray *ids = NULL;
-	GList *contacts = NULL, *temp_list = NULL;
-	//Number of multiple restriction to apply
-	guint res_count = 6;
-	ESource *source;
-	guint32 options = MAPI_OPTIONS_FETCH_ALL; 
-	gboolean is_public = FALSE;
-	GError *err = NULL;
-	GError *mapi_error = NULL;
+	OperationBookView *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
 
-	source = e_book_backend_get_source(E_BOOK_BACKEND(backend));
-	if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
-		options |= MAPI_OPTIONS_USE_PFSTORE;
-		is_public = TRUE;
-	}
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+	g_return_if_fail (book_view != NULL);
 
-	if (enable_debug)
-		printf("mapi: book view\n");
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-	e_data_book_view_notify_status_message (book_view, "Searching...");
-	query = e_data_book_view_get_card_query (book_view);
+	op = g_new0 (OperationBookView, 1);
+	op->base.ot = OP_STOP_BOOK_VIEW;
+	op->base.book = NULL;
+	op->base.opid = 0;
+	op->book_view = g_object_ref (book_view);
 
-	switch (priv->mode) {
+	g_hash_table_remove (priv->running_book_views, book_view);
 
-	case E_DATA_BOOK_MODE_LOCAL:
-		if (!priv->marked_for_offline) {
-			err = EDB_ERROR (OFFLINE_UNAVAILABLE);
-			e_data_book_view_notify_complete (book_view, err);
-			g_error_free (err);
-			untrack_book_view (backend, book_view);
-			destroy_closure (closure);
-			return;
-		}
-		if (!priv->cache) {
-			printf("The cache is not yet built\n");
-			e_data_book_view_notify_complete (book_view, NULL /* Success */);
-			untrack_book_view (backend, book_view);
-			destroy_closure (closure);
-			return;
-		}
+	em_operation_queue_push (priv->op_queue, op);
+}
 
-		if (priv->is_summary_ready &&
-		    e_book_backend_summary_is_summary_query (priv->summary, query)) {
-			if (enable_debug)
-				printf ("reading the contacts from summary \n");
-			ids = e_book_backend_summary_search (priv->summary, query);
-			if (ids && ids->len > 0)
-				get_contacts_from_cache (backend, query, ids, book_view, closure);
-			if (ids)
-				g_ptr_array_free (ids, TRUE);
-			untrack_book_view (backend, book_view);
-			destroy_closure (closure);
-			return;
-		}
+static void
+ebbm_op_authenticate_user (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *user, const gchar *passwd, const gchar *auth_method)
+{
+	OperationAuthenticateUser *op;
+	EBookBackendMAPI *ebbm;
+	EBookBackendMAPIPrivate *priv;
 
-		/* fall back to cache */
-		if (enable_debug)
-			printf ("summary not found or a summary query  reading the contacts from cache %s\n", query);
-
-		contacts = e_book_backend_cache_get_contacts (priv->cache,
-							      query);
-		temp_list = contacts;
-		for (; contacts != NULL; contacts = g_list_next(contacts)) {
-			if (closure->stop) {
-				for (;contacts != NULL; contacts = g_list_next (contacts))
-					g_object_unref (contacts->data);
-				break;
-			}
-			e_data_book_view_notify_update (book_view,
-							E_CONTACT(contacts->data));
-			g_object_unref (contacts->data);
-		}
-		e_data_book_view_notify_complete (book_view, NULL /* Success */);
-		if (temp_list)
-			 g_list_free (temp_list);
-		untrack_book_view (backend, book_view);
-		destroy_closure (closure);
-		return;
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
 
-	case E_DATA_BOOK_MODE_REMOTE:
+	ebbm = E_BOOK_BACKEND_MAPI (backend);
+	priv = ebbm->priv;
+	g_return_if_fail (priv != NULL);
 
-		if (!priv->conn || !exchange_mapi_connection_connected (priv->conn)) {
-			e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
-			err = EDB_ERROR (AUTHENTICATION_REQUIRED);
-			e_data_book_view_notify_complete (book_view, err);
-			g_error_free (err);
-			untrack_book_view (backend, book_view);
-			destroy_closure (closure);
-			return;
-		}
+	op = g_new0 (OperationAuthenticateUser, 1);
+	op->base.ot = OP_AUTHENTICATE_USER;
+	op->base.book = book;
+	op->base.opid = opid;
+	op->user = g_strdup (user);
+	op->passwd = g_strdup (passwd);
+	op->auth_method = g_strdup (auth_method);
 
-		if (priv->marked_for_offline && priv->cache && priv->is_cache_ready) {
-			if (priv->is_summary_ready &&
-			    e_book_backend_summary_is_summary_query (priv->summary, query)) {
-				if (enable_debug)
-					printf ("reading the contacts from summary \n");
-				ids = e_book_backend_summary_search (priv->summary, query);
-				if (ids && ids->len > 0)
-					get_contacts_from_cache (backend, query, ids, book_view, closure);
-				if (ids)
-					g_ptr_array_free (ids, TRUE);
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
-				return;
-			}
+	em_operation_queue_push (priv->op_queue, op);
+}
 
-			printf("Summary seems to be not there or not a summary query, lets fetch from cache directly\n");
+static void
+e_book_backend_mapi_init (EBookBackendMAPI *ebma)
+{
+	EBookBackendMAPIPrivate *priv;
 
-			/* We are already cached. Lets return from there. */
-			contacts = e_book_backend_cache_get_contacts (priv->cache,
-								      query);
-			temp_list = contacts;
-			for (; contacts != NULL; contacts = g_list_next(contacts)) {
-				if (closure->stop) {
-					for (;contacts != NULL; contacts = g_list_next (contacts))
-						g_object_unref (contacts->data);
-					break;
-				}
-				e_data_book_view_notify_update (book_view,
-								E_CONTACT(contacts->data));
-				g_object_unref (contacts->data);
-			}
-			e_data_book_view_notify_complete (book_view, NULL /* Success */);
-			if (temp_list)
-				 g_list_free (temp_list);
-			untrack_book_view (backend, book_view);
-			destroy_closure (closure);
-			return;
-		}
+	priv = G_TYPE_INSTANCE_GET_PRIVATE (ebma, E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIPrivate);
 
-		if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
-			/* free when done with or_res, not before */
-			gchar *to_free = NULL;
+	/* Priv Struct init */
+	ebma->priv = priv;
 
-			or_res = g_new0 (struct mapi_SRestriction_or, res_count);
+	priv->op_queue = em_operation_queue_new ((EMOperationQueueFunc) ebbm_operation_cb, ebma);
+	priv->running_book_views = g_hash_table_new (g_direct_hash, g_direct_equal);
+	priv->conn_lock = g_mutex_new ();
 
-			if (!build_multiple_restriction_emails_contains (priv->conn, priv->fid, &res, or_res, query, &to_free)) {
-				err = EDB_ERROR_EX (OTHER_ERROR, "Cannot build query based on email");
-				e_data_book_view_notify_complete (book_view, err);
-				g_error_free (err);
-				g_free (or_res);
-				g_free (to_free);
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
-				return;
-			}
+	priv->update_cache = g_cancellable_new ();
+}
 
-			//FIXME: We need to fetch only the query from the server live and not everything.
-			if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, &res, NULL,
-							   is_public ? NULL : mapi_book_utils_get_prop_list, GET_SHORT_SUMMARY,
-							   create_contact_cb, closure,
-							   options, &mapi_error)) {
-				mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
-				e_data_book_view_notify_complete (book_view, err);
-				g_error_free (err);
+static void
+ebbm_dispose (GObject *object)
+{
+	EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (object);
+	EBookBackendMAPIPrivate *priv = ebma->priv;
 
-				if (mapi_error)
-					g_error_free (mapi_error);
+	if (priv) {
+		if (priv->update_cache_thread) {
+			g_cancellable_cancel (priv->update_cache);
+			g_thread_join (priv->update_cache_thread);
+			priv->update_cache_thread = NULL;
+		}
 
-				if (or_res)
-					g_free(or_res);
-				g_free (to_free);
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
+		#define FREE(x) if (x) { g_free (x); x = NULL; }
+		#define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
 
-				return;
-			}
+		e_book_backend_mapi_lock_connection (ebma);
+		UNREF (priv->conn);
+		e_book_backend_mapi_unlock_connection (ebma);
+		UNREF (priv->op_queue);
+		UNREF (priv->summary);
+		UNREF (priv->cache);
+		UNREF (priv->update_cache);
 
-			g_free (to_free);
-		} else {
-			if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, NULL, NULL,
-							is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-							create_contact_cb, closure,
-							options, &mapi_error)) {
-				mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
-				e_data_book_view_notify_complete (book_view, err);
-				g_error_free (err);
+		FREE (priv->profile);
+		FREE (priv->book_uri);
 
-				if (mapi_error)
-					g_error_free (mapi_error);
+		g_hash_table_destroy (priv->running_book_views);
+		g_mutex_free (priv->conn_lock);
 
-				untrack_book_view (backend, book_view);
-				destroy_closure (closure);
-				return;
-			}
-		}
+		#undef UNREF
+		#undef FREE
 
-		e_data_book_view_notify_complete (book_view, NULL /* Success */);
-	default:
-		break;
+		ebma->priv = NULL;
 	}
 
-	if (or_res)
-		g_free(or_res);
-
-	untrack_book_view (backend, book_view);
-	destroy_closure (closure);
+	/* Chain up to parent's dispose() method. */
+	if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
+		G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
 }
 
 static void
-e_book_backend_mapi_start_book_view (EBookBackend  *backend,
-					   EDataBookView *book_view)
+e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
 {
-	BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPI (backend));
+	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+	EBookBackendClass *backend_class = E_BOOK_BACKEND_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (EBookBackendMAPIPrivate));
+
+	object_class->dispose                     = ebbm_dispose;
+
+	backend_class->load_source		  = ebbm_op_load_source;
+	backend_class->remove			  = ebbm_op_remove;
+	backend_class->get_static_capabilities    = ebbm_get_static_capabilities;
+	backend_class->create_contact		  = ebbm_op_create_contact;
+	backend_class->remove_contacts		  = ebbm_op_remove_contacts;
+	backend_class->modify_contact		  = ebbm_op_modify_contact;
+	backend_class->get_contact                = ebbm_op_get_contact;
+	backend_class->get_contact_list           = ebbm_op_get_contact_list;
+	backend_class->start_book_view            = ebbm_op_start_book_view;
+	backend_class->stop_book_view             = ebbm_op_stop_book_view;
+	backend_class->get_changes                = ebbm_op_get_changes;
+	backend_class->authenticate_user          = ebbm_op_authenticate_user;
+	backend_class->get_required_fields	  = ebbm_op_get_required_fields;
+	backend_class->get_supported_fields	  = ebbm_op_get_supported_fields;
+	backend_class->get_supported_auth_methods = ebbm_op_get_supported_auth_methods;
+	backend_class->cancel_operation		  = ebbm_cancel_operation;
+	backend_class->set_mode                   = ebbm_set_mode;
+
+	klass->op_load_source                     = ebbm_load_source;
+	klass->op_remove                          = ebbm_remove;
+	klass->op_get_required_fields             = ebbm_get_required_fields;
+	klass->op_get_supported_fields            = ebbm_get_supported_fields;
+	klass->op_get_supported_auth_methods      = ebbm_get_supported_auth_methods;
+	klass->op_authenticate_user               = ebbm_authenticate_user;
+	klass->op_get_contact                     = ebbm_get_contact;
+	klass->op_get_contact_list                = ebbm_get_contact_list;
+
+	klass->op_connection_status_changed       = NULL;
+	klass->op_get_status_message              = NULL;
+	klass->op_book_view_thread                = NULL;
+	klass->op_fetch_contacts                  = NULL;
+	klass->op_fetch_known_uids                = NULL;
+}
 
-	g_return_if_fail (closure != NULL);
+gboolean
+e_book_backend_mapi_debug_enabled (void)
+{
+	gint8 debug_enabled = -1;
 
-	if (enable_debug)
-		printf ("mapi: start_book_view...\n");
+	if (debug_enabled == -1) {
+		if (g_getenv ("MAPI_DEBUG"))
+			debug_enabled = 1;
+		else
+			debug_enabled = 0;
+	}
 
-	g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
+	return debug_enabled != 0;
 }
 
-static void
-e_book_backend_mapi_stop_book_view (EBookBackend  *backend,
-					  EDataBookView *book_view)
+const gchar *
+e_book_backend_mapi_get_book_uri (EBookBackendMAPI *ebma)
 {
-	if (enable_debug)
-		printf("mapi: stop book view\n");
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
+	g_return_val_if_fail (ebma->priv != NULL, NULL);
 
-	untrack_book_view (E_BOOK_BACKEND_MAPI (backend), book_view);
+	return ebma->priv->book_uri;
 }
 
-static void
-e_book_backend_mapi_get_changes (EBookBackend *backend,
-				       EDataBook    *book,
-				       guint32       opid,
-				       const gchar *change_id  )
+void
+e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma)
 {
-	if (enable_debug)
-		printf("mapi: get changes\n");
-	/* FIXME : provide implmentation */
-	e_data_book_respond_get_changes (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+	g_return_if_fail (ebma->priv != NULL);
+	g_return_if_fail (ebma->priv->conn_lock != NULL);
+
+	g_mutex_lock (ebma->priv->conn_lock);
 }
 
-static gboolean
-cache_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+void
+e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma)
 {
-	EBookBackendMAPI *be = data;
-	EContact *contact;
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
-	gchar *suid;
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+	g_return_if_fail (ebma->priv != NULL);
+	g_return_if_fail (ebma->priv->conn_lock != NULL);
 
-	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
-	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	g_mutex_unlock (ebma->priv->conn_lock);
+}
 
-	if (contact) {
-		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-		e_contact_set (contact, E_CONTACT_UID, suid);
-		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
-		e_book_backend_cache_add_contact (priv->cache, contact);
-		e_book_backend_summary_add_contact (priv->summary, contact);
-		g_object_unref(contact);
-	}
+ExchangeMapiConnection *
+e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma)
+{
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
+	g_return_val_if_fail (ebma->priv != NULL, NULL);
 
-	g_free (suid);
-	return TRUE;
+	return ebma->priv->conn;
 }
 
-static gpointer
-build_cache (EBookBackendMAPI *ebmapi)
+void
+e_book_backend_mapi_get_summary_and_cache (EBookBackendMAPI *ebma, EBookBackendSummary **summary, EBookBackendCache **cache)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
-	gchar *tmp;
-	ESource *source;
-	guint32 options = MAPI_OPTIONS_FETCH_ALL; 
-	gboolean is_public = FALSE; 
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+	g_return_if_fail (ebma->priv != NULL);
 
-	source = e_book_backend_get_source(E_BOOK_BACKEND(ebmapi));
-	if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
-		options |= MAPI_OPTIONS_USE_PFSTORE;
-		is_public = TRUE;
-	}
+	if (summary)
+		*summary = ebma->priv->summary;
 
-	//FIXME: What if book view is NULL? Can it be? Check that.
-	if (!priv->cache) {
-		priv->cache = e_book_backend_cache_new (priv->uri);
-	}
+	if (cache)
+		*cache = ebma->priv->cache;
+}
 
-	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+gboolean
+e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view)
+{
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+	g_return_val_if_fail (ebma->priv != NULL, FALSE);
 
-	if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, NULL, NULL,
-						is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-						cache_contact_cb, ebmapi,
-						options, NULL)) {
-		printf("Error during caching addressbook\n");
-		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
-		return NULL;
-	}
-	tmp = g_strdup_printf("%d", (gint)time (NULL));
-	e_book_backend_cache_set_time (priv->cache, tmp);
-	printf("setting time  %s\n", tmp);
-	g_free (tmp);
-	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
-	e_book_backend_summary_save (priv->summary);
-	priv->is_cache_ready = TRUE;
-	priv->is_summary_ready = TRUE;
-	return NULL;
+	return g_hash_table_lookup (ebma->priv->running_book_views, book_view) != NULL;
 }
 
-#if 0
-static gpointer
-update_cache (EBookBackendMAPI *ebmapi)
+gboolean
+e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
-	gchar *tmp = e_book_backend_cache_get_time (priv->cache);
-	//FIXME: What if book view is NULL? Can it be? Check that.
-	time_t t=0;
-//	struct mapi_SRestriction res;
-
-	if (tmp)
-		t = atoi (tmp);
-
-//	res.rt = RES_PROPERTY;
-//	res.res.resProperty.relop = RES_PROPERTY;
-//	res.res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
-//	res.res.resProperty.lpProp.ulPropTag = PR_LAST_MODIFICATION_TIME;
-//	res.res.resProperty.lpProp.value.lpszA = email;
-
-#if 0
-	printf("time updated was %d\n", t);
-	/* Assume the cache and summary are already there */
-
-	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
-
-	if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, &res, NULL,
-						mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-						cache_contact_cb, ebmapi,
-						MAPI_OPTIONS_FETCH_ALL, NULL)) {
-		printf("Error during caching addressbook\n");
-		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
-		return NULL;
-	}
-	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
-	e_book_backend_summary_save (priv->summary);
-	priv->is_cache_ready = TRUE;
-	priv->is_summary_ready = TRUE;
-#endif
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+	g_return_val_if_fail (ebma->priv != NULL, FALSE);
 
-	return NULL;
+	return ebma->priv->marked_for_offline;
 }
-#endif
 
-static void
-e_book_backend_mapi_authenticate_user (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid,
-					    const gchar *user,
-					    const gchar *passwd,
-					    const gchar *auth_method)
+void
+e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	GError *mapi_error = NULL;
+	gint i;
+	const gchar *query = NULL;
+	EBookBackendCache *cache = NULL;
+	EBookBackendSummary *summary = NULL;
 
-	if (enable_debug) {
-		printf ("mapi: authenticate user\n");
-	}
+	g_return_if_fail (ebma != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+	g_return_if_fail (book_view != NULL);
+	g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
 
-	switch (priv->mode) {
-	case E_DATA_BOOK_MODE_LOCAL:
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
-		return;
+	query = e_data_book_view_get_card_query (book_view);
+	e_book_backend_mapi_get_summary_and_cache (ebma, &summary, &cache);
 
-	case E_DATA_BOOK_MODE_REMOTE:
-		g_static_mutex_lock (&priv->running_mutex);
+	if (e_book_backend_summary_is_summary_query (summary, query)) {
+		GPtrArray *ids = NULL;
 
-		/* rather reuse already established connection */
-		priv->conn = exchange_mapi_connection_find (priv->profile);
-		if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
-			exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
-		else if (!priv->conn)
-			priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
+		ids = e_book_backend_summary_search (summary, query);
+		if (ids) {
+			for (i = 0; i < ids->len; i ++) {
+				gchar *uid;
+				EContact *contact;
 
-		if (!priv->conn || mapi_error) {
-			GError *err = NULL;
+				if (i > 0 && (i % 10) == 0 && !e_book_backend_mapi_book_view_is_running (ebma, book_view))
+					break;
 
-			if (priv->conn) {
-				g_object_unref (priv->conn);
-				priv->conn = NULL;
+				uid = g_ptr_array_index (ids, i);
+				contact = e_book_backend_cache_get_contact (cache, uid);
+				if (contact) {
+					e_data_book_view_notify_update (book_view, contact);
+					g_object_unref (contact);
+				}
 			}
-				
-			mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
-			e_data_book_respond_authenticate_user (book, opid, err);
-			g_static_mutex_unlock (&priv->running_mutex);
 
-			if (mapi_error)
-				g_error_free (mapi_error);
-			return;
+			g_ptr_array_free (ids, TRUE);
 		}
+	} else {
+		GList *contacts = NULL, *c;
 
-		if (priv->cache && priv->is_cache_ready) {
-			printf("FIXME: Should check for an update in the cache\n");
-//			g_thread_create ((GThreadFunc) update_cache,
-	//					  backend, FALSE, backend);
-		} else if (priv->marked_for_offline && !priv->is_cache_ready) {
-			/* Means we dont have a cache. Lets build that first */
-			printf("Preparing to build cache\n");
-			g_thread_create ((GThreadFunc) build_cache, backend, FALSE, NULL);
+		contacts = e_book_backend_cache_get_contacts (cache, query);
+		for (c = contacts, i = 0; c != NULL; c = g_list_next (c), i++) {
+			if (i > 0 && (i % 10) == 0 && !e_book_backend_mapi_book_view_is_running (ebma, book_view))
+				break;
+
+			e_data_book_view_notify_update (book_view, E_CONTACT (c->data));
 		}
-		e_book_backend_set_is_writable (backend, TRUE);
-		e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
-		g_static_mutex_unlock (&priv->running_mutex);
-		return;
 
-	default :
-		break;
+		g_list_foreach (contacts, (GFunc) g_object_unref, NULL);
+		g_list_free (contacts);
 	}
 }
 
-static void
-e_book_backend_mapi_get_required_fields (EBookBackend *backend,
-					       EDataBook    *book,
-					       guint32       opid)
+static glong
+get_current_time_ms (void)
 {
-	GList *fields = NULL;
+	GTimeVal tv;
 
-	if (enable_debug)
-		printf ("mapi get_required_fields...\n");
+	g_get_current_time (&tv);
 
-	fields = g_list_append (fields, (gchar *)e_contact_field_name (E_CONTACT_FILE_AS));
-	e_data_book_respond_get_supported_fields (book, opid,
-						  NULL /* Success */,
-						  fields);
-	g_list_free (fields);
+	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
 }
 
-static void
-e_book_backend_mapi_get_supported_fields (EBookBackend *backend,
-					       EDataBook    *book,
-					       guint32       opid)
+/* called from op_fetch_contacts - book_view and notify_contact_data are taken from there;
+   notify_contact_data is a pointer to FetchContactsData, if not NULL;
+   returns whether can continue with fetching */
+gboolean
+e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *pbook_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data)
 {
-	GList *fields;
+	EBookBackendMAPIPrivate *priv;
+	struct FetchContactsData *fcd = notify_contact_data;
+	EDataBookView *book_view = pbook_view;
 
-	if (enable_debug)
-		printf ("mapi get_supported_fields...\n");
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+	g_return_val_if_fail (ebma->priv, FALSE);
+	g_return_val_if_fail (contact != NULL, FALSE);
 
-	fields = mapi_book_utils_get_supported_fields ();
-	e_data_book_respond_get_supported_fields (book, opid,
-						  NULL /* Success */,
-						  fields);
-	g_list_free (fields);
+	priv = ebma->priv;
+	g_return_val_if_fail (priv != NULL, FALSE);
 
-}
+	/* report progres to any book_view, if not passed in;
+	   it can happen when cache is filling and the book view started later */
+	if (!book_view)
+		book_view = ebbm_pick_book_view (ebma);
 
-static void
-e_book_backend_mapi_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	GList *auth_methods = NULL;
-	gchar *auth_method;
+	if (book_view) {
+		guint32 current_time;
 
-	if (enable_debug)
-		printf ("mapi get_supported_auth_methods...\n");
-
-	auth_method =  g_strdup_printf ("plain/password");
-	auth_methods = g_list_append (auth_methods, auth_method);
-	e_data_book_respond_get_supported_auth_methods (book,
-							opid,
-							NULL /* Success */,
-							auth_methods);
-	g_free (auth_method);
-	g_list_free (auth_methods);
-}
+		if (!e_book_backend_mapi_book_view_is_running (ebma, book_view))
+			return FALSE;
 
-static void
-e_book_backend_mapi_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
-	if (enable_debug)
-		printf ("mapi cancel_operation...\n");
-	g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
-}
+		current_time = get_current_time_ms ();
+		if (index > 0 && fcd && current_time - fcd->last_notification > 333) {
+			gchar *status_msg = NULL;
+			EBookBackendMAPIClass *ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
 
-static void
-e_book_backend_mapi_remove (EBookBackend *backend,
-				  EDataBook    *book,
-				  guint32      opid)
-{
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
-	gchar *cache_uri = NULL;
-	gboolean status = TRUE;
-	ESource *source;
-	GError *mapi_error = NULL;
+			if (ebmac->op_get_status_message)
+				status_msg = ebmac->op_get_status_message (ebma, index, total);
 
-	source = e_book_backend_get_source (backend);
+			if (status_msg)
+				e_data_book_view_notify_status_message (book_view, status_msg);
 
-	if (enable_debug)
-		printf("mapi: remove\n");
+			g_free (status_msg);
 
-	switch (priv->mode) {
+			fcd->last_notification = current_time;
+		}
+	}
 
-	case E_DATA_BOOK_MODE_LOCAL:
-		e_data_book_respond_remove (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
-		return;
+	if (!pbook_view && g_cancellable_is_cancelled (priv->update_cache))
+		return FALSE;
 
-	case E_DATA_BOOK_MODE_REMOTE:
-		
-		if (strcmp (e_source_get_property(source, "public"), "yes") != 0)
-			status = exchange_mapi_connection_remove_folder (priv->conn, priv->fid, 0, &mapi_error);
-		
-		if (!status) {
-			GError *err = NULL;
+	e_book_backend_cache_add_contact (ebma->priv->cache, contact);
+	e_book_backend_summary_add_contact (ebma->priv->summary, contact);
+	e_book_backend_notify_update (E_BOOK_BACKEND (ebma), contact);
 
-			if (mapi_error) {
-				mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder"));
-				g_error_free (mapi_error);
-			} else {
-				err = EDB_ERROR (OTHER_ERROR);
-			}
+	if (fcd && pr_last_modification_time) {
+		if (fcd->last_modification < pr_last_modification_time->tv_sec)
+			fcd->last_modification = pr_last_modification_time->tv_sec;
+	}
 
-			e_data_book_respond_remove (book, opid, err);
-			return;
-		}
+	return TRUE;
+}
 
-		if (priv->marked_for_offline && priv->is_summary_ready) {
-			g_object_unref (priv->summary);
-			priv->summary = NULL;
-		}
+void
+e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid)
+{
+	EBookBackendMAPIPrivate *priv;
 
-		if (e_book_backend_cache_exists (priv->uri)) {
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+	g_return_if_fail (ebma->priv);
+	g_return_if_fail (uid != NULL);
 
-			g_object_unref (priv->cache);
-			priv->cache= NULL;
+	priv = ebma->priv;
+	g_return_if_fail (priv != NULL);
 
-		}
+	e_book_backend_cache_remove_contact (priv->cache, uid);
+	e_book_backend_summary_remove_contact (priv->summary, uid);
+	e_book_backend_notify_remove (E_BOOK_BACKEND (ebma), uid);
+}
 
-		/* Remove the summary and cache independent of whether they are loaded or not. */
-		cache_uri = get_filename_from_uri (priv->uri, "cache.summary");
-		if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
-			g_unlink (cache_uri);
-		}
-		g_free (cache_uri);
+/* utility functions/macros */
 
-		cache_uri = get_filename_from_uri (priv->uri, "cache.xml");
-		if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
-			g_unlink (cache_uri);
-		}
-		g_free (cache_uri);
+/* 'data' is one of GET_ALL_KNOWN_IDS or GET_UIDS_ONLY */
+gboolean
+mapi_book_utils_get_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data)
+{
+	/* this is a list of all known book MAPI tag IDs;
+	   if you add new add it here too, otherwise it may not be fetched */
+	static uint32_t known_book_mapi_ids[] = {
+		PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE,
+		PR_ASSISTANT_UNICODE,
+		PR_BIRTHDAY,
+		PR_BODY,
+		PR_BODY_UNICODE,
+		PR_BUSINESS_FAX_NUMBER_UNICODE,
+		PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE,
+		PR_COMPANY_NAME_UNICODE,
+		PR_COUNTRY_UNICODE,
+		PR_DEPARTMENT_NAME_UNICODE,
+		PR_DISPLAY_NAME_UNICODE,
+		PR_EMAIL_ADDRESS_UNICODE,
+		PR_SMTP_ADDRESS_UNICODE, /* used in GAL */
+		PR_FID,
+		PR_GIVEN_NAME_UNICODE,
+		PR_HASATTACH,
+		PR_HOME_ADDRESS_CITY_UNICODE,
+		PR_HOME_ADDRESS_COUNTRY_UNICODE,
+		PR_HOME_ADDRESS_POSTAL_CODE_UNICODE,
+		PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE,
+		PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE,
+		PR_HOME_FAX_NUMBER_UNICODE,
+		PR_HOME_TELEPHONE_NUMBER_UNICODE,
+		PR_INSTANCE_NUM,
+		PR_INST_ID,
+		PR_LAST_MODIFICATION_TIME,
+		PR_LOCALITY_UNICODE,
+		PR_MANAGER_NAME_UNICODE,
+		PR_MESSAGE_CLASS,
+		PR_MID,
+		PR_MOBILE_TELEPHONE_NUMBER_UNICODE,
+		PR_NICKNAME_UNICODE,
+		PR_NORMALIZED_SUBJECT_UNICODE,
+		PR_OFFICE_LOCATION_UNICODE,
+		PR_OFFICE_TELEPHONE_NUMBER_UNICODE,
+		PR_PAGER_TELEPHONE_NUMBER_UNICODE,
+		PR_POSTAL_CODE_UNICODE,
+		PR_POST_OFFICE_BOX_UNICODE,
+		PR_PROFESSION_UNICODE,
+		PR_RULE_MSG_NAME,
+		PR_RULE_MSG_PROVIDER,
+		PR_SPOUSE_NAME_UNICODE,
+		PR_STATE_OR_PROVINCE_UNICODE,
+		PR_SUBJECT_UNICODE,
+		PR_SURNAME_UNICODE,
+		PR_TITLE_UNICODE,
+		PR_WEDDING_ANNIVERSARY,
+		PROP_TAG(PT_UNICODE, 0x801f)
+	};
 
-		e_data_book_respond_remove (book, opid, NULL /* Success */);
-		return;
+	static uint32_t uids_only_ids[] = {
+		PR_FID,
+		PR_MID,
+		PR_EMAIL_ADDRESS_UNICODE
+	};
+	
+	/* do not make this array static, the function modifies it on run */
+	ResolveNamedIDsData nids[] = {
+		{ PidLidDistributionListName, 0 },
+		{ PidLidDistributionListOneOffMembers, 0 },
+		{ PidLidDistributionListMembers, 0 },
+		{ PidLidDistributionListChecksum, 0 },
 
-	default:
-		break;
-	}
+		{ PidLidFileUnder, 0 },
 
-	return;
+		{ PidLidEmail1OriginalDisplayName, 0 },
+		{ PidLidEmail2OriginalDisplayName, 0 },
+		{ PidLidEmail3OriginalDisplayName, 0 },
+		{ PidLidInstantMessagingAddress, 0 },
+		{ PidLidHtml, 0 },
+		{ PidLidFreeBusyLocation, 0 }
+	};
+
+	g_return_val_if_fail (props != NULL, FALSE);
+
+	if (data == GET_UIDS_ONLY)
+		return exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, uids_only_ids, G_N_ELEMENTS (uids_only_ids));
 
-	/* FIXME : provide implmentation */
+	if (data == GET_ALL_KNOWN_IDS && !exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, known_book_mapi_ids, G_N_ELEMENTS (known_book_mapi_ids)))
+		return FALSE;
+
+	/* called with fid = 0 from GAL */
+	if (!fid)
+		fid = exchange_mapi_connection_get_default_folder_id (conn, olFolderContacts, NULL);
+
+	return exchange_mapi_utils_add_named_ids_to_props_array (conn, fid, mem_ctx, props, nids, G_N_ELEMENTS (nids));
 }
 
-static void
-e_book_backend_mapi_set_mode (EBookBackend *backend, EDataBookMode mode)
+static gchar *
+bin_to_string (const uint8_t *lpb, uint32_t cb)
 {
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	gchar *res, *p;
+	uint32_t i;
 
-	if (enable_debug)
-		printf("mapi: set_mode \n");
+	g_return_val_if_fail (lpb != NULL, NULL);
+	g_return_val_if_fail (cb > 0, NULL);
 
-	priv->mode = mode;
-	if (e_book_backend_is_loaded (backend)) {
-		if (mode == E_DATA_BOOK_MODE_LOCAL) {
-			e_book_backend_notify_writable (backend, FALSE);
-			e_book_backend_notify_connection_status (backend, FALSE);
-			/* FIXME: Uninitialize mapi here. may be.*/
-		}
-		else if (mode == E_DATA_BOOK_MODE_REMOTE) {
-			e_book_backend_notify_writable (backend, TRUE);
-			e_book_backend_notify_connection_status (backend, TRUE);
-			e_book_backend_notify_auth_required (backend); //FIXME: WTH is this required.
-		}
+	res = g_new0 (gchar, cb * 2 + 1);
+	for (i = 0, p = res; i < cb; i++, p += 2) {
+		sprintf (p, "%02x", lpb[i] & 0xFF);
 	}
+
+	return res;
 }
 
-static void
-e_book_backend_mapi_init (EBookBackendMAPI *backend)
+static const gchar *
+not_null (gconstpointer ptr)
 {
-	EBookBackendMAPIPrivate *priv;
+	return ptr ? (const gchar *) ptr : "";
+}
 
-	priv = g_new0 (EBookBackendMAPIPrivate, 1);
-	/* Priv Struct init */
-	backend->priv = priv;
+/* This is not setting E_CONTACT_UID */
+EContact *
+mapi_book_utils_contact_from_props (ExchangeMapiConnection *conn, mapi_id_t fid, const gchar *book_uri, struct mapi_SPropValue_array *mapi_properties, struct SRow *aRow)
+{
+	EContact *contact = e_contact_new ();
+	gint i;
 
-	priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
-	priv->summary = NULL;
+	if (book_uri)
+		e_contact_set (contact, E_CONTACT_BOOK_URI, book_uri);
 
-	priv->marked_for_offline = FALSE;
-	priv->uri = NULL;
-	priv->cache = NULL;
-	priv->is_summary_ready = FALSE;
-	priv->is_cache_ready = FALSE;
-	g_static_mutex_init (&priv->running_mutex);
+	#define get_proptag(proptag) (aRow ? exchange_mapi_util_find_row_propval (aRow, proptag) : exchange_mapi_util_find_array_propval (mapi_properties, proptag))
+	#define get_str_proptag(proptag) not_null (get_proptag (proptag))
+	#define get_namedid(nid) (aRow ? exchange_mapi_util_find_row_namedid (aRow, conn, fid, nid) : exchange_mapi_util_find_array_namedid (mapi_properties, conn, fid, nid))
+	#define get_str_namedid(nid) not_null (get_namedid (nid))
 
-	if (g_getenv ("MAPI_DEBUG"))
-		enable_debug = TRUE;
-	else
-		enable_debug = FALSE;
+	if (g_str_equal (get_str_proptag (PR_MESSAGE_CLASS), IPM_DISTLIST)) {
+		const struct mapi_SBinaryArray *members, *members_dlist;
+		GSList *attrs = NULL, *a;
+		gint i;
 
-}
+		/* it's a contact list/distribution list, fetch members and return it */
+		e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+		/* we do not support this option, same as GroupWise */
+		e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
 
-static void
-e_book_backend_mapi_dispose (GObject *object)
-{
-	EBookBackendMAPI *mapi_backend = E_BOOK_BACKEND_MAPI (object);
-	EBookBackendMAPIPrivate *priv = mapi_backend->priv;
+		e_contact_set (contact, E_CONTACT_FILE_AS, get_str_namedid (PidLidDistributionListName));
 
-	if (priv) {
-		if (priv->view_to_closure_hash) {
-			g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
-			g_hash_table_destroy (priv->view_to_closure_hash);
-			priv->view_to_closure_hash = NULL;
+		members = get_namedid (PidLidDistributionListOneOffMembers);
+		members_dlist = get_namedid (PidLidDistributionListMembers);
+
+		g_return_val_if_fail (members != NULL, NULL);
+		g_return_val_if_fail (members_dlist != NULL, NULL);
+
+		/* these two lists should be in sync */
+		g_return_val_if_fail (members_dlist->cValues == members->cValues, NULL);
+
+		for (i = 0; i < members->cValues; i++) {
+			struct Binary_r br;
+			gchar *display_name = NULL, *email = NULL;
+			gchar *str;
+
+			br.lpb = members->bin[i].lpb;
+			br.cb = members->bin[i].cb;
+			if (exchange_mapi_util_entryid_decode_oneoff (&br, &display_name, &email)) {
+				EVCardAttribute *attr;
+				gchar *value;
+				CamelInternetAddress *addr;
+
+				addr = camel_internet_address_new ();
+				attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+
+				camel_internet_address_add (addr, display_name, email);
+
+				value = camel_address_encode (CAMEL_ADDRESS (addr));
+
+				if (value)
+					e_vcard_attribute_add_value (attr, value);
+
+				g_free (value);
+				g_object_unref (addr);
+
+				str = g_strdup_printf ("%d", i + 1);
+				e_vcard_attribute_add_param_with_value (attr,
+						e_vcard_attribute_param_new (EMA_X_MEMBERID),
+						str);
+				g_free (str);
+
+				/* keep the value from ListMembers with the email, to not need to generate it on list changes;
+				   new values added in evolution-mapi will be always SMTP addresses anyway */
+				str = bin_to_string (members_dlist->bin[i].lpb, members_dlist->bin[i].cb);
+				if (str) {
+					e_vcard_attribute_add_param_with_value (attr,
+						e_vcard_attribute_param_new (EMA_X_MEMBERVALUE),
+						str);
+					g_free (str);
+				}
+
+				attrs = g_slist_prepend (attrs, attr);
+			}
+
+			g_free (display_name);
+			g_free (email);
 		}
 
-		#define FREE(x) if (x) { g_free (x); x = NULL; }
-		#define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
+		for (a = attrs; a; a = a->next) {
+			e_vcard_add_attribute (E_VCARD (contact), a->data);
+		}
 
-		/* this will also ensure any pending authentication
-		   request is finished and it's safe to free memory */
-		g_static_mutex_lock (&priv->running_mutex);
+		g_slist_free (attrs);
 
-		UNREF (priv->summary);
-		UNREF (priv->cache);
-		UNREF (priv->conn);
+		return contact;
+	}
 
-		FREE (priv->profile);
-		FREE (priv->uri);
-		FREE (priv->summary_file_name);
+	for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+		gpointer value;
+		gint contact_type;
+
+		/* can cast value, no writing to the value; and it'll be freed not before the end of this function */
+		if (mappings[i].contact_type & ELEMENT_TYPE_NAMEDID)
+			value = (gpointer) get_namedid (mappings[i].mapi_id);
+		else
+			value = (gpointer) get_proptag (mappings[i].mapi_id);
+		contact_type = mappings[i].contact_type & ELEMENT_TYPE_MASK;
+		if (mappings[i].element_type == PT_UNICODE && contact_type == ELEMENT_TYPE_SIMPLE) {
+			if (value)
+				e_contact_set (contact, mappings[i].field_id, value);
+		} else if (contact_type == ELEMENT_TYPE_SIMPLE) {
+			if (value && mappings[i].element_type == PT_SYSTIME) {
+				struct FILETIME *t = value;
+				time_t time;
+				NTTIME nt;
+				gchar buff[129];
+
+				nt = t->dwHighDateTime;
+				nt = nt << 32;
+				nt |= t->dwLowDateTime;
+				time = nt_time_to_unix (nt);
+				e_contact_set (contact, mappings[i].field_id, ctime_r (&time, buff));
+			}
+		} else if (contact_type == ELEMENT_TYPE_COMPLEX) {
+			if (mappings[i].field_id == E_CONTACT_IM_AIM) {
+				GList *list = g_list_append (NULL, value);
+
+				e_contact_set (contact, mappings[i].field_id, list);
+
+				g_list_free (list);
+			} else if (mappings[i].field_id == E_CONTACT_BIRTH_DATE
+				   || mappings[i].field_id == E_CONTACT_ANNIVERSARY) {
+				struct FILETIME *t = value;
+				time_t time;
+				NTTIME nt;
+				struct tm * tmtime;
+				if (value) {
+					EContactDate date = {0};
+					nt = t->dwHighDateTime;
+					nt = nt << 32;
+					nt |= t->dwLowDateTime;
+					time = nt_time_to_unix (nt);
+					tmtime = gmtime (&time);
+					//FIXME: Move to new libmapi api to get string dates.
+					date.day = tmtime->tm_mday;
+					date.month = tmtime->tm_mon + 1;
+					date.year = tmtime->tm_year + 1900;
+					e_contact_set (contact, mappings[i].field_id, &date);
+				}
 
-		g_static_mutex_unlock (&priv->running_mutex);
-		g_static_mutex_free (&priv->running_mutex);
+			} else if (mappings[i].field_id == E_CONTACT_ADDRESS_WORK
+				   || mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+				EContactAddress contact_addr = { 0 };
+
+				/* type-casting below to not allocate memory twice; e_contact_set will copy values itself. */
+				if (mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+					contact_addr.address_format = NULL;
+					contact_addr.po = NULL;
+					contact_addr.street = (gchar *)value;
+					contact_addr.ext = (gchar *) get_str_proptag (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE);
+					contact_addr.locality = (gchar *) get_str_proptag (PR_HOME_ADDRESS_CITY_UNICODE);
+					contact_addr.region = (gchar *) get_str_proptag (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE);
+					contact_addr.code = (gchar *) get_str_proptag (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE);
+					contact_addr.country = (gchar *) get_str_proptag (PR_HOME_ADDRESS_COUNTRY_UNICODE);
+				} else {
+					contact_addr.address_format = NULL;
+					contact_addr.po = NULL;
+					contact_addr.street = (gchar *)value;
+					contact_addr.ext = (gchar *) get_str_proptag (PR_POST_OFFICE_BOX_UNICODE);
+					contact_addr.locality = (gchar *) get_str_proptag (PR_LOCALITY_UNICODE);
+					contact_addr.region = (gchar *) get_str_proptag (PR_STATE_OR_PROVINCE_UNICODE);
+					contact_addr.code = (gchar *) get_str_proptag (PR_POSTAL_CODE_UNICODE);
+					contact_addr.country = (gchar *) get_str_proptag (PR_COUNTRY_UNICODE);
+				}
+				e_contact_set (contact, mappings[i].field_id, &contact_addr);
+			}
+		}
+	}
 
-		FREE (mapi_backend->priv);
+	if (!e_contact_get (contact, E_CONTACT_EMAIL_1)) {
+		gconstpointer value = get_proptag (PR_SMTP_ADDRESS_UNICODE);
 
-		#undef UNREF
-		#undef FREE
+		if (value)
+			e_contact_set (contact, E_CONTACT_EMAIL_1, value);
 	}
 
-	/* Chain up to parent's dispose() method. */
-	if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
-		G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
-}
+	#undef get_proptag
+	#undef get_str_proptag
+	#undef get_namedid
+	#undef get_str_namedid
 
-static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
-{
-	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
-	EBookBackendClass *parent_class;
-
-	parent_class = E_BOOK_BACKEND_CLASS (klass);
-
-	/* Set the virtual methods. */
-	parent_class->load_source		   = e_book_backend_mapi_load_source;
-	parent_class->get_static_capabilities    = e_book_backend_mapi_get_static_capabilities;
-	parent_class->create_contact             = e_book_backend_mapi_create_contact;
-	parent_class->remove_contacts            = e_book_backend_mapi_remove_contacts;
-	parent_class->modify_contact             = e_book_backend_mapi_modify_contact;
-	parent_class->get_contact                = e_book_backend_mapi_get_contact;
-	parent_class->get_contact_list           = e_book_backend_mapi_get_contact_list;
-	parent_class->start_book_view            = e_book_backend_mapi_start_book_view;
-	parent_class->stop_book_view             = e_book_backend_mapi_stop_book_view;
-	parent_class->get_changes                = e_book_backend_mapi_get_changes;
-	parent_class->authenticate_user          = e_book_backend_mapi_authenticate_user;
-	parent_class->get_required_fields        = e_book_backend_mapi_get_required_fields;
-	parent_class->get_supported_fields       = e_book_backend_mapi_get_supported_fields;
-	parent_class->get_supported_auth_methods = e_book_backend_mapi_get_supported_auth_methods;
-	parent_class->cancel_operation           = e_book_backend_mapi_cancel_operation;
-	parent_class->remove                     = e_book_backend_mapi_remove;
-	parent_class->set_mode                   = e_book_backend_mapi_set_mode;
-
-	object_class->dispose                    = e_book_backend_mapi_dispose;
+	return contact;
 }
 
-EBookBackend *e_book_backend_mapi_new (void)
+void
+mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar *context)
 {
-	EBookBackendMAPI *backend;
+	gchar *err_msg = NULL;
+
+	if (!perror)
+		return;
+
+	if (code == E_DATA_BOOK_STATUS_OTHER_ERROR && mapi_error) {
+		/* Change error to more accurate only with OTHER_ERROR */
+		switch (mapi_error->code) {
+		case MAPI_E_PASSWORD_CHANGE_REQUIRED:
+		case MAPI_E_PASSWORD_EXPIRED:
+			code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (context)
+		err_msg = g_strconcat (context, mapi_error ? ": " : NULL, mapi_error ? mapi_error->message : NULL, NULL);
+	else if (!mapi_error)
+		err_msg = g_strdup (_("Uknown error"));
+
+	g_propagate_error (perror, e_data_book_create_error (code, err_msg ? err_msg : mapi_error->message));
 
-	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI, NULL);
-	return E_BOOK_BACKEND (backend);
+	g_free (err_msg);
 }
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index 46d495d..ffba273 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -14,9 +14,6 @@
  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  *
  *
- * Authors:
- *    Srinivasa Ragavan <sragavan novell com>
- *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
@@ -24,20 +21,27 @@
 #ifndef __E_BOOK_BACKEND_MAPI_H__
 #define __E_BOOK_BACKEND_MAPI_H__
 
+#include <glib.h>
+#include <gio/gio.h>
+
 #include <libedata-book/e-book-backend.h>
-#include <libedata-book/e-book-backend-sync.h>
+#include <libedata-book/e-book-backend-cache.h>
+#include <libedata-book/e-book-backend-summary.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+
 #include "exchange-mapi-connection.h"
 #include "exchange-mapi-defs.h"
 #include "exchange-mapi-utils.h"
 
-/* #include "db.h" */
+G_BEGIN_DECLS
 
-#define E_TYPE_BOOK_BACKEND_MAPI         (e_book_backend_mapi_get_type ())
-#define E_BOOK_BACKEND_MAPI(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPI))
-#define E_BOOK_BACKEND_MAPI_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
-#define E_IS_BOOK_BACKEND_MAPI(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI))
-#define E_IS_BOOK_BACKEND_MAPI_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI))
-#define E_BOOK_BACKEND_MAPI_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+#define E_TYPE_BOOK_BACKEND_MAPI           (e_book_backend_mapi_get_type ())
+#define E_BOOK_BACKEND_MAPI(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPI))
+#define E_BOOK_BACKEND_MAPI_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+#define E_IS_BOOK_BACKEND_MAPI(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_IS_BOOK_BACKEND_MAPI_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_BOOK_BACKEND_MAPI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
 
 typedef struct _EBookBackendMAPIPrivate EBookBackendMAPIPrivate;
 
@@ -50,9 +54,78 @@ typedef struct
 typedef struct
 {
 	EBookBackendClass parent_class;
+
+	void (*op_load_source) (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **error);
+	void (*op_remove) (EBookBackendMAPI *ebma, GError **error);
+
+	void (*op_create_contact)  (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error);
+	void (*op_remove_contacts) (EBookBackendMAPI *ebma, const GList *id_list, GList **removed_ids, GError **error);
+	void (*op_modify_contact)  (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error);
+	void (*op_get_contact) (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error);
+	void (*op_get_contact_list) (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error);
+	void (*op_get_changes) (EBookBackendMAPI *ebma, const gchar *change_id, GList **changes, GError **error);
+	void (*op_authenticate_user) (EBookBackendMAPI *ebma, const gchar *user, const gchar *passwd, const gchar *auth_method, GError **error);
+	void (*op_get_required_fields) (EBookBackendMAPI *ebma, GList **fields, GError **error);
+	void (*op_get_supported_fields) (EBookBackendMAPI *ebma, GList **fields, GError **error);
+	void (*op_get_supported_auth_methods) (EBookBackendMAPI *ebma, GList **auth_methods, GError **error);
+
+	/* called when online state changes on the backend */
+	void (*op_connection_status_changed) (EBookBackendMAPI *ebma, gboolean is_online);
+
+	/* returns a status message for a progress of fetching entries "index/total";
+	   returned string is freed by g_free() */
+	gchar * (*op_get_status_message) (EBookBackendMAPI *ebma, gint index, gint total);
+
+	/* function called for each new book_view, in a separate thread;
+	   this function is optional, contacts from cache are always processed
+	   before this function call */
+	void (*op_book_view_thread) (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
+
+	/* function called to populate cache or similar operations;
+	   restriction and book_view can be NULL, call e_book_backend_mapi_notify_contact_update for each
+	   fetched contact with this book_view and notify_contact_data */
+	void (*op_fetch_contacts) (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error);
+
+	/* function to fetch list of known uids (strings) on the server;
+	   it's used to synchronize local cache with deleted items;
+	   uids has the uid key, as a newly allocated string; value should be GINT_TO_POINTER(1) always */
+	void (*op_fetch_known_uids) (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error);
 } EBookBackendMAPIClass;
 
-EBookBackend *e_book_backend_mapi_new      (void);
-GType         e_book_backend_mapi_get_type (void);
+GType e_book_backend_mapi_get_type (void);
+
+gboolean e_book_backend_mapi_debug_enabled (void);
+const gchar *e_book_backend_mapi_get_book_uri (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma);
+ExchangeMapiConnection *e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_get_summary_and_cache (EBookBackendMAPI *ebma, EBookBackendSummary **summary, EBookBackendCache **cache);
+gboolean e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view);
+void e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
+gboolean e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma);
+gboolean e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *book_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data);
+void e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid);
+
+/* utility functions/macros */
+
+#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
+#define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
+
+void mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar *context);
+
+/* vCard parameter name in contact list */
+#define EMA_X_MEMBERID "X-EMA-MEMBER-ID"
+#define EMA_X_MEMBERVALUE "X-EMA-MEMBER-VALUE"
+
+#define GET_ALL_KNOWN_IDS (GINT_TO_POINTER(1))
+#define GET_UIDS_ONLY     (GINT_TO_POINTER(2))
+
+/* data is one of GET_ALL_KNOWN_IDS or GET_UIDS_ONLY */
+gboolean mapi_book_utils_get_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data);
+
+/* only one of mapi_properties and aRow can be set */
+EContact *mapi_book_utils_contact_from_props (ExchangeMapiConnection *conn, mapi_id_t fid, const gchar *book_uri, struct mapi_SPropValue_array *mapi_properties, struct SRow *aRow);
+
+G_END_DECLS
 
 #endif /* __E_BOOK_BACKEND_MAPI_H__ */
diff --git a/src/libexchangemapi/exchange-mapi-connection.c b/src/libexchangemapi/exchange-mapi-connection.c
index ffb11c5..4329bd9 100644
--- a/src/libexchangemapi/exchange-mapi-connection.c
+++ b/src/libexchangemapi/exchange-mapi-connection.c
@@ -1119,7 +1119,7 @@ cleanup:
 }
 
 gboolean
-exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, BuildReadPropsCB build_props, gpointer brp_data, FetchGALCallback cb, gpointer data, GError **perror)
+exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, struct mapi_SRestriction *restrictions, BuildReadPropsCB build_props, gpointer brp_data, FetchGALCallback cb, gpointer data, GError **perror)
 {
 	struct SPropTagArray	*propsTagArray;
 	struct SRowSet		*aRowSet;
@@ -1157,8 +1157,8 @@ exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, BuildReadProps
 	ulFlags = TABLE_START;
 	while (ms == MAPI_E_SUCCESS) {
 		aRowSet = NULL;
-		/* fetch per 10 items */
-		ms = GetGALTable (priv->session, propsTagArray, &aRowSet, 10, ulFlags);
+		/* fetch per 100 items */
+		ms = GetGALTable (priv->session, propsTagArray, &aRowSet, 100, ulFlags);
 		if ((!aRowSet) || (!(aRowSet->aRow)) || ms != MAPI_E_SUCCESS) {
 			break;
 		}
diff --git a/src/libexchangemapi/exchange-mapi-connection.h b/src/libexchangemapi/exchange-mapi-connection.h
index c7fe895..491bba2 100644
--- a/src/libexchangemapi/exchange-mapi-connection.h
+++ b/src/libexchangemapi/exchange-mapi-connection.h
@@ -175,7 +175,7 @@ gboolean		exchange_mapi_connection_fetch_items (ExchangeMapiConnection *conn, ma
 					FetchCallback cb, gpointer data,
 					guint32 options, GError **perror);
 
-gboolean		exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn,
+gboolean		exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, struct mapi_SRestriction *restrictions,
 					BuildReadPropsCB build_props, gpointer brp_data,
 					FetchGALCallback cb, gpointer data, GError **perror);
 



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