Fix NULL pointer dereference in LDAP lookup code.
[claws.git] / src / ldapupdate.c
index 15c984baf709f5ea0f2c091ddf0b3ed717478bdd..e8ea64ae2779012888f1c841ba1a8ba7b2a3c0f5 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2003-2007 Michael Rasmussen and the Claws Mail team
+ * Copyright (C) 2003-2012 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
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * 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.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 /*
  * Functions necessary to access LDAP servers.
  */
 
+/*
+ * Outstanding bugs
+ * 1) When adding a contact to an empty addressbook from the pop-up menu
+ * when right-clicking on an email address causes claws-mail to crash in
+ * addritem.c line 965. Severity: Show stopper. Solved in 2.9.2cvs17
+ * 2) Updating a contact gets lost if the user makes a new search on the
+ * same LdapServer. Severity: Medium. Solved in 2.9.2cvs17 (patch added to solve 1) also solved this bug)
+ * 3) After adding a new contact the displayName for the contact is empty
+ * until the user makes a reread from the LdapServer. Severity: minor.
+ * Solved in 2.9.2cvs24
+ */
+
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
+#include "claws-features.h"
 #endif
 
 #ifdef USE_LDAP
@@ -31,8 +44,6 @@
 #include <glib/gi18n.h>
 #include <sys/time.h>
 #include <string.h>
-#include <ldap.h>
-#include <lber.h>
 
 #include "ldapupdate.h"
 #include "mgutils.h"
@@ -44,6 +55,7 @@
 #include "ldaputil.h"
 #include "utils.h"
 #include "adbookbase.h"
+#include "editaddress_other_attributes_ldap.h"
 
 /**
  * Structure to hold user defined attributes
@@ -83,7 +95,7 @@ struct _Rdn {
  */
 void ldapsvr_retrieve_item_group(ItemGroup *group, GHashTable *array) {
        /* Not implemented in this release */
-       g_return_if_fail(group != NULL);
+       cm_return_if_fail(group != NULL);
 }
 
 /**
@@ -113,6 +125,23 @@ AttrKeyValue *attrkeyvalue_create() {
        return buf;
 }
 
+/**
+ * Free created AttrKeyValue structure
+ * \param akv AttrKeyValue structure to free
+ */
+void attrkeyvalue_free(AttrKeyValue *akv) {
+       if (akv->key) {
+               g_free(akv->key);
+               akv->key = NULL;
+       }
+       if (akv->value) {
+               g_free(akv->value);
+               akv->value = NULL;
+       }
+       g_free(akv);
+       akv = NULL;
+}
+
 /**
  * Retrieve E-Mail address object for update.
  * \param item   ItemEmail to update.
@@ -120,7 +149,7 @@ AttrKeyValue *attrkeyvalue_create() {
  */
 EmailKeyValue *ldapsvr_retrieve_item_email(ItemEMail *item) {
        EmailKeyValue *newItem;
-       g_return_val_if_fail(item != NULL, NULL);
+       cm_return_val_if_fail(item != NULL, NULL);
        newItem = emailkeyvalue_create();               
        newItem->alias = g_strdup(ADDRITEM_NAME(item));
        newItem->mail = g_strdup(item->address);
@@ -135,7 +164,7 @@ EmailKeyValue *ldapsvr_retrieve_item_email(ItemEMail *item) {
  */
 AttrKeyValue *ldapsvr_retrieve_attribute(UserAttribute *item) {
        AttrKeyValue *newItem;
-       g_return_val_if_fail(item != NULL, NULL);
+       cm_return_val_if_fail(item != NULL, NULL);
        newItem = attrkeyvalue_create();
        newItem->key = g_strdup(item->name);
        newItem->value = g_strdup(item->value);
@@ -151,13 +180,13 @@ AttrKeyValue *ldapsvr_retrieve_attribute(UserAttribute *item) {
 gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
        GList *node, *attr;
 
-       g_return_val_if_fail(person != NULL, FALSE);
+       cm_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);
+               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));
@@ -165,6 +194,7 @@ gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
        g_hash_table_insert(array, "sn", person->lastName);
        g_hash_table_insert(array, "nickName", person->nickName);
        g_hash_table_insert(array, "dn", person->externalID);
+       g_hash_table_insert(array, "person", person);
        node = person->listEMail;
        attr = NULL;
        while (node) {
@@ -174,17 +204,15 @@ gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
                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)
+               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;
 }
 
@@ -204,15 +232,15 @@ void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd)
                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);
+                               debug_print("\t\talias = %s\n", item->alias?item->alias:"null");
+                               debug_print("\t\tmail = %s\n", item->mail?item->mail:"null");
+                               debug_print("\t\tremarks = %s\n", item->remarks?item->remarks:"null");
                        }
                        else if (fd) {
                                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);
