? src/a
? src/all
? src/anno
? src/fix-addressbook_peek_folder_exists-rev1.diff
? src/fix-addressbook_peek_folder_exists-rev2.diff
? src/imap_alert.patch
? src/ldapupdate.c
? src/ldapupdate.h
? src/log
? src/massif.2784.aux
? src/massif.2784.hp
? src/massif.2784.ps
? src/massif.2784.txt
? src/massif.2785.hp
? src/massif.2785.txt
? src/massif.2788.hp
? src/massif.2788.txt
? src/massif.2791.hp
? src/massif.2791.txt
? src/tee
? src/tmp
? src/vlog
? src/gtk/gtksctree.c.try
? src/pixmaps/magnifying.xpm
Index: src/Makefile.am
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/Makefile.am,v
retrieving revision 1.155.2.59
diff -u -p -u -r1.155.2.59 Makefile.am
--- src/Makefile.am	2007/03/25 17:15:36	1.155.2.59
+++ src/Makefile.am	2007/04/04 07:04:34
@@ -73,6 +73,7 @@ claws_mail_SOURCES = \
 	ldaplocate.c \
 	ldapquery.c \
 	ldapserver.c \
+	ldapupdate.c \
 	ldaputil.c \
 	ldif.c \
 	localfolder.c \
@@ -214,6 +215,7 @@ claws_mailinclude_HEADERS = \
 	ldaplocate.h \
 	ldapquery.h \
 	ldapserver.h \
+	ldapupdate.h \
 	ldaputil.h \
 	ldif.h \
 	localfolder.h \
@@ -317,7 +319,7 @@ EXTRA_DIST = \
 	pixmaps/deleted.xpm \
 	pixmaps/dir_close.xpm \
 	pixmaps/dir_noselect.xpm \
-        pixmaps/dir_open_hrm.xpm \
+    pixmaps/dir_open_hrm.xpm \
 	pixmaps/dir_open.xpm \
 	pixmaps/down_arrow.xpm \
 	pixmaps/drafts_close.xpm \
Index: src/addressadd.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/addressadd.c,v
retrieving revision 1.9.2.13
diff -u -p -u -r1.9.2.13 addressadd.c
--- src/addressadd.c	2007/02/04 11:51:12	1.9.2.13
+++ src/addressadd.c	2007/04/04 07:04:34
@@ -46,6 +46,9 @@
 #include "addrbook.h"
 #include "addrindex.h"
 #include "manage_window.h"
