diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/configure.in dovecot-1.2.10/configure.in
--- ORIG/dovecot-1.2.10/configure.in	2010-01-24 23:31:57.000000000 +0000
+++ dovecot-1.2.10/configure.in	2010-02-05 07:19:44.000000000 +0000
@@ -1936,10 +1936,13 @@
     userdb="$userdb (plugin)"
     passdb="$passdb (plugin)"
   fi
+# Need to run some specific initialization if LDAP is built,
+# see lib-dict/Makefile.am which builds dict-drivers-register.c instead
+#  dict_drivers="$dict_drivers ldap"
 fi
 AM_CONDITIONAL(LDAP_PLUGIN, test "$have_ldap_plugin" = "yes")
 
-dict_drivers=client
+dict_drivers="$dict_drivers client"
 
 if test $want_db != no; then
 	AC_MSG_CHECKING([db_env_create in -ldb])
@@ -2456,6 +2459,7 @@
 src/Makefile
 src/lib/Makefile
 src/lib-sql/Makefile
+src/lib-ldap/Makefile
 src/lib-auth/Makefile
 src/lib-charset/Makefile
 src/lib-dict/Makefile
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/doc/wiki/Makefile.am.in dovecot-1.2.10/doc/wiki/Makefile.am.in
--- ORIG/dovecot-1.2.10/doc/wiki/Makefile.am.in	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/doc/wiki/Makefile.am.in	2010-02-05 11:59:29.000000000 +0000
@@ -0,0 +1,9 @@
+if BUILD_DOCS
+wikidir = $(docdir)/wiki
+wiki_DATA = $(wikifiles)
+endif
+
+EXTRA_DIST = \
+	$(wikifiles)
+
+wikifiles = 
\ No newline at end of file
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/Makefile.am dovecot-1.2.10/src/Makefile.am
--- ORIG/dovecot-1.2.10/src/Makefile.am	2009-07-10 14:47:39.000000000 +0000
+++ dovecot-1.2.10/src/Makefile.am	2010-02-05 07:19:44.000000000 +0000
@@ -1,10 +1,11 @@
 SUBDIRS = \
 	lib \
-	lib-dict \
 	lib-sql \
 	lib-ntlm \
 	lib-otp \
 	lib-settings \
+	lib-ldap \
+	lib-dict \
 	lib-charset \
 	lib-mail \
 	lib-imap \
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/deliver/Makefile.am dovecot-1.2.10/src/deliver/Makefile.am
--- ORIG/dovecot-1.2.10/src/deliver/Makefile.am	2010-01-19 11:56:56.000000000 +0000
+++ dovecot-1.2.10/src/deliver/Makefile.am	2010-02-05 07:19:44.000000000 +0000
@@ -1,18 +1,21 @@
 pkglibexecdir = $(libexecdir)/dovecot
 
+
 pkglibexec_PROGRAMS = deliver
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-auth \
 	-I$(top_srcdir)/src/lib-dict \
 	-I$(top_srcdir)/src/lib-mail \
 	-I$(top_srcdir)/src/lib-imap \
 	-I$(top_srcdir)/src/lib-index \
-	-I$(top_srcdir)/src/lib-settings \
+	-I$(top_srcdir)/src/lib-ldap \
 	-I$(top_srcdir)/src/lib-storage \
 	-I$(top_srcdir)/src/lib-storage/index \
 	-I$(top_srcdir)/src/lib-storage/index/raw \
+	-DDICT_MODULE_DIR=\""$(moduledir)/dict"\" \
 	-DSYSCONFDIR=\""$(sysconfdir)"\" \
 	-DPKG_RUNDIR=\""$(rundir)"\" \
 	-DMODULEDIR=\""$(moduledir)"\"
@@ -29,6 +32,10 @@
 libs = \
 	$(STORAGE_LIBS) \
 	../lib-dict/libdict.a \
+	../lib-dict/libdict_backend.a \
+	../lib-ldap/libldap.a \
+	../lib-settings/libsettings.a \
+	../lib/liblib.a \
 	$(unused_objects)
 
 deliver_LDADD = \
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/deliver/deliver.c dovecot-1.2.10/src/deliver/deliver.c
--- ORIG/dovecot-1.2.10/src/deliver/deliver.c	2010-01-24 23:14:17.000000000 +0000
+++ dovecot-1.2.10/src/deliver/deliver.c	2010-02-05 07:19:44.000000000 +0000
@@ -30,6 +30,7 @@
 #include "raw-storage.h"
 #include "imap-utf7.h"
 #include "dict.h"
+#include "dict-ldap.h"
 #include "auth-client.h"
 #include "mail-send.h"
 #include "duplicate.h"
@@ -1169,9 +1170,11 @@
 		deliver_set->log_format = DEFAULT_LOG_FORMAT;
 
 	dict_drivers_register_builtin();
-        duplicate_init();
+	// FIXME: should also add dict-sql here
+	dict_ldap_register();
+	duplicate_init();
 	mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
-        mail_storage_init();
+	mail_storage_init();
 	mail_storage_register_all();
 	mailbox_list_register_all();
 
@@ -1310,6 +1313,7 @@
 
 	duplicate_deinit();
 	dict_drivers_unregister_builtin();
+	dict_ldap_unregister();
 	lib_signals_deinit();
 
 	io_loop_destroy(&ioloop);
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/dict/Makefile.am dovecot-1.2.10/src/dict/Makefile.am
--- ORIG/dovecot-1.2.10/src/dict/Makefile.am	2008-08-27 08:43:56.000000000 +0000
+++ dovecot-1.2.10/src/dict/Makefile.am	2010-02-05 07:19:44.000000000 +0000
@@ -5,6 +5,7 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-dict \
+	-I$(top_srcdir)/src/lib-ldap \
 	-I$(top_srcdir)/src/lib-sql \
 	-DDICT_MODULE_DIR=\""$(moduledir)/dict"\" \
 	-DPKG_RUNDIR=\""$(rundir)"\"
@@ -14,6 +15,7 @@
 libs = \
 	../lib-dict/libdict_backend.a \
 	../lib-dict/libdict.a \
+	../lib-ldap/libldap.a \
 	../lib-sql/libsql.a \
 	../lib-settings/libsettings.a \
 	../lib/liblib.a
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib/failures.c dovecot-1.2.10/src/lib/failures.c
--- ORIG/dovecot-1.2.10/src/lib/failures.c	2010-01-24 23:14:17.000000000 +0000
+++ dovecot-1.2.10/src/lib/failures.c	2010-02-09 05:21:43.000000000 +0000
@@ -16,6 +16,7 @@
 #include <time.h>
 
 const char *failure_log_type_prefixes[] = {
+	"Debug: ",
 	"Info: ",
 	"Warning: ",
 	"Error: ",
@@ -23,7 +24,7 @@
 	"Panic: "
 };
 static char log_type_internal_chars[] = {
-	'I', 'W', 'E', 'F', 'P'
+	'D', 'I', 'W', 'E', 'F', 'P'
 };
 
 /* Initialize working defaults */
@@ -262,6 +263,18 @@
 	errno = old_errno;
 }
 