+                               fprintf(stream, "\t\talias = %s\n", item->alias?item->alias:"null");
+                               fprintf(stream, "\t\tmail = %s\n", item->mail?item->mail:"null");
+                               fprintf(stream, "\t\tremarks = %s\n", item->remarks?item->remarks:"null");
                        }
                        node = g_list_next(node);
                }
@@ -222,21 +250,23 @@ void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd)
                while (node) {
                        AttrKeyValue *item = node->data;
                        if (debug_get_mode()) {
-                               debug_print("\t\t%s = %s\n", item->key, item->value);
+                               debug_print("\t\t%s = %s\n", item->key?item->key:"null",
+                                               item->value?item->value:"null");
                        }
                        else if (fd) {
                                FILE *stream = (FILE *) fd;
-                               fprintf(stream, "\t\t%s = %s\n", item->key, item->value);
+                               fprintf(stream, "\t\t%s = %s\n", item->key?item->key:"null",
+                                               item->value?item->value:"null");
                        }
                        node = g_list_next(node);
                }
        }
        else {
                if (debug_get_mode())
-                       debug_print("\t\t%s = %s\n", keyName, (gchar *) data);
+                       debug_print("\t\t%s = %s\n", keyName?keyName:"null", data?(gchar *)data:"null");
                else if (fd) {
                        FILE *stream = (FILE *) fd;
-                       fprintf(stream, "\t\t%s = %s\n", keyName, (gchar *) data);
+                       fprintf(stream, "\t\t%s = %s\n", keyName?keyName:"null", data?(gchar *)data:"null");
                }
        }
 }
@@ -247,11 +277,14 @@ void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd)
  * \param list List of GHashTable
  */
 void ldapsvr_free_hashtable(GList *list) {
-       while (list) {
-               g_hash_table_destroy(list->data);
-               list = g_list_next(list);
+       GList *tmp = list;
+       while (tmp) {
+               g_hash_table_destroy(tmp->data);
+               tmp->data = NULL;
+               tmp = g_list_next(tmp);
        }
        g_list_free(list);
+       list = NULL;
 }
 
 /**
@@ -263,7 +296,7 @@ void ldapsvr_free_hashtable(GList *list) {
  */
 ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
        AddrItemObject *aio;
-       g_return_val_if_fail(server != NULL || uid != NULL, NULL);
+       cm_return_val_if_fail(server != NULL || uid != NULL, NULL);
        aio = addrcache_get_object(server->addressCache, uid);
        if (aio) {
                if(aio->type == ITEMTYPE_PERSON) {
@@ -273,76 +306,6 @@ ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
        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
  *
@@ -358,6 +321,27 @@ Rdn *rdn_create() {
        return buf;
 }
 
+/**
+ * Free a created Rdn structure
+ * \param rdn Structure to free
+ */
+void rdn_free(Rdn *rdn) {
+       if (rdn->attribute) {
+               g_free(rdn->attribute);
+               rdn->attribute = NULL;
+       }
+       if (rdn->value) {
+               g_free(rdn->value);
+               rdn->value = NULL;
+       }
+       if (rdn->new_dn) {
+               g_free(rdn->new_dn);
+               rdn->new_dn = NULL;
+       }
+       g_free(rdn);
+       rdn = NULL;
+}
+
 /**
  * update Rdn structure
  *
@@ -367,7 +351,7 @@ Rdn *rdn_create() {
  */
 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);
+       rdn->new_dn = g_strdup_printf("%s=%s%s", rdn->attribute, head, tail);
 }
 
 /**
@@ -382,13 +366,14 @@ Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
        gchar *pos, *compare;
        gchar *rest;
        gchar *val;
-       g_return_val_if_fail(hash != NULL || dn != NULL, NULL);
+       cm_return_val_if_fail(hash != NULL || dn != NULL, NULL);
        
        pos = g_strstr_len(dn, strlen(dn), "=");
-       compare = g_strndup(dn, pos - dn);
-
        if (!pos)
                return NULL;
+
+       compare = g_strndup(dn, pos - dn);
+
        pos++;
        rest = g_strstr_len(pos, strlen(pos), ",");
        val = g_strndup(pos, rest - pos);
@@ -398,17 +383,16 @@ Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
                return NULL;
        }
        rdn = rdn_create();
-       rdn->value = g_strdup(val);
-       rdn->attribute = g_strdup(compare);
-       g_free(val);
+       rdn->value = val;
+       rdn->attribute = compare;
+
        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);
+                       compare = (gchar *) item->mail;
                        if (strcmp(compare, rdn->value) == 0) {
                                update_rdn(rdn, compare, rest);
-                               g_free(compare);
                                return rdn;
                        }
                        list = g_list_next(list);
@@ -417,27 +401,18 @@ Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
                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) {
+               if (compare != NULL && strcmp(compare, rdn->attribute) != 0) {
                        update_rdn(rdn, compare, rest);
                        return rdn;
                }
-               else {
-                       /* We cannot remove dn */
-                       return NULL;
-               }
        }
