[evolution-mapi/gal-ldap: 1/3] GAL LDAP : Dump from eds mapi branch.



commit 88d40a546d4feec6009076d77489b471beafb084
Author: Johnny Jacob <jjohnny novell com>
Date:   Tue Jun 16 09:53:32 2009 +0530

    GAL LDAP : Dump from eds mapi branch.

 src/galldap/ChangeLog                              |   53 +
 src/galldap/Makefile.am                            |   52 +
 src/galldap/apps_galldap_addressbook.schemas.in.in |   21 +
 src/galldap/e-book-backend-galldap-factory.c       |   50 +
 src/galldap/e-book-backend-galldap.c               | 2781 ++++++++++++++++++++
 src/galldap/e-book-backend-galldap.h               |   55 +
 6 files changed, 3012 insertions(+), 0 deletions(-)
---
diff --git a/src/galldap/ChangeLog b/src/galldap/ChangeLog
new file mode 100644
index 0000000..491eba7
--- /dev/null
+++ b/src/galldap/ChangeLog
@@ -0,0 +1,53 @@
+2008-10-30  Suman Manjunath  <msuman novell com>
+
+	* e-book-backend-galldap.c (ldap_reconnect), (gal_reconnect),
+	(ldap_op_finished), (build_contact_from_entry),
+	(parse_page_control), (dosearch), (call_dtor), (dispose):
+	Replace ALL deprecated OpenLDAP API usages with the newer ones. 
+	NOTE: Some portion of the code might have to be re-written due to 
+	this. Also, someone needs to figure out if we want to have code-paths
+	for the deprecated APIs as well and make necessary changes. 
+
+2008-10-29  Suman Manjunath  <msuman novell com>
+
+	* e-book-backend-galldap.c (gal_connect), (ldap_reconnect),
+	(gal_reconnect), (build_contact_from_entry), (load_source):
+	Fix some serious compilation warnings. 
+
+2008-10-15  Ashish Shrivastava  <shashish novell com>
+
+	* e-book-backend-galldap.c (func_contains): Fix for a GAL search issue. 
+
+2008-09-09  Suman Manjunath  <msuman novell com>
+
+	* Makefile.am: 
+	* e-book-backend-galldap.c (load_source): 
+	Fixed a build break. 
+
+2008-08-21  Suman Manjunath  <msuman novell com>
+
+	Patch from Patrick Ohly  <patrick ohly gmx de>
+	* Makefile.am: Include necessary directories for compiling out-of-tree.
+
+2008-07-02  Suman Manjunath  <msuman novell com>
+
+	* e-book-backend-galldap-factory.h: Removed this empty file. 
+	* Makefile.am: Related change. 
+
+2008-06-23  Suman Manjunath  <msuman novell com>
+
+	* e-book-backend-galldap.c (authenticate_user): Use different 
+	identifiers for better readability. 
+
+2008-01-11  Suman Manjunath  <msuman novell com>
+
+	* e-book-backend-galldap-factory.h: File was missing. Added it. 
+
+2007-11-19  Srinivasa Ragavan  <sragavan novell com>
+
+	* e-book-backend-galldap.c: (load_source): Read the proper gal server
+	and limit from the uri.
+
+2007-11-11  Srinivasa Ragavan <sragavan novell com>
+
+	** Added initial support for GAL-LDAP.
diff --git a/src/galldap/Makefile.am b/src/galldap/Makefile.am
new file mode 100644
index 0000000..69b7655
--- /dev/null
+++ b/src/galldap/Makefile.am
@@ -0,0 +1,52 @@
+INCLUDES =						\
+	-DG_LOG_DOMAIN=\"libebookbackendgalldap\"	\
+	$(LIBEXCHANGE_STORAGE_CFLAGS)			\
+	$(LIBEDATASERVER_CFLAGS)			\
+	$(LIBEBACKEND_CFLAGS)				\
+	$(LIBEBOOK_CFLAGS)				\
+	$(LIBEDATABOOK_CFLAGS)				\
+	$(EVOLUTION_PLUGIN_CFLAGS)			\
+	$(LDAP_CFLAGS)
+
+# GConf schemas
+
+schemadir   = $(GCONF_SCHEMA_FILE_DIR)
+schema_in_files = apps_galldap_addressbook.schemas.in.in
+schema_DATA = $(schema_in_files:.schemas.in.in=-$(BASE_VERSION).schemas)
+%-$(BASE_VERSION).schemas.in: %.schemas.in.in
+	cp $< $@
+
+ INTLTOOL_SCHEMAS_RULE@
+
+install-data-local:
+	if test -z "$(DESTDIR)" ; then \
+		for p in $(schema_DATA) ; do \
+			GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $$p; \
+		done \
+	fi
+
+extension_LTLIBRARIES = libebookbackendgalldap.la
+
+libebookbackendgalldap_la_SOURCES =			\
+	e-book-backend-galldap-factory.c		\
+	e-book-backend-galldap.c			\
+	e-book-backend-galldap.h		
+
+libebookbackendgalldap_la_LIBADD = 			\
+	$(LIBEXCHANGE_STORAGE_LIBS)			\
+	$(LIBEDATASERVER_LIBS)				\
+	$(LIBEBACKEND_LIBS)				\
+	$(LIBEBOOK_LIBS)				\
+	$(LIBEDATABOOK_LIBS)				\
+	$(EVOLUTION_PLUGIN_LIBS)			\
+	$(LDAP_LIBS)
+
+libebookbackendgalldap_la_LDFLAGS =			\
+	-module -avoid-version $(NO_UNDEFINED)
+
+EXTRA_DIST =						\
+	$(schema_in_files)
+ 
+CLEANFILES = 						\
+	apps_galldap_addressbook-$(BASE_VERSION).schemas
+
diff --git a/src/galldap/apps_galldap_addressbook.schemas.in.in b/src/galldap/apps_galldap_addressbook.schemas.in.in
new file mode 100644
index 0000000..b51d925
--- /dev/null
+++ b/src/galldap/apps_galldap_addressbook.schemas.in.in
@@ -0,0 +1,21 @@
+<gconfschemafile>
+  <schemalist>
+
+    <!-- Completion uris -->
+
+    <schema>
+      <key>/schemas/apps/evolution/addressbook/gal_cache_interval</key>
+      <applyto>/apps/evolution/addressbook/gal_cache_interval</applyto>
+      <owner>evolution-addressbook</owner>
+      <type>int</type>
+      <default>7</default>
+      <locale name="C">
+        <short>Specifies the time interval to refresh the GAL Cache. </short>
+        <long>This key specifies the number of days interval between
+	the GAL cache refresh. Set this value to zero, if you don't want to 
+	update GAL and use the current cache forever. This will work only if
+	you have enabled offline caching for GAL.</long>
+      </locale>
+    </schema>
+  </schemalist>
+</gconfschemafile>
diff --git a/src/galldap/e-book-backend-galldap-factory.c b/src/galldap/e-book-backend-galldap-factory.c
new file mode 100644
index 0000000..5cbf36d
--- /dev/null
+++ b/src/galldap/e-book-backend-galldap-factory.c
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public 
+ *  License along with this program; if not, write to: 
+ *  Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libebackend/e-data-server-module.h>
+#include <libedata-book/e-book-backend-factory.h>
+#include "e-book-backend-galldap.h"
+
+E_BOOK_BACKEND_FACTORY_SIMPLE (galldap, GALLDAP, e_book_backend_galldap_new)
+
+static GType  galldap_type;
+
+void
+eds_module_initialize (GTypeModule *module)
+{
+	galldap_type = _galldap_factory_get_type (module);
+}
+
+void
+eds_module_shutdown   (void)
+{
+}
+
+void
+eds_module_list_types (const GType **types, int *num_types)
+{
+	*types = & galldap_type;
+	*num_types = 1;
+}
+
diff --git a/src/galldap/e-book-backend-galldap.c b/src/galldap/e-book-backend-galldap.c
new file mode 100644
index 0000000..75714a1
--- /dev/null
+++ b/src/galldap/e-book-backend-galldap.c
@@ -0,0 +1,2781 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public 
+ *  License along with this program; if not, write to: 
+ *  Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "e-book-backend-gallap"
+#undef DEBUG
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>  
+#endif
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <glib/gprintf.h>
+#include <glib.h>
+
+#ifdef DEBUG
+#define LDAP_DEBUG
+#define LDAP_DEBUG_ADD
+#endif
+#include <ldap.h>
+#ifdef DEBUG
+#undef LDAP_DEBUG
+#endif
+
+#define d(x) x
+
+#include <sys/time.h>
+#include <libedataserver/e-sexp.h>
+#include <libebackend/e-db3-utils.h>
+#include <libedataserver/e-data-server-util.h>
+#include <libebook/e-contact.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-summary.h>
+#include "e-book-backend-galldap.h"
+
+#include <e2k-global-catalog.h>
+#include <gconf/gconf-client.h>
+
+#ifndef LDAP_CONTROL_PAGEDRESULTS
+#ifdef ENABLE_CACHE
+#undef ENABLE_CACHE
+#endif
+#define ENABLE_CACHE 0
+#else
+#define ENABLE_CACHE 1
+#endif
+
+#if ENABLE_CACHE
+#include  <libedata-book/e-book-backend-db-cache.h>
+/* #include "db.h" */
+#endif
+
+/* interval for our poll_ldap timeout */
+#define LDAP_POLL_INTERVAL 20
+
+/* timeout for ldap_result */
+#define LDAP_RESULT_TIMEOUT_MILLIS 10
+
+#define TV_TO_MILLIS(timeval) ((timeval).tv_sec * 1000 + (timeval).tv_usec / 1000)
+
+extern LDAP * e2k_global_catalog_get_ldap (E2kGlobalCatalog *gc, E2kOperation *op, int *ldap_error); 
+
+static gchar *query_prop_to_ldap(gchar *query_prop);
+static int build_query (EBookBackendGALLDAP *bl, const char *query, char **ldap_query);
+
+#define PARENT_TYPE E_TYPE_BOOK_BACKEND
+static EBookBackendClass *parent_class;
+
+typedef struct LDAPOp LDAPOp;
+
+static GList *supported_fields;
+static char **search_attrs;
+
+struct _EBookBackendGALLDAPPrivate {
+	char             *gal_uri;
+	gboolean          connected;
+
+	LDAP             *ldap;
+	int port;
+	char *server;
+	E2kGlobalCatalog *gc;
+
+	gboolean marked_for_offline;
+	GMutex		*ldap_lock;
+
+	/* our operations */
+	GStaticRecMutex op_hash_mutex;
+	GHashTable *id_to_op;
+	int active_ops;
+	int mode;
+	int poll_timeout;
+#if ENABLE_CACHE
+	DB *file_db;
+	DB_ENV *env;
+#endif
+	/* Summary */
+	char *summary_file_name;
+	gboolean is_summary_ready;
+	EBookBackendSummary *summary;
+};
+
+#define SUMMARY_FLUSH_TIMEOUT 5000
+
+#if ENABLE_CACHE
+static GStaticMutex global_env_lock = G_STATIC_MUTEX_INIT;
+static struct {
+	int ref_count;
+	DB_ENV *env;
+} global_env;
+#endif
+
+typedef void (*LDAPOpHandler)(LDAPOp *op, LDAPMessage *res);
+typedef void (*LDAPOpDtor)(LDAPOp *op);
+
+struct LDAPOp {
+	LDAPOpHandler  handler;
+	LDAPOpDtor     dtor;
+	EBookBackend  *backend;
+	EDataBook     *book;
+	EDataBookView *view;
+	guint32        opid; /* the libebook operation id */
+	int            id;   /* the ldap msg id */
+};
+
+static void     ldap_op_add (LDAPOp *op, EBookBackend *backend, EDataBook *book,
+			     EDataBookView *view, int opid, int msgid, LDAPOpHandler handler, LDAPOpDtor dtor);
+static void     ldap_op_finished (LDAPOp *op);
+
+static gboolean poll_ldap (EBookBackendGALLDAP *bl);
+
+static EContact *build_contact_from_entry (EBookBackendGALLDAP *bl, LDAPMessage *e, GList **existing_objectclasses);
+
+static void manager_populate (EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op);
+
+static void member_populate (EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op);
+
+static void last_mod_time_populate (EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op);
+
+struct prop_info {
+	EContactField field_id;
+	char *ldap_attr;
+#define PROP_TYPE_STRING   0x01
+#define PROP_TYPE_COMPLEX  0x02
+#define PROP_TYPE_GROUP    0x04
+	int prop_type;
+
+	/* the remaining items are only used for the TYPE_COMPLEX props */
+
+	/* used when reading from the ldap server populates EContact with the values in **values. */
+	void (*populate_contact_func)(EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op);
+
+} prop_info[] = {
+
+#define COMPLEX_PROP(fid,a,ctor) {fid, a, PROP_TYPE_COMPLEX, ctor}
+#define STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING}
+#define GROUP_PROP(fid,a,ctor) {fid, a, PROP_TYPE_GROUP, ctor}
+
+
+	/* name fields */
+	STRING_PROP   (E_CONTACT_FULL_NAME,   "displayName" ),
+	STRING_PROP   (E_CONTACT_GIVEN_NAME,  "givenName" ),
+	STRING_PROP   (E_CONTACT_FAMILY_NAME, "sn" ),
+	STRING_PROP   (E_CONTACT_NICKNAME,    "mailNickname" ),
+
+	/* email addresses */
+	STRING_PROP   (E_CONTACT_EMAIL_1,     "mail" ),
+	GROUP_PROP    (E_CONTACT_EMAIL,       "member", member_populate),
+
+	/* phone numbers */
+	STRING_PROP   (E_CONTACT_PHONE_BUSINESS,     "telephoneNumber"),
+	STRING_PROP   (E_CONTACT_PHONE_BUSINESS_2,   "otherTelephone"),
+	STRING_PROP   (E_CONTACT_PHONE_HOME,         "homePhone"),
+	STRING_PROP   (E_CONTACT_PHONE_HOME_2,       "otherHomePhone"),
+	STRING_PROP   (E_CONTACT_PHONE_MOBILE,       "mobile"),
+	STRING_PROP   (E_CONTACT_PHONE_BUSINESS_FAX, "facsimileTelephoneNumber"), 
+	STRING_PROP   (E_CONTACT_PHONE_OTHER_FAX,    "otherFacsimileTelephoneNumber"), 
+	STRING_PROP   (E_CONTACT_PHONE_PAGER,        "pager"),
+
+	/* org information */
+	STRING_PROP   (E_CONTACT_ORG,                "company"),
+	STRING_PROP   (E_CONTACT_ORG_UNIT,           "department"),
+	STRING_PROP   (E_CONTACT_OFFICE,             "physicalDeliveryOfficeName"),
+	STRING_PROP   (E_CONTACT_TITLE,              "title"),
+
+	COMPLEX_PROP  (E_CONTACT_MANAGER,            "manager", manager_populate),
+
+	/* FIXME: we should aggregate streetAddress, l, st, c, postalCode
+	 * into business_address
+	 */
+
+	/* misc fields */
+	STRING_PROP   (E_CONTACT_HOMEPAGE_URL,       "wWWHomePage"),
+	STRING_PROP   (E_CONTACT_FREEBUSY_URL,       "msExchFBURL"),
+	STRING_PROP   (E_CONTACT_NOTE,               "info"), 
+	STRING_PROP   (E_CONTACT_FILE_AS,            "fileAs"),
+
+	/* whenChanged is a string value, but since we need to re-format it,
+	 * defining it as a complex property
+	 */
+	COMPLEX_PROP   (E_CONTACT_REV,                "whenChanged", last_mod_time_populate),
+
+#undef STRING_PROP
+#undef COMPLEX_PROP
+#undef GROUP_PROP
+};
+
+static int num_prop_infos = sizeof(prop_info) / sizeof(prop_info[0]);
+
+static void
+book_view_notify_status (EDataBookView *view, const char *status)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	if (!view)
+		return;
+	e_data_book_view_notify_status_message (view, status);
+}
+
+static EDataBookView*
+find_book_view (EBookBackendGALLDAP *bl)
+{
+	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (bl));
+	EIterator *iter = e_list_get_iterator (views);
+	EDataBookView *rv = NULL;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	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 GNOME_Evolution_Addressbook_CallStatus
+gal_connect (EBookBackendGALLDAP *bl)
+{
+	EBookBackendGALLDAPPrivate *blpriv = bl->priv;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+#ifdef DEBUG
+	{
+		int debug_level = 1;
+		ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &debug_level);
+	}
+#endif
+
+	blpriv->connected = FALSE;
+
+	g_mutex_lock (blpriv->ldap_lock);
+	blpriv->ldap = e2k_global_catalog_get_ldap (blpriv->gc, NULL, NULL);
+	if (!blpriv->ldap) {
+		g_mutex_unlock (blpriv->ldap_lock);
+		return GNOME_Evolution_Addressbook_RepositoryOffline;
+	}
+	g_mutex_unlock (blpriv->ldap_lock);
+
+	blpriv->connected = TRUE;
+	e_book_backend_set_is_loaded (E_BOOK_BACKEND (bl), TRUE);
+	return GNOME_Evolution_Addressbook_Success;
+}
+
+static gboolean
+ldap_reconnect (EBookBackendGALLDAP *bl, EDataBookView *book_view, LDAP **ldap, int status)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	
+	if (!ldap || !*ldap)
+		return FALSE;
+
+	if (status == LDAP_SERVER_DOWN) {
+
+		if (book_view)
+			book_view_notify_status (book_view, _("Reconnecting to LDAP server..."));
+		
+		ldap_unbind_ext (*ldap, NULL, NULL);
+		*ldap = e2k_global_catalog_get_ldap (bl->priv->gc, NULL, NULL);
+		if (book_view)
+			book_view_notify_status (book_view, "");
+
+		if (*ldap)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+gal_reconnect (EBookBackendGALLDAP *bl, EDataBookView *book_view, int ldap_status)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	/* we need to reconnect if we were previously connected */
+	if ((bl->priv->connected && ldap_status == LDAP_SERVER_DOWN) || (!bl->priv->ldap && !bl->priv->connected)) {
+		g_mutex_lock (bl->priv->ldap_lock);
+		if (book_view)
+			book_view_notify_status (book_view, _("Reconnecting to LDAP server..."));
+		if (bl->priv->ldap)
+			ldap_unbind_ext (bl->priv->ldap, NULL, NULL);
+		bl->priv->ldap = e2k_global_catalog_get_ldap (bl->priv->gc, NULL, NULL);
+		if (book_view)
+			book_view_notify_status (book_view, "");
+
+		if (bl->priv->ldap != NULL) {
+			bl->priv->connected = TRUE;
+			g_mutex_unlock (bl->priv->ldap_lock);
+			return TRUE;
+		} else {
+			g_mutex_unlock (bl->priv->ldap_lock);
+			return FALSE;
+		}
+	}
+	else {
+		printf("Connected and ldap is null sigh\n");
+		return FALSE;
+	}
+}
+
+static void
+ldap_op_add (LDAPOp *op, EBookBackend *backend,
+	     EDataBook *book, EDataBookView *view,
+	     int opid,
+	     int msgid,
+	     LDAPOpHandler handler, LDAPOpDtor dtor)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	op->backend = backend;
+	op->book = book;
+	op->view = view;
+	op->opid = opid;
+	op->id = msgid;
+	op->handler = handler;
+	op->dtor = dtor;
+
+	g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
+	if (g_hash_table_lookup (bl->priv->id_to_op, &op->id)) {
+		g_warning ("conflicting ldap msgid's");
+	}
+
+	g_hash_table_insert (bl->priv->id_to_op,
+			     &op->id, op);
+
+	bl->priv->active_ops ++;
+
+	if (bl->priv->poll_timeout == -1)
+		bl->priv->poll_timeout = g_timeout_add (LDAP_POLL_INTERVAL,
+							(GSourceFunc) poll_ldap,
+							bl);
+
+	g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
+}
+
+static void
+ldap_op_finished (LDAPOp *op)
+{
+	EBookBackend *backend = op->backend;
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
+	g_hash_table_remove (bl->priv->id_to_op, &op->id);
+
+	/* should handle errors here */
+	g_mutex_lock (bl->priv->ldap_lock);
+	if (bl->priv->ldap)
+		ldap_abandon_ext (bl->priv->ldap, op->id, NULL, NULL);
+	g_mutex_unlock (bl->priv->ldap_lock);
+
+	op->dtor (op);
+
+	bl->priv->active_ops--;
+
+	if (bl->priv->active_ops == 0) {
+		if (bl->priv->poll_timeout != -1)
+			g_source_remove (bl->priv->poll_timeout);
+		bl->priv->poll_timeout = -1;
+	}
+	g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
+}
+
+static int
+ldap_error_to_response (int ldap_error)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	if (ldap_error == LDAP_SUCCESS)
+		return GNOME_Evolution_Addressbook_Success;
+	else if (LDAP_NAME_ERROR (ldap_error))
+		return GNOME_Evolution_Addressbook_ContactNotFound;
+	else if (ldap_error == LDAP_INSUFFICIENT_ACCESS)
+		return GNOME_Evolution_Addressbook_PermissionDenied;
+	else if (ldap_error == LDAP_SERVER_DOWN)
+		return GNOME_Evolution_Addressbook_RepositoryOffline;
+	else if (ldap_error == LDAP_ALREADY_EXISTS)
+		return GNOME_Evolution_Addressbook_ContactIdAlreadyExists;
+	else
+		return GNOME_Evolution_Addressbook_OtherError;
+}
+
+
+
+static void
+create_contact (EBookBackend *backend,
+		EDataBook    *book,
+		guint32       opid,
+		const char   *vcard)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	e_data_book_respond_create (book, opid,
+				    GNOME_Evolution_Addressbook_PermissionDenied,
+				    NULL);
+}
+
+static void
+remove_contacts (EBookBackend *backend,
+		 EDataBook    *book,
+		 guint32       opid,
+		 GList        *ids)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	e_data_book_respond_remove_contacts (book, opid,
+					     GNOME_Evolution_Addressbook_PermissionDenied,
+					     NULL);
+}
+
+static void
+modify_contact (EBookBackend *backend,
+		EDataBook    *book,
+		guint32       opid,
+		const char   *vcard)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	e_data_book_respond_modify (book, opid,
+				    GNOME_Evolution_Addressbook_PermissionDenied,
+				    NULL);
+}
+
+typedef struct {
+	LDAPOp op;
+} LDAPGetContactOp;
+
+static void
+get_contact_handler (LDAPOp *op, LDAPMessage *res)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (op->backend);
+	int msg_type;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	if (!bl->priv->ldap) {
+		e_data_book_respond_get_contact (op->book, op->opid, 
+					GNOME_Evolution_Addressbook_OtherError, "");
+		ldap_op_finished (op);
+		return;
+	}
+
+	/* the msg_type will be either SEARCH_ENTRY (if we're
+	   successful) or SEARCH_RESULT (if we're not), so we finish
+	   the op after either */
+	msg_type = ldap_msgtype (res);
+	if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+		LDAPMessage *e;
+		EContact *contact;
+		char *vcard;
+
+		g_mutex_lock (bl->priv->ldap_lock);
+		e = ldap_first_entry(bl->priv->ldap, res);
+		g_mutex_unlock (bl->priv->ldap_lock);
+
+		if (!e) {
+			g_warning ("uh, this shouldn't happen");
+			e_data_book_respond_get_contact (op->book,
+							 op->opid,
+							 GNOME_Evolution_Addressbook_OtherError,
+							 "");
+			ldap_op_finished (op);
+			return;
+		}
+
+		contact = build_contact_from_entry (bl, e, NULL);
+		vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+		e_data_book_respond_get_contact (op->book,
+						 op->opid,
+						 GNOME_Evolution_Addressbook_Success,
+						 vcard);
+		g_free (vcard);
+		g_object_unref (contact);
+		ldap_op_finished (op);
+	}
+	else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+		char *ldap_error_msg;
+		int ldap_error;
+	
+		g_mutex_lock (bl->priv->ldap_lock);
+		ldap_parse_result (bl->priv->ldap, res, &ldap_error,
+				   NULL, &ldap_error_msg, NULL, NULL, 0);
+		g_mutex_unlock (bl->priv->ldap_lock);
+
+		if (ldap_error != LDAP_SUCCESS) {
+			g_warning ("get_contact_handler: %02X (%s), additional info: %s",
+				   ldap_error,
+				   ldap_err2string (ldap_error), ldap_error_msg);
+		}
+		ldap_memfree (ldap_error_msg);
+
+		e_data_book_respond_get_contact (op->book,
+						 op->opid,
+						 ldap_error_to_response (ldap_error),
+						 "");
+		ldap_op_finished (op);
+	}
+	else {
+		g_warning ("unhandled result type %d returned", msg_type);
+		e_data_book_respond_get_contact (op->book,
+						 op->opid,
+						 GNOME_Evolution_Addressbook_OtherError,
+						 "");
+		ldap_op_finished (op);
+	}
+
+}
+
+static void
+get_contact_dtor (LDAPOp *op)
+{
+	LDAPGetContactOp *get_contact_op = (LDAPGetContactOp*)op;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	g_free (get_contact_op);
+}
+
+static void
+get_contact (EBookBackend *backend,
+	     EDataBook    *book,
+	     guint32       opid,
+	     const char   *id)
+{
+	LDAPGetContactOp *get_contact_op;
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	LDAP *ldap = bl->priv->ldap;
+	int get_contact_msgid;
+	EDataBookView *book_view;
+	int ldap_error;
+	
+	printf("get contact\n");
+	switch (bl->priv->mode) {
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+#if ENABLE_CACHE		
+		if (bl->priv->marked_for_offline && bl->priv->file_db) {
+			EContact *contact = e_book_backend_db_cache_get_contact (bl->priv->file_db, id);
+			gchar *vcard_str;
+
+			if (!contact) {
+				e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_OtherError, "");
+				return;
+			}
+
+			vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+			e_data_book_respond_get_contact (book,
+							 opid,
+							 GNOME_Evolution_Addressbook_Success,
+							 vcard_str);
+			g_free (vcard_str);
+			g_object_unref (contact);
+			return;
+		}
+#endif
+		e_data_book_respond_get_contact(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, "");
+		return;
+
+	case GNOME_Evolution_Addressbook_MODE_REMOTE :
+#if ENABLE_CACHE		
+		printf("Mode:Remote\n"); 
+		if (bl->priv->marked_for_offline && bl->priv->file_db) {
+			EContact *contact = e_book_backend_db_cache_get_contact (bl->priv->file_db, id);
+			gchar *vcard_str ;
+			if (!contact) {
+				e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_OtherError, "");
+				return;
+			}
+
+			vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+			e_data_book_respond_get_contact (book,
+							 opid, 
+							 GNOME_Evolution_Addressbook_Success,
+							 vcard_str);
+			g_free (vcard_str);
+			g_object_unref (contact);
+			return ;
+		}
+		else {
+#endif		
+			if (!ldap) {
+				e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_OtherError, "");
+				return;
+			}
+
+			get_contact_op = g_new0 (LDAPGetContactOp, 1);
+	
+			book_view = find_book_view (bl);
+
+			do {	
+				g_mutex_lock (bl->priv->ldap_lock);
+				ldap_error = ldap_search_ext (ldap, id,
+							      LDAP_SCOPE_BASE,
+							      "(objectclass=*)",
+							      search_attrs, 0, NULL, NULL,
+							      NULL, /* XXX timeout */
+							      1, &get_contact_msgid);
+				g_mutex_unlock (bl->priv->ldap_lock);
+			} while (gal_reconnect (bl, book_view, ldap_error));
+
+			if (ldap_error == LDAP_SUCCESS) {
+				ldap_op_add ((LDAPOp*)get_contact_op, backend, book,
+					     book_view, opid, get_contact_msgid,
+					     get_contact_handler, get_contact_dtor);
+			}
+			else {
+				e_data_book_respond_get_contact (book,
+								 opid,
+								 ldap_error_to_response (ldap_error),
+								 "");
+				get_contact_dtor ((LDAPOp*)get_contact_op);
+			}
+#if ENABLE_CACHE			
+		}
+#endif		
+	}
+}
+
+typedef struct {
+	LDAPOp op;
+	GList *contacts;
+} LDAPGetContactListOp;
+
+static void
+contact_list_handler (LDAPOp *op, LDAPMessage *res)
+{
+	LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp*)op;
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (op->backend);
+	LDAP *ldap = bl->priv->ldap;
+	LDAPMessage *e;
+	int msg_type;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	if (!ldap) {
+		e_data_book_respond_get_contact_list (op->book, op->opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+		ldap_op_finished (op);
+		return;
+	}
+
+	msg_type = ldap_msgtype (res);
+	if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+		g_mutex_lock (bl->priv->ldap_lock);	
+		e = ldap_first_entry(ldap, res);
+		g_mutex_unlock (bl->priv->ldap_lock);
+
+		while (NULL != e) {
+			EContact *contact = build_contact_from_entry (bl, e, NULL);
+			char *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+			d(printf ("vcard = %s\n", vcard));
+ 
+			contact_list_op->contacts = g_list_append (contact_list_op->contacts,
+								   vcard);
+
+			g_object_unref (contact);
+			g_mutex_lock (bl->priv->ldap_lock);
+			e = ldap_next_entry(ldap, e);
+			g_mutex_unlock (bl->priv->ldap_lock);
+		}
+	}
+	else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+		char *ldap_error_msg;
+		int ldap_error;
+
+		g_mutex_lock (bl->priv->ldap_lock);
+		ldap_parse_result (ldap, res, &ldap_error,
+				   NULL, &ldap_error_msg, NULL, NULL, 0);
+		g_mutex_unlock (bl->priv->ldap_lock);
+		if (ldap_error != LDAP_SUCCESS) {
+			g_warning ("contact_list_handler: %02X (%s), additional info: %s",
+				   ldap_error,
+				   ldap_err2string (ldap_error), ldap_error_msg);
+		}
+		ldap_memfree (ldap_error_msg);
+
+		d(printf ("search returned %d\n", ldap_error));
+
+		if (ldap_error == LDAP_TIMELIMIT_EXCEEDED)
+			e_data_book_respond_get_contact_list (op->book,
+							      op->opid,
+							      GNOME_Evolution_Addressbook_SearchTimeLimitExceeded,
+							      contact_list_op->contacts);
+		else if (ldap_error == LDAP_SIZELIMIT_EXCEEDED)
+			e_data_book_respond_get_contact_list (op->book,
+							      op->opid,
+							      GNOME_Evolution_Addressbook_SearchSizeLimitExceeded,
+							      contact_list_op->contacts);
+		else if (ldap_error == LDAP_SUCCESS)
+			e_data_book_respond_get_contact_list (op->book,
+							      op->opid,
+							      GNOME_Evolution_Addressbook_Success,
+							      contact_list_op->contacts);
+		else
+			e_data_book_respond_get_contact_list (op->book,
+							      op->opid,
+							      GNOME_Evolution_Addressbook_OtherError,
+							      contact_list_op->contacts);
+
+		ldap_op_finished (op);
+	}
+	else {
+		g_warning ("unhandled search result type %d returned", msg_type);
+		e_data_book_respond_get_contact_list (op->book,
+						      op->opid,
+						      GNOME_Evolution_Addressbook_OtherError,
+						      NULL);
+		ldap_op_finished (op);
+	}
+
+}
+
+static void
+contact_list_dtor (LDAPOp *op)
+{
+	LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp*)op;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	g_free (contact_list_op);
+}
+
+
+static void
+get_contact_list (EBookBackend *backend,
+		  EDataBook    *book,
+		  guint32       opid,
+		  const char   *query)
+{
+	LDAPGetContactListOp *contact_list_op;
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	LDAP *ldap = bl->priv->ldap;
+	GNOME_Evolution_Addressbook_CallStatus status;
+	int contact_list_msgid;
+	EDataBookView *book_view;
+	int ldap_error;
+	char *ldap_query;
+	
+	printf("get contact list\n");
+	switch (bl->priv->mode) {
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+#if ENABLE_CACHE				
+		if (bl->priv->marked_for_offline && bl->priv->file_db) {
+			GList *contacts;
+			GList *vcard_strings = NULL;
+			GList *l;
+
+			contacts = e_book_backend_db_cache_get_contacts (bl->priv->file_db, 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_list_free (contacts);
+			e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_strings);
+			return;
+		}
+#endif		
+		e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_RepositoryOffline,
+						      NULL);
+		return;
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+#if ENABLE_CACHE				
+		printf("Mode : Remote\n");
+		if (bl->priv->marked_for_offline && bl->priv->file_db) {
+			GList *contacts;
+			GList *vcard_strings = NULL;
+			GList *l;
+
+			contacts = e_book_backend_db_cache_get_contacts (bl->priv->file_db, 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_list_free (contacts);
+			e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_strings);
+			return ;
+		}
+		else {
+#endif			
+			if (!ldap) {
+				e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+				return;
+			}
+
+			contact_list_op = g_new0 (LDAPGetContactListOp, 1);
+			book_view = find_book_view (bl);
+
+			status = build_query (bl, query, &ldap_query);
+			if (status != GNOME_Evolution_Addressbook_Success || !ldap_query) {
+				e_data_book_respond_get_contact_list (book, opid, status, NULL);
+				return;
+			}
+
+			d(printf ("getting contact list with filter: %s\n", ldap_query));
+
+			do {	
+				g_mutex_lock (bl->priv->ldap_lock);
+				ldap_error = ldap_search_ext (bl->priv->ldap, LDAP_ROOT_DSE,
+							      LDAP_SCOPE_SUBTREE,
+							      ldap_query,
+							      search_attrs, 0, NULL, NULL,
+							      NULL, /* XXX timeout */
+							      LDAP_NO_LIMIT, &contact_list_msgid);
+				g_mutex_unlock (bl->priv->ldap_lock);
+			} while (gal_reconnect (bl, book_view, ldap_error));
+
+			g_free (ldap_query);
+
+			if (ldap_error == LDAP_SUCCESS) {
+				ldap_op_add ((LDAPOp*)contact_list_op, backend, book,
+					     book_view, opid, contact_list_msgid,
+					     contact_list_handler, contact_list_dtor);
+			}	
+			else {
+				e_data_book_respond_get_contact_list (book,
+								      opid,
+								      ldap_error_to_response (ldap_error),
+								      NULL);
+				contact_list_dtor ((LDAPOp*)contact_list_op);
+			}
+#if ENABLE_CACHE					
+		}
+#endif		
+	}
+}
+
+
+#define IS_RFC2254_CHAR(c) ((c) == '*' || (c) =='\\' || (c) == '(' || (c) == ')' || (c) == '\0')
+static char *
+rfc2254_escape(char *str)
+{
+	int i;
+	int len = strlen(str);
+	int newlen = 0;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	for (i = 0; i < len; i ++) {
+		if (IS_RFC2254_CHAR(str[i]))
+			newlen += 3;
+		else
+			newlen ++;
+	}
+
+	if (len == newlen) {
+		return g_strdup (str);
+	}
+	else {
+		char *newstr = g_malloc0 (newlen + 1);
+		int j = 0;
+		for (i = 0; i < len; i ++) {
+			if (IS_RFC2254_CHAR(str[i])) {
+				sprintf (newstr + j, "\\%02x", str[i]);
+				j+= 3;
+			}
+			else {
+				newstr[j++] = str[i];
+			}
+		}
+		return newstr;
+	}
+}
+
+static ESExpResult *
+func_and(ESExp *f, int argc, ESExpResult **argv, void *data)
+{
+	ESExpResult *r;
+	GString *string;
+	int i;
+
+	/* Check for short circuit */
+	for (i = 0; i < argc; i++) {
+		if (argv[i]->type == ESEXP_RES_BOOL &&
+		    argv[i]->value.bool == FALSE) {
+			r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+			r->value.bool = FALSE;
+			return r;
+		} else if (argv[i]->type == ESEXP_RES_UNDEFINED)
+			return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+	}
+
+	string = g_string_new("(&");
+	for (i = 0; i < argc; i ++) {
+		if (argv[i]->type != ESEXP_RES_STRING)
+			continue;
+		g_string_append(string, argv[i]->value.string);
+	}
+	g_string_append(string, ")");
+
+	r = e_sexp_result_new(f, ESEXP_RES_STRING);
+	r->value.string = string->str;
+	g_string_free(string, FALSE);
+
+	return r;
+}
+
+static ESExpResult *
+func_or(ESExp *f, int argc, ESExpResult **argv, void *data)
+{
+	ESExpResult *r;
+	GString *string;
+	int i;
+
+	/* Check for short circuit */
+	for (i = 0; i < argc; i++) {
+		if (argv[i]->type == ESEXP_RES_BOOL &&
+		    argv[i]->value.bool == TRUE) {
+			r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+			r->value.bool = TRUE;
+			return r;
+		} else if (argv[i]->type == ESEXP_RES_UNDEFINED)
+			return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+	}
+
+	string = g_string_new("(|");
+	for (i = 0; i < argc; i ++) {
+		if (argv[i]->type != ESEXP_RES_STRING)
+			continue;
+		g_string_append(string, argv[i]->value.string);
+	}
+	g_string_append(string, ")");
+
+	r = e_sexp_result_new(f, ESEXP_RES_STRING);
+	r->value.string = string->str;
+	g_string_free(string, FALSE);
+
+	return r;
+}
+
+static ESExpResult *
+func_not(ESExp *f, int argc, ESExpResult **argv, void *data)
+{
+	ESExpResult *r;
+
+	if (argc != 1 ||
+	    (argv[0]->type != ESEXP_RES_STRING &&
+	     argv[0]->type != ESEXP_RES_BOOL))
+		return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+
+	if (argv[0]->type == ESEXP_RES_STRING) {
+		r = e_sexp_result_new(f, ESEXP_RES_STRING);
+		r->value.string = g_strdup_printf ("(!%s)",
+						   argv[0]->value.string);
+	} else {
+		r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+		r->value.bool = !argv[0]->value.bool;
+	}
+
+	return r;
+}
+
+static gchar *
+query_prop_to_ldap(gchar *query_prop)
+{
+	int i;
+
+	if (!strcmp (query_prop, "email"))
+		query_prop = "email_1";
+
+	for (i = 0; i < num_prop_infos; i ++)
+		if (!strcmp (query_prop, e_contact_field_name (prop_info[i].field_id)))
+			return prop_info[i].ldap_attr;
+
+	return NULL;
+}
+
+
+static ESExpResult *
+func_contains(ESExp *f, int argc, ESExpResult **argv, void *data)
+{
+	ESExpResult *r;
+	char *propname, *ldap_attr, *str;
+
+	if (argc != 2 ||
+	    argv[0]->type != ESEXP_RES_STRING ||
+	    argv[1]->type != ESEXP_RES_STRING)
+		return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+
+	propname = argv[0]->value.string;
+	str = argv[1]->value.string;
+
+	if (!strcmp(propname, "x-evolution-any-field")) {
+		/* This gui does (contains "x-evolution-any-field" ""),
+		 * when you hit "Clear". We want that to be empty. But
+		 * other "any field contains" searches should give an
+		 * error.
+		 */
+		if (strlen(str) == 0) {
+			r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+			r->value.bool = FALSE;
+		} else {
+			r = e_sexp_result_new(f, ESEXP_RES_STRING);
+			r->value.string = g_strdup_printf ("(mailNickname=%s)", str);			
+		}
+		
+		return r;
+	}
+
+	ldap_attr = query_prop_to_ldap(argv[0]->value.string);
+	if (!ldap_attr) {
+		/* Attribute doesn't exist, so it can't possibly match */
+		r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+		r->value.bool = FALSE;
+		return r;
+	}
+
+	/* AD doesn't do substring indexes, so we only allow
+	 * (contains FIELD ""), meaning "FIELD exists".
+	 */
+	if (strlen(str) == 0) {
+		r = e_sexp_result_new(f, ESEXP_RES_STRING);
+		r->value.string = g_strdup_printf ("(%s=*)", ldap_attr);
+	} else if (!strcmp(propname, "file_as")) {
+		r = e_sexp_result_new(f, ESEXP_RES_STRING);
+		r->value.string = g_strdup_printf ("(|(displayName=%s*)(sn=%s*)(%s=%s*))", str, str, ldap_attr, str);
+	} else if (g_str_equal (ldap_attr, "displayName")) {
+		r = e_sexp_result_new(f, ESEXP_RES_STRING);
+		r->value.string = g_strdup_printf("(|(displayName=%s*)(sn=%s*)(givenName=%s*))", str, str, str);
+	} else 
+		r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+	return r;
+}
+
+static ESExpResult *
+func_is_or_begins_with(ESExp *f, int argc, ESExpResult **argv, gboolean exact)
+{
+	ESExpResult *r;
+	char *propname, *str, *ldap_attr, *star, *filter;
+
+	if (argc != 2
+	    || argv[0]->type != ESEXP_RES_STRING
+	    || argv[1]->type != ESEXP_RES_STRING)
+		return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+
+	propname = argv[0]->value.string;
+	str = rfc2254_escape(argv[1]->value.string);
+	star = exact ? "" : "*";
+
+	if (!exact && strlen (str) == 0 && strcmp(propname, "file_as")) {
+		/* Can't do (beginswith FIELD "") */
+		return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+	}
+
+	/* We use the query "(beginswith fileas "")" while building cache for
+	 * GAL offline, where we try to retrive all the contacts and store it 
+	 * locally. Retrieving *all* the contacts may not be possible in case 
+	 * of large number of contacts and huge data, (for the same reason
+	 * we don't support empty queries in GAL when online.) In such cases 
+	 * cache may not be complete.
+	 */
+	if (!strcmp(propname, "file_as")) {
+		filter = g_strdup_printf("(displayName=%s%s)", str, star);
+		goto done;
+	}
+
+	ldap_attr = query_prop_to_ldap(propname);
+	if (!ldap_attr) {
+		g_free (str);
+
+		/* Property doesn't exist, so it can't ever match */
+		r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+		r->value.bool = FALSE;
+		return r;
+	}
+
+	if (!strcmp (propname, "full_name")) {
+		char *first, *last, *space;
+
+		space = strchr (str, ' ');
+		if (space && space > str) {
+			if (*(space - 1) == ',') {
+				first = g_strdup (space + 1);
+				last = g_strndup (str, space - str - 1);
+			} else {
+				first = g_strndup (str, space - str);
+				last = g_strdup (space + 1);
+			}
+			filter = g_strdup_printf("(|(displayName=%s%s)(sn=%s%s)(givenName=%s%s)(&(givenName=%s%s)(sn=%s%s)))",
+						 str, star, str, star,
+						 str, star, first, star,
+						 last, star);
+			g_free (first);
+			g_free (last);
+		} else {
+			filter = g_strdup_printf("(|(displayName=%s%s)(sn=%s%s)(givenName=%s%s)(mailNickname=%s%s))",
+						 str, star, str, star,
+						 str, star, str, star);
+		}
+	} else 
+		filter = g_strdup_printf("(%s=%s%s)", ldap_attr, str, star);
+
+ done:
+	g_free (str);
+
+	r = e_sexp_result_new(f, ESEXP_RES_STRING);
+	r->value.string = filter;
+	return r;
+}
+
+static ESExpResult *
+func_is(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+{
+	return func_is_or_begins_with(f, argc, argv, TRUE);
+}
+
+static ESExpResult *
+func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+{
+	return func_is_or_begins_with(f, argc, argv, FALSE);
+}
+
+static ESExpResult *
+func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+{
+	/* We don't allow endswith searches */
+	return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+}
+
+/* 'builtin' functions */
+static struct {
+	char *name;
+	ESExpFunc *func;
+} symbols[] = {
+	{ "and", func_and },
+	{ "or", func_or },
+	{ "not", func_not },
+	{ "contains", func_contains },
+	{ "is", func_is },
+	{ "beginswith", func_beginswith },
+	{ "endswith", func_endswith },
+};
+
+static int
+build_query (EBookBackendGALLDAP *bl, const char *query, char **ldap_query)
+{
+	ESExp *sexp;
+	ESExpResult *r;
+	int i, retval;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	sexp = e_sexp_new();
+
+	for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
+		e_sexp_add_function(sexp, 0, symbols[i].name,
+				    symbols[i].func, NULL);
+	}
+
+	e_sexp_input_text (sexp, query, strlen (query));
+	e_sexp_parse (sexp);
+
+	r = e_sexp_eval (sexp);
+
+	if (r->type == ESEXP_RES_STRING) {
+		if (!strcmp (r->value.string, "(mail=*)")) {
+			/* If the query is empty, 
+			 * don't search for all the contats 
+			 */ 
+			*ldap_query = NULL;
+			retval = GNOME_Evolution_Addressbook_QueryRefused;
+		}
+		else {
+			*ldap_query = g_strdup_printf ("(&(mail=*)(!(msExchHideFromAddressLists=TRUE))%s)", r->value.string);
+			retval = GNOME_Evolution_Addressbook_Success;
+		}
+	} else if (r->type == ESEXP_RES_BOOL) {
+		/* If it's FALSE, that means "no matches". If it's TRUE
+		 * that means "everything matches", but we don't support
+		 * that, so it also means "no matches".
+		 */
+		*ldap_query = NULL;
+		retval = GNOME_Evolution_Addressbook_Success;
+	} else {
+		/* Bad query */
+		*ldap_query = NULL;
+		retval = GNOME_Evolution_Addressbook_QueryRefused;
+	}
+
+	e_sexp_result_free(sexp, r);
+	e_sexp_unref (sexp);
+
+	return retval;
+}
+
+static void
+manager_populate(EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op)
+{
+	E2kGlobalCatalogEntry *entry;
+	E2kGlobalCatalogStatus status;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	status = e2k_global_catalog_lookup (bl->priv->gc,
+					    op,
+					    E2K_GLOBAL_CATALOG_LOOKUP_BY_DN,
+					    values[0], 0, &entry);
+	if (status != E2K_GLOBAL_CATALOG_OK)
+		return;
+
+	e_contact_set (contact, E_CONTACT_MANAGER,
+		       entry->display_name);
+	e2k_global_catalog_entry_free (bl->priv->gc, entry);
+}
+
+#define G_STRNDUP(str, len) g_strndup(str, len); \
+				str += len;
+
+static void
+member_populate (EContact *contact, char **values, EBookBackendGALLDAP *bl, E2kOperation *op)
+{
+	int i;
+	gchar **member_info;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);					
+	e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+	e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
+
+	for (i=0; values[i]; i++) {
+		EVCardAttribute *attr;
+
+		member_info = g_strsplit (values [i], ";", -1);
+		attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+		e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_EMAIL), member_info [0]);
+		e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_CONTACT_UID), member_info [1]);
+		if (member_info [2])
+			e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_NAME), member_info [2]);
+		e_vcard_attribute_add_value (attr, member_info [0]);
+		e_vcard_add_attribute (E_VCARD (contact), attr);
+	}
+}
+ 
+static char *
+get_time_stamp (char *serv_time_str)
+{
+	char *input_str = serv_time_str, *result_str = NULL;
+	char *year, *month, *date, *hour, *minute, *second, *zone;
+
+	/* input time string will be of the format 20050419162256.0Z
+	 * out put string shd be of the format 2005-04-19T16:22:56.0Z
+	 * ("%04d-%02d-%02dT%02d:%02d:%02dZ") 
+	 */
+
+	/* FIXME : Add a check for proper input string */
+	year = G_STRNDUP(input_str, 4)
+	month = G_STRNDUP(input_str, 2)
+	date = G_STRNDUP(input_str, 2)
+	hour = G_STRNDUP(input_str, 2)
+	minute = G_STRNDUP(input_str, 2)
+	second = G_STRNDUP(input_str, 2)
+	input_str ++; // parse over the dot
+	zone = G_STRNDUP(input_str, 1)
+
+	result_str = g_strdup_printf ("%s-%s-%sT%s:%s:%s.%sZ", 
+		year, month, date, hour, minute, second, zone);
+
+	d(printf ("rev time : %s\n", result_str));
+
+	g_free (year);
+	g_free (month);
+	g_free (date);
+	g_free (hour);
+	g_free (minute);
+	g_free (second);
+	g_free (zone);
+
+	return result_str;
+}
+
+static void
+last_mod_time_populate (EContact *contact, char **values,
+			EBookBackendGALLDAP *bl, E2kOperation *op)
+{
+	char *time_str;
+
+	/* FIXME: Some better way to do this  */
+	time_str = get_time_stamp (values[0]);
+	if (time_str)
+		e_contact_set (contact, E_CONTACT_REV, time_str);
+	g_free (time_str);
+}
+
+
+typedef struct {
+	LDAPOp op;
+	EDataBookView *view;
+
+	/* used to detect problems with start/stop_book_view racing */
+	gboolean aborted;
+	/* used by search_handler to only send the status messages once */
+	gboolean notified_receiving_results;
+} LDAPSearchOp;
+
+static EContact *
+build_contact_from_entry (EBookBackendGALLDAP *bl, LDAPMessage *e, GList **existing_objectclasses)
+{
+	LDAP *ldap = bl->priv->ldap;
+	LDAP *subldap = NULL;
+	EContact *contact = e_contact_new ();
+	char *dn;
+	char *attr;
+	BerElement *ber = NULL, *tber = NULL;
+	gboolean is_group = FALSE;
+	
+	dn = ldap_get_dn(ldap, e);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	e_contact_set (contact, E_CONTACT_UID, dn);
+	ldap_memfree (dn);
+
+	g_mutex_lock (bl->priv->ldap_lock);
+	attr = ldap_first_attribute (ldap, e, &tber);
+	while (attr) {
+		if (!strcmp(attr, "member")) {
+			printf("It is a DL\n");
+			is_group = TRUE;
+			ldap_memfree (attr);
+			break;
+		}
+		ldap_memfree (attr);
+		attr = ldap_next_attribute (ldap, e, tber);
+	}
+	if (tber)
+		ber_free (tber, 0);
+	g_mutex_unlock (bl->priv->ldap_lock);
+	
+	g_mutex_lock (bl->priv->ldap_lock);
+	attr = ldap_first_attribute (ldap, e, &ber);
+	g_mutex_unlock (bl->priv->ldap_lock);
+
+	while (attr) {
+		int i;
+		struct prop_info *info = NULL;
+		struct berval **values;
+
+		if (existing_objectclasses && !g_ascii_strcasecmp (attr, "objectclass")) {
+			g_mutex_lock (bl->priv->ldap_lock);
+			values = ldap_get_values_len (ldap, e, attr);
+			g_mutex_unlock (bl->priv->ldap_lock);
+			for (i = 0; values[i]; i ++) {
+				if (!g_ascii_strcasecmp (values[i]->bv_val, "groupOfNames")) {
+					printf ("groupOfNames\n");
+					e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+					e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
+				}
+				if (existing_objectclasses)
+					*existing_objectclasses = g_list_append (*existing_objectclasses, g_strdup (values[i]->bv_val));
+			}
+			ldap_value_free_len (values);
+		}
+		else {
+			for (i = 0; i < num_prop_infos; i ++)
+				if (!g_ascii_strcasecmp (attr, prop_info[i].ldap_attr)) {
+					info = &prop_info[i];
+					break;
+				}
+
+			d(printf ("attr = %s, ", attr));
+			d(printf ("info = %p\n", info));
+
+			if (info) {
+				if (1) {
+					g_mutex_lock (bl->priv->ldap_lock);
+					values = ldap_get_values_len (ldap, e, attr);
+					g_mutex_unlock (bl->priv->ldap_lock);
+
+					if (values) {
+						if (info->prop_type & PROP_TYPE_STRING && !(is_group && (info->field_id == E_CONTACT_EMAIL_1))) {
+							d(printf ("value = %s %s\n", e_contact_field_name(info->field_id), values[0]->bv_val));
+							/* if it's a normal property just set the string */
+							if (values[0])
+								e_contact_set (contact, info->field_id, values[0]);
+						}
+						else if (info->prop_type & PROP_TYPE_COMPLEX) {
+							/* if it's a list call the contact-populate function,
+							   which calls g_object_set to set the property */
+							   /* FIXME: This portion needs to be re-written to suit 
+							    * the non-deprecated stuff in OpenLDAP 
+							    */
+							/*info->populate_contact_func(contact, values, bl, NULL);*/
+						}
+						else if (info->prop_type & PROP_TYPE_GROUP) {
+							char *grpattrs[3];
+							int i, view_limit = -1, ldap_error, count;
+							EDataBookView *book_view;
+							LDAPMessage *result;
+							struct berval **email_values, **cn_values;
+							gchar **member_info;
+
+							if (!subldap) {
+								subldap = e2k_global_catalog_get_ldap (bl->priv->gc, NULL, NULL);
+							}
+							grpattrs[0] = "cn";
+							grpattrs[1] = "mail";
+							grpattrs[2] = NULL;
+							/*search for member attributes*/
+							/*get the e-mail id for each member and add them to the list*/
+
+							book_view = find_book_view (bl);
+							if (book_view)
+								view_limit = e_data_book_view_get_max_results (book_view);
+							if (view_limit == -1 || view_limit > bl->priv->gc->response_limit)
+								view_limit = bl->priv->gc->response_limit;
+
+							count = ldap_count_values_len (values);
+							member_info = g_new0 (gchar *, count+1);
+							printf ("Fetching members\n");
+							for (i=0; values[i]; i++) {
+								/* get the email id for the given dn */
+								/* set base to DN and scope to base */
+								d(printf("value (dn) = %s \n", values[i]->bv_val));
+								do {
+									if ((ldap_error = ldap_search_ext_s (subldap,
+												values[i]->bv_val,
+												LDAP_SCOPE_BASE,
+												"(objectclass=User)",
+												grpattrs, 0,
+												NULL,
+												NULL,
+												NULL,
+												view_limit,
+												&result)) == LDAP_SUCCESS) {
+										/* find email ids of members */
+										cn_values = ldap_get_values_len (ldap, result, "cn");
+										email_values = ldap_get_values_len (ldap, result, "mail");
+
+										if (email_values) {
+											d(printf ("email = %s \n", email_values[0]->bv_val));
+											*(member_info+i) = 
+												g_strdup_printf ("%s;%s;",
+														email_values[0]->bv_val, values[i]->bv_val);
+											ldap_value_free_len (email_values);
+										}
+										if (cn_values) {
+											d(printf ("cn = %s \n", cn_values[0]->bv_val));
+											*(member_info+i) = 
+												g_strconcat (* (member_info +i),
+														cn_values[0], NULL);
+											ldap_value_free_len (cn_values);
+										}
+									}
+								}
+								while (ldap_reconnect (bl, book_view, &subldap, ldap_error));
+
+								if (ldap_error != LDAP_SUCCESS) {
+									book_view_notify_status (book_view,
+											ldap_err2string(ldap_error));
+									continue ;
+								}
+							}
+							/* call populate function */
+							info->populate_contact_func (contact, member_info, bl, NULL);
+							
+							for(i=0; i<count; i++) {
+								g_free (*(member_info+i));
+							}
+							g_free (member_info);
+						}
+
+						ldap_value_free_len (values);
+					}
+				}
+			}
+		}
+
+		ldap_memfree (attr);
+		g_mutex_lock (bl->priv->ldap_lock);
+		attr = ldap_next_attribute (ldap, e, ber);
+		g_mutex_unlock (bl->priv->ldap_lock);
+	}
+
+	if (ber)
+		ber_free (ber, 0);
+
+	if (subldap)
+		ldap_unbind_ext (subldap, NULL, NULL); 
+	
+	return contact;
+}
+
+static gboolean
+poll_ldap (EBookBackendGALLDAP *bl)
+{
+	LDAP           *ldap = bl->priv->ldap;
+	int            rc;
+	LDAPMessage    *res;
+	struct timeval timeout;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	if (!ldap) {
+		bl->priv->poll_timeout = -1;
+		return FALSE;
+	}
+
+	if (!bl->priv->active_ops) {
+		g_warning ("poll_ldap being called for backend with no active operations");
+		bl->priv->poll_timeout = -1;
+		return FALSE;
+	}
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = LDAP_RESULT_TIMEOUT_MILLIS * 1000;
+
+	g_mutex_lock (bl->priv->ldap_lock);
+	rc = ldap_result (ldap, LDAP_RES_ANY, 0, &timeout, &res);
+	g_mutex_unlock (bl->priv->ldap_lock);
+	if (rc != 0) {/* rc == 0 means timeout exceeded */
+		if (rc == -1) {
+			EDataBookView *book_view = find_book_view (bl);
+			d(printf ("ldap_result returned -1, restarting ops\n"));
+
+			gal_reconnect (bl, book_view, LDAP_SERVER_DOWN);
+#if 0
+			if (bl->priv->connected)
+				restart_ops (bl);
+#endif
+		}
+		else {
+			int msgid = ldap_msgid (res);
+			LDAPOp *op;
+
+			g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
+			op = g_hash_table_lookup (bl->priv->id_to_op, &msgid);
+
+			d(printf ("looked up msgid %d, got op %p\n", msgid, op));
+
+			if (op)
+				op->handler (op, res);
+			else
+				g_warning ("unknown operation, msgid = %d", msgid);
+
+			/* XXX should the call to op->handler be
+			   protected by the lock? */
+			g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
+
+			ldap_msgfree(res);
+		}
+	}
+
+	return TRUE;
+}
+
+static void
+ldap_search_handler (LDAPOp *op, LDAPMessage *res)
+{
+	LDAPSearchOp *search_op = (LDAPSearchOp*)op;
+	EDataBookView *view = search_op->view;
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (op->backend);
+	LDAP *ldap = bl->priv->ldap;
+	LDAPMessage *e;
+	int msg_type;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	d(printf ("ldap_search_handler (%p)\n", view));
+	printf("%s(%d):%s: search handler \n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+	if (!ldap) {
+		printf("%s(%d):%s: other error\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+		e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
+		ldap_op_finished (op);
+		return;
+	}
+
+	if (!search_op->notified_receiving_results) {
+		search_op->notified_receiving_results = TRUE;
+		book_view_notify_status (op->view, _("Receiving LDAP search results..."));
+	}
+
+	msg_type = ldap_msgtype (res);
+	if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+		g_mutex_lock (bl->priv->ldap_lock);
+		e = ldap_first_entry(ldap, res);
+		g_mutex_unlock (bl->priv->ldap_lock);
+
+		while (NULL != e) {
+			EContact *contact = build_contact_from_entry (bl, e, NULL);
+
+			e_data_book_view_notify_update (view, contact);
+
+			g_object_unref (contact);
+
+			g_mutex_lock (bl->priv->ldap_lock);
+			e = ldap_next_entry(ldap, e);
+			g_mutex_unlock (bl->priv->ldap_lock);
+		}
+	}
+	else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+		char *ldap_error_msg;
+		int ldap_error;
+
+		g_mutex_lock (bl->priv->ldap_lock);
+		ldap_parse_result (ldap, res, &ldap_error,
+				   NULL, &ldap_error_msg, NULL, NULL, 0);
+		g_mutex_unlock (bl->priv->ldap_lock);
+		if (ldap_error != LDAP_SUCCESS) {
+			printf("%s(%d):%s: error result\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+			g_warning ("ldap_search_handler: %02X (%s), additional info: %s",
+				   ldap_error,
+				   ldap_err2string (ldap_error), ldap_error_msg);
+		}
+		ldap_memfree (ldap_error_msg);
+
+		if (ldap_error == LDAP_TIMELIMIT_EXCEEDED)
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_SearchTimeLimitExceeded);
+		else if (ldap_error == LDAP_SIZELIMIT_EXCEEDED)
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_SearchSizeLimitExceeded);
+		else if (ldap_error == LDAP_SUCCESS)
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
+		else
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
+		printf("%s(%d):%s: o/p %d %d\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, ldap_error, LDAP_SUCCESS);
+		ldap_op_finished (op);
+	}
+	else {
+		g_warning ("unhandled search result type %d returned", msg_type);
+		e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
+		ldap_op_finished (op);
+
+	}
+}
+
+static void
+ldap_search_dtor (LDAPOp *op)
+{
+	LDAPSearchOp *search_op = (LDAPSearchOp*) op;
+
+	d(printf ("ldap_search_dtor (%p)\n", search_op->view));
+
+	/* unhook us from our EDataBookView */
+	printf ("ldap_search_dtor: Setting null inplace of %p in view %p\n", op, search_op->view);
+	g_object_set_data (G_OBJECT (search_op->view), "EBookBackendGALLDAP.BookView::search_op", NULL);
+
+	bonobo_object_unref (search_op->view);
+
+	if (!search_op->aborted)
+		g_free (search_op);
+}
+
+#if ENABLE_CACHE		
+static void
+get_contacts_from_cache (EBookBackendGALLDAP *ebg, 
+			 const char *query,
+			 GPtrArray *ids,
+			 EDataBookView *book_view)
+	
+{
+	int i;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	for (i = 0; i < ids->len; i ++) {
+		char *uid = g_ptr_array_index (ids, i);
+
+
+		EContact *contact = 
+			e_book_backend_db_cache_get_contact (ebg->priv->file_db, uid);
+		if (contact) {
+			e_data_book_view_notify_update (book_view, contact);
+			g_object_unref (contact);
+		}
+	}
+	e_data_book_view_notify_complete (book_view, 
+					  GNOME_Evolution_Addressbook_Success);
+}
+#endif
+
+static void
+start_book_view (EBookBackend  *backend,
+		 EDataBookView *view)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	GNOME_Evolution_Addressbook_CallStatus status;
+	GList *contacts;
+	char *ldap_query;
+	int ldap_err = LDAP_SUCCESS;
+	int search_msgid;
+	int view_limit;
+	GList *l;
+	
+	printf("start book view\n");
+	switch (bl->priv->mode) {
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+#if ENABLE_CACHE	
+		if (!(bl->priv->marked_for_offline && bl->priv->file_db)) {
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_RepositoryOffline);
+			return;
+		}
+
+		contacts = e_book_backend_db_cache_get_contacts (bl->priv->file_db,
+							      e_data_book_view_get_card_query (view));
+
+		for (l = contacts; l; l = g_list_next (l)) {
+			EContact *contact = l->data;
+			e_data_book_view_notify_update (view, contact);
+			g_object_unref (contact);
+		}
+
+		g_list_free (contacts);
+
+		e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
+		return;
+#else
+		e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_RepositoryOffline);
+		return;
+#endif		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+#if ENABLE_CACHE		
+		printf("Mode:Remote\n");
+		if (bl->priv->marked_for_offline && bl->priv->file_db) {
+			const char *query = e_data_book_view_get_card_query (view);
+			GPtrArray *ids = NULL;
+			printf("Marked for offline and cache present\n");
+
+			status = build_query (bl, e_data_book_view_get_card_query (view),
+					      &ldap_query);
+			if (status != GNOME_Evolution_Addressbook_Success || !ldap_query) {
+				e_data_book_view_notify_complete (view, status);
+				if (ldap_query)
+					g_free (ldap_query);
+				return;
+			}
+	
+			if (bl->priv->is_summary_ready && 
+			    e_book_backend_summary_is_summary_query (bl->priv->summary, query)) {
+				printf("Summary ready and summary_query, searching from summary \n");
+				ids = e_book_backend_summary_search (bl->priv->summary, query);
+				if (ids && ids->len > 0) {
+					get_contacts_from_cache (bl, query, ids, view);
+					g_ptr_array_free (ids, TRUE);
+				}
+				return;
+			}
+			
+			
+			contacts = e_book_backend_db_cache_get_contacts (bl->priv->file_db,
+									 e_data_book_view_get_card_query (view));
+			for (l = contacts; l ;l = g_list_next (l)) {
+				EContact *contact = l->data;
+				e_data_book_view_notify_update (view, contact);
+				g_object_unref (contact);
+			}
+
+			g_list_free (contacts);
+
+			e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
+			return ;
+		}
+		else {
+#endif			
+			printf("Not marked for offline or cache not there\n");
+			if (!bl->priv->ldap) {
+				if (!gal_reconnect (bl, view, 0)) {
+					printf("%s(%d):%s: no ldap :(\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+					e_data_book_view_notify_complete (view,
+									  GNOME_Evolution_Addressbook_InvalidQuery);
+					return;
+				}
+			}
+
+			/* we start at 1 so the user sees stuff as it appears and we
+			   aren't left waiting for more cards to show up, if the
+			   connection is slow. */
+			e_data_book_view_set_thresholds (view, 1, 3000);
+
+			view_limit = e_data_book_view_get_max_results (view);
+			if (view_limit == -1 || view_limit > bl->priv->gc->response_limit)
+				view_limit = bl->priv->gc->response_limit;
+
+			d(printf ("start_book_view (%p)\n", view));
+
+			status = build_query (bl, e_data_book_view_get_card_query (view),
+					      &ldap_query);
+			printf("%s(%d):%s: %s\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, ldap_query);
+			if (status != GNOME_Evolution_Addressbook_Success || !ldap_query) {
+				e_data_book_view_notify_complete (view, status);
+				if (ldap_query)
+					g_free (ldap_query);
+				printf("%s(%d):%s: failure \n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+				return;
+			}
+
+			do {
+				if (bl->priv->ldap) {
+					book_view_notify_status (view, _("Searching..."));
+	
+					g_mutex_lock (bl->priv->ldap_lock);
+					printf("%s(%d):%s: starting \n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+					ldap_err = ldap_search_ext (bl->priv->ldap, LDAP_ROOT_DSE,
+								    LDAP_SCOPE_SUBTREE,
+								    ldap_query,
+								    search_attrs, 0,
+								    NULL, /* XXX */
+								    NULL, /* XXX */
+								    NULL, /* XXX timeout */
+								    view_limit,
+								    &search_msgid);
+					g_mutex_unlock (bl->priv->ldap_lock);
+					printf("%s(%d):%s: %d\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, ldap_err);
+				} else 
+					bl->priv->connected = FALSE;
+			} while (gal_reconnect (bl, view, ldap_err));
+
+			g_free (ldap_query);
+
+			if (ldap_err != LDAP_SUCCESS) {
+				printf("%s(%d):%s: error\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+				book_view_notify_status (view, ldap_err2string(ldap_err));
+				return;
+			}
+			else if (search_msgid == -1) {
+				printf("%s(%d):%s: error\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+				book_view_notify_status (view,
+							 _("Error performing search"));
+				return;
+			}
+			else {
+				LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1);
+				
+				d(printf ("adding search_op (%p, %d)\n", view, search_msgid));
+				printf("%s(%d):%s: adding search \n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+				op->view = view;
+				op->aborted = FALSE;
+
+				bonobo_object_ref (view);
+
+				ldap_op_add ((LDAPOp*)op, E_BOOK_BACKEND (bl), NULL, view,
+					     0, search_msgid,
+					     ldap_search_handler, ldap_search_dtor);
+				printf("start_book_view: Setting op %p in book %p\n", op, view);
+				g_object_set_data (G_OBJECT (view), "EBookBackendGALLDAP.BookView::search_op", op);
+			}
+#if ENABLE_CACHE			
+		}
+#endif		
+	}
+}
+
+static void
+stop_book_view (EBookBackend  *backend,
+		EDataBookView *view)
+{
+	LDAPSearchOp *op;
+
+	d(printf ("stop_book_view (%p)\n", view));
+
+	op = g_object_get_data (G_OBJECT (view), "EBookBackendGALLDAP.BookView::search_op");
+	printf("STOP BOOK VIEW: Getting op %p from view %p\n", op, view);
+	if (op) {
+		op->aborted = TRUE;
+		ldap_op_finished ((LDAPOp*)op);
+		g_free (op);
+	}
+}
+
+static void
+get_changes (EBookBackend *backend,
+	     EDataBook    *book,
+	     guint32 	   opid,
+	     const char   *change_id)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	/* FIXME: implement */
+}
+
+static int pagedResults = 1;
+static ber_int_t pageSize = 1000;
+static ber_int_t entriesLeft = 0;
+static ber_int_t morePagedResults = 1;
+static struct berval cookie = { 0, NULL };
+static int npagedresponses;
+static int npagedentries;
+static int npagedreferences;
+static int npagedextended;
+static int npagedpartial;
+
+/* Set server controls.  Add controls extra_c[0..count-1], if set. */
+static void
+tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count )
+{
+	int i = 0, j, crit = 0, err;
+	LDAPControl c[3], **ctrls;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	ctrls = (LDAPControl**) malloc(sizeof(c) + (count+1)*sizeof(LDAPControl*));
+	if ( ctrls == NULL ) {
+		fprintf( stderr, "No memory\n" );
+		exit( EXIT_FAILURE );
+	}
+
+	while ( count-- ) {
+		ctrls[i++] = extra_c++;
+	}
+	ctrls[i] = NULL;
+
+	err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
+
+	if ( err != LDAP_SUCCESS ) {
+		for ( j = 0; j < i; j++ ) {
+			if ( ctrls[j]->ldctl_iscritical ) crit = 1;
+		}
+		fprintf( stderr, "Could not set %scontrols\n",
+			crit ? "critical " : "" );
+	}
+
+ 	free( ctrls );
+	if ( crit ) {
+		exit( EXIT_FAILURE );
+	}
+}
+
+#ifdef SUNLDAP
+static struct berval *
+ber_dupbv( struct berval *dst, struct berval *src )
+{
+	struct berval *tmp;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	tmp = ber_bvdup(src);
+	if (!tmp)
+		return NULL;
+
+	dst->bv_len = tmp->bv_len;
+	dst->bv_val = tmp->bv_val;
+	tmp->bv_len = 0;
+	tmp->bv_val = NULL;
+	ber_bvfree (tmp);
+
+	return dst;
+}
+#endif
+
+static int 
+parse_page_control(
+	LDAP *ld,
+	LDAPMessage *result,
+	struct berval *cookie )
+{
+	int rc;
+	int err;
+	LDAPControl **ctrl = NULL;
+	LDAPControl *ctrlp = NULL;
+	BerElement *ber;
+	ber_tag_t tag;
+	struct berval servercookie = { 0, NULL };
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	rc = ldap_parse_result( ld, result,
+		&err, NULL, NULL, NULL, &ctrl, 0 );
+
+	if( rc != LDAP_SUCCESS ) {
+		g_print ("ldap_parse_result - %s", ldap_err2string(rc));
+		exit( EXIT_FAILURE );
+	}
+
+	if ( err != LDAP_SUCCESS ) {
+		fprintf( stderr, "Error: %s (%d)\n", ldap_err2string(err), err );
+	}
+
+	if( ctrl ) {
+		/* Parse the control value
+		 * searchResult ::= SEQUENCE {
+		 *		size	INTEGER (0..maxInt),
+		 *				-- result set size estimate from server - unused
+		 *		cookie	OCTET STRING
+		 * }
+		 */
+		ctrlp = *ctrl;
+		ber = ber_init( &ctrlp->ldctl_value );
+		if ( ber == NULL ) {
+			fprintf( stderr, "Internal error.\n");
+			return EXIT_FAILURE;
+		}
+
+		tag = ber_scanf( ber, "{im}", &entriesLeft, &servercookie );
+		ber_dupbv( cookie, &servercookie );
+		(void) ber_free( ber, 1 );
+
+		if( tag == LBER_ERROR ) {
+			fprintf( stderr,
+				"Paged results response control could not be decoded.\n");
+			return EXIT_FAILURE;
+		}
+
+		if( entriesLeft < 0 ) {
+			fprintf( stderr,
+				"Invalid entries estimate in paged results response.\n");
+			return EXIT_FAILURE;
+		}
+		ldap_controls_free( ctrl );
+
+	} else {
+		morePagedResults = 0;
+	}
+	if (cookie->bv_len>0) {
+		printf("\n");
+	}
+	else {
+		morePagedResults = 0;
+	}
+
+	return err;
+}
+
+#if ENABLE_CACHE
+static int dosearch(
+	EBookBackendGALLDAP *bl,
+	LDAP	*ld,
+	char	*base,
+	int		scope,
+	char	*filtpatt,
+	char	*value,
+	char	**attrs,
+	int		attrsonly,
+	LDAPControl **sctrls,
+	LDAPControl **cctrls,
+	struct timeval *timeout,
+	int sizelimit )
+{
+	int			rc;
+	LDAPMessage		*res, *msg;
+	ber_int_t		msgid;
+	static int count = 0;
+	char *ssize = getenv("LDAP_LIMIT");
+	int size = 0;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	if (ssize && *ssize) 
+		size = atoi(ssize);
+	
+	rc = ldap_search_ext( ld, base, scope, value, attrs, attrsonly,
+		sctrls, cctrls, timeout, size /*LDAP_NO_LIMIT*/, &msgid );
+
+	if( rc != LDAP_SUCCESS ) {
+		return( rc );
+	}
+
+	res = NULL;
+
+	while ((rc = ldap_result( ld, LDAP_RES_ANY,
+		0,
+		NULL, &res )) > 0 )
+	{
+		for ( msg = ldap_first_message( ld, res );
+			msg != NULL;
+			msg = ldap_next_message( ld, msg ) )
+		{
+			EContact *contact;
+
+			switch( ldap_msgtype( msg ) ) {
+			case LDAP_RES_SEARCH_ENTRY:
+				count ++;
+				contact = build_contact_from_entry (bl, msg, NULL);
+				e_book_backend_db_cache_add_contact (bl->priv->file_db, contact);
+				e_book_backend_summary_add_contact (bl->priv->summary, contact);
+				g_object_unref (contact);
+				break;
+
+			case LDAP_RES_SEARCH_RESULT:
+				if ( pageSize != 0 ) {
+					rc = parse_page_control( ld, msg, &cookie );
+				}
+
+				goto done;
+			}
+
+		}
+
+		ldap_msgfree( res );
+	}
+
+	if ( rc == -1 ) {
+		g_print ("ldap_result - %s", ldap_err2string(rc));
+		return( rc );
+	}
+
+done:
+	ldap_msgfree( res );
+	return( rc );
+}
+
+static void
+generate_cache (EBookBackendGALLDAP *book_backend_gal)
+{
+	LDAPGetContactListOp *contact_list_op = g_new0 (LDAPGetContactListOp, 1);
+	EBookBackendGALLDAPPrivate *priv;
+	gchar *ldap_query;
+	int  i = 0, rc ;
+	BerElement *prber = NULL;
+	time_t t1;
+	char t[15];
+	LDAPControl c[6];
+
+	printf ("Generate Cache\n");
+	priv = book_backend_gal->priv;
+
+
+	npagedresponses = npagedentries = npagedreferences =
+		npagedextended = npagedpartial = 0;
+
+	build_query (book_backend_gal, 
+		     "(beginswith \"file_as\" \"\")", &ldap_query);
+
+
+getNextPage:
+	
+	/*start iteration*/
+
+	i = 0;
+	if ( pagedResults ) {
+		if (( prber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
+			return;
+		}
+		ber_printf( prber, "{iO}", pageSize, &cookie );
+		if ( ber_flatten2( prber, &c[i].ldctl_value, 0 ) == -1 ) {
+			return;
+		}
+		printf ("Setting parameters		\n");
+		c[i].ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
+		c[i].ldctl_iscritical = pagedResults > 1;
+		i++;
+	} 
+	
+	tool_server_controls( priv->ldap, c, i );
+	ber_free (prber, 1);
+
+	if (!priv->ldap) {
+		g_free (contact_list_op);
+		return;
+	}
+
+	rc = dosearch (book_backend_gal, priv->ldap, LDAP_ROOT_DSE, LDAP_SCOPE_SUBTREE, NULL, ldap_query, NULL, 0, NULL, NULL, NULL, -1);
+
+
+	/* loop to get the next set of entries */
+	
+	if ( (pageSize !=0 ) && (morePagedResults != 0)) {
+		printf ("Start next iteration\n");
+		goto getNextPage;
+	}
+	else
+		printf ("All the entries fetched and finished building the cache\n");
+	
+	/* Set the cache to populated and thaw the changes */
+
+	e_book_backend_db_cache_set_populated (priv->file_db);
+	t1 = time (NULL);
+	g_sprintf (t," %d", (int)t1);
+	e_book_backend_db_cache_set_time (priv->file_db, t);
+	priv->is_summary_ready = TRUE;
+	book_backend_gal->priv->file_db->sync (book_backend_gal->priv->file_db, 0);
+	
+	g_free (ldap_query);
+
+}
+#endif
+
+static void
+authenticate_user (EBookBackend *backend,
+		   EDataBook    *book,
+		   guint32       opid,
+		   const char   *user,
+		   const char   *password,
+		   const char   *auth_method)
+{
+	EBookBackendGALLDAP *be = E_BOOK_BACKEND_GALLDAP (backend);
+	EBookBackendGALLDAPPrivate *bepriv = be->priv;
+	GNOME_Evolution_Addressbook_CallStatus res;
+	GConfClient *gc = gconf_client_get_default();
+	int interval = gconf_client_get_int (gc, "/apps/evolution/addressbook/gal_cache_interval", NULL);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	/* We should not be here */
+/* 	e_data_book_respond_authenticate_user (book, */
+/* 					       opid, */
+/* 					       GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod); */
+/* 	return; */
+	
+	d(printf("authenticate_user(%p, %p, %s, %s, %s)\n", backend, book, user, password, auth_method));
+
+	switch (bepriv->mode) {
+
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		e_book_backend_notify_writable (E_BOOK_BACKEND (backend), FALSE);
+		e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), FALSE);
+		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success);
+		return;
+			
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+	
+		e2k_global_catalog_set_password (be->priv->gc, password);
+		res = gal_connect (be);
+		if (res != GNOME_Evolution_Addressbook_Success) {
+			e_data_book_respond_authenticate_user (book, opid, res);
+			return;
+		}
+		printf("Cache is %d\n", ENABLE_CACHE);
+#if ENABLE_CACHE		
+		if (be->priv->marked_for_offline) {
+			char *t = e_book_backend_db_cache_get_time (be->priv->file_db);
+			
+			if (t) {
+				time_t t1, t2;
+				int diff;
+
+				char *cache_time = e_book_backend_db_cache_get_time (be->priv->file_db);
+				printf("Cache is populated, check if refresh is required \n");
+				if (cache_time && *cache_time)
+					t1 = atoi (cache_time);
+				else
+					t1=0;
+				t2 = time (NULL);
+				diff = interval * 24 * 60 *60;
+				/* We have a day specified, then we cache it. */
+				if (!diff || t2 - t1 > diff) {
+					printf ("Cache older than specified period, refreshing \n");
+					generate_cache (be);
+				}
+				else
+					be->priv->is_summary_ready= TRUE;
+			}
+			else {
+				printf("Cache not there, generate cache\n");
+				generate_cache(be);
+			}
+		}
+#endif		
+		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success);
+		return;		
+		
+	default:
+		break;
+	}
+
+
+	/* We should not be here */
+	e_data_book_respond_authenticate_user (book,
+					       opid,
+					       GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod);
+	return;
+}
+
+#ifdef SUNLDAP
+static int
+ber_flatten2( BerElement *ber, struct berval *bv, int alloc )
+{
+	struct berval *tmp;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	if ( ber_flatten( ber, &tmp) == -1 ) {
+		return;
+	}
+	bv->bv_len = tmp->bv_len;
+	bv->bv_val = tmp->bv_val;
+	tmp->bv_len = 0;
+	tmp->bv_val = NULL;
+	ber_bvfree (tmp);
+
+	return 0;
+}		
+#endif
+
+static void
+ldap_cancel_op(void *key, void *value, void *data)
+{
+	EBookBackendGALLDAP *bl = data;
+	LDAPOp *op = value;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	/* ignore errors, its only best effort? */
+	g_mutex_lock (bl->priv->ldap_lock);
+	if (bl->priv->ldap)
+		ldap_abandon_ext (bl->priv->ldap, op->id, NULL, NULL);
+	g_mutex_unlock (bl->priv->ldap_lock);
+}
+
+static GNOME_Evolution_Addressbook_CallStatus
+cancel_operation (EBookBackend *backend, EDataBook *book)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
+	g_hash_table_foreach (bl->priv->id_to_op, ldap_cancel_op, bl);
+	g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
+
+	return GNOME_Evolution_Addressbook_Success;
+}
+
+static void
+set_mode (EBookBackend *backend, int mode)
+{
+	EBookBackendGALLDAP *be = E_BOOK_BACKEND_GALLDAP (backend);
+	EBookBackendGALLDAPPrivate *bepriv;
+
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	bepriv = be->priv;
+	printf("set mode\n");
+	if (bepriv->mode == mode)
+		return;
+
+	bepriv->mode = mode;
+
+	/* Cancel all running operations */
+	cancel_operation (backend, NULL);
+
+	if (e_book_backend_is_loaded (backend)) {
+		if (mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
+			e_book_backend_set_is_writable (backend, FALSE);
+			e_book_backend_notify_writable (backend, FALSE);
+			e_book_backend_notify_connection_status (backend, FALSE);
+		} else if (mode == GNOME_Evolution_Addressbook_MODE_REMOTE) {
+			e_book_backend_set_is_writable (backend, FALSE);
+			e_book_backend_notify_writable (backend, FALSE);
+			e_book_backend_notify_connection_status (backend, TRUE);
+
+			if (e_book_backend_is_loaded (backend)) {
+				gal_connect (be);
+				e_book_backend_notify_auth_required (backend);
+#if ENABLE_CACHE
+				if (bepriv->marked_for_offline && bepriv->file_db)
+					generate_cache (be);
+#endif				
+			}
+		}
+	}
+}
+
+static void
+get_supported_fields (EBookBackend *backend,
+		      EDataBook    *book,
+		      guint32 	    opid)
+
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	e_data_book_respond_get_supported_fields (book,
+						  opid,
+						  GNOME_Evolution_Addressbook_Success,
+						  supported_fields);
+}
+
+static void
+get_required_fields (EBookBackend *backend,
+		     EDataBook *book,
+		     guint32 opid)
+{
+	GList *fields = NULL;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
+	e_data_book_respond_get_required_fields (book,
+						  opid,
+						  GNOME_Evolution_Addressbook_Success,
+						  fields);
+	g_list_free (fields);
+
+}
+
+static void
+get_supported_auth_methods (EBookBackend *backend,
+			    EDataBook    *book,
+			    guint32       opid)
+
+{
+	printf("%s(%d):%s: NONE\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
+	e_data_book_respond_get_supported_auth_methods (book,
+							opid,
+							GNOME_Evolution_Addressbook_Success,
+							NULL);
+}
+
+static GNOME_Evolution_Addressbook_CallStatus
+load_source (EBookBackend *backend,
+	     ESource      *source,
+	     gboolean      only_if_exists)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (backend);
+	GConfClient *gc = gconf_client_get_default();
+	const char *host;
+	char **tokens;
+	const char *offline;
+	char *uri;
+	char *book_name;
+	char *dirname, *filename;
+	int i, db_error;
+	char *domain, *user;
+	const char *slimit;
+	int limit=500;
+#if ENABLE_CACHE	
+	DB *db;
+	DB_ENV *env;
+#endif
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	printf("load_source\n");
+	g_object_unref (gc);
+	g_return_val_if_fail (bl->priv->connected == FALSE, GNOME_Evolution_Addressbook_OtherError);
+
+	offline = e_source_get_property (source, "offline_sync");
+	if (offline && g_str_equal (offline, "1"))
+		bl->priv->marked_for_offline = TRUE;
+
+	if (bl->priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL &&
+	    !bl->priv->marked_for_offline)
+		return GNOME_Evolution_Addressbook_OfflineUnavailable;
+
+
+	uri = e_source_get_uri (source);
+	host = uri + sizeof ("galldap://";) - 1;
+	if (strncmp (uri, "galldap://";, host - uri))
+		return GNOME_Evolution_Addressbook_OtherError;
+
+	bl->priv->server = e_source_get_duped_property (source, "host");
+	bl->priv->port = 3268;
+	user = e_source_get_duped_property (source, "user");
+	domain = e_source_get_duped_property (source, "domain");
+	slimit = e_source_get_property (source, "view-limit");
+	printf("slimit is %s\n", slimit);
+	if (slimit && *slimit) {
+		limit = atoi (slimit);
+		if (limit <= 0)
+			limit = 500;
+	}
+	bl->priv->gc = e2k_global_catalog_new (bl->priv->server, limit, user, domain, NULL, E2K_AUTOCONFIG_USE_GAL_DEFAULT);
+  	bl->priv->gal_uri = g_strdup (uri);
+  	tokens = g_strsplit (uri, ";", 2);
+  	g_free (uri);
+  	if (tokens[0])
+ 		uri = g_strdup (tokens [0]);
+  	book_name = g_strdup (tokens[1]);
+  	if (book_name == NULL)
+  		return GNOME_Evolution_Addressbook_OtherError;
+  	g_strfreev (tokens);
+   
+  	for (i=0; i< strlen (uri); i++) {
+  		switch (uri[i]) {
+ 		case ':' :
+ 		case '/' :
+ 			uri[i] = '_';
+  		}
+ 	}
+#if ENABLE_CACHE
+	bl->priv->file_db = NULL;
+#endif
+	if (bl->priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL && !bl->priv->marked_for_offline) {
+		/* Offline */
+
+		e_book_backend_set_is_loaded (backend, FALSE);
+		e_book_backend_set_is_writable (backend, FALSE);
+		e_book_backend_notify_writable (backend, FALSE);
+		e_book_backend_notify_connection_status (backend, FALSE);
+
+		return GNOME_Evolution_Addressbook_RepositoryOffline;
+	}
+#if ENABLE_CACHE
+ 	if (bl->priv->marked_for_offline) {
+ 		printf("offlin==============\n");
+ 		bl->priv->summary_file_name = g_build_filename (g_get_home_dir(), ".evolution/cache/addressbook" , uri, book_name, NULL);
+ 		bl->priv->summary_file_name = g_build_filename (bl->priv->summary_file_name, "cache.summary", NULL);
+ 		bl->priv->summary = e_book_backend_summary_new (bl->priv->summary_file_name, 
+ 							    SUMMARY_FLUSH_TIMEOUT);
+ 		e_book_backend_summary_load (bl->priv->summary);
+ 		
+ 		dirname = g_build_filename (g_get_home_dir(), ".evolution/cache/addressbook", uri, book_name, NULL);
+ 		filename = g_build_filename (dirname, "cache.db", NULL);
+ 		printf("Loading %s\n", filename);
+ 		db_error = e_db3_utils_maybe_recover (filename);
+ 		if (db_error != 0) {
+ 			g_warning ("db recovery failed with %d", db_error);
+ 			g_free (dirname);
+ 			g_free (filename);
+ 			return GNOME_Evolution_Addressbook_OtherError;
+ 		}
+ 
+ 		g_static_mutex_lock (&global_env_lock);
+ 		if (global_env.ref_count > 0) {
+ 			env = global_env.env;
+ 			global_env.ref_count ++;
+ 		}
+ 		else {
+ 			db_error = db_env_create (&env, 0);
+ 			if (db_error != 0) {
+ 				g_warning ("db_env_create failed with %d", db_error);
+ 				g_static_mutex_unlock (&global_env_lock);
+ 				g_free (dirname);
+ 				g_free (filename);
+ 				return GNOME_Evolution_Addressbook_OtherError;
+ 			}
+ 
+ 			db_error = (*env->open) (env, NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD, 0);
+ 			if (db_error != 0) {
+ 				env->close (env, 0);
+ 				g_warning ("db_env_open failed with %d", db_error);
+ 				g_static_mutex_unlock (&global_env_lock);
+ 				g_free(dirname);
+ 				g_free(filename);
+ 				return GNOME_Evolution_Addressbook_OtherError;
+ 			}
+ 
+ 			//env->set_errcall (env, file_errcall);
+ 			global_env.env = env;
+ 			global_env.ref_count = 1;
+ 		}
+ 		g_static_mutex_unlock(&global_env_lock);
+ 
+ 		bl->priv->env = env;
+ 		db_error = db_create (&db, env, 0);
+ 		if (db_error != 0) {
+ 			g_warning ("db_create failed with %d", db_error);
+ 			g_free (dirname);
+ 			g_free (filename);
+ 			return GNOME_Evolution_Addressbook_OtherError;
+ 		}
+ 
+ 		db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_THREAD, 0666);
+ 
+ 		if (db_error == DB_OLD_VERSION) {
+ 			db_error = e_db3_utils_upgrade_format (filename);
+ 
+ 			if (db_error != 0) {
+ 				g_warning ("db format upgrade failed with %d", db_error);
+ 				g_free (filename);
+ 				g_free (dirname);
+ 				return GNOME_Evolution_Addressbook_OtherError;
+ 			}
+ 
+ 			db_error = (*db->open) (db, NULL,filename, NULL, DB_HASH, DB_THREAD, 0666);
+ 		}
+ 
+ 		bl->priv->file_db = db;
+ 		if (db_error != 0) {
+ 			int rv;
+ 
+ 			/* the database didn't exist, so we create the directory then the .db */
+ 			rv= g_mkdir_with_parents (dirname, 0777);
+ 			if (rv == -1 && errno != EEXIST) {
+ 				g_warning ("failed to make directory %s: %s", dirname, strerror (errno));
+ 				g_free (dirname);
+ 				g_free (filename);
+ 				if (errno == EACCES || errno == EPERM)
+ 					return GNOME_Evolution_Addressbook_PermissionDenied;
+ 				else
+ 					return GNOME_Evolution_Addressbook_OtherError;
+ 			}
+ 
+ 			db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_CREATE | DB_THREAD, 0666);
+ 			if (db_error != 0) {
+ 				g_warning ("db->open (...DB_CREATE...) failed with %d", db_error);
+ 			}
+ 		}
+ 	
+ 		bl->priv->file_db = db;
+ 	
+ 		if (db_error != 0 || bl->priv->file_db == NULL) {
+ 
+ 			g_free (filename);
+ 			g_free (dirname);
+ 			return GNOME_Evolution_Addressbook_OtherError;
+ 		}
+ 
+ 		e_book_backend_db_cache_set_filename (bl->priv->file_db, filename);
+ 		g_free (filename);
+ 		g_free (dirname);
+ 		g_free (uri);
+ 	}
+#endif 
+ 	/* Online */
+ 	e_book_backend_set_is_writable (E_BOOK_BACKEND(backend), FALSE);
+ 	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
+ 	e_book_backend_notify_writable (backend, FALSE);
+  
+  	if (bl->priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL)
+  		e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), FALSE);
+  	else
+  		e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
+ 
+ 	return GNOME_Evolution_Addressbook_Success;
+}
+
+static void
+remove_gal (EBookBackend *backend, EDataBook *book, guint32 opid)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_PermissionDenied);
+}
+
+static char *
+get_static_capabilities (EBookBackend *backend)
+{
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	
+	return g_strdup("net");
+}
+
+/* FIXME: unused */
+#if 0
+/**
+ * e_book_backend_galldapnew:
+ *
+ * Creates a new #EBookBackendGALLDAP.
+ *
+ * Return value: the new #EBookBackendGALLDAP.
+ */
+EBookBackend *
+e_book_backend_galldapnew (void)
+{
+	EBookBackendGALLDAP *backend;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	backend = g_object_new (E_TYPE_BOOK_BACKEND_GALLDAP, NULL);
+	if (!e_book_backend_construct (E_BOOK_BACKEND (backend))) {
+		g_object_unref (backend);
+
+		return NULL;
+	}
+
+	return E_BOOK_BACKEND (backend);
+}
+#endif 
+
+static gboolean
+call_dtor (int msgid, LDAPOp *op, gpointer data)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (op->backend);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	g_mutex_lock (bl->priv->ldap_lock);
+	ldap_abandon_ext (bl->priv->ldap, op->id, NULL, NULL);
+	g_mutex_unlock (bl->priv->ldap_lock);
+
+	op->dtor (op);
+
+	return TRUE;
+}
+
+static void
+dispose (GObject *object)
+{
+	EBookBackendGALLDAP *bl = E_BOOK_BACKEND_GALLDAP (object);
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	if (bl->priv) {
+		g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
+		g_hash_table_foreach_remove (bl->priv->id_to_op, (GHRFunc)call_dtor, NULL);
+		g_hash_table_destroy (bl->priv->id_to_op);
+		g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
+		g_static_rec_mutex_free (&bl->priv->op_hash_mutex);
+
+		if (bl->priv->poll_timeout != -1) {
+			d(printf ("removing timeout\n"));
+			g_source_remove (bl->priv->poll_timeout);
+		}
+
+		g_mutex_lock (bl->priv->ldap_lock);
+		if (bl->priv->ldap)
+			ldap_unbind_ext (bl->priv->ldap, NULL, NULL);
+		g_mutex_unlock (bl->priv->ldap_lock);
+
+		if (bl->priv->gc)
+			g_object_unref (bl->priv->gc);
+		
+ 		if (bl->priv->summary_file_name) {
+ 			g_free (bl->priv->summary_file_name);
+ 			bl->priv->summary_file_name = NULL;
+ 		}
+ 
+ 		if (bl->priv->summary) {
+ 			e_book_backend_summary_save (bl->priv->summary);
+ 			g_object_unref (bl->priv->summary);
+ 			bl->priv->summary = NULL;
+ 		}
+#if ENABLE_CACHE 
+ 		if (bl->priv->file_db)
+ 			bl->priv->file_db->close (bl->priv->file_db, 0);
+ 		g_static_mutex_lock (&global_env_lock);
+ 		global_env.ref_count--;
+ 		if (global_env.ref_count == 0) {
+ 			global_env.env->close (global_env.env, 0);
+ 			global_env.env = NULL;
+ 		}
+ 		g_static_mutex_unlock(&global_env_lock);
+
+#endif
+		if (bl->priv->ldap_lock)
+			g_mutex_free (bl->priv->ldap_lock);
+
+
+		g_free (bl->priv->gal_uri);
+		g_free (bl->priv);
+		bl->priv = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+EBookBackend *
+e_book_backend_galldap_new (void)
+{
+	EBookBackendGALLDAP *backend;
+
+	printf ("\ne_book_backend_galldap_new...\n");
+                                                                                                                             
+	backend = g_object_new (E_TYPE_BOOK_BACKEND_GALLDAP, NULL);
+                                                                                                       
+	return E_BOOK_BACKEND (backend);
+}
+
+static void
+e_book_backend_galldap_class_init (EBookBackendGALLDAPClass *klass)
+{
+	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+	EBookBackendClass *backend_class = E_BOOK_BACKEND_CLASS (klass);
+	int i;
+
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);	parent_class = g_type_class_peek_parent (klass);
+
+	/* Set the virtual methods. */
+	backend_class->load_source                = load_source;
+	backend_class->remove                     = remove_gal;
+	backend_class->get_static_capabilities    = get_static_capabilities;
+
+	backend_class->create_contact             = create_contact;
+	backend_class->remove_contacts            = remove_contacts;
+	backend_class->modify_contact             = modify_contact;
+	backend_class->get_contact                = get_contact;
+	backend_class->get_contact_list           = get_contact_list;
+	backend_class->start_book_view            = start_book_view;
+	backend_class->stop_book_view             = stop_book_view;
+	backend_class->get_changes                = get_changes;
+	backend_class->authenticate_user          = authenticate_user;
+	backend_class->get_supported_fields       = get_supported_fields;
+	backend_class->set_mode      		  = set_mode;
+	backend_class->get_required_fields        = get_required_fields;
+	backend_class->get_supported_auth_methods = get_supported_auth_methods;
+	backend_class->cancel_operation           = cancel_operation;
+
+	object_class->dispose = dispose;
+
+	/* Set up static data */
+	supported_fields = NULL;
+	for (i = 0; i < num_prop_infos; i++) {
+		supported_fields = g_list_append (supported_fields,
+						  (char *)e_contact_field_name (prop_info[i].field_id));
+	}
+	supported_fields = g_list_append (supported_fields, "file_as");
+
+	search_attrs = g_new (char *, num_prop_infos + 1);
+	for (i = 0; i < num_prop_infos; i++)
+		search_attrs[i] = prop_info[i].ldap_attr;
+	search_attrs[num_prop_infos] = NULL;
+}
+
+static void
+e_book_backend_galldap_init (EBookBackendGALLDAP *backend)
+{
+	EBookBackendGALLDAPPrivate *priv;
+	printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	priv                         = g_new0 (EBookBackendGALLDAPPrivate, 1);
+
+	priv->id_to_op         	     = g_hash_table_new (g_int_hash, g_int_equal);
+	priv->poll_timeout     	     = -1;
+	priv->ldap_lock		     = g_mutex_new ();
+
+	g_static_rec_mutex_init (&priv->op_hash_mutex);
+
+	backend->priv = priv;
+}
+G_DEFINE_TYPE (EBookBackendGALLDAP, e_book_backend_galldap, E_TYPE_BOOK_BACKEND);
+
+//E2K_MAKE_TYPE (e_book_backend_gal, EBookBackendGALLDAP, class_init, init, PARENT_TYPE)
diff --git a/src/galldap/e-book-backend-galldap.h b/src/galldap/e-book-backend-galldap.h
new file mode 100644
index 0000000..affccbc
--- /dev/null
+++ b/src/galldap/e-book-backend-galldap.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public 
+ *  License along with this program; if not, write to: 
+ *  Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __E_BOOK_BACKEND_GALLDAP_H__
+#define __E_BOOK_BACKEND_GALLDAP_H__
+
+#include <libedata-book/e-book-backend.h>
+
+#ifdef SUNLDAP
+/*   copy from openldap ldap.h   */
+#define LDAP_RANGE(n,x,y)      (((x) <= (n)) && ((n) <= (y)))
+#define LDAP_NAME_ERROR(n)     LDAP_RANGE((n), 0x20, 0x24)
+#define LBER_USE_DER			0x01
+#define LDAP_CONTROL_PAGEDRESULTS      "1.2.840.113556.1.4.319"
+#endif
+
+typedef struct _EBookBackendGALLDAPPrivate EBookBackendGALLDAPPrivate;
+
+typedef struct {
+	EBookBackend             parent_object;
+	EBookBackendGALLDAPPrivate *priv;
+} EBookBackendGALLDAP;
+
+typedef struct {
+	EBookBackendClass parent_class;
+} EBookBackendGALLDAPClass;
+
+EBookBackend *e_book_backend_galldap_new      (void);
+GType       e_book_backend_galldap_get_type (void);
+
+#define E_TYPE_BOOK_BACKEND_GALLDAP        (e_book_backend_galldap_get_type ())
+#define E_BOOK_BACKEND_GALLDAP(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_GALLDAP, EBookBackendGALLDAP))
+#define E_BOOK_BACKEND_GALLDAPLDAP_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_BACKEND_GALLDAP, EBookBackendGALLDAPClass))
+#define E_IS_BOOK_BACKEND_GALLDAP(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_GALLDAP))
+#define E_IS_BOOK_BACKEND_GALLDAP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_GALLDAP))
+
+#endif /* ! __E_BOOK_BACKEND_GALLDAP_H__ */
+



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