+#include "ldapserver.h"
+#include "ldapupdate.h"
+#include "alertpanel.h"
 
 typedef struct {
 	AddressBookFile	*book;
@@ -339,7 +342,8 @@ static void addressadd_load_data( Addres
 	list = addrindex_get_interface_list( addrIndex );
 	while( list ) {
 		AddressInterface *interface = list->data;
-		if( interface->type == ADDR_IF_BOOK ) {
+		if( interface->type == ADDR_IF_BOOK || 
+				interface->type == ADDR_IF_LDAP ) {
 			nodeDS = interface->listSource;
 			while( nodeDS ) {
 				ds = nodeDS->data;
@@ -378,6 +382,7 @@ gboolean addressadd_selection( AddressIn
 	ItemPerson *person = NULL;
 	FolderInfo *fi = NULL;
 	addressadd_cancelled = FALSE;
+
 	if( ! addressadd_dlg.window ) addressadd_create();
 	gtk_widget_grab_focus(addressadd_dlg.ok_btn);
 	gtk_widget_show(addressadd_dlg.window);
@@ -415,6 +420,18 @@ gboolean addressadd_selection( AddressIn
 							returned_name, 
 							address, 
 							returned_remarks);
+			person->status = ADD_ENTRY;
+			if (fi->book->type == ADBOOKTYPE_LDAP) {
+				LdapServer *server = (LdapServer *) fi->book;
+				ldapsvr_set_modified(server, TRUE);
+				ldapsvr_update_book(server, person);
+				if (server->retVal != LDAPRC_SUCCESS) {
+					alertpanel( _("Add address(es)"),
+						"I was not able to add the specified address",
+						GTK_STOCK_CLOSE, NULL, NULL );
+					return server->retVal;
+				}
+			}
 			g_free(returned_name);
 			g_free(returned_remarks);
 			if( person ) retVal = TRUE;
Index: src/addressbook.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/addressbook.c,v
retrieving revision 1.60.2.84
diff -u -p -u -r1.60.2.84 addressbook.c
--- src/addressbook.c	2007/03/21 17:44:15	1.60.2.84
+++ src/addressbook.c	2007/04/04 07:04:35
@@ -89,6 +89,7 @@
 #include <pthread.h>
 #include "ldapserver.h"
 #include "editldap.h"
+#include "ldapupdate.h"
 
 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
 #endif
@@ -534,16 +535,19 @@ static ErrMsgTableEntry _lutErrorsGenera
  * Lookup table of error messages for LDAP errors.
  */
 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
-	{ LDAPRC_SUCCESS,	N_("Success") },
-	{ LDAPRC_CONNECT,	N_("Error connecting to LDAP server") },
-	{ LDAPRC_INIT,		N_("Error initializing LDAP") },
-	{ LDAPRC_BIND,		N_("Error binding to LDAP server") },
-	{ LDAPRC_SEARCH,	N_("Error searching LDAP database") },
-	{ LDAPRC_TIMEOUT,	N_("Timeout performing LDAP operation") },
-	{ LDAPRC_CRITERIA,	N_("Error in LDAP search criteria") },
-	{ LDAPRC_NOENTRIES,	N_("No LDAP entries found for search criteria") },
-	{ LDAPRC_STOP_FLAG,	N_("LDAP search terminated on request") },
-	{ LDAPRC_TLS,		N_("Error starting TLS connection") },
+	{ LDAPRC_SUCCESS,			N_("Success") },
+	{ LDAPRC_CONNECT,			N_("Error connecting to LDAP server") },
+	{ LDAPRC_INIT,				N_("Error initializing LDAP") },
+	{ LDAPRC_BIND,				N_("Error binding to LDAP server") },
+	{ LDAPRC_SEARCH,			N_("Error searching LDAP database") },
+	{ LDAPRC_TIMEOUT,			N_("Timeout performing LDAP operation") },
+	{ LDAPRC_CRITERIA,			N_("Error in LDAP search criteria") },
+	{ LDAPRC_NOENTRIES,			N_("No LDAP entries found for search criteria") },
+	{ LDAPRC_STOP_FLAG,			N_("LDAP search terminated on request") },
+	{ LDAPRC_TLS,				N_("Error starting TLS connection") },
+	{ LDAPRC_NODN,				N_("Distinguised Name (dn) is missing") },
+	{ LDAPRC_NAMING_VIOLATION,	N_("Missing required information") },
+	{ LDAPRC_ALREADY_EXIST,		N_("Another contact exists with that key") },
 	{ 0,			NULL }
 };
 #endif
@@ -1456,10 +1460,16 @@ static void addressbook_del_clicked(GtkB
 			}
 			else if( aio->type == ADDR_ITEM_PERSON ) {
 				ItemPerson *item = ( ItemPerson * ) aio;
+				item->status = DELETE_ENTRY; 
 				addressbook_folder_remove_one_person( clist, item );
 				if (pobj->type == ADDR_ITEM_FOLDER)
 					addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
 				item = addrbook_remove_person( abf, item );
+				if (ds->type == ADDR_IF_LDAP) {
+					LdapServer *server = ds->rawDataSource;
+					ldapsvr_set_modified(server, TRUE);
+					ldapsvr_update_book(server, item);
+				}
 				if( item ) {
 					addritem_free_item_person( item );
 				}
@@ -1881,7 +1891,8 @@ static void addressbook_list_menu_setup(
 		iface = ds->interface;
 		if( ! iface->readOnly ) {
 			menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
-			menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+			if (iface->type != ADDR_IF_LDAP)
+				menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
 			gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
 			if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
 			if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
@@ -1902,7 +1913,8 @@ static void addressbook_list_menu_setup(
 			}
 			/* Folder */
 			if( pobj->type == ADDR_ITEM_FOLDER ) {
-				menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+				if (iface->type != ADDR_IF_LDAP)
+					menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
 				if( obj ) canEdit = TRUE;
 			}
 			if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
@@ -1912,7 +1924,7 @@ static void addressbook_list_menu_setup(
 		if( iface->type == ADDR_IF_LDAP ) {
 			if( obj ) canBrowse = TRUE;
 			canEdit = TRUE;
-			canDelete = FALSE;
+			canDelete = TRUE;
 		}
 	}
 	if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
@@ -2849,6 +2861,7 @@ static void addressbook_treenode_delete_
 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
 {
 	if( person && addrbook.treeSelected == addrbook.opened ) {
+		person->status = ADD_ENTRY;
 		gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
 		addressbook_folder_refresh_one_person(
 			GTK_CTREE(addrbook.clist), person );
@@ -2859,6 +2872,7 @@ static void addressbook_new_address_from
 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
 {
 	if( person && addrbook.treeSelected == addrbook.opened) {
+		person->status = ADD_ENTRY;
 		gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
 		addressbook_set_clist(
 			gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
@@ -2888,6 +2902,17 @@ static void addressbook_new_address_cb( 
 														  addrbook.editaddress_vbox,
 														  addressbook_new_address_from_book_post_cb,
 														  TRUE );
+			if (abf->type == ADDR_IF_LDAP) {
+				LdapServer *server = ds->rawDataSource;
+				ldapsvr_set_modified(server, TRUE);
+				ldapsvr_update_book(server, NULL);
+				if (server->retVal != LDAPRC_SUCCESS) {
+					alertpanel( _("Add address(es)"),
+						addressbook_err2string(_lutErrorsLDAP_, server->retVal),
+						GTK_STOCK_CLOSE, NULL, NULL );
+					return;
+				}
+			}
 			if (prefs_common.addressbook_use_editaddress_dialog)
 				addressbook_new_address_from_book_post_cb( person );
 		}
@@ -2899,6 +2924,17 @@ static void addressbook_new_address_cb( 
 													  addrbook.editaddress_vbox,
 													  addressbook_new_address_from_folder_post_cb,
 													  TRUE );
+		if (abf->type == ADDR_IF_LDAP) {
+			LdapServer *server = ds->rawDataSource;
+			ldapsvr_set_modified(server, TRUE);
+			ldapsvr_update_book(server, NULL);
+			if (server->retVal != LDAPRC_SUCCESS) {
+				alertpanel( _("Add address(es)"),
+						addressbook_err2string(_lutErrorsLDAP_, server->retVal),
+					GTK_STOCK_CLOSE, NULL, NULL );
+				return;
+			}
+		}
 		if (prefs_common.addressbook_use_editaddress_dialog)
 			addressbook_new_address_from_folder_post_cb( person );
 	}
@@ -2951,7 +2987,7 @@ static AddressBookFile *addressbook_get_
 
 	ds = addressbook_find_datasource( addrbook.treeSelected );
 	if( ds == NULL ) return NULL;
-	if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
+	if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
 	return abf;
 }
 
@@ -2984,6 +3020,7 @@ static void addressbook_move_nodes_up( G
 static void addressbook_edit_address_post_cb( ItemPerson *person )
 {
 	if( person ) {
+
 		addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
 		invalidate_address_completion();
 	}
@@ -3057,7 +3094,11 @@ static void addressbook_edit_address( gp
 			if  ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
 										   addressbook_edit_address_post_cb,
 										   (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
-				  != NULL ) {
+				  != NULL ) { 
+				if (abf->type == ADDR_IF_LDAP) {
+					ldapsvr_set_modified( (LdapServer *) abf, TRUE );
+					person->status = UPDATE_ENTRY;
+				}
 				if (prefs_common.addressbook_use_editaddress_dialog)
 					addressbook_edit_address_post_cb( person );
 			}
@@ -3071,8 +3112,12 @@ static void addressbook_edit_address( gp
 									  addressbook_edit_address_post_cb,
 									  (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
 			!= NULL ) {
-			if (prefs_common.addressbook_use_editaddress_dialog)
-				addressbook_edit_address_post_cb( person );
+				if (abf->type == ADDR_IF_LDAP) {
+					ldapsvr_set_modified( (LdapServer *) abf, TRUE );
+					person->status = UPDATE_ENTRY;
+				}
+				if (prefs_common.addressbook_use_editaddress_dialog)
+					addressbook_edit_address_post_cb( person );
 		}
 		return;
 	}
@@ -3207,6 +3252,9 @@ static void addressbook_folder_load_one_
 			gchar *str = addressbook_format_item_clist( person, email );
 			if( str ) {
 				text[COL_NAME] = str;
+			}
+			else if( person->nickName ) {
+				text[COL_NAME] = person->nickName;
 			}
 			else {
 				text[COL_NAME] = ADDRITEM_NAME(person);
Index: src/addrindex.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/addrindex.c,v
retrieving revision 1.28.2.25
diff -u -p -u -r1.28.2.25 addrindex.c
--- src/addrindex.c	2007/03/22 17:53:15	1.28.2.25
+++ src/addrindex.c	2007/04/04 07:04:35
@@ -40,6 +40,7 @@
 #include "addrquery.h"
 #include "addr_compl.h"
 #include "utils.h"
+#include "alertpanel.h"
 
 #ifndef DEV_STANDALONE
 #include "prefs_gtk.h"
@@ -56,6 +57,7 @@
 #include "ldapserver.h"
 #include "ldapctrl.h"
 #include "ldapquery.h"
+#include "ldapupdate.h"
 #include "ldaputil.h"
 #endif
 
@@ -290,14 +292,15 @@ static void addrindex_build_if_list( Add
 	iface = addrindex_create_interface(
 			ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
 #ifdef USE_LDAP
+	iface->readOnly = FALSE;
 	/* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
 	iface->haveLibrary = ldaputil_test_ldap_lib();
 	iface->useInterface = iface->haveLibrary;
-	/* iface->getModifyFlag = ( void * ) ldapsvr_get_modified; */
+	iface->getModifyFlag = ( void * ) ldapsvr_get_modified;
 	iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
-	/* iface->getReadFlag   = ( void * ) ldapsvr_get_read_flag; */
+	iface->getReadFlag   = ( void * ) ldapsvr_get_read_flag;
 	iface->getStatusCode = ( void * ) ldapsvr_get_status;
-	/* iface->getReadData   = ( void * ) ldapsvr_read_data; */
+	iface->getReadData   = ( void * ) ldapsvr_read_data;
 	iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
 	iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
 	iface->getListPerson = ( void * ) ldapsvr_get_list_person;
@@ -1713,7 +1716,39 @@ static gint addrindex_write_to( AddressI
 * return: Status code, from addrIndex->retVal.
 */
 gint addrindex_save_data( AddressIndex *addrIndex ) {
+	GList *nodeIf, *nodeDS;
+
 	g_return_val_if_fail( addrIndex != NULL, -1 );
+	nodeIf = addrIndex->interfaceList;
+
+	/* save LDAP interfaces */
+	while ( nodeIf ) {
+		AddressInterface *iface = nodeIf->data;
+		if( iface->type == ADDR_IF_LDAP ) {
+			nodeDS = iface->listSource;
+			while( nodeDS ) {
+				AddressDataSource *ds = nodeDS->data;
+				LdapServer *abf = ds->rawDataSource;
+				if( ldapsvr_get_read_flag( abf ) ) {
+					if( ldapsvr_get_modified( abf ) ) {
+						ldapsvr_update_book( abf, NULL );
+						if( abf->retVal != LDAPRC_SUCCESS ) {
+							alertpanel( _("Updating address(es)"),
+								_("Updating did not success. Changes are not written to Directory."),
+								GTK_STOCK_CLOSE, NULL, NULL );
+						}
+						else {
+							abf->retVal = MGU_SUCCESS;
+							ldapsvr_set_modified( abf, FALSE );
+						}
+					}
+				}
+				nodeDS = g_list_next( nodeDS );
+			}
+			break;
+		}
+		nodeIf = g_list_next( nodeIf );
+	}
 
 	addrIndex->retVal = MGU_NO_FILE;
 	if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
Index: src/addritem.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/addritem.c,v
retrieving revision 1.13.2.10
diff -u -p -u -r1.13.2.10 addritem.c
--- src/addritem.c	2007/01/23 20:24:47	1.13.2.10
+++ src/addritem.c	2007/04/04 07:04:35
@@ -224,6 +224,7 @@ ItemPerson *addritem_create_item_person(
 	person->listAttrib = NULL;
 	person->externalID = NULL;
 	person->isOpened = FALSE;
+	person->status = NONE;
 	return person;
 }
 
@@ -243,6 +244,7 @@ ItemPerson *addritem_copy_item_person( I
 		itemNew->lastName = g_strdup( item->lastName );
 		itemNew->nickName = g_strdup( item->nickName );
 		itemNew->externalID = g_strdup( item->externalID );
+		itemNew->status = item->status;
 	}
 	return itemNew;
 }
@@ -463,6 +465,17 @@ void addritem_print_item_person( ItemPer
 		addritem_print_attribute( node->data, stream );
 		node = g_list_next( node );
 	}
+	gchar *current_status;
+	switch (person->status) {
+		case NONE: current_status = g_strdup("Unchanged"); break;
+		case ADD_ENTRY: current_status = g_strdup("New"); break;
+		case UPDATE_ENTRY: current_status = g_strdup("Updated"); break;
+		case DELETE_ENTRY: current_status = g_strdup("Deleted"); break;
+		default: current_status = g_strdup("Unknown");
+	}
+	fprintf( stream, "\t\tStatus: %s\n", current_status );
+	if ( current_status )
+		g_free(current_status);
 	fprintf( stream, "\t===\n" );
 }
 
Index: src/addritem.h
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/addritem.h,v
retrieving revision 1.12.2.8
diff -u -p -u -r1.12.2.8 addritem.h
--- src/addritem.h	2007/01/23 20:24:48	1.12.2.8
+++ src/addritem.h	2007/04/04 07:04:35
@@ -53,6 +53,13 @@ typedef enum {
 	ADDRFOLDER_QUERY_RESULTS
 } AddressFolderType;
 
+typedef enum {
+	NONE,
+	ADD_ENTRY,
+	UPDATE_ENTRY,
+	DELETE_ENTRY
+} ContactStatus;
+
 typedef struct _AddrItemObject AddrItemObject;
 struct _AddrItemObject {
 	ItemObjectType type;
@@ -72,6 +79,7 @@ struct _ItemPerson {
 	GList    *listEMail;
 	GList    *listAttrib;
 	gboolean isOpened;
+	ContactStatus status;
 };
 
 typedef struct _ItemEMail ItemEMail;
Index: src/editaddress.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/editaddress.c,v
retrieving revision 1.14.2.23
diff -u -p -u -r1.14.2.23 editaddress.c
--- src/editaddress.c	2007/02/04 11:51:15	1.14.2.23
+++ src/editaddress.c	2007/04/04 07:04:35
@@ -83,6 +83,7 @@ static struct _PersonEdit_dlg {
 	gint rowIndAttrib;
 	gboolean editNew;
 	gboolean read_only;
+	gboolean ldap;
 } personeditdlg;
 
 /* transient data */
@@ -471,7 +472,7 @@ static void edit_person_load_attrib( Ite
 
 static void edit_person_attrib_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
 	UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
-	if( attrib && !personeditdlg.read_only) {
+	if( attrib && !personeditdlg.read_only && !personeditdlg.ldap ) {
 		gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), attrib->name );
 		gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
 		gtk_widget_set_sensitive(personeditdlg.attrib_del, TRUE);
@@ -500,7 +501,7 @@ static void edit_person_attrib_delete( g
 		personeditdlg.rowIndAttrib = -1 + row;
 	} 
 	
-	if (!personeditdlg.read_only)
+	if (!personeditdlg.read_only && !personeditdlg.ldap)
 		gtk_widget_set_sensitive(personeditdlg.attrib_del, gtk_clist_get_row_data(clist, 0) != NULL);
 	
 	edit_person_status_show( NULL );
@@ -986,7 +987,7 @@ static void edit_person_entry_att_change
 {
 	gboolean non_empty = gtk_clist_get_row_data(GTK_CLIST(personeditdlg.clist_attrib), 0) != NULL;
 
-	if (personeditdlg.read_only)
+	if (personeditdlg.read_only || personeditdlg.ldap)
 		return;
 
 	if (gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_atname)) == NULL
@@ -1201,20 +1202,20 @@ static void update_sensitivity(void)
 	gtk_widget_set_sensitive(personeditdlg.entry_name,    !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.entry_first,   !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.entry_last,    !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.entry_nick,    !personeditdlg.read_only);
+	gtk_widget_set_sensitive(personeditdlg.entry_nick,    !personeditdlg.read_only && !personeditdlg.ldap);
 	gtk_widget_set_sensitive(personeditdlg.entry_email,   !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.entry_alias,   !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.entry_remarks, !personeditdlg.read_only);
+	gtk_widget_set_sensitive(personeditdlg.entry_alias,   !personeditdlg.read_only && !personeditdlg.ldap);
+	gtk_widget_set_sensitive(personeditdlg.entry_remarks, !personeditdlg.read_only && !personeditdlg.ldap);
 	gtk_widget_set_sensitive(personeditdlg.email_up,      !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.email_down,    !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.email_del,     !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.email_mod,     !personeditdlg.read_only);
 	gtk_widget_set_sensitive(personeditdlg.email_add,     !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.entry_atname,  !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.entry_atvalue, !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.attrib_add,    !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.attrib_del,    !personeditdlg.read_only);
-	gtk_widget_set_sensitive(personeditdlg.attrib_mod,    !personeditdlg.read_only);
+	gtk_widget_set_sensitive(personeditdlg.entry_atname,  !personeditdlg.read_only && !personeditdlg.ldap);
+	gtk_widget_set_sensitive(personeditdlg.entry_atvalue, !personeditdlg.read_only && !personeditdlg.ldap);
+	gtk_widget_set_sensitive(personeditdlg.attrib_add,    !personeditdlg.read_only && !personeditdlg.ldap);
+	gtk_widget_set_sensitive(personeditdlg.attrib_del,    !personeditdlg.read_only && !personeditdlg.ldap);
+	gtk_widget_set_sensitive(personeditdlg.attrib_mod,    !personeditdlg.read_only && !personeditdlg.ldap);
 }
 
 static void addressbook_edit_person_flush_transient( void )
@@ -1343,6 +1344,7 @@ ItemPerson *addressbook_edit_person( Add
 	current_person = person;
 	current_parent_folder = parent_folder;
 	edit_person_close_post_update_cb = post_update_cb;
+	personeditdlg.ldap = (abf->type == ADBOOKTYPE_LDAP)? TRUE : FALSE;
 
 	if( !personeditdlg.container )
 		addressbook_edit_person_create(parent_container, &cancelled);
Index: src/ldapctrl.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/ldapctrl.c,v
retrieving revision 1.2.2.8
diff -u -p -u -r1.2.2.8 ldapctrl.c
--- src/ldapctrl.c	2007/01/23 20:24:49	1.2.2.8
+++ src/ldapctrl.c	2007/04/04 07:04:35
@@ -52,6 +52,7 @@ LdapControl *ldapctl_create( void ) {
 	ctl->attribCName = g_strdup( LDAPCTL_ATTR_COMMONNAME );
 	ctl->attribFName = g_strdup( LDAPCTL_ATTR_GIVENNAME );
 	ctl->attribLName = g_strdup( LDAPCTL_ATTR_SURNAME );
+	ctl->attribDName = g_strdup( LDAPCTL_ATTR_DISPLAYNAME );
 	ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
 	ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
 	ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
@@ -256,6 +257,7 @@ static void ldapctl_clear( LdapControl *
 	g_free( ctl->attribCName );
 	g_free( ctl->attribFName );
 	g_free( ctl->attribLName );
+	g_free( ctl->attribDName );
 
 	ldapctl_criteria_list_clear( ctl );
 
@@ -269,6 +271,7 @@ static void ldapctl_clear( LdapControl *
 	ctl->attribCName = NULL;
 	ctl->attribFName = NULL;
 	ctl->attribLName = NULL;
+	ctl->attribDName = NULL;
 	ctl->maxEntries = 0;
 	ctl->timeOut = 0;
 	ctl->maxQueryAge = 0;
@@ -316,6 +319,7 @@ void ldapctl_print( const LdapControl *c
 	fprintf( stream, "attr comn: '%s'\n", ctl->attribCName );
 	fprintf( stream, "attr frst: '%s'\n", ctl->attribFName );
 	fprintf( stream, "attr last: '%s'\n", ctl->attribLName );
+	fprintf( stream, "attr disn: '%s'\n", ctl->attribDName );
 	fprintf( stream, "max entry: %d\n",   ctl->maxEntries );
 	fprintf( stream, "  timeout: %d\n",   ctl->timeOut );
 	fprintf( stream, "  max age: %d\n",   ctl->maxQueryAge );
@@ -361,6 +365,7 @@ void ldapctl_copy( const LdapControl *ct
 	ctlTo->attribCName = g_strdup( ctlFrom->attribCName );
 	ctlTo->attribFName = g_strdup( ctlFrom->attribFName );
 	ctlTo->attribLName = g_strdup( ctlFrom->attribLName );
+	ctlTo->attribDName = g_strdup( ctlFrom->attribDName );
 
 	/* Copy search criteria */
 	node = ctlFrom->listCriteria;
Index: src/ldapctrl.h
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/ldapctrl.h,v
retrieving revision 1.1.4.9
diff -u -p -u -r1.1.4.9 ldapctrl.h
--- src/ldapctrl.h	2007/03/22 17:53:17	1.1.4.9
+++ src/ldapctrl.h	2007/04/04 07:04:35
@@ -45,8 +45,9 @@
 #define LDAPCTL_ATTR_GIVENNAME  "givenName"
 #define LDAPCTL_ATTR_SURNAME    "sn"
 #define LDAPCTL_ATTR_PHONE     "telephoneNumber"
+#define LDAPCTL_ATTR_DISPLAYNAME "displayName"
 
-#define LDAPCTL_DFL_ATTR_LIST   "mail, cn, givenName, sn, telephoneNumber"
+#define LDAPCTL_DFL_ATTR_LIST   "mail, cn, givenName, sn, displayName, telephoneNumber"
 
 /*
  * Search matching options.
@@ -75,6 +76,7 @@ struct _LdapControl {
 	gchar     *attribCName;
 	gchar     *attribFName;
 	gchar     *attribLName;
+	gchar	  *attribDName;
 	GList     *listCriteria;
 	pthread_mutex_t *mutexCtl;
 };
Index: src/ldapquery.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/ldapquery.c,v
retrieving revision 1.3.2.17
diff -u -p -u -r1.3.2.17 ldapquery.c
--- src/ldapquery.c	2007/03/22 17:53:17	1.3.2.17
+++ src/ldapquery.c	2007/04/04 07:04:36
@@ -353,13 +353,14 @@ void ldapqry_free( LdapQuery *qry ) {
  */
 static void ldapqry_free_lists(
 		GSList *listName, GSList *listAddr, GSList *listFirst,
-		GSList *listLast, GSList *other_attrs )
+		GSList *listLast, GSList *listDisplay, GSList *other_attrs )
 {
 	GSList *cur = other_attrs;
 	mgu_free_list( listName );
 	mgu_free_list( listAddr );
 	mgu_free_list( listFirst );
 	mgu_free_list( listLast );
+	mgu_free_list( listDisplay );
 	for(;cur; cur = cur->next)
 		addritem_free_attribute((UserAttribute *)cur->data);
 	g_slist_free(other_attrs);
@@ -434,7 +435,7 @@ static GSList *ldapqry_add_single_value(
 static GList *ldapqry_build_items_fl(
 		AddressCache *cache, LdapQuery *qry, gchar *dn,
 		GSList *listName, GSList *listAddr, GSList *listFirst,
-		GSList *listLast, GSList *attributes )
+		GSList *listLast, GSList *listDisplay, GSList *attributes )
 {
 	GSList *nodeAddress, *cur;
 	gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
@@ -448,6 +449,11 @@ static GList *ldapqry_build_items_fl(
 	if( folder == NULL ) return listReturn;
 	if( listAddr == NULL ) return listReturn;
 
+	if ( listDisplay ) {
+		allocated = FALSE;
+		fullName = listDisplay->data;
+	}
+
 	/* Find longest first name in list */
 	firstName = mgu_slist_longest_entry( listFirst );
 
@@ -456,28 +462,30 @@ static GList *ldapqry_build_items_fl(
 		lastName = listLast->data;
 	}
 
-	/* Find longest common name */
-	allocated = FALSE;
-	fullName = mgu_slist_longest_entry( listName );
-	if( fullName == NULL ) {
-		/* Format a full name from first and last names */
-		if( firstName ) {
-			if( lastName ) {
-				fullName = g_strdup_printf( "%s %s", firstName, lastName );
+	if ( fullName == NULL ) {
+		/* Find longest common name */
+		allocated = FALSE;
+		fullName = mgu_slist_longest_entry( listName );
+		if( fullName == NULL ) {
+			/* Format a full name from first and last names */
+			if( firstName ) {
+				if( lastName ) {
+					fullName = g_strdup_printf( "%s %s", firstName, lastName );
+				}
+				else {
+					fullName = g_strdup_printf( "%s", firstName );
+				}
 			}
 			else {
-				fullName = g_strdup_printf( "%s", firstName );
+				if( lastName ) {
+					fullName = g_strdup_printf( "%s", lastName );
+				}
 			}
-		}
-		else {
-			if( lastName ) {
-				fullName = g_strdup_printf( "%s", lastName );
+			if( fullName ) {
+				g_strchug( fullName ); g_strchomp( fullName );
+				allocated = TRUE;
 			}
 		}
-		if( fullName ) {
-			g_strchug( fullName ); g_strchomp( fullName );
-			allocated = TRUE;
-		}
 	}
 
 	/* Add person into folder */		
@@ -505,6 +513,7 @@ static GList *ldapqry_build_items_fl(
 		addrcache_id_email( cache, email );
 		addrcache_person_add_email( cache, person, email );
 		addritem_person_add_email( person, email );
+		/*addritem_print_item_email(email, stdout);*/
 		listReturn = g_list_append( listReturn, email );
 		nodeAddress = g_slist_next( nodeAddress );
 	}
@@ -535,6 +544,7 @@ static GList *ldapqry_process_single_ent
 	BerElement *ber;
 	GSList *listName = NULL, *listAddress = NULL;
 	GSList *listFirst = NULL, *listLast = NULL;
+	GSList *listDisplay = NULL;
 	GSList *other_attrs = NULL;
 	GList *listReturn;
 
@@ -574,11 +584,11 @@ static GList *ldapqry_process_single_ent
 
 	/* Format and add items to cache */
 	listReturn = ldapqry_build_items_fl(
-		cache, qry, dnEntry, listName, listAddress, listFirst, listLast, other_attrs );
+		cache, qry, dnEntry, listName, listAddress, listFirst, listLast, listDisplay, other_attrs );
 
 	/* Free up */
-	ldapqry_free_lists( listName, listAddress, listFirst, listLast, other_attrs );
-	listName = listAddress = listFirst = listLast = other_attrs = NULL;
+	ldapqry_free_lists( listName, listAddress, listFirst, listLast, listDisplay, other_attrs );
+	listName = listAddress = listFirst = listLast = listDisplay = other_attrs = NULL;
 
 	if( ber != NULL ) {
 		ber_free( ber, 0 );
@@ -822,6 +832,9 @@ static gint ldapqry_search_retrieve( Lda
 		if( ldapqry_get_stop_flag( qry ) ) {
 			break;
 		}
+		else if( strcasecmp( attribute, ctl->attribDName ) == 0 ) {
+			listDisplay = ldapqry_add_single_value( ld, e, attribute );
+		}
 
 		/* Retrieve entry */		
 		if( first ) {
@@ -845,6 +858,11 @@ static gint ldapqry_search_retrieve( Lda
 			qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data );
 		}
 		else {
+			/*GList *node = listEMail;
+			while (node) {
+				addritem_print_item_email(node->data, stdout);
+				node = g_list_next(node);
+			}*/
 			g_list_free( listEMail );
 		}
 		pthread_mutex_unlock( qry->mutexEntry );
Index: src/ldapserver.c
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/ldapserver.c,v
retrieving revision 1.4.2.8
diff -u -p -u -r1.4.2.8 ldapserver.c
--- src/ldapserver.c	2007/01/03 05:40:58	1.4.2.8
+++ src/ldapserver.c	2007/04/04 07:04:36
@@ -39,6 +39,7 @@
 #include "ldapctrl.h"
 #include "ldapquery.h"
 #include "ldapserver.h"
+#include "ldaputil.h"
 #include "utils.h"
 #include "adbookbase.h"
 
@@ -693,6 +694,20 @@ LdapQuery *ldapsvr_new_explicit_search(
 	g_free( name );
 
 	return qry;
+}
+
+gint ldapsvr_read_data( LdapServer *server )
+{
+	g_return_val_if_fail( server != NULL, -1 );
+
+	//printf( "...addrbook_read_data :%s:\n", addrcache_get_name( server->addressCache ) );
+	
+	addrcache_clear(server->addressCache);
+	server->addressCache->modified = FALSE;
+	server->addressCache->accessFlag = FALSE;
+	server->addressCache->dataRead = TRUE;
+	addrcache_set_dirty(server->addressCache, FALSE);
+	return 0;
 }
 
 #endif	/* USE_LDAP */
Index: src/ldapserver.h
===================================================================
RCS file: /pack/anoncvs/sylpheedclaws/sylpheed-claws/src/ldapserver.h,v
retrieving revision 1.2.2.7
diff -u -p -u -r1.2.2.7 ldapserver.h
--- src/ldapserver.h	2007/01/03 05:40:58	1.2.2.7
+++ src/ldapserver.h	2007/04/04 07:04:36
@@ -45,6 +45,9 @@
 #define LDAPRC_NOENTRIES  -7
 #define LDAPRC_STOP_FLAG  -8
 #define LDAPRC_TLS        -9
+#define LDAPRC_NODN		  -10
+#define LDAPRC_NAMING_VIOLATION  -11
+#define LDAPRC_ALREADY_EXIST -12
 
 typedef struct _LdapServer LdapServer;
 struct _LdapServer {
@@ -72,6 +75,7 @@ void ldapsvr_set_modified	( LdapServer *
 gboolean ldapsvr_get_read_flag	( LdapServer *server );
 gboolean ldapsvr_get_search_flag( LdapServer *server );
 void ldapsvr_set_search_flag	( LdapServer *server, const gboolean value );
+gint ldapsvr_read_data ( LdapServer *server );
 
 void ldapsvr_print_data		( LdapServer *server, FILE *stream );
 void ldapsvr_cancel_read	( LdapServer *server );
--- /dev/null	2006-05-22 16:25:23.000000000 +0200
+++ src/ldapupdate.h	2007-04-04 09:02:15.000000000 +0200
@@ -0,0 +1,39 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2003-2007 Michael Rasmussen and the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Definitions necessary to update LDAP servers.
+ */
+
+#ifndef __LDAPUPDATE_H__
+#define __LDAPUPDATE_H__
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+
+#include "ldapserver.h"
+
+/* Function proto types */
+void ldapsvr_update_book(LdapServer *server, ItemPerson *item);
+
+#endif	/* USE_LDAP */
+
+#endif /* __LDAPUPDATE_H__ */
+
--- /dev/null	2006-05-22 16:25:23.000000000 +0200
+++ src/ldapupdate.c	2007-04-04 09:02:15.000000000 +0200
@@ -0,0 +1,923 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2003-2007 Michael Rasmussen and the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Functions necessary to access LDAP servers.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <ldap.h>
+#include <lber.h>
+
+#include "ldapupdate.h"
+#include "mgutils.h"
+#include "addritem.h"
+#include "addrcache.h"
+#include "ldapctrl.h"
+#include "ldapquery.h"
+#include "ldapserver.h"
+#include "ldaputil.h"
+#include "utils.h"
+#include "adbookbase.h"
+
+/**
+ * Structure to hold user defined attributes
+ * from contacts
+ */
+typedef struct _AttrKeyValue AttrKeyValue;
+struct _AttrKeyValue {
+	gchar *key;
+	gchar *value;
+};
+
+/**
+ * Structure to hold contact information.
+ * Each addressbook will have 0..N contacts.
+ */
+typedef struct _EmailKeyValue EmailKeyValue;
+struct _EmailKeyValue {
+	gchar *mail;
+	gchar *alias;
+	gchar *remarks;
+};
+
+/**
+ * Structure to hold information about RDN.
+ */
+typedef struct _Rdn Rdn;
+struct _Rdn {
+	gchar *attribute;
+	gchar *value;
+	gchar *new_dn;
+};
+
+/**
+ * Retrieve address group item for update.
+ * \param group  Group to print.
+ * \param array  GHashTAble of item_group, or <i>NULL</i> if none created.
+ */
+void ldapsvr_retrieve_item_group(ItemGroup *group, GHashTable *array) {
+	/* Not implemented in this release */
+	g_return_if_fail(group != NULL);
+}
+
+/**
+ * Create an initial EmailKeyValue structure
+ * \return empty structure
+ */
+EmailKeyValue *emailkeyvalue_create() {
+	EmailKeyValue *buf;
+
+	buf = g_new0(EmailKeyValue, 1);
+	buf->alias = NULL;
+	buf->mail = NULL;
+	buf->remarks = NULL;
+	return buf;
+}
+
+/**
+ * Create an initial AttrKeyValue structure
+ * \return empty structure
+ */
+AttrKeyValue *attrkeyvalue_create() {
+	AttrKeyValue *buf;
+
+	buf = g_new0(AttrKeyValue, 1);
+	buf->key = NULL;
+	buf->value = NULL;
+	return buf;
+}
+
+/**
+ * Retrieve E-Mail address object for update.
+ * \param item   ItemEmail to update.
+ * \return object, or <i>NULL</i> if none created.
+ */
+EmailKeyValue *ldapsvr_retrieve_item_email(ItemEMail *item) {
+	g_return_val_if_fail(item != NULL, NULL);
+	EmailKeyValue *newItem = emailkeyvalue_create();		
+	newItem->alias = g_strdup(ADDRITEM_NAME(item));
+	newItem->mail = g_strdup(item->address);
+	newItem->remarks = g_strdup(item->remarks);
+	return newItem;
+}
+
+/**
+ * Retrieve user attribute object for update.
+ * \param item   UserAttribute to update.
+ * \return object, or <i>NULL</i> if none created.
+ */
+AttrKeyValue *ldapsvr_retrieve_attribute(UserAttribute *item) {
+	g_return_val_if_fail(item != NULL, NULL);
+	AttrKeyValue *newItem = attrkeyvalue_create();
+	newItem->key = g_strdup(item->name);
+	newItem->value = g_strdup(item->value);
+	return newItem;
+}
+
+/**
+ * Retrieve person object for update.
+ * \param person ItemPerson to update.
+ * \param array GHashTable with user input.
+ * \return false if update is not needed, or true if update is needed.
+ */
+gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
+	GList *node, *attr;
+
+	g_return_val_if_fail(person != NULL, FALSE);
+	switch (person->status) {
+		case NONE: return FALSE;
+		case ADD_ENTRY: g_hash_table_insert(array, "status", "new"); break;
+		case UPDATE_ENTRY: g_hash_table_insert(array, "status", "update"); break;
+		case DELETE_ENTRY: g_hash_table_insert(array, "status", "delete"); break;
+		default: g_critical("ldapsvr_retrieve_item_person->Unknown status: %d", person->status);
+	}
+	g_hash_table_insert(array, "uid", ADDRITEM_ID(person));
+	g_hash_table_insert(array, "cn", ADDRITEM_NAME(person));
+	g_hash_table_insert(array, "givenName", person->firstName);
+	g_hash_table_insert(array, "sn", person->lastName);
+	g_hash_table_insert(array, "nickName", person->nickName);
+	g_hash_table_insert(array, "dn", person->externalID);
+	node = person->listEMail;
+	attr = NULL;
+	while (node) {
+		EmailKeyValue *newEmail = ldapsvr_retrieve_item_email(node->data);
+		if (newEmail)
+			attr = g_list_append(attr, newEmail);
+		node = g_list_next(node);
+	}
+	g_hash_table_insert(array, "mail", attr);
+/* Not implemented in this release.
+	node = person->listAttrib;
+	attr = NULL;
+	while (node) {
+		AttrKeyValue *newAttr = ldapsvr_retrieve_attribute(node->data)
+		if (newAttr)
+			attr = g_list_append(attr, newAttr);
+		node = g_list_next(node);
+	}
+	g_hash_table_insert(array, "attribute", attr);
+*/
+	return TRUE;
+}
+
+/**
+ * Print contents of contacts hashtable for debug.
+ * This function must be called with g_hash_table_foreach.
+ * \param key Key to process.
+ * \param data Data to process.
+ * \param fd Output stream.
+ */
+void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd) {
+	gchar *keyName = (gchar *) key;
+	GList *node;
+
+	if (g_ascii_strcasecmp("mail", keyName) == 0) {
+		node = (GList *) data;
+		while (node) {
+			EmailKeyValue *item = node->data;
+			if (debug_get_mode()) {
+				debug_print("\t\talias = %s\n", item->alias);
+				debug_print("\t\tmail = %s\n", item->mail);
+				debug_print("\t\tremarks = %s\n", item->remarks);
+			}
+			else {
+				FILE *stream = (FILE *) fd;
+				fprintf(stream, "\t\talias = %s\n", item->alias);
+				fprintf(stream, "\t\tmail = %s\n", item->mail);
+				fprintf(stream, "\t\tremarks = %s\n", item->remarks);
+			}
+			node = g_list_next(node);
+		}
+	}
+	else if (g_ascii_strcasecmp("attribute", keyName) == 0) {
+		node = (GList *) data;
+		while (node) {
+			AttrKeyValue *item = node->data;
+			if (debug_get_mode()) {
+				debug_print("\t\t%s = %s\n", item->key, item->value);
+			}
+			else {
+				FILE *stream = (FILE *) fd;
+				fprintf(stream, "\t\t%s = %s\n", item->key, item->value);
+			}
+			node = g_list_next(node);
+		}
+	}
+	else {
+		if (debug_get_mode())
+			debug_print("\t\t%s = %s\n", keyName, (gchar *) data);
+		else {
+			FILE *stream = (FILE *) fd;
+			fprintf(stream, "\t\t%s = %s\n", keyName, (gchar *) data);
+		}
+	}
+}
+
+/**
+ * Free list of changed contacts
+ *
+ * \param list List of GHashTable
+ */
+void ldapsvr_free_hashtable(GList *list) {
+	while (list) {
+		g_hash_table_destroy(list->data);
+		list = g_list_next(list);
+	}
+	g_list_free(list);
+}
+
+/**
+ * Get person object from cache
+ *
+ * \param server Resource to LDAP
+ * \param uid PersonID in cache
+ * \return person object, or <i>NULL</i> if fail
+ */
+ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
+	g_return_val_if_fail(server != NULL || uid != NULL, NULL);
+	AddrItemObject *aio = addrcache_get_object(server->addressCache, uid);
+	if (aio) {
+		if(aio->type == ITEMTYPE_PERSON) {
+			return (ItemPerson *) aio;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Connect to LDAP server.
+ * \param  ctl Control object to process.
+ * \return LDAP Resource to LDAP.
+ */
+LDAP *ldapsvr_connect(LdapControl *ctl) {
+	LDAP *ld = NULL;
+	gint rc;
+	gint version;
+	gchar *uri = NULL;
+
+	g_return_val_if_fail(ctl != NULL, NULL);
+
+	uri = g_strdup_printf("ldap%s://%s:%d",
+				ctl->enableSSL?"s":"",
+				ctl->hostName, ctl->port);
+	ldap_initialize(&ld, uri);
+	g_free(uri);
+
+	if (ld == NULL)
+		return NULL;
+
+	debug_print("connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
+
+#ifdef USE_LDAP_TLS
+	/* Handle TLS */
+	version = LDAP_VERSION3;
+	rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+	if (rc == LDAP_OPT_SUCCESS) {
+		ctl->version = LDAP_VERSION3;
+	}
+
+	if (ctl->version == LDAP_VERSION3) {
+		if (ctl->enableTLS && !ctl->enableSSL) {
+			rc = ldap_start_tls_s(ld, NULL, NULL);
+			
+			if (rc != LDAP_SUCCESS) {
+				fprintf(stderr, "LDAP Error(tls): ldap_simple_bind_s: %s\n",
+					ldap_err2string(rc));
+				return NULL;
+			}
+		}
+	}
+#endif
+
+	/* Bind to the server, if required */
+	if (ctl->bindDN) {
+		if (* ctl->bindDN != '\0') {
+			rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, ctl->bindPass);
+			if (rc != LDAP_SUCCESS) {
+				fprintf(stderr, "bindDN: %s, bindPass: %s\n", ctl->bindDN, ctl->bindPass);
+				fprintf(stderr, "LDAP Error(bind): ldap_simple_bind_s: %s\n",
+					ldap_err2string(rc));
+				return NULL;
+			}
+		}
+	}
+	return ld;
+}
+
+/**
+ * Disconnect to LDAP server.
+ * \param ld Resource to LDAP.
+ */
+void ldapsvr_disconnect(LDAP *ld) {
+	/* Disconnect */
+	g_return_if_fail(ld != NULL);
+	ldap_unbind_ext(ld, NULL, NULL);
+}
+
+/**
+ * Create an initial Rdn structure
+ *
+ * \return empty structure
+ */
+Rdn *rdn_create() {
+	Rdn *buf;
+
+	buf = g_new0(Rdn, 1);
+	buf->attribute = NULL;
+	buf->value = NULL;
+	buf->new_dn = NULL;
+	return buf;
+}
+
+/**
+ * update Rdn structure
+ *
+ * \param rdn Rdn structure to update
+ * \param head Uniq part of dn
+ * \param tail Common part of dn
+ */
+void update_rdn(Rdn *rdn, gchar *head, gchar *tail) {
+	rdn->value = g_strdup(head);
+	rdn->new_dn = g_strdup_printf("mail=%s%s", head, tail);
+}
+
+/**
+ * Deside if dn needs to be changed
+ *
+ * \param hash GHashTable with user input.
+ * \param dn dn for current object
+ * \return Rdn structure
+ */
+Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
+	Rdn *rdn;
+
+	g_return_val_if_fail(hash != NULL || dn != NULL, NULL);
+	gchar *pos = g_strstr_len(dn, strlen(dn), "=");
+	gchar *compare = g_strndup(dn, pos - dn);
+	/* To avoid futile warning */
+	if (*pos++) ;
+	gchar *rest = g_strstr_len(pos, strlen(pos), ",");
+	gchar *val = g_strndup(pos, rest - pos);
+	if (val == NULL) {
+		if (compare)
+			g_free(compare);
+		return NULL;
+	}
+	rdn = rdn_create();
+	rdn->value = g_strdup(val);
+	rdn->attribute = g_strdup(compare);
+	g_free(val);
+	if (strcmp("mail", rdn->attribute) == 0) {
+		GList *list = g_hash_table_lookup(hash, rdn->attribute);
+		while (list) {
+			EmailKeyValue *item = list->data;
+			compare = g_strdup((gchar *) item->mail);
+			if (strcmp(compare, rdn->value) == 0) {
+				update_rdn(rdn, compare, rest);
+				g_free(compare);
+				return rdn;
+			}
+			list = g_list_next(list);
+		}
+		// if compare and rdn->attribute are equal then last email removed/empty
+		if (strcmp(compare, rdn->attribute) != 0) {
+	 		// RDN changed. Find new
+			update_rdn(rdn, compare, rest);
+			g_free(compare);
+			return rdn;
+		}
+		else {
+			// We cannot remove dn
+			g_free(compare);
+			return NULL;
+		}
+	}
+	else {
+		compare = g_hash_table_lookup(hash, rdn->attribute);
+		// if compare and rdn->attribute are equal then dn removed/empty
+		if (strcmp(compare, rdn->attribute) != 0) {
+			update_rdn(rdn, compare, rest);
+			return rdn;
+		}
+		else {
+			// We cannot remove dn
+			return NULL;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * This macro is borrowed from the Balsa project
+ * Creates a LDAPMod structure
+ *
+ * \param mods Empty LDAPMod structure
+ * \param modarr Array with values to insert
+ * \param op Operation to perform on LDAP
+ * \param attr Attribute to insert
+ * \param strv Empty array which is NULL terminated
+ * \param val Value for attribute
+ */
+#define SETMOD(mods,modarr,op,attr,strv,val) \
+   do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
+        (strv)[0]=(val); (modarr).mod_values=strv; \
+      } while(0)
+
+/**
+ * Creates a LDAPMod structure
+ *
+ * \param mods Empty LDAPMod structure
+ * \param modarr Array with values to insert
+ * \param op Operation to perform on LDAP
+ * \param attr Attribute to insert
+ * \param strv Array with values to insert. Must be NULL terminated
+ */
+#define SETMODS(mods,modarr,op,attr,strv) \
+   do { (mods) = &(modarr); (modarr).mod_type=attr; \
+	   	(modarr).mod_op=op; (modarr).mod_values=strv; \
+      } while(0)
+#define MODSIZE 10
+
+/**
+ * Clean up, close LDAP connection, and refresh cache
+ *
+ * \param ld Resource to LDAP
+ * \param server AddressBook resource
+ * \param contact GHashTable with current changed object
+ */
+void clean_up(LDAP *ld, LdapServer *server, GHashTable *contact) {
+	ItemPerson *person = 
+		ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
+	if (person) {
+		person->status = NONE;
+		gchar *displayName = g_hash_table_lookup(contact, "displayName");
+		if (displayName)
+			person->nickName = g_strdup(displayName);
+	}
+	if (ld)
+		ldapsvr_disconnect(ld);
+	ldapsvr_force_refresh(server);
+	ldapsvr_free_all_query(server);
+}
+
+/**
+ * Get cn attribute from dn
+ *
+ * \param dn Distinguesh Name for current object
+ * \return AttrKeyValue, or <i>NULL</i> if none created
+ */
+AttrKeyValue *get_cn(gchar *dn) {
+	g_return_val_if_fail(dn != NULL, NULL);
+	AttrKeyValue *cn = attrkeyvalue_create();
+	gchar *start = g_strstr_len(dn, strlen(dn), "cn");
+	if (start == NULL)
+		return NULL;
+	gchar *end = g_strstr_len(start, strlen(start), ",");
+	gchar *item = g_strndup(start, end - start);
+	if (item == NULL)
+		return NULL;
+	gchar **key_value = g_strsplit(item, "=", 2);
+	cn->key = g_strdup(key_value[0]);
+	cn->value = g_strdup(key_value[1]);
+	g_strfreev(key_value);
+	g_free(item);
+	return cn;
+}
+
+/**
+ * Get ou or o attribute from dn
+ *
+ * \param dn Distinguesh Name for current object
+ * \return AttrKeyValue, or <i>NULL</i> if none created
+ */
+AttrKeyValue *get_ou(gchar *dn) {
+	g_return_val_if_fail(dn != NULL, NULL);
+	AttrKeyValue *ou = attrkeyvalue_create();
+	gchar *start = g_strstr_len(dn, strlen(dn), ",o=");
+	if (start == NULL)
+		start = g_strstr_len(dn, strlen(dn), ",ou=");
+	if (start == NULL)
+		return NULL;
+	// avoid futile warning
+	if (*start++);
+	gchar *end = g_strstr_len(start, strlen(start), ",");
+	gchar *item = g_strndup(start, end - start);
+	if (item == NULL)
+		return NULL;
+	gchar **key_value = g_strsplit(item, "=", 2);
+	ou->key = g_strdup(key_value[0]);
+	ou->value = g_strdup(key_value[1]);
+	g_strfreev(key_value);
+	g_free(item);
+	return ou;
+}
+
+/**
+ * Print the contents of a LDAPMod structure for debuging purposes
+ *
+ * \param mods LDAPMod structure
+ */
+void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
+	gchar *mod_op;
+	int i;
+
+	fprintf( stderr, "Type\n");
+	for (i = 0; NULL != mods[i]; i++) {
+		LDAPMod *mod = (LDAPMod *) mods[i];
+		switch (mod->mod_op) {
+			case LDAP_MOD_ADD: mod_op = g_strdup("ADD"); break;
+			case LDAP_MOD_REPLACE: mod_op = g_strdup("MODIFY"); break;
+			case LDAP_MOD_DELETE: mod_op = g_strdup("DELETE"); break;
+			default: mod_op = g_strdup("UNKNOWN");
+		}
+		fprintf( stderr, "Operation: %s\tType:%s\nValues:\n", mod_op, mod->mod_type);
+		gchar **vals = mod->mod_vals.modv_strvals;
+		while (*vals) {
+			fprintf( stderr, "\t%s\n", *vals++);
+		}
+	}
+}
+
+/**
+ * Add new contact to LDAP
+ *
+ * \param server AddressBook resource
+ * \param contact GHashTable with object to add
+ */
+void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
+	gchar *email = NULL, *param = NULL;
+	LDAP *ld = NULL;
+	LDAPMod *mods[MODSIZE];
+	LDAPMod modarr[7];
+	gint cnt = 0;
+    char *cn[] = {NULL, NULL};
+	char *displayName[] = {NULL, NULL};
+    char *givenName[] = {NULL, NULL};
+    char **mail = NULL;
+    char *sn[] = {NULL, NULL};
+	char *org[] = {NULL, NULL};
+	char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL}; 
+
+	g_return_if_fail(server != NULL || contact != NULL);
+	GList *node = g_hash_table_lookup(contact , "mail");
+	if (node) {
+		EmailKeyValue *newEmail = node->data;
+		email = g_strdup(newEmail->mail);
+	}
+	if (email == NULL) {
+		server->retVal = LDAPRC_NODN;
+		return;
+	}
+	gchar *base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN);
+	g_free(email);
+	ItemPerson *person = 
+		ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
+	person->externalID = g_strdup(base_dn);
+	debug_print("dn: %s\n", base_dn);
+	ld = ldapsvr_connect(server->control);
+	if (ld == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj);
+	cnt++;
+	AttrKeyValue *ou = get_ou(base_dn);
+	if (ou == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, ou->key, org, ou->value);
+	cnt++;
+	AttrKeyValue *commonName = get_cn(base_dn);
+	if (commonName == NULL) {
+		param = g_hash_table_lookup(contact , "cn");
+		if (param) {
+			SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param);
+		}
+		else {
+			clean_up(ld, server, contact);
+			return;
+		}
+	}
+	else {
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, commonName->key, cn, commonName->value);
+		cnt++;
+		param = g_hash_table_lookup(contact , "cn");
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "displayName", displayName, param);
+		g_hash_table_insert(contact, "displayName", param);
+	}
+	cnt++;
+	param = g_hash_table_lookup(contact , "givenName");
+	if (param) {
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param);
+		cnt++;
+	}
+	GList *mailList = g_hash_table_lookup(contact , "mail");
+	if (mailList) {
+		mail = g_malloc(sizeof(*mail));
+		char **tmp = g_malloc(sizeof(*tmp));
+		mail = tmp;
+		while (mailList) {
+			EmailKeyValue *item = mailList->data;
+			*tmp++ = g_strdup((gchar *) item->mail);
+			mailList = g_list_next(mailList);
+		}
+		*tmp = NULL;
+		SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail);
+		cnt++;
+	}
+	param = g_hash_table_lookup(contact, "sn");
+	if (param == NULL)
+		param = g_strdup("Some SN");
+	SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param);
+	cnt++;
+	mods[cnt] = NULL;
+	if (debug_get_mode()) {
+		ldapsvr_print_ldapmod(mods);
+	}
+	server->retVal = LDAPRC_SUCCESS;
+	int rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL);
+	if (rc) {
+		switch (rc) {
+			case LDAP_ALREADY_EXISTS: 
+				server->retVal = LDAPRC_ALREADY_EXIST;
+				break;
+			default:
+				fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",base_dn, rc, ldap_err2string(rc));
+				server->retVal = LDAPRC_NAMING_VIOLATION;
+		}
+	}
+	g_free(base_dn);
+	clean_up(ld, server, contact);
+}
+
+/**
+ * Update contact to LDAP
+ *
+ * \param server AddressBook resource
+ * \param contact GHashTable with object to update
+ */
+void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
+	LDAP *ld = NULL;
+	LDAPMod *mods[MODSIZE];
+	LDAPMod modarr[4];
+	gint cnt = 0;
+	gchar *param, *dn;
+	Rdn *NoRemove = NULL;
+    char *cn[]   = {NULL, NULL};
+    char *givenName[]   = {NULL, NULL};
+    char **mail = NULL;
+    char *sn[]   = {NULL, NULL};
+
+	g_return_if_fail(server != NULL || contact != NULL);
+	ld = ldapsvr_connect(server->control);
+	if (ld == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	dn = g_hash_table_lookup(contact, "dn");
+	if (dn == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	NoRemove = ldapsvr_modify_dn(contact, dn);
+	if (NoRemove) {
+		/* We are trying to change RDN */
+		gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value);
+		int rc = ldap_modrdn2_s(ld, dn, newRdn, 1);
+		if(rc != LDAP_SUCCESS) {
+			if (rc ==  LDAP_ALREADY_EXISTS) {
+				/* We are messing with a contact with more than one listed email
+				 * address and the email we are changing is not the one used for dn
+				 */
+				/* It needs to be able to handle renaming errors to an already defined
+				 * dn. For now we just refuse the update. It will be caught later on as
+				 * a LDAPRC_NAMING_VIOLATION error.
+				 */
+			}
+			else {
+				fprintf(stderr, "Current dn: %s\n", dn);
+				fprintf(stderr, "new dn: %s\n", newRdn);
+				fprintf(stderr, "LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldap_err2string(rc));
+				g_free(newRdn);
+				return;
+			}
+		}
+		else {
+			g_free(newRdn);
+			dn = g_strdup(NoRemove->new_dn);
+		}
+	}
+	else {
+		server->retVal = LDAPRC_NODN;
+		clean_up(ld, server, contact);
+		return;
+	}
+	param = g_hash_table_lookup(contact , "cn");
+	if (param && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) {
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "cn", cn, param);
+		cnt++;
+	}
+	param = g_hash_table_lookup(contact , "givenName");
+	if (param && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) {
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "givenName", givenName, param);
+		cnt++;
+	}
+	GList *mailList = g_hash_table_lookup(contact , "mail");
+	if (mailList) {
+		if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) {
+			mail = g_malloc(sizeof(*mail));
+			char **tmp = g_malloc(sizeof(*tmp));
+			mail = tmp;
+			while (mailList) {
+				EmailKeyValue *item = mailList->data;
+				*tmp++ = g_strdup((gchar *) item->mail);
+				mailList = g_list_next(mailList);
+			}
+			*tmp = NULL;
+			SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail);
+			cnt++;
+		}
+	}
+	param = g_hash_table_lookup(contact , "sn");
+	if (param && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) {
+		SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "sn", sn, param);
+		cnt++;
+	}
+	debug_print("newDN: %s\n", dn);
+	if (NoRemove)
+		g_free(NoRemove);
+	server->retVal = LDAPRC_SUCCESS;
+	if (cnt > 0) {
+		mods[cnt] = NULL;
+		int rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
+		if (rc) {
+			fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
+                    dn, rc, ldap_err2string(rc));
+			server->retVal = LDAPRC_NAMING_VIOLATION;
+		}
+		if (mail)
+			g_free(mail);
+	}
+	clean_up(ld, server, contact);
+}
+
+/**
+ * Delete contact from LDAP
+ *
+ * \param server AddressBook resource
+ * \param contact GHashTable with object to delete
+ */
+void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
+	LDAP *ld = NULL;
+	gchar *dn;
+
+	g_return_if_fail(server != NULL || contact != NULL);
+	ld = ldapsvr_connect(server->control);
+	if (ld == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	dn = g_hash_table_lookup(contact, "dn");
+	if (dn == NULL) {
+		clean_up(ld, server, contact);
+		return;
+	}
+	int rc = ldap_delete_ext_s(ld, dn, NULL, NULL);
+	if (rc) {
+		fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
+				dn, rc, ldap_err2string(rc));
+		server->retVal = LDAPRC_NODN;
+	}
+	clean_up(ld, server, contact);
+}
+
+/**
+ * Update any changes to the server.
+ *
+ * \param server AddressBook resource.
+ * \param person ItemPerson holding user input.
+ */
+void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
+	GList *node = NULL;
+	GHashTable *contact = NULL;
+	GList *contacts = NULL, *head = NULL;
+
+	g_return_if_fail(server != NULL);
+
+	debug_set_mode(FALSE);
+	contact = g_hash_table_new(g_str_hash, g_str_equal);
+	if (item) {
+		gboolean result = ldapsvr_retrieve_item_person(item, contact);
+		debug_print("Found contact to update: %s\n", result? "Yes" : "No");
+		if (result) {
+			if (debug_get_mode()) {
+				addritem_print_item_person(item, stdout);
+			}
+			contacts = g_list_append(contacts, contact);
+		}
+	}
+	else {
+		ItemFolder *folder = server->addressCache->rootFolder;
+		node = folder->listFolder;
+		if (node) {
+			while (node) {
+				AddrItemObject *aio = node->data;
+				if (aio) {
+					if (aio->type == ITEMTYPE_FOLDER) {
+						ItemFolder *folder = (ItemFolder *) aio;
+						GList *persons = folder->listPerson;
+						while (persons) {
+							AddrItemObject *aio = persons->data;
+							if (aio) {
+								if (aio->type == ITEMTYPE_PERSON) {
+									ItemPerson *item = (ItemPerson *) aio;
+									gboolean result = ldapsvr_retrieve_item_person(item, contact);
+									debug_print("Found contact to update: %s\n", result? "Yes" : "No");
+									if (result) {
+										if (debug_get_mode()) {
+											gchar *uid = g_hash_table_lookup(contact, "uid");
+											item = ldapsvr_get_contact(server, uid);
+											addritem_print_item_person(item, stdout);
+										}
+										contacts = g_list_append(contacts, contact);
+									}
+								}
+							}
+							persons = g_list_next(persons);
+						}
+					}
+				}
+				else {
+					fprintf(stderr, "\t\tpid : ???\n");
+				}
+				node = g_list_next(node);
+			}
+		}
+	}
+	head = contacts;
+	if (debug_get_mode()) {
+		if (contacts)
+			debug_print("Contacts which must be updated in LDAP:\n");
+		while (contacts) {
+			debug_print("\tContact:\n");
+			g_hash_table_foreach(contacts->data, 
+				ldapsvr_print_contacts_hashtable, stderr);
+			contacts = g_list_next(contacts);
+		}
+	}
+	if (contacts == NULL)
+		contacts = head;
+	while (contacts) {
+		contact = (GHashTable *) contacts->data;
+		gchar *status = (gchar *) g_hash_table_lookup(contact, "status");
+		if (status == NULL)
+			status = g_strdup("NULL");
+		if (g_ascii_strcasecmp(status, "new") == 0) {
+			ldapsvr_add_contact(server, contact);
+		}
+		else if (g_ascii_strcasecmp(status, "update") == 0) {
+			ldapsvr_update_contact(server, contact);
+		}
+		else if (g_ascii_strcasecmp(status, "delete") == 0) {
+			ldapsvr_delete_contact(server, contact);
+		}
+		else
+			g_critical("ldapsvr_update_book->Unknown status: %s\n", status);
+		contacts = g_list_next(contacts);
+	}
+	ldapsvr_free_hashtable(head);
+	debug_set_mode(FALSE);
+}
+
+#endif	/* USE_LDAP */
+
+/*
+ * End of Source.
+ */
+