+       rdn_free(rdn);
        return NULL;
 }
 
@@ -489,10 +464,18 @@ void clean_up(LDAP *ld, LdapServer *server, GHashTable *contact) {
                if (displayName)
                        person->nickName = g_strdup(displayName);
        }
+       if (server->retVal != LDAPRC_SUCCESS) {
+               if (person) {
+                       ItemPerson *res = 
+                               addrcache_remove_person(server->addressCache, person);
+                       if (!res)
+                               g_critical("ldapsvr_update_book: Could not clean cache\n");
+                       else
+                               addritem_free_item_person(res);
+               }
+       }
        if (ld)
                ldapsvr_disconnect(ld);
-       ldapsvr_force_refresh(server);
-/*     ldapsvr_free_all_query(server);*/
 }
 
 /**
@@ -507,16 +490,20 @@ AttrKeyValue *get_cn(gchar *dn) {
        gchar *end;
        gchar *item;
        gchar **key_value;
-       g_return_val_if_fail(dn != NULL, NULL);
+       cm_return_val_if_fail(dn != NULL, NULL);
        
        cn = attrkeyvalue_create();
        start = g_strstr_len(dn, strlen(dn), "cn");
-       if (start == NULL)
+       if (start == NULL) {
+               attrkeyvalue_free(cn);
                return NULL;
+       }
        end = g_strstr_len(start, strlen(start), ",");
        item = g_strndup(start, end - start);
-       if (item == NULL)
+       if (item == NULL) {
+               attrkeyvalue_free(cn);
                return NULL;
+       }
        key_value = g_strsplit(item, "=", 2);
        cn->key = g_strdup(key_value[0]);
        cn->value = g_strdup(key_value[1]);
@@ -525,6 +512,40 @@ AttrKeyValue *get_cn(gchar *dn) {
        return cn;
 }
 
+/**
+ * Get mail attribute from dn
+ *
+ * \param dn Distinguesh Name for current object
+ * \return AttrKeyValue, or <i>NULL</i> if none created
+ */
+AttrKeyValue *get_mail(gchar *dn) {
+       AttrKeyValue *mail;
+       gchar *start;
+       gchar *end;
+       gchar *item;
+       gchar **key_value;
+       cm_return_val_if_fail(dn != NULL, NULL);
+       
+       mail = attrkeyvalue_create();
+       start = g_strstr_len(dn, strlen(dn), "mail");
+       if (start == NULL) {
+               attrkeyvalue_free(mail);
+               return NULL;
+       }
+       end = g_strstr_len(start, strlen(start), ",");
+       item = g_strndup(start, end - start);
+       if (item == NULL) {
+               attrkeyvalue_free(mail);
+               return NULL;
+       }
+       key_value = g_strsplit(item, "=", 2);
+       mail->key = g_strdup(key_value[0]);
+       mail->value = g_strdup(key_value[1]);
+       g_strfreev(key_value);
+       g_free(item);
+       return mail;
+}
+
 /**
  * Get ou or o attribute from dn
  *
@@ -538,18 +559,22 @@ AttrKeyValue *get_ou(gchar *dn) {
        gchar *item;
        gchar **key_value;
        
-       g_return_val_if_fail(dn != NULL, NULL);
+       cm_return_val_if_fail(dn != NULL, NULL);
        ou = attrkeyvalue_create();
        start = g_strstr_len(dn, strlen(dn), ",o=");
        if (start == NULL)
                start = g_strstr_len(dn, strlen(dn), ",ou=");
-       if (start == NULL)
+       if (start == NULL) {
+               attrkeyvalue_free(ou);
                return NULL;
+       }
        start++;
        end = g_strstr_len(start, strlen(start), ",");
        item = g_strndup(start, end - start);
-       if (item == NULL)
+       if (item == NULL) {
+               attrkeyvalue_free(ou);
                return NULL;
+       }
        key_value = g_strsplit(item, "=", 2);
        ou->key = g_strdup(key_value[0]);
        ou->value = g_strdup(key_value[1]);
@@ -567,7 +592,8 @@ void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
        gchar *mod_op;
        int i;
 
-       fprintf( stderr, "Type\n");
+       cm_return_if_fail(mods != NULL);
+       g_printerr( "Type\n");
        for (i = 0; NULL != mods[i]; i++) {
                LDAPMod *mod = (LDAPMod *) mods[i];
                gchar **vals;
@@ -577,12 +603,353 @@ void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
                        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);
+               g_printerr( "Operation: %s\tType:%s\nValues:\n", mod_op, mod->mod_type);
                vals = mod->mod_vals.modv_strvals;
                while (*vals) {
-                       fprintf( stderr, "\t%s\n", *vals++);
+                       g_printerr( "\t%s\n", *vals++);
+               }
+       }
+}
+
+/**
+ * Make a compare for every new value we want to store in the
+ * directory with the current values. Great tool for debugging
+ * against invalid syntax in attributes
+ *
+ * \param ld AddressBook resource
+ * \param dn dn for the entry
+ * \param cnt Number of attributes to compare
+ * \param  mods LDAPMod structure
+ */
+void ldapsvr_compare_attr(LDAP *ld, gchar *dn, gint cnt, LDAPMod *mods[]) {
+       int i, rc;
+
+#ifdef OPEN_LDAP_API_AT_LEAST_3000
+
+       struct berval val;
+
+#endif
+
+       cm_return_if_fail(ld != NULL || dn != NULL || cnt >= 0 || mods != NULL);
+       for (i = 0; i < cnt; i++) {
+               gchar *value = g_strdup(mods[i]->mod_vals.modv_strvals[0]);
+               if (!value || strcmp(value, "") == 0)
+                       value = g_strdup("thisisonlyadummy");
+
+#ifdef OPEN_LDAP_API_AT_LEAST_3000
+
+               val.bv_val = value;
+               val.bv_len = strlen(value);
+
+               rc = ldap_compare_ext_s(ld, dn, mods[i]->mod_type, &val, NULL, NULL);
+
+#else
+
+               /* This is deprecated as of OpenLDAP-2.3.0 */
+               rc = ldap_compare_s(ld, dn, mods[i]->mod_type, value);
+
+#endif
+
+               g_printerr("ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
+               mods[i]->mod_type, value, rc, ldaputil_get_error(ld));
+               g_free(value);
+       }
+}
+
+/**
+ * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING
+ *
+ * \param ld AddressBook resource
+ * \param server Reference to server
+ * \param dn dn for the entry
+ * \param attr Attribute
+ * \param value New value
+ * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
+ */
+int ldapsvr_compare_manual_attr(LDAP *ld, LdapServer *server, gchar *dn, char *attr, char *value) {
+       LDAPMessage *res, *e = NULL;
+       BerElement *ber;
+       struct berval **vals;
+       int rc;
+       LdapControl *ctl;
+       gchar *filter;
+       gchar *attribute;
+       int retVal = -2, i;
+       AttrKeyValue *mail;
+
+       cm_return_val_if_fail(ld != NULL || server != NULL || attr != NULL, -1);
+       ctl = server->control;
+       mail = get_mail(dn);
+       if (! mail)
+               return -2;
+       filter = g_strdup_printf("(&(mail=%s)(%s=*))", mail->value, attr);
+       attrkeyvalue_free(mail);
+       if (ctl) {
+
+               rc = ldap_search_ext_s(ld, ctl->baseDN, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, NULL, NULL, NULL, 0, &res);
+
+               if (rc) {
+                       g_printerr("ldap_search for attr=%s\" failed[0x%x]: %s\n",attr, rc, ldaputil_get_error(ld));
+                       retVal = -2;
+               }
+               else {
+                       e = ldap_first_entry(ld, res);
+                       /* entry has this attribute */
+                       if (e) {
+                               attribute = ldap_first_attribute( ld, e, &ber );
+                               if (attribute) {
+                                       if (value) {
+                                               if( ( vals = ldap_get_values_len( ld, e, attr ) ) != NULL ) {
+                                                       for( i = 0; vals[i] != NULL; i++ ) {
+                                                               debug_print("Compare: %s=%s\n", attr, vals[i]->bv_val);
+                                                               /* attribute has same value */
+                                                               if (strcmp(vals[i]->bv_val, value) == 0)
+                                                                       retVal = -1;
+                                                               /* attribute has new value */
+                                                               else
+                                                                       retVal = LDAP_MOD_REPLACE;
+                                                       }
+                                               }
+                                               ldap_value_free_len(vals);
+                                       }
+                                       else
+                                               retVal = LDAP_MOD_DELETE;
+                               }
+                               if( ber != NULL ) {
+                                       ber_free( ber, 0 );
+                               }
+                               ldap_memfree(attribute);
+                       }
+                       /* entry does not have this attribute */
+                       else {
+                               /* Only add if this is a real attribute */
+                               if (value)
+                                       retVal = LDAP_MOD_ADD;
+                               /* This is dummy value used to avoid ldap_compare error */
+                               else
+                                       retVal = -1;
+                       }
+               }
+       }
+       else
+               retVal = -2;
+       g_free(filter);
+       return retVal;
+}
+
+/**
+ * Deside which kind of operation is required to handle
+ * updating the specified attribute
+ *
+ * \param ld AddressBook resource
+ * \param server Reference to server
+ * \param dn dn for the entry
+ * \param attr Attribute
+ * \param value New value
+ * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
+ */
+int ldapsvr_deside_operation(LDAP *ld, LdapServer *server, char *dn, char *attr, char *value) {
+       int rc;
+       gboolean dummy = FALSE;
+
+#ifdef OPEN_LDAP_API_AT_LEAST_3000
+
+       struct berval val;
+
+#endif
+
+       cm_return_val_if_fail(ld != NULL || server != NULL || dn != NULL || attr != NULL, -1);
+       if (value == NULL)
+               return -1;
+       /* value containing empty string cause invalid syntax. A bug in
+        * the LDAP library? Therefore we add a dummy value
+        */
+       if (strcmp(value,"") == 0) {
+               value = g_strdup("thisisonlyadummy");
+               dummy = TRUE;
+       }
+
+#ifdef OPEN_LDAP_API_AT_LEAST_3000
+
+       val.bv_val = value;
+       val.bv_len = strlen(value);
+
+       rc = ldap_compare_ext_s(ld, dn, attr, &val, NULL, NULL);
+
+#else
+
+       /* This is deprecated as of OpenLDAP-2.3.0 */
+       rc = ldap_compare_s(ld, dn, attr, value);
+
+#endif
+
+       debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
+               attr, value, rc, ldaputil_get_error(ld));
+       switch (rc) {
+               case LDAP_COMPARE_FALSE: 
+                       if (dummy)
+                               return LDAP_MOD_DELETE;
+                       else
+                               return LDAP_MOD_REPLACE;
+               case LDAP_COMPARE_TRUE: return -1;
+               case LDAP_NO_SUCH_ATTRIBUTE: return LDAP_MOD_ADD;
+               /* LDAP_INAPPROPRIATE_MATCHING needs extensive testing because I
+                * am not aware off the condition causing this return value!
+                */
+               case LDAP_INAPPROPRIATE_MATCHING:
+                       if (dummy)
+                               value = NULL;
+                       return ldapsvr_compare_manual_attr(ld, server, dn, attr, value);
+               case LDAP_UNDEFINED_TYPE: return -2;
+               case LDAP_INVALID_SYNTAX: return -2;
+               default: return -2;
+       }
+}
+
+/**
+ * Check if attribute is part of the current search criteria
+ *
+ * \param list Array containing attributes in the current search criteria
+ * \param attr Attribute to check
+ * \result <i>TRUE</i> if attribute is found in the current search criteria
+ */
+gboolean ldapsvr_check_search_attributes(char **list, char *attr) {
+       while (*list) {
+               if (strcmp(*list++, attr) == 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Deside which other attributes needs updating
+ *
+ * \param ld LDAP resource
+ * \param server AddressBook resource
+ * \param dn dn for the entry
+ * \param contact GHashTable with information for the current contact
+ */
+void ldapsvr_handle_other_attributes(LDAP *ld, LdapServer *server, char *dn, GHashTable *contact) {
+       GList *node;
+       gboolean CHECKED_ATTRIBUTE[ATTRIBUTE_SIZE + 1];
+       LDAPMod *mods[ATTRIBUTE_SIZE + 1];
+       LDAPMod modarr[ATTRIBUTE_SIZE];
+       gint cnt = 0;
+       char *attr[ATTRIBUTE_SIZE + 1][2];
+       int mod_op, rc, i;
+
+       cm_return_if_fail(server != NULL || dn != NULL || contact != NULL);
+       for (i = 0; i <= ATTRIBUTE_SIZE; i++) {
+               CHECKED_ATTRIBUTE[i] = FALSE;
+               attr[i][0] = attr[i][1] = NULL;
+       }
+       node = g_hash_table_lookup(contact , "attribute");
+       while (node) {
+               AttrKeyValue *item = node->data;
+               if (item) {
+                       int index = get_attribute_index(item->key);
+                       if (index >= 0) {
+                               debug_print("Found other attribute: %s = %s\n",
+                                               item->key?item->key:"null", item->value?item->value:"null");
+                               mod_op = ldapsvr_deside_operation(ld, server, dn, item->key, item->value);
+                               /* Only consider attributes which we no how to handle.
+                                * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action
+                                */
+                               if (mod_op < 0) {
+                                       CHECKED_ATTRIBUTE[index] = TRUE;
+                                       node = g_list_next(node);
+                                       continue;
+                               }
+                               if (mod_op == LDAP_MOD_DELETE) {
+                                       /* Setting param to NULL instructs OpenLDAP to remove any
+                                       * value stored for this attribute and remove the attribute
+                                       * completely. Should multiple instances of an attribute be
+                                       * allowed in the future param is required to have the value
+                                       * store for the attribute which is going to be deleted
+                                       */
+                                       item->value = NULL;
+                               }
+                               if (mod_op == LDAP_MOD_REPLACE && strcmp(item->value, "") == 0) {
+                                       /* Having an empty string is considered a syntax error in
+                                       * ldap. E.g attributes with empty strings are not allowed
+                                       * in which case we treate this as a request for deleting
+                                       * the attribute.
+                                       */
+                                       mod_op = LDAP_MOD_DELETE;
+                                       item->value = NULL;
+                               }
+                               if (mod_op == LDAP_MOD_ADD && strcmp(item->value, "") == 0) {
+                                       /* Adding an empty string is considered a syntax error in
+                                       * ldap. E.g attributes with empty strings are not allowed
+                                       * in which case we silently refuse to add this entry
+                                       */
+                               }
+                               else {
+                                       SETMOD(mods[cnt], modarr[cnt], mod_op, g_strdup(item->key), attr[cnt], g_strdup(item->value));
+                                       cnt++;
+                                       CHECKED_ATTRIBUTE[index] = TRUE;
+                               }
+                       }
+               }
+               node = g_list_next(node);
+       }
+       char **attribs = ldapctl_full_attribute_array(server->control);
+       for (i = 0; i < ATTRIBUTE_SIZE; i++) {
+               /* Attributes which holds no information are to be removed */
+               if (CHECKED_ATTRIBUTE[i] == FALSE) {
+                       /* Only consider those attributes which is currently part of the search criteria.
+                        * If attributes are not part of the search criteria they would seem to hold
+                        * no information since their values will not be populated in the GUI
+                        */
+                       if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) {
+                               debug_print("not updating jpegPhoto\n");
+                               continue;
+                       }
+                       if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) {
+                               mod_op = ldapsvr_deside_operation(ld, server, dn, (char *) ATTRIBUTE[i], "");
+                               if (mod_op == LDAP_MOD_DELETE) {
+                                       SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_DELETE, g_strdup((char *) ATTRIBUTE[i]), attr[cnt], NULL);
+                                       cnt++;
+                               }
+                       }
+               }
+       }
+       ldapctl_free_attribute_array(attribs);
+       mods[cnt] = NULL;
+       if (debug_get_mode())
+               ldapsvr_print_ldapmod(mods);
+       server->retVal = LDAPRC_SUCCESS;
+       rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
+       if (rc) {
+               switch (rc) {
+                       case LDAP_ALREADY_EXISTS: 
+                               server->retVal = LDAPRC_ALREADY_EXIST;
+                               break;
+                       default:
+                               g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld));
+                               if (rc == 0x8)
+                                       server->retVal = LDAPRC_STRONG_AUTH;
+                               else
+                                       server->retVal = LDAPRC_NAMING_VIOLATION;
                }
        }