+void i_debug(const char *format, ...)
+{
+	int old_errno = errno;
+	va_list args;
+
+	va_start(args, format);
+	info_handler(LOG_TYPE_DEBUG, format, args);
+	va_end(args);
+
+	errno = old_errno;
+}
+
 void i_set_fatal_handler(fatal_failure_callback_t *callback ATTR_NORETURN)
 {
 	if (callback == NULL)
@@ -320,6 +333,8 @@
 	int level = LOG_ERR;
 
 	switch (type) {
+	case LOG_TYPE_DEBUG:
+		level = LOG_DEBUG;
 	case LOG_TYPE_INFO:
 		level = LOG_INFO;
 		break;
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib/failures.h dovecot-1.2.10/src/lib/failures.h
--- ORIG/dovecot-1.2.10/src/lib/failures.h	2009-02-21 19:17:03.000000000 +0000
+++ dovecot-1.2.10/src/lib/failures.h	2010-02-09 05:02:01.000000000 +0000
@@ -15,6 +15,7 @@
 };
 
 enum log_type {
+	LOG_TYPE_DEBUG,
 	LOG_TYPE_INFO,
 	LOG_TYPE_WARNING,
 	LOG_TYPE_ERROR,
@@ -37,6 +38,7 @@
 void i_error(const char *format, ...) ATTR_FORMAT(1, 2);
 void i_warning(const char *format, ...) ATTR_FORMAT(1, 2);
 void i_info(const char *format, ...) ATTR_FORMAT(1, 2);
+void i_debug(const char *format, ...) ATTR_FORMAT(1, 2);
 
 void i_fatal_status(int status, const char *format, ...)
 	ATTR_FORMAT(2, 3) ATTR_NORETURN;
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib/macros.h dovecot-1.2.10/src/lib/macros.h
--- ORIG/dovecot-1.2.10/src/lib/macros.h	2008-06-20 06:52:12.000000000 +0000
+++ dovecot-1.2.10/src/lib/macros.h	2010-02-05 07:19:44.000000000 +0000
@@ -138,6 +138,9 @@
 #  define MEMBER(name)
 #endif
 
+// FIXME: help, no idea if this is the right spot
+#define S_MEMBER(s, name) s->name =
+
 /* Macros to provide type safety for callback functions' context parameters */
 #ifdef __GNUC__
 #  define CONTEXT_TYPE_SAFETY
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-dict/Makefile.am dovecot-1.2.10/src/lib-dict/Makefile.am
--- ORIG/dovecot-1.2.10/src/lib-dict/Makefile.am	2009-07-10 14:47:39.000000000 +0000
+++ dovecot-1.2.10/src/lib-dict/Makefile.am	2010-02-05 07:19:44.000000000 +0000
@@ -2,8 +2,10 @@
 
 dict_drivers = @dict_drivers@
 
+# DICTLDAP: add auth modules
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-ldap \
 	-I$(top_srcdir)/src/lib-sql \
 	-I$(top_srcdir)/src/lib-settings \
 	$(SQL_CFLAGS)
@@ -15,12 +17,18 @@
 
 backend_sources = \
 	dict-db.c \
+	dict-ldap.c \
+	dict-ldap-settings.c \
 	dict-sql.c \
 	dict-sql-settings.c
 
+#libdict_a_LIBADD = \
+#	../lib-ldap/libldap.a
 libdict_a_SOURCES = \
 	$(base_sources)
 
+#libdict_backend_a_LIBADD = \
+#	../lib-ldap/libldap.a
 libdict_backend_a_SOURCES = \
 	$(backend_sources) \
 	dict-drivers-register.c
@@ -28,6 +36,8 @@
 headers = \
 	dict.h \
 	dict-client.h \
+	dict-ldap.h \
+	dict-ldap-settings.h \
 	dict-private.h \
 	dict-sql.h \
 	dict-sql-settings.h
@@ -44,6 +54,7 @@
 	echo '/* this file automatically generated by Makefile */' >$@
 	echo '#include "lib.h"' >>$@
 	echo '#include "dict.h"' >>$@
+	echo '#include "dict-ldap.h"' >>$@
 	echo '#include "dict-sql.h"' >>$@
 	for i in $(dict_drivers) null; do \
 	  if [ "$${i}" != "null" ]; then \
@@ -51,6 +62,7 @@
 	  fi; \
 	done
 	echo 'void dict_drivers_register_all(void) {' >>$@
+	echo 'dict_ldap_register();' >>$@
 	echo 'dict_sql_register();' >>$@
 	for i in $(dict_drivers) null; do \
 	  if [ "$${i}" != "null" ]; then \
@@ -59,6 +71,7 @@
 	done
 	echo '}' >>$@
 	echo 'void dict_drivers_unregister_all(void) {' >>$@
+	echo 'dict_ldap_unregister();' >>$@
 	echo 'dict_sql_unregister();' >>$@
 	for i in $(dict_drivers) null; do \
 	  if [ "$${i}" != "null" ]; then \
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap-settings.c dovecot-1.2.10/src/lib-dict/dict-ldap-settings.c
--- ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap-settings.c	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-dict/dict-ldap-settings.c	2010-02-11 15:01:08.000000000 +0000
@@ -0,0 +1,254 @@
+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
+
+/* based on (copied from) lib-dict/lib-sql-settings.c */
+
+#include "dict-ldap-settings.h"
+
+/* FIXME: a lot of this stuff should be generic for SQL, LDAP, and FILE (?) maps
+ * 	- we probably don't need two parsers
+ */
+
+/* dict-ldap config file elements
+ */
+
+#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
+#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
+#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
+
+// FIXME: resolve settings differences between dict-ldap & db-ldap (auth, dovecot-ldap.conf)
+// struct setting_def dict_ldap_setting_defs[]  >> define here, not in dict-ldap-settings.h
+static struct setting_def dict_ldap_setting_defs[] = {
+	DEF_STR(pattern),
+	DEF_STR(filter),
+	DEF_STR(attrlist),
+	DEF_STR(encoding),
+
+	DEF_STR(hosts),
+	DEF_STR(uris),
+	DEF_STR(dn),
+	DEF_STR(dnpass),
+	DEF_BOOL(auth_bind),
+	DEF_STR(auth_bind_userdn),
+	DEF_BOOL(tls),
+	DEF_BOOL(sasl_bind),
+	DEF_STR(sasl_mech),
+	DEF_STR(sasl_realm),
+	DEF_STR(sasl_authz_id),
+	DEF_STR(tls_ca_cert_file),
+	DEF_STR(tls_ca_cert_dir),
+	DEF_STR(tls_cert_file),
+	DEF_STR(tls_key_file),
+	DEF_STR(tls_cipher_suite),
+	DEF_STR(tls_require_cert),
+	DEF_STR(deref),
+	DEF_STR(scope),
+	DEF_STR(base),
+	DEF_INT(ldap_version),
+	DEF_STR(debug_level),
+	DEF_STR(ldaprc_path),
+	DEF_STR(user_attrs),
+	DEF_STR(user_filter),
+	DEF_STR(pass_attrs),
+	DEF_STR(pass_filter),
+	DEF_STR(default_pass_scheme),
+
+	{ 0, NULL, 0 }
+};
+
+
+/* config file parsing
+ */
+static const char *ldap_pattern_read_name(const char **pattern)
+{
+	const char *p = *pattern, *name;
+
+	if (*p == '{') {
+		/* ${name} */
+		name = ++p;
+		p = strchr(p, '}');
+		if (p == NULL) {
+			/* error, but allow anyway */
+			*pattern += strlen(*pattern);
+			return "";
+		}
+		*pattern = p + 1;
+	} else {
+		/* $name - ends at the first non-alnum_ character */
+		name = p;
+		for (; *p != '\0'; p++) {
+			if (!i_isalnum(*p) && *p != '_')
+				break;
+		}
+		*pattern = p;
+	}
+	name = t_strdup_until(name, p);
+	return name;
+}
+
+static const char *dict_ldap_fields_map(struct ldap_setting_parser_ctx *ctx)
+{
+	struct dict_ldap_map_field *fields;
+	string_t *pattern;
+	const char *p, *name;
+	unsigned int i, count;
+
+	/* go through the variables in the pattern, replace them with plain
+	   '$' character and add its field */
+	pattern = t_str_new(strlen(ctx->cur_conn.set.pattern) + 1);
+	fields = array_get_modifiable(&ctx->cur_fields, &count);
+
+	p_array_init(&ctx->cur_conn.set.ldap_fields, ctx->pool, count);
+	for (p = ctx->cur_conn.set.pattern; *p != '\0';) {
+		if (*p != '$') {
+			str_append_c(pattern, *p);
+			p++;
+			continue;
+		}
+		p++;
+		str_append_c(pattern, '$');
+
+		name = ldap_pattern_read_name(&p);
+		for (i = 0; i < count; i++) {
+			if (fields[i].variable != NULL &&
+			    strcmp(fields[i].variable, name) == 0)
+				break;
+		}
+		if (i == count) {
+			return t_strconcat("Missing LDAP field for variable: ",
+					   name, NULL);
+		}
+
+		/* mark this field as used */
+		fields[i].variable = NULL;
+		array_append(&ctx->cur_conn.set.ldap_fields,
+			     &fields[i].ldap_field, 1);
+	}
+
+	/* make sure there aren't any unused fields */
+	for (i = 0; i < count; i++) {
+		if (fields[i].variable != NULL) {
+			return t_strconcat("Unused variable: ",
+					   fields[i].variable, NULL);
+		}
+	}
+
+	if (ctx->set->max_field_count < count)
+		ctx->set->max_field_count = count;
+	ctx->cur_conn.set.pattern = p_strdup(ctx->pool, str_c(pattern));
+	return NULL;
+}
+
+static const char *dict_ldap_map_finish(struct ldap_setting_parser_ctx *ctx)
+{
+	if (ctx->cur_conn.set.pattern == NULL)
+		return "Missing setting: pattern";
+	if (ctx->cur_conn.set.filter == NULL)
+		return "Missing setting: filter";
+	if (ctx->cur_conn.set.attrlist == NULL)
+		return "Missing setting: attrlist";
+
+	if (ctx->cur_conn.set.encoding == NULL) {
+		/* DEFAULT: none, not all queries require this */
+		ctx->cur_conn.set.encoding = "none";
+	}
+
+	if (!array_is_created(&ctx->cur_conn.set.ldap_fields)) {
+		/* no fields besides value. allocate the array anyway. */
+		p_array_init(&ctx->cur_conn.set.ldap_fields, ctx->pool, 1);
+		if (strchr(ctx->cur_conn.set.pattern, '$') != NULL)
+			return "Missing fields for pattern variables";
+	}
+	array_append(&ctx->set->conns, &ctx->cur_conn, 1);
+	memset(&ctx->cur_conn, 0, sizeof(ctx->cur_conn));
+	return NULL;
+}
+
+static const char *
+ldap_parse_setting(const char *key, const char *value,
+	struct ldap_setting_parser_ctx *ctx)
+{
+	struct dict_ldap_map_field *field;
+
+	switch (ctx->type) {
+	case SECTION_ROOT:
+		/* nothing in the root section that we want, all per-map */
+// From SQL, for comparison:
+//		if (strcmp(key, "connect") == 0) {
+//			ctx->set->connect = p_strdup(ctx->pool, value);
+//			return NULL;
+//		}
+		break;
+	case SECTION_MAP:
+		return parse_setting_from_defs(ctx->pool,
+					       dict_ldap_setting_defs,
+					       &ctx->cur_conn.set, key, value);
+	case SECTION_FIELDS:
+		if (*value != '$') {
+			return t_strconcat("Value is missing '$' for field: ",
+					   key, NULL);
+		}
+		field = array_append_space(&ctx->cur_fields);
+		field->ldap_field = p_strdup(ctx->pool, key);
+		field->variable = p_strdup(ctx->pool, value + 1);
+		return NULL;
+	}
+	return t_strconcat("Unknown setting: ", key, NULL);
+}
+
+static bool
+ldap_parse_section(const char *type, const char *name ATTR_UNUSED,
+	      struct ldap_setting_parser_ctx *ctx, const char **error_r)
+{
+	switch (ctx->type) {
+	case SECTION_ROOT:
+		if (type == NULL)
+			return FALSE;
+		if (strcmp(type, "map") == 0) {
+			array_clear(&ctx->cur_fields);
+			ctx->type = SECTION_MAP;
+			/* about to enter a new map, which holds ldap_connection->ldap_setting data.
+			   init settings with defaults */
+			libldap_set_default_ldap_settings(&ctx->cur_conn.set);
+			return TRUE;
+		}
+		break;
+	case SECTION_MAP:
+		if (type == NULL) {
+			ctx->type = SECTION_ROOT;
+			*error_r = dict_ldap_map_finish(ctx);
+			return FALSE;
+		}
+		if (strcmp(type, "fields") == 0) {
+			ctx->type = SECTION_FIELDS;
+			return TRUE;
+		}
+		break;
+	case SECTION_FIELDS:
+		if (type == NULL) {
+			ctx->type = SECTION_MAP;
+			*error_r = dict_ldap_fields_map(ctx);
+			return FALSE;
+		}
+		break;
+	}
+	*error_r = t_strconcat("Unknown section: ", type, NULL);
+	return FALSE;
+}
+
+/* LDAP vs SQL: LDAP has no settings, all in the map section */
+struct dict_ldap_settings *
+dict_ldap_settings_read(pool_t pool, const char *path)
+{
+	struct ldap_setting_parser_ctx ctx;
+
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.pool = pool;
+	ctx.set = p_new(pool, struct dict_ldap_settings, 1);
+	t_array_init(&ctx.cur_fields, 16);
+	p_array_init(&ctx.set->conns, pool, 8);
+
+	if (!settings_read(path, NULL, ldap_parse_setting, ldap_parse_section, &ctx))
+		return NULL;
+
+	return ctx.set;
+}
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap-settings.h dovecot-1.2.10/src/lib-dict/dict-ldap-settings.h
--- ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap-settings.h	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-dict/dict-ldap-settings.h	2010-02-05 07:19:44.000000000 +0000
@@ -0,0 +1,49 @@
+#ifndef DICT_LDAP_SETTINGS_H
+#define DICT_LDAP_SETTINGS_H
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "settings.h"
+#include "lib-ldap.h"
+#include "dict-ldap-settings.h"
+
+#include <ctype.h>
+
+/* difference vs dict-sql-settings.h
+ * 1. no root fields (like "connect" for SQL)
+ * 2. many potential maps, each map has its own fields from ldap_settings struct (see: lib-ldap/lib-ldap.h)
+ * 3. there is no dict_ldap_map (as with dict-sql-settings.h), use an expanded ldap_settings struct instead
+ */
+
+enum ldap_section_type {
+	SECTION_ROOT = 0,
+	SECTION_MAP,
+	SECTION_FIELDS
+};
+
+struct dict_ldap_map_field {
+	const char *ldap_field;
+	const char *variable;
+};
+
+struct ldap_setting_parser_ctx {
+	pool_t pool;
+	struct dict_ldap_settings *set;
+	enum ldap_section_type type;
+
+	struct ldap_connection cur_conn;
+	ARRAY_DEFINE(cur_fields, struct dict_ldap_map_field);
+};
+
+struct dict_ldap_settings {
+	unsigned int max_field_count;
+	ARRAY_DEFINE(conns, struct ldap_connection);
+};
+
+// FIXME: resolve settings differences between dict-ldap & db-ldap (auth, dovecot-ldap.conf)
+// struct setting_def dict_ldap_setting_defs[]  >> moved to dict-ldap-settings.c
+
+struct dict_ldap_settings *
+dict_ldap_settings_read(pool_t pool, const char *path);
+#endif
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap.c dovecot-1.2.10/src/lib-dict/dict-ldap.c
--- ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap.c	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-dict/dict-ldap.c	2010-02-11 14:58:26.000000000 +0000
@@ -0,0 +1,324 @@
+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
+
+#include "dict-ldap.h"
+
+#define LDAP_MODULE_NAME "ldap"
+
+/* ldap_conn_init
+ * - initialize ldap connections, dict->set->conns[]->conn
+ * - remember, each dict-ldap map can use a different set of ldap_settings
+ * - uses overloaded lib-ldap/lib-ldap.c:libldap_init(struct ldap_connection *conn)
+ * FIXME: 
+ * - conns[i]->conn should be initialized with defaults first?
+ */
+static int
+ldap_conn_init(
+	struct ldap_dict *dict)
+{
+	struct ldap_connection *conn;
+	const struct ldap_connection *conns;
+	pool_t pool;
+	unsigned int i, count;
+	int ret=1;
+
+	// FIXME: 2.0 has array_foreach_modifiable, 1.x doesn't.
+	conns = array_get_modifiable(&dict->dls->conns, &count);
+	for (i=0; i<count; i++) {
+
+		// FIXME: are individual connections properly initialized?
+		//        are default settings properly loaded elsewhere?
+		pool = pool_alloconly_create("ldap_connection", 1024);
+
+		// initialize ldap_connection parameters
+		conn = &conns[i];
+		conn->pool = pool;
+		conn->refcount = 1;
+		conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
+		conn->default_bind_msgid = -1;
+		conn->fd = -1;
+
+		if (libldap_init(conn) == NULL) {
+			i_error("ldap conn init: failed to initialize map number '%d'.", i);
+			ret--;
+		}
+
+	}
+
+	return ret;
+}
+
+/* ldap_dict_init
+ * - dict RO
+ */
+static struct dict *
+ldap_dict_init(
+	struct dict *dict_driver,
+	const char *uri,
+	enum dict_data_type value_type,
+	const char *username,
+	const char *base_dir)
+{
+
+	struct ldap_dict *dict;
+	pool_t pool;
+
+	pool = pool_alloconly_create("ldap dict", 2048);
+	dict = p_new(pool, struct ldap_dict, 1);
+	dict->pool = pool;
+	dict->dict = *dict_driver;
+	dict->username = p_strdup(pool, username);
+
+	/* settings: dict-ldap-settings.c calls lib-settings/settings.c
+	 *           dict->conns is an array of ldap_connection
+	 */
+	dict->dls = dict_ldap_settings_read(pool, uri);
+	if (dict->dls == NULL) {
+		pool_unref(&pool);
+		return NULL;
+	}
+
+	ldap_conn_init(dict);
+	return &dict->dict;
+}
+
+/* ldap_dict_deinit
+ * - dict RO
+ */
+static void
+ldap_dict_deinit(
+	struct dict *_dict)
+{
+	struct ldap_dict *dict = (struct ldap_dict *)_dict;
+	// FIXME: incomplete. eg: ldap_conn_deinit() ?
+	pool_unref(&dict->pool);
+}
+
+
+/* ldap_dict_lookup
+ * - dict RO
+ */
+static int
+ldap_dict_lookup(
+	struct dict *_dict,
+	pool_t pool,
+	const char *key,
+	const char **value_r)
+{
+	struct ldap_dict *dict = (struct ldap_dict *)_dict;
+	struct ldap_connection *conn = NULL;
+	struct ldap_result_context *rctx;
+	struct ldap_request *req;
+	struct ldap_request_search *sreq;
+	const struct var_expand_table *vars;
+	const struct ldap_connection *conns;
+	string_t *str;
+	LDAPMessage *res;
+	unsigned int count, i;
+	int ret;
+
+	// Find the conn where key==pattern
+	conns = array_get(&dict->dls->conns, &count);
+	for (i=0; i<count; i++) {
+		if (strcmp(conns[i].set.pattern, key) == 0) {
+			conn = &conns[i];
+			conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;  // FIXME: init should do this
+
+			/* STEP 1: CONNECT */
+			ret = libldap_connect_s(conn);
+
+			if (ret != 0) {
+				i_error("ldap_dict_lookup: connection failure: %s", libldap_get_error(conn));
+				*value_r = NULL;
+				return -1;
+			}
+
+			/* STEP 2: Build search request, expand filter with username data (for %u -> user@domain) */
+			req = libldap_init_request(LDAP_REQUEST_TYPE_SEARCH_S);
+			sreq = libldap_init_request_search_s(req, conn->set.base, conn->set.filter, conn->set.attrlist);
+
+			vars = libldap_request_search_var_expand_string(sreq, dict->username);
+			str = t_str_new(512);
+			var_expand( str, conn->set.filter, vars);
+			sreq->filter = p_strdup(sreq->request.pool, str_c(str));
+			str_free(&str);
+
+			/* STEP 3: search */
+			ret = libldap_search_s(conn, sreq, &rctx);
+
+			/* STEP 4: get first value.  API say:s key<>value, not: key<>val1,val2,... */
+			/* use calling pool, value can persist outside this context */
+			*value_r = p_strdup(pool, libldap_result_context_first_value(rctx));
+			
+			/* STEP 5: clean up */
+			libldap_unref_request(req);
+			libldap_unref_result_context(rctx);
+			
+			// FIXME: maybe there should be a warning for >1 results?
+			i_debug("ldap_dict_lookup: FOUND: username: '%s' key: '%s' value: '%s'",
+					dict->username, key, *value_r);
+			return ret;
+		}
+	}
+	if (conn == NULL) {
+		i_debug("ldap_dict_lookup: NOTFOUND: username: '%s' key: '%s'",
+				dict->username, key);
+		*value_r = NULL;
+		return 0;
+	}
+
+	// Should not reach
+	i_unreached();
+	*value_r = NULL;
+	return -1;
+}
+
+/* ldap_dict_iterate_init
+ * - dict RO
+ */
+static struct dict_iterate_context *
+ldap_dict_iterate_init(
+	struct dict *_dict,
+	const char *path,
+	enum dict_iterate_flags flags)
+{
+	struct ldap_dict *dict = (struct ldap_dict *)_dict;
+	i_error("ldap_dict_iterate_init: not implemented");
+
+	// FIXME
+	return NULL;
+}
+
+/* ldap_dict_iterate
+ * - dict RO
+ */
+static int
+ldap_dict_iterate(
+	struct dict_iterate_context *_ctx,
+	const char **key_r,
+	const char **value_r)
+{
+	i_error("ldap_dict_iterate: not implemented");
+
+	// FIXME
+	return -1;
+}
+
+/* ldap_dict_iterate_deinit
+ * - dict RO
+ */
+static void
+ldap_dict_iterate_deinit(
+	struct dict_iterate_context *_ctx)
+{
+	i_error("ldap_dict_iterate_deinit: not implemented");
+}
+
+/* ldap_dict_transaction_init
+ * - dict RW
+ */
+struct dict_transaction_context *
+ldap_dict_transaction_init(
+	struct dict *_dict);
+
+/* ldap_dict_transaction_commit
+ * - dict RW
+ */
+static int
+ldap_dict_transaction_commit(
+	struct dict_transaction_context *_ctx,
+	bool async ATTR_UNUSED,
+	dict_transaction_commit_callback_t *callback,
+	void *context);
+
+/* ldap_dict_transaction_rollback
+ * - dict RW
+ */
+static void
+ldap_dict_transaction_rollback(
+	struct dict_transaction_context *_ctx);
+
+/* ldap_dict_set
+ * - dict RW
+ */
+static void
+ldap_dict_set(
+	struct dict_transaction_context *_ctx,
+	const char *key,
+	const char *value);
+
+/* ldap_dict_unset
+ * - dict RW
+ */
+static void
+ldap_dict_unset(
+	struct dict_transaction_context *_ctx,
+	const char *key);
+
+/* ldap_dict_atomic_inc
+ * - dict RW
+ */
+static void
+ldap_dict_atomic_inc(
+	struct dict_transaction_context *_ctx,
+	const char *key,
+	long long diff);
+
+
+/* register the dict type
+	see dict-private.h
+	name, struct dict_vfuncs
+*/
+static struct dict dict_driver_ldap = {
+	MEMBER(name) LDAP_MODULE_NAME,
+
+/*
+	{
+		ldap_dict_init,                      // init
+		ldap_dict_deinit,                    // deinit
+		NULL,                                // wait
+		ldap_dict_lookup,                    // lookup
+		ldap_dict_iterate_init,              // iterate_init
+		ldap_dict_iterate,                   // iterate
+		ldap_dict_iterate_deinit,            // iterate_deinit
+		ldap_dict_transaction_init,          // transaction_init
+		ldap_dict_transaction_commit,        // transaction_commit
+		ldap_dict_transaction_rollback,      // transaction_rollback
+		ldap_dict_set,                       // set
+		ldap_dict_unset,                     // unset
+		ldap_dict_atomic_inc                 // atomic_inc
+	}
+*/
+
+// bare minimum for lookup only?
+	{
+		ldap_dict_init,                      // init
+		ldap_dict_deinit,                    // deinit
+		NULL,                                // wait
+		ldap_dict_lookup,                    // lookup
+		ldap_dict_iterate_init,              // iterate_init
+		ldap_dict_iterate,                   // iterate
+		ldap_dict_iterate_deinit,            // iterate_deinit
+		NULL, // transaction_init
+		NULL, // transaction_commit
+		NULL, // transaction_rollback
+		NULL, // set
+		NULL, // unset
+		NULL // atomic_inc
+	}
+};
+
+
+/* called from dict-drivers-register.c
+ * - generated by Makefile (see Makefile.am)
+ */
+void dict_ldap_register(void)
+{
+	// FIXME: should not happen unless --with-ldap ?
+	dict_driver_register(&dict_driver_ldap);
+}
+
+void dict_ldap_unregister(void)
+{
+	dict_driver_unregister(&dict_driver_ldap);
+}
+
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap.h dovecot-1.2.10/src/lib-dict/dict-ldap.h
--- ORIG/dovecot-1.2.10/src/lib-dict/dict-ldap.h	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-dict/dict-ldap.h	2010-02-05 07:19:44.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef DICT_LDAP_H
+#define DICT_LDAP_H
+
+#include "lib.h"
+#include "module-dir.h"
+#include "array.h"
+#include "istream.h"
+#include "str.h"
+#include "dict.h"
+#include "dict-client.h"
+#include "dict-ldap-settings.h"
+#include "dict-private.h"
+#include "lib-ldap.h"
+#include "settings.h"
+
+#include <stdlib.h>
+
+struct ldap_dict {
+	struct dict dict;
+
+	pool_t pool;
+	const char *username;
+
+	// FIXME: no need for anything other than the conns? (ldap_connection).  impact on dict-ldap-settings.h:struct dict_ldap_settings
+	struct dict_ldap_settings *dls;
+};
+
+void dict_ldap_register(void);
+void dict_ldap_unregister(void);
+
+#endif
+
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-ldap/Makefile.am dovecot-1.2.10/src/lib-ldap/Makefile.am
--- ORIG/dovecot-1.2.10/src/lib-ldap/Makefile.am	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-ldap/Makefile.am	2010-02-05 07:19:44.000000000 +0000
@@ -0,0 +1,21 @@
+noinst_LIBRARIES = libldap.a
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-settings
+
+libldap_a_LIBADD = \
+	../lib/liblib.a \
+	../lib-settings/libsettings.a
+libldap_a_SOURCES = \
+	lib-ldap.c
+
+headers = \
+	lib-ldap.h
+
+if INSTALL_HEADERS
+  pkginc_libdir=$(pkgincludedir)/src/lib-ldap
+  pkginc_lib_HEADERS = $(headers)
+else
+  noinst_HEADERS = $(headers)
+endif
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-ldap/lib-ldap.c dovecot-1.2.10/src/lib-ldap/lib-ldap.c
--- ORIG/dovecot-1.2.10/src/lib-ldap/lib-ldap.c	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-ldap/lib-ldap.c	2010-02-11 14:56:31.000000000 +0000
@@ -0,0 +1,816 @@
+/* see notes at the top of lib-ldap.h */
+#include "lib-ldap.h"
+
+#define MASTER_SOCKET_FD 0
+#define CLIENT_LISTEN_FD 3
+#define WORKER_SERVER_FD 4
+
+/* functions */
+
+static int
+deref2str(const char *str)
+{
+	if (strcasecmp(str, "never") == 0)
+		return LDAP_DEREF_NEVER;
+	if (strcasecmp(str, "searching") == 0)
+		return LDAP_DEREF_SEARCHING;
+	if (strcasecmp(str, "finding") == 0)
+		return LDAP_DEREF_FINDING;
+	if (strcasecmp(str, "always") == 0)
+		return LDAP_DEREF_ALWAYS;
+
+	i_fatal("LDAP: Unknown deref option '%s'", str);
+}
+
+static int
+scope2str(const char *str)
+{
+	if (strcasecmp(str, "base") == 0)
+		return LDAP_SCOPE_BASE;
+	if (strcasecmp(str, "onelevel") == 0)
+		return LDAP_SCOPE_ONELEVEL;
+	if (strcasecmp(str, "subtree") == 0)
+		return LDAP_SCOPE_SUBTREE;
+
+	i_fatal("LDAP: Unknown scope option '%s'", str);
+}
+
+#ifdef OPENLDAP_TLS_OPTIONS
+static int
+tls_require_cert2str(const char *str)
+{
+	if (strcasecmp(str, "never") == 0)
+		return LDAP_OPT_X_TLS_NEVER;
+	if (strcasecmp(str, "hard") == 0)
+		return LDAP_OPT_X_TLS_HARD;
+	if (strcasecmp(str, "demand") == 0)
+		return LDAP_OPT_X_TLS_DEMAND;
+	if (strcasecmp(str, "allow") == 0)
+		return LDAP_OPT_X_TLS_ALLOW;
+	if (strcasecmp(str, "try") == 0)
+		return LDAP_OPT_X_TLS_TRY;
+
+	i_fatal("LDAP: Unknown tls_require_cert value '%s'", str);
+}
+#endif
+
+void
+libldap_set_default_ldap_settings(struct ldap_settings *set)
+{
+	S_MEMBER(set, pattern) NULL;
+	S_MEMBER(set, filter) NULL;
+	S_MEMBER(set, attrlist) NULL;
+	S_MEMBER(set, encoding) NULL;
+
+	S_MEMBER(set, hosts) NULL;
+	S_MEMBER(set, uris) NULL;
+	S_MEMBER(set, dn) NULL;
+	S_MEMBER(set, dnpass) NULL;
+	S_MEMBER(set, auth_bind) FALSE;
+	S_MEMBER(set, auth_bind_userdn) NULL;
+	S_MEMBER(set, tls) FALSE;
+	S_MEMBER(set, sasl_bind) FALSE;
+	S_MEMBER(set, sasl_mech) NULL;
+	S_MEMBER(set, sasl_realm) NULL;
+	S_MEMBER(set, sasl_authz_id) NULL;
+	S_MEMBER(set, tls_ca_cert_file) NULL;
+	S_MEMBER(set, tls_ca_cert_dir) NULL;
+	S_MEMBER(set, tls_cert_file) NULL;
+	S_MEMBER(set, tls_key_file) NULL;
+	S_MEMBER(set, tls_cipher_suite) NULL;
+	S_MEMBER(set, tls_require_cert) NULL;
+	S_MEMBER(set, deref) "never";
+	S_MEMBER(set, scope) "subtree";
+	S_MEMBER(set, base) NULL;
+	S_MEMBER(set, ldap_version) 3;
+	S_MEMBER(set, debug_level) "0";
+	S_MEMBER(set, ldaprc_path) "";
+	S_MEMBER(set, default_pass_scheme) "crypt";
+}
+
+static int libldap_bind(struct ldap_connection *conn);
+static void libldap_conn_close(struct ldap_connection *conn);
+
+// FIXME: static const char *
+const char *
+libldap_conn_state2str(int state) {
+	switch (state) {
+		case LDAP_CONN_STATE_DISCONNECTED:
+			return "LDAP_CONN_STATE_DISCONNECTED";
+		case LDAP_CONN_STATE_BINDING:
+			return "LDAP_CONN_STATE_BINDING";
+		case LDAP_CONN_STATE_BOUND_AUTH:
+			return "LDAP_CONN_STATE_BOUND_AUTH";
+		case LDAP_CONN_STATE_BOUND_DEFAULT:
+			return "LDAP_CONN_STATE_BOUND_DEFAULT";
+	}
+	return "LDAP_CONN_STATE_UNKNOWN";
+}
+
+static int
+libldap_get_errno(struct ldap_connection *conn)
+{
+	int ret, err;
+
+	ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
+	if (ret != LDAP_SUCCESS) {
+		i_error("LDAP: Can't get error number: %s",
+			ldap_err2string(ret));
+		return LDAP_UNAVAILABLE;
+	}
+
+	return err;
+}
+
+static void
+libldap_conn_reconnect(struct ldap_connection *conn)
+{
+	libldap_conn_close(conn);
+	if (libldap_connect(conn) < 0)
+		libldap_conn_close(conn);
+}
+
+const char *
+libldap_get_error(struct ldap_connection *conn)
+{
+	const char *ret;
+	char *str = NULL;
+
+	ret = ldap_err2string(libldap_get_errno(conn));
+
+	ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, (void *)&str);
+	if (str != NULL) {
+		ret = t_strconcat(ret, ", ", str, NULL);
+		ldap_memfree(str);
+	}
+	ldap_set_option(conn->ld, LDAP_OPT_ERROR_STRING, NULL);
+	return ret;
+}
+
+
+static int
+libldap_handle_error(struct ldap_connection *conn)
+{
+	int err = libldap_get_errno(conn);
+
+	switch (err) {
+	case LDAP_SUCCESS:
+		i_unreached();
+	case LDAP_SIZELIMIT_EXCEEDED:
+	case LDAP_TIMELIMIT_EXCEEDED:
+	case LDAP_NO_SUCH_ATTRIBUTE:
+	case LDAP_UNDEFINED_TYPE:
+	case LDAP_INAPPROPRIATE_MATCHING:
+	case LDAP_CONSTRAINT_VIOLATION:
+	case LDAP_TYPE_OR_VALUE_EXISTS:
+	case LDAP_INVALID_SYNTAX:
+	case LDAP_NO_SUCH_OBJECT:
+	case LDAP_ALIAS_PROBLEM:
+	case LDAP_INVALID_DN_SYNTAX:
+	case LDAP_IS_LEAF:
+	case LDAP_ALIAS_DEREF_PROBLEM:
+	case LDAP_FILTER_ERROR:
+		/* invalid input */
+		return -1;
+	case LDAP_SERVER_DOWN:
+	case LDAP_TIMEOUT:
+	case LDAP_UNAVAILABLE:
+	case LDAP_BUSY:
+#ifdef LDAP_CONNECT_ERROR
+	case LDAP_CONNECT_ERROR:
+#endif
+	case LDAP_LOCAL_ERROR:
+	case LDAP_INVALID_CREDENTIALS:
+	default:
+		/* connection problems */
+		libldap_conn_reconnect(conn);
+		return 0;
+	}
+}
+
+static int
+libldap_connect_finish(struct ldap_connection *conn, int ret)
+{
+	if (ret == LDAP_SERVER_DOWN) {
+		i_error("LDAP: Can't connect to server: %s",
+			conn->set.uris != NULL ?
+			conn->set.uris : conn->set.hosts);
+		return -1;
+	}
+	if (ret != LDAP_SUCCESS) {
+		i_error("LDAP: binding failed (dn %s): %s",
+			conn->set.dn == NULL ? "(none)" : conn->set.dn,
+			libldap_get_error(conn));
+		return -1;
+	}
+
+	conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
+	return 0;
+}
+
+
+#ifdef HAVE_LDAP_SASL
+static int
+sasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
+		void *defaults, void *interact)
+{
+	struct libldap_sasl_bind_context *context = defaults;
+	sasl_interact_t *in;
+	const char *str;
+
+	for (in = interact; in->id != SASL_CB_LIST_END; in++) {
+		switch (in->id) {
+		case SASL_CB_GETREALM:
+			str = context->realm;
+			break;
+		case SASL_CB_AUTHNAME:
+			str = context->authcid;
+			break;
+		case SASL_CB_USER:
+			str = context->authzid;
+			break;
+		case SASL_CB_PASS:
+			str = context->passwd;
+			break;
+		default:
+			str = NULL;
+			break;
+		}
+		if (str != NULL) {
+			in->len = strlen(str);
+			in->result = str;
+		}
+		
+	}
+	return LDAP_SUCCESS;
+}
+#endif
+
+static int
+libldap_request_bind_s(struct ldap_connection *conn)
+{
+	i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
+	i_assert(conn->default_bind_msgid == -1);
+
+	ldap_bind_s(conn->ld, conn->set.dn, conn->set.dnpass,
+			  LDAP_AUTH_SIMPLE);
+	/* ldap_bind_s indicates error vi ld_errno, no useful return */
+	if (libldap_get_errno(conn) != LDAP_SUCCESS) {
+		if (libldap_connect_finish(conn, libldap_get_errno(conn)) < 0) {
+			/* lost connection, close it */
+			libldap_conn_close(conn);
+		}
+		return -1;
+	}
+
+	conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
+	return 0;
+}
+
+static void
+libldap_get_fd(struct ldap_connection *conn)
+{
+	int ret;
+
+	/* get the connection's fd */
+	ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
+	if (ret != LDAP_SUCCESS) {
+		i_fatal("LDAP: Can't get connection fd: %s",
+			ldap_err2string(ret));
+	}
+	if (conn->fd <= CLIENT_LISTEN_FD) {
+		/* Solaris LDAP library seems to be broken */
+		i_fatal("LDAP: Buggy LDAP library returned wrong fd: %d",
+			conn->fd);
+	}
+	i_assert(conn->fd != -1);
+	net_set_nonblock(conn->fd, TRUE);
+}
+
+static void
+libldap_set_opt(struct ldap_connection *conn, int opt, const void *value,
+		const char *optname, const char *value_str)
+{
+	int ret;
+
+	ret = ldap_set_option(conn == NULL ? NULL : conn->ld, opt, value);
+	if (ret != LDAP_SUCCESS) {
+		i_fatal("LDAP: Can't set option %s to %s: %s",
+			optname, value_str, ldap_err2string(ret));
+	}
+}
+
+static void
+libldap_set_opt_str(struct ldap_connection *conn, int opt, const char *value,
+		const char *optname)
+{
+	if (value != NULL)
+		libldap_set_opt(conn, opt, value, optname, value);
+}
+
+static void
+libldap_set_tls_options(struct ldap_connection *conn)
+{
+	if (!conn->set.tls)
+		return;
+
+#ifdef OPENLDAP_TLS_OPTIONS
+	libldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+			    conn->set.tls_ca_cert_file, "tls_ca_cert_file");
+	libldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTDIR,
+			    conn->set.tls_ca_cert_dir, "tls_ca_cert_dir");
+	libldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CERTFILE,
+			    conn->set.tls_cert_file, "tls_cert_file");
+	libldap_set_opt_str(NULL, LDAP_OPT_X_TLS_KEYFILE,
+			    conn->set.tls_key_file, "tls_key_file");
+	libldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
+			    conn->set.tls_cipher_suite, "tls_cipher_suite");
+	if (conn->set.tls_require_cert != NULL) {
+		int value = tls_require_cert2str(conn->set.tls_require_cert);
+		libldap_set_opt(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &value,
+				"tls_require_cert", conn->set.tls_require_cert);
+	}
+#else
+	if (conn->set.tls_ca_cert_file != NULL ||
+	    conn->set.tls_ca_cert_dir != NULL ||
+	    conn->set.tls_cert_file != NULL ||
+	    conn->set.tls_key_file != NULL ||
+	    conn->set.tls_cipher_suite != NULL)
+		i_warning("LDAP: tls_* settings ignored, "
+			  "your LDAP library doesn't seem to support them");
+#endif
+}
+
+static void
+libldap_set_options(struct ldap_connection *conn)
+{
+	unsigned int ldap_version;
+	int value;
+
+	libldap_set_opt(conn, LDAP_OPT_DEREF, &conn->set.ldap_deref,
+			"deref", conn->set.deref);
+#ifdef LDAP_OPT_DEBUG_LEVEL
+	value = atoi(conn->set.debug_level);
+	if (value != 0) {
+		libldap_set_opt(NULL, LDAP_OPT_DEBUG_LEVEL, &value,
+				"debug_level", conn->set.debug_level);
+	}
+#endif
+
+	if (conn->set.ldap_version < 3) {
+		if (conn->set.sasl_bind)
+			i_fatal("LDAP: sasl_bind=yes requires ldap_version=3");
+		if (conn->set.tls)
+			i_fatal("LDAP: tls=yes requires ldap_version=3");
+	}
+
+	ldap_version = conn->set.ldap_version;
+	libldap_set_opt(conn, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
+			"protocol_version", dec2str(ldap_version));
+	libldap_set_tls_options(conn);
+}
+
+int
+libldap_connect_s(struct ldap_connection *conn)
+{
+	int ret;
+
+	if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED) {
+		return 0;
+	}
+
+	if (conn->ld == NULL) {
+		if (conn->set.uris != NULL) {
+#ifdef LDAP_HAVE_INITIALIZE
+			if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
+				conn->ld = NULL;
+#else
+			i_fatal("LDAP: Your LDAP library doesn't support "
+				"'uris' setting, use 'hosts' instead.");
+#endif
+		} else
+			conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
+
+		if (conn->ld == NULL)
+			i_fatal("LDAP: ldap_init() failed with hosts: %s",
+				conn->set.hosts);
+
+		libldap_set_options(conn);
+	}
+
+	if (conn->set.tls) {
+#ifdef LDAP_HAVE_START_TLS_S
+		ret = ldap_start_tls_s(conn->ld, NULL, NULL);
+		if (ret != LDAP_SUCCESS) {
+			if (ret == LDAP_OPERATIONS_ERROR &&
+			    strncmp(conn->set.uris, "ldaps:", 6) == 0) {
+				i_fatal("LDAP: Don't use both tls=yes "
+					"and ldaps URI");
+			}
+			i_error("LDAP: ldap_start_tls_s() failed: %s",
+				ldap_err2string(ret));
+			return -1;
+		}
+#else
+		i_error("LDAP: Your LDAP library doesn't support TLS");
+		return -1;
+#endif
+	}
+
+	if (conn->set.sasl_bind) {
+#ifdef HAVE_LDAP_SASL
+		struct libldap_sasl_bind_context context;
+
+		memset(&context, 0, sizeof(context));
+		context.authcid = conn->set.dn;
+		context.passwd = conn->set.dnpass;
+		context.realm = conn->set.sasl_realm;
+		context.authzid = conn->set.sasl_authz_id;
+
+		/* There doesn't seem to be a way to do SASL binding
+		   asynchronously.. */
+		ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
+						   conn->set.sasl_mech,
+						   NULL, NULL, LDAP_SASL_QUIET,
+						   sasl_interact, &context);
+		if (libldap_connect_finish(conn, ret) < 0)
+			return -1;
+#else
+		i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
+#endif
+		conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
+	} else {
+		if (libldap_request_bind_s(conn) < 0)
+			return -1;
+	}
+
+	libldap_get_fd(conn);
+	return 0;
+}
+
+static void
+libldap_conn_close(struct ldap_connection *conn)
+{
+	conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
+	conn->default_bind_msgid = -1;
+
+	if (conn->ld != NULL) {
+		ldap_unbind(conn->ld);
+		conn->ld = NULL;
+	}
+	conn->fd = -1;
+
+	if (conn->io != NULL) {
+		/* the fd may have already been closed before ldap_unbind(),
+		   so we'll have to use io_remove_closed(). */
+		io_remove_closed(&conn->io);
+	}
+}
+
+// this is what takes '(uid=%u)' and changes it to '(uid=someperson@domain.com)'
+// uses libldap_escape only
+struct var_expand_table *
+libldap_request_search_var_expand_string(struct ldap_request_search *request_search,
+		const char *string)
+{
+	// limited set of vars for LDAP
+	static struct var_expand_table static_tab[] = {
+		{ 'u', NULL, "user" },
+		{ 'n', NULL, "username" },
+		{ 'd', NULL, "domain" },
+		{ '\0', NULL, NULL }
+	};
+	struct var_expand_table *tab;
+
+	tab = t_malloc(sizeof(static_tab));
+	memcpy(tab, static_tab, sizeof(static_tab));
+
+	tab[0].value = libldap_escape(string);
+	tab[1].value = libldap_escape(t_strcut(string, '@'));
+	tab[2].value = strchr(string, '@');
+	if (tab[2].value != NULL)
+		tab[2].value = libldap_escape(tab[2].value+1);
+
+	return tab;
+}
+
+#define IS_LDAP_ESCAPED_CHAR(c) \
+	((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
+
+const char *
+libldap_escape(const char *str)
+{
+	const char *p;
+	string_t *ret;
+
+	for (p = str; *p != '\0'; p++) {
+		if (IS_LDAP_ESCAPED_CHAR(*p))
+			break;
+	}
+
+	if (*p == '\0')
+		return str;
+
+	ret = t_str_new((size_t) (p - str) + 64);
+	str_append_n(ret, str, (size_t) (p - str));
+
+	for (; *p != '\0'; p++) {
+		if (IS_LDAP_ESCAPED_CHAR(*p))
+			str_append_c(ret, '\\');
+		str_append_c(ret, *p);
+	}
+	return str_c(ret);
+}
+
+// FIXME: not sure if I like *attrlist vs **attributes
+struct ldap_request_search *
+libldap_init_request_search_s(struct ldap_request *r, char *base, char *filter, char *attrlist)
+{
+	struct ldap_request_search *sr;
+
+	sr = p_new(r->pool, struct ldap_request_search, 1);
+	sr->request = *r;
+	sr->request.type = LDAP_REQUEST_TYPE_SEARCH_S;
+
+	sr->base   = p_strdup(sr->request.pool, base);
+	sr->filter = p_strdup(sr->request.pool, filter);
+
+	if (attrlist != NULL) {
+		sr->attributes = p_strsplit_spaces(sr->request.pool, attrlist, ",");
+	}
+
+	return sr;
+}
+
+struct ldap_request *
+libldap_init_request(int type)
+{
+	struct ldap_request *r;
+	pool_t pool;
+
+	pool = pool_alloconly_create("ldap request", 1024);
+	r = p_new(pool, struct ldap_request, 1);
+	r->pool = pool;
+	r->type = type;
+
+	if ((type == LDAP_REQUEST_TYPE_BIND_S) ||
+		(type == LDAP_REQUEST_TYPE_SEARCH_S))
+	{
+		r->err = LDAP_SUCCESS;
+		r->timeout.tv_sec = LIBLDAP_SYNCH_TIMEOUT_SECS;
+		r->timeout.tv_usec = 0;
+	}
+
+	return r;
+}
+
+void
+libldap_unref_request(struct ldap_request *request)
+{
+	pool_unref(&request->pool);
+}
+
+static void
+libldap_init_result_attribute_context(struct ldap_result_context *rctx,
+	struct ldap_result_entry_context *ectx, int no_attributes)
+{
+	struct ldap_result_attribute_context **actx;
+	int i;
+
+	ectx->no_attributes = no_attributes;
+	if (no_attributes > 0) {
+		actx = p_new(rctx->pool, struct ldap_result_attribute_context *, no_attributes);
+	}
+	ectx->actx = actx;
+
+	for(i = 0; i<no_attributes; i++) {
+		ectx->actx[i] = p_new(rctx->pool, struct ldap_result_attribute_context, no_attributes);
+		ectx->actx[i]->no_values = 0;
+		ectx->actx[i]->values = NULL;
+	}
+}
+
+static void
+libldap_init_result_entry_context(struct ldap_result_context *rctx, int no_entries)
+{
+	struct ldap_result_entry_context **ectx;
+	int i;
+
+	rctx->no_entries = no_entries;
+	if (no_entries > 0) {
+		ectx = p_new(rctx->pool, struct ldap_result_entry_context *, no_entries);
+	}
+	rctx->ectx = ectx;
+
+	for(i = 0; i<no_entries; i++) {
+		rctx->ectx[i] = p_new(rctx->pool, struct ldap_result_entry_context, 1);
+		rctx->ectx[i]->no_attributes = 0;
+		rctx->ectx[i]->actx = NULL;
+	}
+}
+
+void
+libldap_init_result_context(struct ldap_result_context **rctx)
+{
+	pool_t pool;
+
+	pool = pool_alloconly_create("ldap result context", 2048);
+	*rctx = p_new(pool, struct ldap_result_context, 1);
+	(*rctx)->pool = pool;
+	(*rctx)->no_entries = 0;
+}
+
+void
+libldap_unref_result_context(struct ldap_result_context *rctx)
+{
+	pool_unref(&rctx->pool);
+}
+
+/* number of attributes in an entry */
+static int
+libldap_attribute_count(LDAP *ld, LDAPMessage *entry)
+{
+	BerElement *ber;
+	char *attr;
+	int iatt = 0;
+
+	for (attr = ldap_first_attribute(ld, entry, &ber); attr != NULL;
+			attr = ldap_next_attribute(ld, entry, ber)) {
+		iatt++;
+	}
+
+	ber_free(ber, 0);
+	return iatt;
+}
+
+/* accross all entries in a ldap_result_context, how many values for attr X? */
+int
+libldap_result_count_values_for_attr(struct ldap_result_context *rctx, char *attribute)
+{
+	int ret, e, a;
+	
+	i_assert(attribute != NULL);
+	ret = 0;
+	for (e = 0; e < rctx->no_entries; e++) {
+		for (a = 0; a < rctx->ectx[e]->no_attributes; a++) {
+			if (strcmp(attribute, rctx->ectx[e]->actx[a]->attr) == 0) {
+				ret += rctx->ectx[e]->actx[a]->no_values;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* return the first value found in the context only. not an iterator */
+char *
+libldap_result_context_first_value(struct ldap_result_context *rctx)
+{
+	int e, a, v;
+
+	for (e = 0; e < rctx->no_entries; e++) {
+		for (a = 0; a < rctx->ectx[e]->no_attributes; a++) {
+			for (v = 0; v < rctx->ectx[e]->actx[v]->no_values; v++) {
+				if (rctx->ectx[e]->actx[v]->values[v] != NULL) {
+					return rctx->ectx[e]->actx[v]->values[v];
+				}
+			}
+		}
+	}
+	return NULL;
+}
+
+/* search, synchronous
+	- requires a LDAP_REQUEST_TYPE_SEARCH_S ldap_request, with no errors (err=0)
+	- conn must be LDAP_CONN_STATE_BOUND_DEFAULT
+	- request->filter must already be expanded
+		i.e. conn->set.filter '(uid=%u)', request->filter '(uid=userfoo@domainbar.com)'
+	FIXME:
+	- the (*rctx)-> notation is gross, sorry
+ */
+int
+libldap_search_s(struct ldap_connection *conn, struct ldap_request_search *sr, struct ldap_result_context **rctx)
+{
+
+	LDAPMessage *res, *entry;
+	BerElement *ber;
+	int ecount, vcount, acount, ient, ival, iatt;
+	char *attr;
+	char **vals;
+
+	/* must be bound before search */
+	i_assert(sr->request.type == LDAP_REQUEST_TYPE_SEARCH_S);
+	i_assert(sr->request.err  == 0);
+	i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
+
+	/* attrsonly = 0, we want attribute values */
+	sr->request.err = ldap_search_st(conn->ld, sr->base, scope2str(conn->set.scope), sr->filter,
+			sr->attributes, 0, &sr->request.timeout, &res);
+
+	if (sr->request.err != LDAP_SUCCESS) {
+		i_error("libldap_search_s: ldap_search_st: base: %s, scope[%d]: %s, filter: %s, attrs: %s: %s",
+				sr->base, scope2str(conn->set.scope), conn->set.scope, sr->filter, conn->set.attrlist, ldap_err2string(sr->request.err));
+		return -1;
+	} 
+
+	libldap_init_result_context(rctx);
+
+	ecount = ldap_count_entries(conn->ld, res);
+	libldap_init_result_entry_context((*rctx), ecount);
+
+	i_debug("libldap_search_s: base: %s, scope[%d]: %s, filter: %s, attrs: %s: %d entries returned",
+			sr->base, scope2str(conn->set.scope), conn->set.scope, sr->filter, conn->set.attrlist, ecount);
+	// STEP 1: cycle through entries
+	ient = -1;
+	for( entry = ldap_first_entry(conn->ld, res); entry != NULL;
+			entry = ldap_next_entry(conn->ld, entry))
+	{
+		ient++;
+		// STEP 2: cycle through attributes for entry
+		iatt = -1;
+		acount = libldap_attribute_count(conn->ld, entry);
+		libldap_init_result_attribute_context((*rctx), (*rctx)->ectx[ient], acount);
+
+		for ( attr = ldap_first_attribute(conn->ld, entry, &ber); attr != NULL;
+				attr = ldap_next_attribute(conn->ld, entry, ber))
+		{
+			// STEP 3: cycle through values for attribute
+			// FIXME: handle binary?
+			iatt++;
+			vals = ldap_get_values(conn->ld, entry, attr);
+			vcount = ldap_count_values(vals);
+
+			(*rctx)->ectx[ient]->actx[iatt]->attr = p_strdup((*rctx)->pool, attr);
+
+			if (vcount < 0) {
+				(*rctx)->ectx[ient]->actx[iatt]->no_values = -1;
+				i_error("libldap_search_s: negative ldap_count_values(): %s", libldap_get_error(conn->ld));
+				return -1;
+			} else if (vcount == 0) {
+				(*rctx)->ectx[ient]->actx[iatt]->no_values = vcount;
+			} else {
+				if (vals != NULL) {
+					(*rctx)->ectx[ient]->actx[iatt]->no_values = vcount;
+					(*rctx)->ectx[ient]->actx[iatt]->values = p_new((*rctx)->pool, char *, vcount);
+					for(ival=0; ival < vcount; ival++) {
+						// value loading happens here
+						(*rctx)->ectx[ient]->actx[iatt]->values[ival] = p_strdup((*rctx)->pool, vals[ival]);
+					}
+				} else {
+					(*rctx)->ectx[ient]->actx[iatt]->no_values = -1;
+					i_error("libldap_search_s: NULL ldap_get_values(), yet positive ldap_count_values()");
+					return -1;
+				}
+			}
+		}
+		/* ldap_first_attribute() caller solely responsible for freeing BerElement */
+		ber_free(ber,0);
+	}
+	return ecount;
+}
+
+/* reads conn->set, which must be loaded by lib-config beforehand */
+struct ldap_connection *
+libldap_init(struct ldap_connection *conn)
+{
+	const char *str;
+
+	if (conn->set.base == NULL)
+		i_fatal("LDAP: No base given");
+
+	if (conn->set.uris == NULL && conn->set.hosts == NULL)
+		i_fatal("LDAP: No uris or hosts set");
+#ifndef LDAP_HAVE_INITIALIZE
+	if (conn->set.uris != NULL) {
+		i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
+			"(ldap_initialize not found)");
+	}
+#endif
+
+	if (*conn->set.ldaprc_path != '\0') {
+		str = getenv("LDAPRC");
+		if (str != NULL && strcmp(str, conn->set.ldaprc_path) != 0) {
+			i_fatal("LDAP: Multiple different ldaprc_path "
+				"settings not allowed (%s and %s)",
+				str, conn->set.ldaprc_path);
+		}
+		env_put(t_strconcat("LDAPRC=", conn->set.ldaprc_path, NULL));
+	}
+
+	conn->set.ldap_deref = deref2str(conn->set.deref);
+	conn->set.ldap_scope = scope2str(conn->set.scope);
+
+	return conn;
+}
+
+void
+libldap_unref(struct ldap_connection **_conn)
+{
+	struct ldap_connection *conn = *_conn;
+
+	*_conn = NULL;
+	libldap_conn_close(conn);
+
+	pool_unref(&conn->pool);
+}
+
diff -urN --exclude-from=exclude-file ORIG/dovecot-1.2.10/src/lib-ldap/lib-ldap.h dovecot-1.2.10/src/lib-ldap/lib-ldap.h
--- ORIG/dovecot-1.2.10/src/lib-ldap/lib-ldap.h	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-1.2.10/src/lib-ldap/lib-ldap.h	2010-02-11 14:40:17.000000000 +0000
@@ -0,0 +1,288 @@
+#ifndef LIB_LDAP_H
+#define LIB_LDAP_H
+
+/* based on auth/db-ldap.[ch] but for generic ldap queries only
+   (no auth, dict, etc depencies)
+
+   notes:
+   - no async support for now, so no request queue
+   - no support for openldap <2.2 quirks
+   - <ldap.h> functions are ldap_*, lib-ldap functions are libldap_*
+
+   workflow:
+   - init the ldap_connection
+		conn->conn_state
+ */
+
+
+#include "lib.h"
+#include "network.h"
+#include "ioloop.h"
+#include "array.h"
+#include "hash.h"
+#include "aqueue.h"
+#include "str.h"
+#include "env-util.h"
+#include "var-expand.h"
+#include "settings.h"
+
+#include <ldap.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#define HAVE_LDAP_SASL
+#ifdef HAVE_SASL_SASL_H
+#  include <sasl/sasl.h>
+#elif defined (HAVE_SASL_H)
+#  include <sasl.h>
+#else
+#  undef HAVE_LDAP_SASL
+#endif
+#ifdef LDAP_OPT_X_TLS
+#  define OPENLDAP_TLS_OPTIONS
+#endif
+#if SASL_VERSION_MAJOR < 2
+#  undef HAVE_LDAP_SASL
+#endif
+
+#ifndef LDAP_SASL_QUIET
+#  define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
+#endif
+
+/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
+#ifndef LDAP_OPT_SUCCESS
+#  define LDAP_OPT_SUCCESS LDAP_SUCCESS
+#endif
+
+/* Functions like ldap_bind() have been deprecated in OpenLDAP 2.3
+   This define enables them until the code here can be refactored.
+   Update 2010/02: keep using this until all major UNIX/Linux distributions move up */
+#define LDAP_DEPRECATED 1
+
+/* Maximum number of requests in queue. After this new requests are dropped. */
+//#define LIBLDAP_MAX_QUEUE_SIZE 1024
+/* Maximum number of pending requests before delaying new requests. */
+//#define LIBLDAP_MAX_PENDING_REQUESTS 128
+/* If LDAP connection is down, fail requests after waiting for this long. */
+//#define LIBLDAP_REQUEST_DISCONNECT_TIMEOUT_SECS 4
+/* If request is still in queue after this many seconds and other requests
+   have been replied, assume the request was lost and abort it. */
+//#define LIBLDAP_REQUEST_LOST_TIMEOUT_SECS 60
+/* If server disconnects us, don't reconnect if no requests have been sent
+   for this many seconds. */
+//#define LIBLDAP_IDLE_RECONNECT_SECS 60
+/* Timeout for synchronous operations */
+#define LIBLDAP_SYNCH_TIMEOUT_SECS 10
+
+/* macros */
+
+/* forward declarations */
+struct ldap_connection;
+struct ldap_request;
+
+typedef void
+libldap_search_callback_t(struct ldap_connection *conn,
+		struct ldap_request *request,
+		LDAPMessage *res);
+
+/* generic ldap server settings */
+struct ldap_settings {
+	const char *hosts;
+	const char *uris;
+	const char *dn;
+	const char *dnpass;
+	bool auth_bind;
+	const char *auth_bind_userdn;
+
+	bool tls;
+	bool sasl_bind;
+	const char *sasl_mech;
+	const char *sasl_realm;
+	const char *sasl_authz_id;
+
+	const char *tls_ca_cert_file;
+	const char *tls_ca_cert_dir;
+	const char *tls_cert_file;
+	const char *tls_key_file;
+	const char *tls_cipher_suite;
+	const char *tls_require_cert;
+
+	const char *deref;
+	const char *scope;
+	const char *base;
+	unsigned int ldap_version;
+
+	const char *ldaprc_path;
+	const char *debug_level;
+
+	const char *user_attrs;
+	const char *user_filter;
+	const char *pass_attrs;
+	const char *pass_filter;
+
+	const char *default_pass_scheme;
+
+	/* ... */
+	int ldap_deref, ldap_scope;
+	uid_t uid;
+	gid_t gid;
+
+	/* dict ldap map support */
+	const char *pattern;
+	const char *filter;
+	const char *attrlist;
+	const char *encoding;
+
+	ARRAY_TYPE(const_string) ldap_fields;
+};
+
+enum ldap_request_type {
+	LDAP_REQUEST_TYPE_SEARCH_A,
+	LDAP_REQUEST_TYPE_SEARCH_S,
+	LDAP_REQUEST_TYPE_BIND_A,
+	LDAP_REQUEST_TYPE_BIND_S
+};
+
+enum ldap_connection_state {
+	/* Not connected */
+	LDAP_CONN_STATE_DISCONNECTED,
+	/* Binding - either to default dn or doing auth bind */
+	LDAP_CONN_STATE_BINDING,
+	/* Bound to auth dn */
+	LDAP_CONN_STATE_BOUND_AUTH,
+	/* Bound to default dn */
+	LDAP_CONN_STATE_BOUND_DEFAULT
+};
+
+struct ldap_request {
+	pool_t pool;
+	enum ldap_request_type type;
+
+	/* sync: err is ldap_error */
+	int err;
+	struct timeval timeout;
+
+	/* async: msgid for sent requests, -1 if not sent. */
+	int msgid;
+	time_t create_time;
+	libldap_search_callback_t *callback;
+
+};
+
+struct ldap_request_search {
+	struct ldap_request request;
+
+	const char *base;
+	const char *filter;
+	char **attributes;
+};
+
+struct ldap_request_bind {
+	struct ldap_request request;
+
+	const char *dn;
+	const char *dnpass;
+};
+
+struct ldap_result_attribute_context {
+	int no_values;
+	char *attr;
+	char **values;
+};
+
+struct ldap_result_entry_context {
+	int no_attributes;
+	//FIXME: add dn here?
+	struct ldap_result_attribute_context **actx;
+};
+
+struct ldap_result_context {
+	int no_entries;
+	struct ldap_result_entry_context **ectx;
+
+	pool_t pool;
+};
+
+
+struct libldap_sasl_bind_context {
+	const char *authcid;
+	const char *passwd;
+	const char *realm;
+	const char *authzid;
+};
+
+struct ldap_connection {
+	struct ldap_connection *next;
+
+	pool_t pool;
+	int refcount;
+
+	char *config_path;
+	struct ldap_settings set;
+
+	LDAP *ld;
+	enum ldap_connection_state conn_state;
+	int default_bind_msgid;
+
+	int fd;
+	struct io *io;
+	struct timeout *to;
+};
+
+/* libldap public interface */
+int
+libldap_connect_s(struct ldap_connection *conn);
+
+const char *
+libldap_conn_state2str(int state);
+
+const char *
+libldap_escape(const char *str);
+
+const char *
+libldap_get_error(struct ldap_connection *conn);
+
+struct ldap_connection *
+libldap_init(struct ldap_connection *conn);
+
+void
+libldap_init_result_context(struct ldap_result_context **);
+
+struct ldap_request *
+libldap_init_request(int type);
+
+struct ldap_request_search *
+libldap_init_request_search_s(struct ldap_request *r, char *base, char *filter, char *attrlist);
+
+void
+libldap_request(struct ldap_connection *conn, struct ldap_request *request);
+
+char *
+libldap_result_context_first_value(struct ldap_result_context *rctx);
+
+int
+libldap_result_count_values_for_attr(struct ldap_result_context *rctx, char *attribute);
+
+int
+libldap_search_s(struct ldap_connection *conn, struct ldap_request_search *sr, struct ldap_result_context **rctx);
+
+void
+libldap_set_attrs(struct ldap_connection *conn, char ***attr_names_r);
+
+void
+libldap_set_default_ldap_settings(struct ldap_settings *set);
+
+void
+libldap_unref(struct ldap_connection **conn);
+
+void
+libldap_unref_request(struct ldap_request *request);
+
+void
+libldap_unref_result_context(struct ldap_result_context *rctx);
+
+struct var_expand_table *
+libldap_request_search_var_expand_string(struct ldap_request_search *request_search,
+		const char *string);
+
+#endif
