2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2007 Michael Rasmussen and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * Functions necessary to access LDAP servers.
26 * 1) When adding a contact to an empty addressbook from the pop-up menu
27 * when right-clicking on an email address causes claws-mail to crash in
28 * addritem.c line 965. Severity: Show stopper.
29 * 2) Updating a contact gets lost if the user makes a new search on the
30 * same LdapServer. Severity: Medium.
31 * 3) After adding a new contact the displayName for the contact is empty
32 * until the user makes a reread from the LdapServer. Severity: minor.
42 #include <glib/gi18n.h>
48 #include "ldapupdate.h"
51 #include "addrcache.h"
53 #include "ldapquery.h"
54 #include "ldapserver.h"
57 #include "adbookbase.h"
60 * Structure to hold user defined attributes
63 typedef struct _AttrKeyValue AttrKeyValue;
64 struct _AttrKeyValue {
70 * Structure to hold contact information.
71 * Each addressbook will have 0..N contacts.
73 typedef struct _EmailKeyValue EmailKeyValue;
74 struct _EmailKeyValue {
81 * Structure to hold information about RDN.
83 typedef struct _Rdn Rdn;
91 * Retrieve address group item for update.
92 * \param group Group to print.
93 * \param array GHashTAble of item_group, or <i>NULL</i> if none created.
95 void ldapsvr_retrieve_item_group(ItemGroup *group, GHashTable *array) {
96 /* Not implemented in this release */
97 g_return_if_fail(group != NULL);
101 * Create an initial EmailKeyValue structure
102 * \return empty structure
104 EmailKeyValue *emailkeyvalue_create() {
107 buf = g_new0(EmailKeyValue, 1);
115 * Create an initial AttrKeyValue structure
116 * \return empty structure
118 AttrKeyValue *attrkeyvalue_create() {
121 buf = g_new0(AttrKeyValue, 1);
128 * Retrieve E-Mail address object for update.
129 * \param item ItemEmail to update.
130 * \return object, or <i>NULL</i> if none created.
132 EmailKeyValue *ldapsvr_retrieve_item_email(ItemEMail *item) {
133 EmailKeyValue *newItem;
134 g_return_val_if_fail(item != NULL, NULL);
135 newItem = emailkeyvalue_create();
136 newItem->alias = g_strdup(ADDRITEM_NAME(item));
137 newItem->mail = g_strdup(item->address);
138 newItem->remarks = g_strdup(item->remarks);
143 * Retrieve user attribute object for update.
144 * \param item UserAttribute to update.
145 * \return object, or <i>NULL</i> if none created.
147 AttrKeyValue *ldapsvr_retrieve_attribute(UserAttribute *item) {
148 AttrKeyValue *newItem;
149 g_return_val_if_fail(item != NULL, NULL);
150 newItem = attrkeyvalue_create();
151 newItem->key = g_strdup(item->name);
152 newItem->value = g_strdup(item->value);
157 * Retrieve person object for update.
158 * \param person ItemPerson to update.
159 * \param array GHashTable with user input.
160 * \return false if update is not needed, or true if update is needed.
162 gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
165 g_return_val_if_fail(person != NULL, FALSE);
166 switch (person->status) {
167 case NONE: return FALSE;
168 case ADD_ENTRY: g_hash_table_insert(array, "status", "new"); break;
169 case UPDATE_ENTRY: g_hash_table_insert(array, "status", "update"); break;
170 case DELETE_ENTRY: g_hash_table_insert(array, "status", "delete"); break;
171 default: g_critical(_("ldapsvr_retrieve_item_person->Unknown status: %d"), person->status);
173 g_hash_table_insert(array, "uid", ADDRITEM_ID(person));
174 g_hash_table_insert(array, "cn", ADDRITEM_NAME(person));
175 g_hash_table_insert(array, "givenName", person->firstName);
176 g_hash_table_insert(array, "sn", person->lastName);
177 g_hash_table_insert(array, "nickName", person->nickName);
178 g_hash_table_insert(array, "dn", person->externalID);
179 node = person->listEMail;
182 EmailKeyValue *newEmail = ldapsvr_retrieve_item_email(node->data);
184 attr = g_list_append(attr, newEmail);
185 node = g_list_next(node);
187 g_hash_table_insert(array, "mail", attr);
188 /* Not implemented in this release.
189 node = person->listAttrib;
192 AttrKeyValue *newAttr = ldapsvr_retrieve_attribute(node->data)
194 attr = g_list_append(attr, newAttr);
195 node = g_list_next(node);
197 g_hash_table_insert(array, "attribute", attr);
203 * Print contents of contacts hashtable for debug.
204 * This function must be called with g_hash_table_foreach.
205 * \param key Key to process.
206 * \param data Data to process.
207 * \param fd Output stream.
209 void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd) {
210 gchar *keyName = (gchar *) key;
213 if (g_ascii_strcasecmp("mail", keyName) == 0) {
214 node = (GList *) data;
216 EmailKeyValue *item = node->data;
217 if (debug_get_mode()) {
218 debug_print("\t\talias = %s\n", item->alias);
219 debug_print("\t\tmail = %s\n", item->mail);
220 debug_print("\t\tremarks = %s\n", item->remarks);
223 FILE *stream = (FILE *) fd;
224 fprintf(stream, "\t\talias = %s\n", item->alias);
225 fprintf(stream, "\t\tmail = %s\n", item->mail);
226 fprintf(stream, "\t\tremarks = %s\n", item->remarks);
228 node = g_list_next(node);
231 else if (g_ascii_strcasecmp("attribute", keyName) == 0) {
232 node = (GList *) data;
234 AttrKeyValue *item = node->data;
235 if (debug_get_mode()) {
236 debug_print("\t\t%s = %s\n", item->key, item->value);
239 FILE *stream = (FILE *) fd;
240 fprintf(stream, "\t\t%s = %s\n", item->key, item->value);
242 node = g_list_next(node);
246 if (debug_get_mode())
247 debug_print("\t\t%s = %s\n", keyName, (gchar *) data);
249 FILE *stream = (FILE *) fd;
250 fprintf(stream, "\t\t%s = %s\n", keyName, (gchar *) data);
256 * Free list of changed contacts
258 * \param list List of GHashTable
260 void ldapsvr_free_hashtable(GList *list) {
262 g_hash_table_destroy(list->data);
263 list = g_list_next(list);
269 * Get person object from cache
271 * \param server Resource to LDAP
272 * \param uid PersonID in cache
273 * \return person object, or <i>NULL</i> if fail
275 ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
277 g_return_val_if_fail(server != NULL || uid != NULL, NULL);
278 aio = addrcache_get_object(server->addressCache, uid);
280 if(aio->type == ITEMTYPE_PERSON) {
281 return (ItemPerson *) aio;
288 * Connect to LDAP server.
289 * \param ctl Control object to process.
290 * \return LDAP Resource to LDAP.
292 LDAP *ldapsvr_connect(LdapControl *ctl) {
298 g_return_val_if_fail(ctl != NULL, NULL);
300 uri = g_strdup_printf("ldap%s://%s:%d",
301 ctl->enableSSL?"s":"",
302 ctl->hostName, ctl->port);
303 ldap_initialize(&ld, uri);
309 debug_print("connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
313 version = LDAP_VERSION3;
314 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
315 if (rc == LDAP_OPT_SUCCESS) {
316 ctl->version = LDAP_VERSION3;
319 if (ctl->version == LDAP_VERSION3) {
320 if (ctl->enableTLS && !ctl->enableSSL) {
321 rc = ldap_start_tls_s(ld, NULL, NULL);
323 if (rc != LDAP_SUCCESS) {
324 fprintf(stderr, "LDAP Error(tls): ldap_simple_bind_s: %s\n",
325 ldap_err2string(rc));
332 /* Bind to the server, if required */
334 if (* ctl->bindDN != '\0') {
335 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, ctl->bindPass);
336 if (rc != LDAP_SUCCESS) {
337 fprintf(stderr, "bindDN: %s, bindPass: %s\n", ctl->bindDN, ctl->bindPass);
338 fprintf(stderr, "LDAP Error(bind): ldap_simple_bind_s: %s\n",
339 ldap_err2string(rc));
348 * Disconnect to LDAP server.
349 * \param ld Resource to LDAP.
351 void ldapsvr_disconnect(LDAP *ld) {
353 g_return_if_fail(ld != NULL);
354 ldap_unbind_ext(ld, NULL, NULL);
358 * Create an initial Rdn structure
360 * \return empty structure
365 buf = g_new0(Rdn, 1);
366 buf->attribute = NULL;
373 * update Rdn structure
375 * \param rdn Rdn structure to update
376 * \param head Uniq part of dn
377 * \param tail Common part of dn
379 void update_rdn(Rdn *rdn, gchar *head, gchar *tail) {
380 rdn->value = g_strdup(head);
381 rdn->new_dn = g_strdup_printf("mail=%s%s", head, tail);
385 * Deside if dn needs to be changed
387 * \param hash GHashTable with user input.
388 * \param dn dn for current object
389 * \return Rdn structure
391 Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
393 gchar *pos, *compare;
396 g_return_val_if_fail(hash != NULL || dn != NULL, NULL);
398 pos = g_strstr_len(dn, strlen(dn), "=");
399 compare = g_strndup(dn, pos - dn);
404 rest = g_strstr_len(pos, strlen(pos), ",");
405 val = g_strndup(pos, rest - pos);
412 rdn->value = g_strdup(val);
413 rdn->attribute = g_strdup(compare);
415 if (strcmp("mail", rdn->attribute) == 0) {
416 GList *list = g_hash_table_lookup(hash, rdn->attribute);
418 EmailKeyValue *item = list->data;
419 compare = g_strdup((gchar *) item->mail);
420 if (strcmp(compare, rdn->value) == 0) {
421 update_rdn(rdn, compare, rest);
425 list = g_list_next(list);
427 /* if compare and rdn->attribute are equal then last email removed/empty */
428 if (strcmp(compare, rdn->attribute) != 0) {
429 /* RDN changed. Find new */
430 update_rdn(rdn, compare, rest);
435 /* We cannot remove dn */
441 compare = g_hash_table_lookup(hash, rdn->attribute);
442 /* if compare and rdn->attribute are equal then dn removed/empty */
443 if (strcmp(compare, rdn->attribute) != 0) {
444 update_rdn(rdn, compare, rest);
448 /* We cannot remove dn */
456 * This macro is borrowed from the Balsa project
457 * Creates a LDAPMod structure
459 * \param mods Empty LDAPMod structure
460 * \param modarr Array with values to insert
461 * \param op Operation to perform on LDAP
462 * \param attr Attribute to insert
463 * \param strv Empty array which is NULL terminated
464 * \param val Value for attribute
466 #define SETMOD(mods,modarr,op,attr,strv,val) \
467 do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
468 (strv)[0]=(val); (modarr).mod_values=strv; \
472 * Creates a LDAPMod structure
474 * \param mods Empty LDAPMod structure
475 * \param modarr Array with values to insert
476 * \param op Operation to perform on LDAP
477 * \param attr Attribute to insert
478 * \param strv Array with values to insert. Must be NULL terminated
480 #define SETMODS(mods,modarr,op,attr,strv) \
481 do { (mods) = &(modarr); (modarr).mod_type=attr; \
482 (modarr).mod_op=op; (modarr).mod_values=strv; \
487 * Clean up, close LDAP connection, and refresh cache
489 * \param ld Resource to LDAP
490 * \param server AddressBook resource
491 * \param contact GHashTable with current changed object
493 void clean_up(LDAP *ld, LdapServer *server, GHashTable *contact) {
495 ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
498 person->status = NONE;
499 displayName = g_hash_table_lookup(contact, "displayName");
501 person->nickName = g_strdup(displayName);
504 ldapsvr_disconnect(ld);
505 /* ldapsvr_force_refresh(server);
506 ldapsvr_free_all_query(server);*/
510 * Get cn attribute from dn
512 * \param dn Distinguesh Name for current object
513 * \return AttrKeyValue, or <i>NULL</i> if none created
515 AttrKeyValue *get_cn(gchar *dn) {
521 g_return_val_if_fail(dn != NULL, NULL);
523 cn = attrkeyvalue_create();
524 start = g_strstr_len(dn, strlen(dn), "cn");
527 end = g_strstr_len(start, strlen(start), ",");
528 item = g_strndup(start, end - start);
531 key_value = g_strsplit(item, "=", 2);
532 cn->key = g_strdup(key_value[0]);
533 cn->value = g_strdup(key_value[1]);
534 g_strfreev(key_value);
540 * Get ou or o attribute from dn
542 * \param dn Distinguesh Name for current object
543 * \return AttrKeyValue, or <i>NULL</i> if none created
545 AttrKeyValue *get_ou(gchar *dn) {
552 g_return_val_if_fail(dn != NULL, NULL);
553 ou = attrkeyvalue_create();
554 start = g_strstr_len(dn, strlen(dn), ",o=");
556 start = g_strstr_len(dn, strlen(dn), ",ou=");
560 end = g_strstr_len(start, strlen(start), ",");
561 item = g_strndup(start, end - start);
564 key_value = g_strsplit(item, "=", 2);
565 ou->key = g_strdup(key_value[0]);
566 ou->value = g_strdup(key_value[1]);
567 g_strfreev(key_value);
573 * Print the contents of a LDAPMod structure for debuging purposes
575 * \param mods LDAPMod structure
577 void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
581 g_return_if_fail(mods != NULL);
582 fprintf( stderr, "Type\n");
583 for (i = 0; NULL != mods[i]; i++) {
584 LDAPMod *mod = (LDAPMod *) mods[i];
586 switch (mod->mod_op) {
587 case LDAP_MOD_ADD: mod_op = g_strdup("ADD"); break;
588 case LDAP_MOD_REPLACE: mod_op = g_strdup("MODIFY"); break;
589 case LDAP_MOD_DELETE: mod_op = g_strdup("DELETE"); break;
590 default: mod_op = g_strdup("UNKNOWN");
592 fprintf( stderr, "Operation: %s\tType:%s\nValues:\n", mod_op, mod->mod_type);
593 vals = mod->mod_vals.modv_strvals;
595 fprintf( stderr, "\t%s\n", *vals++);
601 * Make a compare for every new value we want to store in the
602 * directory with the current values. Great tool for debugging
603 * against invalid syntax in attributes
605 * \param ld AddressBook resource
606 * \param dn dn for the entry
607 * \param cnt Number of attributes to compare
608 * \param mods LDAPMod structure
610 void ldapsvr_compare_attr(LDAP *ld, gchar *dn, gint cnt, LDAPMod *mods[]) {
613 g_return_if_fail(ld != NULL || dn != NULL || cnt >= 0 || mods != NULL);
614 for (i = 0; i < cnt; i++) {
615 rc = ldap_compare_s(ld, dn, mods[i]->mod_type, mods[i]->mod_vals.modv_strvals[0]);
616 fprintf(stderr, "ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
617 mods[i]->mod_type, mods[i]->mod_vals.modv_strvals[0], rc, ldap_err2string(rc));
622 * Add new contact to LDAP
624 * \param server AddressBook resource
625 * \param contact GHashTable with object to add
627 void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
628 gchar *email = NULL, *param = NULL;
630 LDAPMod *mods[MODSIZE];
633 char *cn[] = {NULL, NULL};
634 char *displayName[] = {NULL, NULL};
635 char *givenName[] = {NULL, NULL};
637 char *sn[] = {NULL, NULL};
638 char *org[] = {NULL, NULL};
639 char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL};
642 AttrKeyValue *ou, *commonName;
647 g_return_if_fail(server != NULL || contact != NULL);
648 node = g_hash_table_lookup(contact , "mail");
650 EmailKeyValue *newEmail = node->data;
651 email = g_strdup(newEmail->mail);
654 server->retVal = LDAPRC_NODN;
657 base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN);
660 ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
661 person->externalID = g_strdup(base_dn);
662 debug_print("dn: %s\n", base_dn);
663 ld = ldapsvr_connect(server->control);
665 clean_up(ld, server, contact);
666 debug_print("no ldap found\n");
669 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj);
671 ou = get_ou(base_dn);
673 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, ou->key, org, ou->value);
677 commonName = get_cn(base_dn);
678 if (commonName == NULL) {
679 param = g_hash_table_lookup(contact , "cn");
681 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param);
684 clean_up(ld, server, contact);
685 debug_print("no CN found\n");
690 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, commonName->key, cn, commonName->value);
692 param = g_hash_table_lookup(contact , "cn");
693 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "displayName", displayName, param);
694 g_hash_table_insert(contact, "displayName", param);
697 param = g_hash_table_lookup(contact , "givenName");
699 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param);
702 mailList = g_hash_table_lookup(contact , "mail");
705 mail = g_malloc(sizeof(*mail));
706 tmp = g_malloc(sizeof(*tmp));
709 EmailKeyValue *item = mailList->data;
710 *tmp++ = g_strdup((gchar *) item->mail);
711 mailList = g_list_next(mailList);
714 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail);
717 param = g_hash_table_lookup(contact, "sn");
719 param = g_strdup(N_("Some SN"));
720 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param);
723 if (debug_get_mode()) {
724 ldapsvr_print_ldapmod(mods);
726 server->retVal = LDAPRC_SUCCESS;
727 rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL);
730 case LDAP_ALREADY_EXISTS:
731 server->retVal = LDAPRC_ALREADY_EXIST;
734 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",base_dn, rc, ldap_err2string(rc));
736 server->retVal = LDAPRC_STRONG_AUTH;
738 server->retVal = LDAPRC_NAMING_VIOLATION;
742 clean_up(ld, server, contact);
746 * Deside which kind of operation is required to handle
747 * updating the specified attribute
749 * \param ld AddressBook resource
750 * \param dn dn for the entry
751 * \param attr Attribute
752 * \param value New value
753 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
755 int ldapsvr_deside_operation(LDAP *ld, char *dn, char *attr, char *value) {
757 gboolean dummy = FALSE;
759 g_return_val_if_fail(ld != NULL || dn != NULL || attr != NULL, -1);
762 /* value containing empty string cause invalid syntax. A bug in
763 * the LDAP library? Therefore we add a dummy value
765 if (strcmp(value,"") == 0) {
766 value = g_strdup("thisisonlyadummy");
769 rc = ldap_compare_s(ld, dn, attr, value);
770 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
771 attr, value, rc, ldap_err2string(rc));
773 case LDAP_COMPARE_FALSE:
775 return LDAP_MOD_DELETE;
777 return LDAP_MOD_REPLACE;
778 case LDAP_COMPARE_TRUE: return -1;
779 case LDAP_NO_SUCH_ATTRIBUTE: return LDAP_MOD_ADD;
780 case LDAP_UNDEFINED_TYPE: return -2;
781 case LDAP_INVALID_SYNTAX: return -2;
787 * Update contact to LDAP
789 * \param server AddressBook resource
790 * \param contact GHashTable with object to update
792 void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
794 LDAPMod *mods[MODSIZE];
798 Rdn *NoRemove = NULL;
799 char *cn[] = {NULL, NULL};
800 char *givenName[] = {NULL, NULL};
802 char *sn[] = {NULL, NULL};
806 g_return_if_fail(server != NULL || contact != NULL);
807 ld = ldapsvr_connect(server->control);
809 clean_up(ld, server, contact);
812 dn = g_hash_table_lookup(contact, "dn");
814 clean_up(ld, server, contact);
817 NoRemove = ldapsvr_modify_dn(contact, dn);
819 /* We are trying to change RDN */
820 gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value);
821 int rc = ldap_modrdn2_s(ld, dn, newRdn, 1);
822 if(rc != LDAP_SUCCESS) {
823 if (rc == LDAP_ALREADY_EXISTS) {
824 /* We are messing with a contact with more than one listed email
825 * address and the email we are changing is not the one used for dn
827 /* It needs to be able to handle renaming errors to an already defined
828 * dn. For now we just refuse the update. It will be caught later on as
829 * a LDAPRC_NAMING_VIOLATION error.
833 fprintf(stderr, "Current dn: %s\n", dn);
834 fprintf(stderr, "new dn: %s\n", newRdn);
835 fprintf(stderr, "LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldap_err2string(rc));
842 dn = g_strdup(NoRemove->new_dn);
846 server->retVal = LDAPRC_NODN;
847 clean_up(ld, server, contact);
850 param = g_hash_table_lookup(contact , "cn");
851 mod_op = ldapsvr_deside_operation(ld, dn, "displayName", param);
852 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) {
853 if (mod_op == LDAP_MOD_DELETE) {
854 /* Setting param to NULL instructs OpenLDAP to remove any
855 * value stored for this attribute and remove the attribute
856 * completely. Should multiple instances of an attribute be
857 * allowed in the future param is required to have the value
858 * store for the attribute which is going to be deleted
862 SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param);
864 g_hash_table_insert(contact, "displayName", param);
866 param = g_hash_table_lookup(contact , "givenName");
867 mod_op = ldapsvr_deside_operation(ld, dn, "givenName", param);
868 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) {
869 if (mod_op == LDAP_MOD_DELETE) {
870 /* Setting param to NULL instructs OpenLDAP to remove any
871 * value stored for this attribute and remove the attribute
872 * completely. Should multiple instances of an attribute be
873 * allowed in the future param is required to have the value
874 * store for the attribute which is going to be deleted
878 SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param);
881 mailList = g_hash_table_lookup(contact , "mail");
883 debug_print("# of mail: %d\n", g_list_length(mailList));
884 if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) {
886 mail = g_malloc(sizeof(*mail));
887 tmp = g_malloc(sizeof(*tmp));
890 EmailKeyValue *item = mailList->data;
891 *tmp++ = g_strdup((gchar *) item->mail);
892 mailList = g_list_next(mailList);
896 * At least one email address is required
897 * in which case it will always be a replace
899 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail);
905 * an error condition since at least one email adress
906 * is required. Should never occur though.
909 param = g_hash_table_lookup(contact , "sn");
910 mod_op = ldapsvr_deside_operation(ld, dn, "sn", param);
911 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) {
912 if (mod_op == LDAP_MOD_DELETE) {
913 /* Setting param to NULL instructs OpenLDAP to remove any
914 * value stored for this attribute and remove the attribute
915 * completely. Should multiple instances of an attribute be
916 * allowed in the future param is required to have the value
917 * store for the attribute which is going to be deleted
921 SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param);
924 debug_print("newDN: %s\n", dn);
927 server->retVal = LDAPRC_SUCCESS;
931 rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
933 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
934 dn, rc, ldap_err2string(rc));
935 server->retVal = LDAPRC_NAMING_VIOLATION;
940 /* If we do not make changes persistent at this point then changes
941 * will be lost if the user makes new search on the same server since
942 * changes are only present in Claws' internal cache. This issue has to
943 * be solved in addressbook.c since this involves access to structures
944 * which are only accessible in addressbook.c */
945 clean_up(ld, server, contact);
949 * Delete contact from LDAP
951 * \param server AddressBook resource
952 * \param contact GHashTable with object to delete
954 void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
959 g_return_if_fail(server != NULL || contact != NULL);
960 ld = ldapsvr_connect(server->control);
962 clean_up(ld, server, contact);
965 dn = g_hash_table_lookup(contact, "dn");
967 clean_up(ld, server, contact);
970 rc = ldap_delete_ext_s(ld, dn, NULL, NULL);
972 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
973 dn, rc, ldap_err2string(rc));
974 server->retVal = LDAPRC_NODN;
976 clean_up(ld, server, contact);
980 * Update any changes to the server.
982 * \param server AddressBook resource.
983 * \param person ItemPerson holding user input.
985 void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
987 GHashTable *contact = NULL;
988 GList *contacts = NULL, *head = NULL;
990 g_return_if_fail(server != NULL);
991 debug_print("updating ldap addressbook\n");
993 contact = g_hash_table_new(g_str_hash, g_str_equal);
995 gboolean result = ldapsvr_retrieve_item_person(item, contact);
996 debug_print("Found contact to update: %s\n", result? "Yes" : "No");
998 if (debug_get_mode()) {
999 addritem_print_item_person(item, stdout);
1001 contacts = g_list_append(contacts, contact);
1005 ItemFolder *folder = server->addressCache->rootFolder;
1006 node = folder->listFolder;
1009 AddrItemObject *aio = node->data;
1011 if (aio->type == ITEMTYPE_FOLDER) {
1012 ItemFolder *folder = (ItemFolder *) aio;
1013 GList *persons = folder->listPerson;
1015 AddrItemObject *aio = persons->data;
1017 if (aio->type == ITEMTYPE_PERSON) {
1018 ItemPerson *item = (ItemPerson *) aio;
1019 gboolean result = ldapsvr_retrieve_item_person(item, contact);
1020 debug_print("Found contact to update: %s\n", result? "Yes" : "No");
1022 if (debug_get_mode()) {
1023 gchar *uid = g_hash_table_lookup(contact, "uid");
1024 item = ldapsvr_get_contact(server, uid);
1025 addritem_print_item_person(item, stdout);
1027 contacts = g_list_append(contacts, contact);
1031 persons = g_list_next(persons);
1036 fprintf(stderr, "\t\tpid : ???\n");
1038 node = g_list_next(node);
1043 if (debug_get_mode()) {
1045 debug_print("Contacts which must be updated in LDAP:\n");
1047 debug_print("\tContact:\n");
1048 g_hash_table_foreach(contacts->data,
1049 ldapsvr_print_contacts_hashtable, stderr);
1050 contacts = g_list_next(contacts);
1053 if (contacts == NULL)
1057 contact = (GHashTable *) contacts->data;
1058 status = (gchar *) g_hash_table_lookup(contact, "status");
1060 status = g_strdup("NULL");
1061 if (g_ascii_strcasecmp(status, "new") == 0) {
1062 ldapsvr_add_contact(server, contact);
1064 else if (g_ascii_strcasecmp(status, "update") == 0) {
1065 ldapsvr_update_contact(server, contact);
1067 else if (g_ascii_strcasecmp(status, "delete") == 0) {
1068 ldapsvr_delete_contact(server, contact);
1071 g_critical(_("ldapsvr_update_book->Unknown status: %s\n"), status);
1072 contacts = g_list_next(contacts);
1074 ldapsvr_free_hashtable(head);
1077 #endif /* USE_LDAP */