+       else {
+               char **attribs = ldapctl_full_attribute_array(server->control);
+               for (i = 0; i < ATTRIBUTE_SIZE; i++) {
+                       if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) {
+                               debug_print("not updating jpegPhoto\n");
+                               continue;
+                       }
+                       if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) {
+                               if (CHECKED_ATTRIBUTE[i] == FALSE) {
+                                       AddrItemObject *aio = addrcache_get_object(server->addressCache, g_hash_table_lookup(contact , "uid"));
+                                       ItemPerson *person = (ItemPerson *) aio;
+                                       addritem_person_remove_attribute(person, (const gchar *) ATTRIBUTE[i]);
+                               }
+                       }
+               }
+               ldapctl_free_attribute_array(attribs);
+       }
 }
 
 /**
@@ -611,7 +978,7 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
        gchar *base_dn;
        GList *mailList;
 
-       g_return_if_fail(server != NULL || contact != NULL);
+       cm_return_if_fail(server != NULL || contact != NULL);
        node = g_hash_table_lookup(contact , "mail");
        if (node) {
                EmailKeyValue *newEmail = node->data;
@@ -619,9 +986,11 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
        }
        if (email == NULL) {
                server->retVal = LDAPRC_NODN;
+               clean_up(ld, server, contact);
                return;
        }
-       base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN);
+       base_dn = g_strdup_printf("mail=%s,%s",
+                       email, server->control->baseDN?server->control->baseDN:"null");
        g_free(email);
        person = 
                ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
@@ -637,8 +1006,9 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
        cnt++;
        ou = get_ou(base_dn);
        if (ou != NULL) {
-               SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, ou->key, org, ou->value);
+               SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(ou->key), org, g_strdup(ou->value));
                cnt++;
+               attrkeyvalue_free(ou);
        }
        
        commonName = get_cn(base_dn);
@@ -654,11 +1024,12 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
                }
        }
        else {
-               SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, commonName->key, cn, commonName->value);
+               SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(commonName->key), cn, g_strdup(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);
+               attrkeyvalue_free(commonName);
        }
        cnt++;
        param = g_hash_table_lookup(contact , "givenName");
@@ -669,8 +1040,7 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
        mailList = g_hash_table_lookup(contact , "mail");
        if (mailList) {
                char **tmp;
-               mail = g_malloc(sizeof(*mail));
-               tmp = g_malloc(sizeof(*tmp));
+               tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
                mail = tmp;
                while (mailList) {
                        EmailKeyValue *item = mailList->data;
@@ -698,13 +1068,15 @@ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
                                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));
+                               g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
+                                               base_dn, rc, ldaputil_get_error(ld));
                                if (rc == 0x8)
                                        server->retVal = LDAPRC_STRONG_AUTH;
                                else
                                        server->retVal = LDAPRC_NAMING_VIOLATION;
                }
        }
+       ldapsvr_handle_other_attributes(ld, server, base_dn, contact);
        g_free(base_dn);
        clean_up(ld, server, contact);
 }
@@ -727,14 +1099,16 @@ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
        char **mail = NULL;
        char *sn[] = {NULL, NULL};
        GList *mailList;
+       int mod_op;
 
-       g_return_if_fail(server != NULL || contact != NULL);
+       cm_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;
@@ -743,7 +1117,18 @@ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
        if (NoRemove) {
                /* We are trying to change RDN */
                gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value);
+
+#ifdef OPEN_LDAP_API_AT_LEAST_3000
+
+               int rc = ldap_rename_s(ld, dn, newRdn, NULL, 1, NULL, NULL);
+
+#else
+
+               /* This is deprecated as of OpenLDAP-2.3.0 */
                int rc = ldap_modrdn2_s(ld, dn, newRdn, 1);
+
+#endif
+
                if(rc != LDAP_SUCCESS) {
                        if (rc ==  LDAP_ALREADY_EXISTS) {
                                /* We are messing with a contact with more than one listed email
@@ -755,16 +1140,23 @@ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
                                 */
                        }
                        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_printerr("Current dn: %s\n", dn);
+                               g_printerr("new dn: %s\n", newRdn);
+                               g_printerr("LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldaputil_get_error(ld));
                                g_free(newRdn);
+                               clean_up(ld, server, contact);
                                return;
                        }
                }
                else {
+                       ItemPerson *person = g_hash_table_lookup(contact, "person");
                        g_free(newRdn);
                        dn = g_strdup(NoRemove->new_dn);
+                       g_hash_table_replace(contact, "dn", dn);
+                       if (person) {
+                               g_free(person->externalID);
+                               person->externalID = dn;
+                       }
                }
        }
        else {
@@ -773,22 +1165,76 @@ void ldapsvr_update_contact(LdapServer *server, GHashTable *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, "displayName", cn, param);
-               cnt++;
-               g_hash_table_insert(contact, "displayName", param);
+       mod_op = ldapsvr_deside_operation(ld, server, dn, "displayName", param);
+       if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) {
+               if (mod_op == LDAP_MOD_DELETE) {
+                       /* Setting param to NULL instructs OpenLDAP to remove any
+                        * value stored for this attribute and remove the attribute
+                        * completely. Should multiple instances of an attribute be
+                        * allowed in the future param is required to have the value
+                        * store for the attribute which is going to be deleted
+                        */
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
+                       /* Having an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we treate this as a request for deleting
+                        * the attribute.
+                        */
+                       mod_op = LDAP_MOD_DELETE;
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
+                       /* Adding an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we silently refuse to add this entry
+                        */
+               }
+               else {
+                       SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param);
+                       cnt++;
+                       g_hash_table_insert(contact, "displayName", param);
+               }
        }
        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++;
+       mod_op = ldapsvr_deside_operation(ld, server, dn, "givenName", param);
+       if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) {
+               if (mod_op == LDAP_MOD_DELETE) {
+                       /* Setting param to NULL instructs OpenLDAP to remove any
+                        * value stored for this attribute and remove the attribute
+                        * completely. Should multiple instances of an attribute be
+                        * allowed in the future param is required to have the value
+                        * store for the attribute which is going to be deleted
+                        */
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
+                       /* Having an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we treate this as a request for deleting
+                        * the attribute.
+                        */
+                       mod_op = LDAP_MOD_DELETE;
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
+                       /* Adding an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we silently refuse to add this entry
+                        */
+               }
+               else {
+                       SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param);
+                       cnt++;
+               }
        }
        mailList = g_hash_table_lookup(contact , "mail");
        if (mailList) {
+               debug_print("# of mail: %d\n", g_list_length(mailList));
                if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) {
                        char **tmp;
-                       mail = g_malloc(sizeof(*mail));
-                       tmp = g_malloc(sizeof(*tmp));
+                       tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
                        mail = tmp;
                        while (mailList) {
                                EmailKeyValue *item = mailList->data;
@@ -796,31 +1242,74 @@ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
                                mailList = g_list_next(mailList);
                        }
                        *tmp = NULL;
+                       /*
+                        * At least one email address is required
+                        * in which case it will always be a replace
+                        */
                        SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail);
                        cnt++;
                }
        }
+       else {
+               /*
+                * an error condition since at least one email adress
+                * is required. Should never occur though.
+                */
+       }
        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++;
+       mod_op = ldapsvr_deside_operation(ld, server, dn, "sn", param);
+       if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) {
+               if (mod_op == LDAP_MOD_DELETE) {
+                       /* Setting param to NULL instructs OpenLDAP to remove any
+                        * value stored for this attribute and remove the attribute
+                        * completely. Should multiple instances of an attribute be
+                        * allowed in the future param is required to have the value
+                        * store for the attribute which is going to be deleted
+                        */
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
+                       /* Having an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we treate this as a request for deleting
+                        * the attribute.
+                        */
+                       mod_op = LDAP_MOD_DELETE;
+                       param = NULL;
+               }
+               if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
+                       /* Adding an empty string is considered a syntax error in
+                        * ldap. E.g attributes with empty strings are not allowed
+                        * in which case we silently refuse to add this entry
+                        */
+               }
+               else {
+                       SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param);
+                       cnt++;
+               }
        }
        debug_print("newDN: %s\n", dn);
        if (NoRemove)
-               g_free(NoRemove);
+               rdn_free(NoRemove);
        server->retVal = LDAPRC_SUCCESS;
        if (cnt > 0) {
                int rc;
                mods[cnt] = NULL;
                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));
+                       g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
+                    dn, rc, ldaputil_get_error(ld));
                        server->retVal = LDAPRC_NAMING_VIOLATION;
                }
                if (mail)
                        g_free(mail);
        }
+       ldapsvr_handle_other_attributes(ld, server, dn, contact);
+       /* If we do not make changes persistent at this point then changes
+        * will be lost if the user makes new search on the same server since
+        * changes are only present in Claws' internal cache. This issue has to
+        * be solved in addressbook.c since this involves access to structures
+        * which are only accessible in addressbook.c */
        clean_up(ld, server, contact);
 }
 
@@ -835,7 +1324,7 @@ void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
        gchar *dn;
        int rc;
 
-       g_return_if_fail(server != NULL || contact != NULL);
+       cm_return_if_fail(server != NULL || contact != NULL);
        ld = ldapsvr_connect(server->control);
        if (ld == NULL) {
                clean_up(ld, server, contact);
@@ -846,10 +1335,11 @@ void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
                clean_up(ld, server, contact);
                return;
        }
+       server->retVal = LDAPRC_SUCCESS;
        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));
+               g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
+                               dn, rc, ldaputil_get_error(ld));
                server->retVal = LDAPRC_NODN;
        }
        clean_up(ld, server, contact);
@@ -866,7 +1356,7 @@ void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
        GHashTable *contact = NULL;
        GList *contacts = NULL, *head = NULL;
 
-       g_return_if_fail(server != NULL);
+       cm_return_if_fail(server != NULL);
        debug_print("updating ldap addressbook\n");
 
        contact = g_hash_table_new(g_str_hash, g_str_equal);
@@ -883,9 +1373,6 @@ void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
        else {
                ItemFolder *folder = server->addressCache->rootFolder;
                node = folder->listFolder;
-               if (node)
-                       node = g_list_copy(node);
-               node = g_list_prepend(node, server->addressCache->rootFolder);
                if (node) {
                        while (node) {
                                AddrItemObject *aio = node->data;
@@ -915,11 +1402,10 @@ void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
                                        }
                                }
                                else {
-                                       fprintf(stderr, "\t\tpid : ???\n");
+                                       g_printerr("\t\tpid : ???\n");
                                }
                                node = g_list_next(node);
                        }
-                       g_list_free(node);
                }
        }
        head = contacts;
@@ -951,7 +1437,7 @@ void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
                        ldapsvr_delete_contact(server, contact);
                }
                else
-                       g_critical(_("ldapsvr_update_book->Unknown status: %s\n"), status);
+                       g_critical("ldapsvr_update_book->Unknown status: %s\n", status);
                contacts = g_list_next(contacts);
        }
        ldapsvr_free_hashtable(head);