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. Solved in 2.9.2cvs17
29 * 2) Updating a contact gets lost if the user makes a new search on the
30 * same LdapServer. Severity: Medium. Solved in 2.9.2cvs17 (patch added to solve 1) also solved this bug)
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.
33 * Solved in 2.9.2cvs24
43 #include <glib/gi18n.h>
49 #include "ldapupdate.h"
52 #include "addrcache.h"
54 #include "ldapquery.h"
55 #include "ldapserver.h"
58 #include "adbookbase.h"
61 * Structure to hold user defined attributes
64 typedef struct _AttrKeyValue AttrKeyValue
;
65 struct _AttrKeyValue
{
71 * Structure to hold contact information.
72 * Each addressbook will have 0..N contacts.
74 typedef struct _EmailKeyValue EmailKeyValue
;
75 struct _EmailKeyValue
{
82 * Structure to hold information about RDN.
84 typedef struct _Rdn Rdn
;
92 * Retrieve address group item for update.
93 * \param group Group to print.
94 * \param array GHashTAble of item_group, or <i>NULL</i> if none created.
96 void ldapsvr_retrieve_item_group(ItemGroup
*group
, GHashTable
*array
) {
97 /* Not implemented in this release */
98 g_return_if_fail(group
!= NULL
);
102 * Create an initial EmailKeyValue structure
103 * \return empty structure
105 EmailKeyValue
*emailkeyvalue_create() {
108 buf
= g_new0(EmailKeyValue
, 1);
116 * Create an initial AttrKeyValue structure
117 * \return empty structure
119 AttrKeyValue
*attrkeyvalue_create() {
122 buf
= g_new0(AttrKeyValue
, 1);
129 * Retrieve E-Mail address object for update.
130 * \param item ItemEmail to update.
131 * \return object, or <i>NULL</i> if none created.
133 EmailKeyValue
*ldapsvr_retrieve_item_email(ItemEMail
*item
) {
134 EmailKeyValue
*newItem
;
135 g_return_val_if_fail(item
!= NULL
, NULL
);
136 newItem
= emailkeyvalue_create();
137 newItem
->alias
= g_strdup(ADDRITEM_NAME(item
));
138 newItem
->mail
= g_strdup(item
->address
);
139 newItem
->remarks
= g_strdup(item
->remarks
);
144 * Retrieve user attribute object for update.
145 * \param item UserAttribute to update.
146 * \return object, or <i>NULL</i> if none created.
148 AttrKeyValue
*ldapsvr_retrieve_attribute(UserAttribute
*item
) {
149 AttrKeyValue
*newItem
;
150 g_return_val_if_fail(item
!= NULL
, NULL
);
151 newItem
= attrkeyvalue_create();
152 newItem
->key
= g_strdup(item
->name
);
153 newItem
->value
= g_strdup(item
->value
);
158 * Retrieve person object for update.
159 * \param person ItemPerson to update.
160 * \param array GHashTable with user input.
161 * \return false if update is not needed, or true if update is needed.
163 gboolean
ldapsvr_retrieve_item_person(ItemPerson
*person
, GHashTable
*array
) {
166 g_return_val_if_fail(person
!= NULL
, FALSE
);
167 switch (person
->status
) {
168 case NONE
: return FALSE
;
169 case ADD_ENTRY
: g_hash_table_insert(array
, "status", "new"); break;
170 case UPDATE_ENTRY
: g_hash_table_insert(array
, "status", "update"); break;
171 case DELETE_ENTRY
: g_hash_table_insert(array
, "status", "delete"); break;
172 default: g_critical(_("ldapsvr_retrieve_item_person->Unknown status: %d"), person
->status
);
174 g_hash_table_insert(array
, "uid", ADDRITEM_ID(person
));
175 g_hash_table_insert(array
, "cn", ADDRITEM_NAME(person
));
176 g_hash_table_insert(array
, "givenName", person
->firstName
);
177 g_hash_table_insert(array
, "sn", person
->lastName
);
178 g_hash_table_insert(array
, "nickName", person
->nickName
);
179 g_hash_table_insert(array
, "dn", person
->externalID
);
180 node
= person
->listEMail
;
183 EmailKeyValue
*newEmail
= ldapsvr_retrieve_item_email(node
->data
);
185 attr
= g_list_append(attr
, newEmail
);
186 node
= g_list_next(node
);
188 g_hash_table_insert(array
, "mail", attr
);
189 /* Not implemented in this release.
190 node = person->listAttrib;
193 AttrKeyValue *newAttr = ldapsvr_retrieve_attribute(node->data)
195 attr = g_list_append(attr, newAttr);
196 node = g_list_next(node);
198 g_hash_table_insert(array, "attribute", attr);
204 * Print contents of contacts hashtable for debug.
205 * This function must be called with g_hash_table_foreach.
206 * \param key Key to process.
207 * \param data Data to process.
208 * \param fd Output stream.
210 void ldapsvr_print_contacts_hashtable(gpointer key
, gpointer data
, gpointer fd
) {
211 gchar
*keyName
= (gchar
*) key
;
214 if (g_ascii_strcasecmp("mail", keyName
) == 0) {
215 node
= (GList
*) data
;
217 EmailKeyValue
*item
= node
->data
;
218 if (debug_get_mode()) {
219 debug_print("\t\talias = %s\n", item
->alias
);
220 debug_print("\t\tmail = %s\n", item
->mail
);
221 debug_print("\t\tremarks = %s\n", item
->remarks
);
224 FILE *stream
= (FILE *) fd
;
225 fprintf(stream
, "\t\talias = %s\n", item
->alias
);
226 fprintf(stream
, "\t\tmail = %s\n", item
->mail
);
227 fprintf(stream
, "\t\tremarks = %s\n", item
->remarks
);
229 node
= g_list_next(node
);
232 else if (g_ascii_strcasecmp("attribute", keyName
) == 0) {
233 node
= (GList
*) data
;
235 AttrKeyValue
*item
= node
->data
;
236 if (debug_get_mode()) {
237 debug_print("\t\t%s = %s\n", item
->key
, item
->value
);
240 FILE *stream
= (FILE *) fd
;
241 fprintf(stream
, "\t\t%s = %s\n", item
->key
, item
->value
);
243 node
= g_list_next(node
);
247 if (debug_get_mode())
248 debug_print("\t\t%s = %s\n", keyName
, (gchar
*) data
);
250 FILE *stream
= (FILE *) fd
;
251 fprintf(stream
, "\t\t%s = %s\n", keyName
, (gchar
*) data
);
257 * Free list of changed contacts
259 * \param list List of GHashTable
261 void ldapsvr_free_hashtable(GList
*list
) {
263 g_hash_table_destroy(list
->data
);
264 list
= g_list_next(list
);
270 * Get person object from cache
272 * \param server Resource to LDAP
273 * \param uid PersonID in cache
274 * \return person object, or <i>NULL</i> if fail
276 ItemPerson
*ldapsvr_get_contact(LdapServer
*server
, gchar
*uid
) {
278 g_return_val_if_fail(server
!= NULL
|| uid
!= NULL
, NULL
);
279 aio
= addrcache_get_object(server
->addressCache
, uid
);
281 if(aio
->type
== ITEMTYPE_PERSON
) {
282 return (ItemPerson
*) aio
;
289 * Connect to LDAP server.
290 * \param ctl Control object to process.
291 * \return LDAP Resource to LDAP.
293 LDAP
*ldapsvr_connect(LdapControl
*ctl
) {
299 g_return_val_if_fail(ctl
!= NULL
, NULL
);
301 uri
= g_strdup_printf("ldap%s://%s:%d",
302 ctl
->enableSSL
?"s":"",
303 ctl
->hostName
, ctl
->port
);
304 ldap_initialize(&ld
, uri
);
310 debug_print("connected to LDAP host %s on port %d\n", ctl
->hostName
, ctl
->port
);
314 version
= LDAP_VERSION3
;
315 rc
= ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
316 if (rc
== LDAP_OPT_SUCCESS
) {
317 ctl
->version
= LDAP_VERSION3
;
320 if (ctl
->version
== LDAP_VERSION3
) {
321 if (ctl
->enableTLS
&& !ctl
->enableSSL
) {
322 rc
= ldap_start_tls_s(ld
, NULL
, NULL
);
324 if (rc
!= LDAP_SUCCESS
) {
325 fprintf(stderr
, "LDAP Error(tls): ldap_simple_bind_s: %s\n",
326 ldap_err2string(rc
));
333 /* Bind to the server, if required */
335 if (* ctl
->bindDN
!= '\0') {
336 rc
= claws_ldap_simple_bind_s(ld
, ctl
->bindDN
, ctl
->bindPass
);
337 if (rc
!= LDAP_SUCCESS
) {
338 fprintf(stderr
, "bindDN: %s, bindPass: %s\n", ctl
->bindDN
, ctl
->bindPass
);
339 fprintf(stderr
, "LDAP Error(bind): ldap_simple_bind_s: %s\n",
340 ldap_err2string(rc
));
349 * Disconnect to LDAP server.
350 * \param ld Resource to LDAP.
352 void ldapsvr_disconnect(LDAP
*ld
) {
354 g_return_if_fail(ld
!= NULL
);
355 ldap_unbind_ext(ld
, NULL
, NULL
);
359 * Create an initial Rdn structure
361 * \return empty structure
366 buf
= g_new0(Rdn
, 1);
367 buf
->attribute
= NULL
;
374 * update Rdn structure
376 * \param rdn Rdn structure to update
377 * \param head Uniq part of dn
378 * \param tail Common part of dn
380 void update_rdn(Rdn
*rdn
, gchar
*head
, gchar
*tail
) {
381 rdn
->value
= g_strdup(head
);
382 rdn
->new_dn
= g_strdup_printf("mail=%s%s", head
, tail
);
386 * Deside if dn needs to be changed
388 * \param hash GHashTable with user input.
389 * \param dn dn for current object
390 * \return Rdn structure
392 Rdn
*ldapsvr_modify_dn(GHashTable
*hash
, gchar
*dn
) {
394 gchar
*pos
, *compare
;
397 g_return_val_if_fail(hash
!= NULL
|| dn
!= NULL
, NULL
);
399 pos
= g_strstr_len(dn
, strlen(dn
), "=");
400 compare
= g_strndup(dn
, pos
- dn
);
405 rest
= g_strstr_len(pos
, strlen(pos
), ",");
406 val
= g_strndup(pos
, rest
- pos
);
413 rdn
->value
= g_strdup(val
);
414 rdn
->attribute
= g_strdup(compare
);
416 if (strcmp("mail", rdn
->attribute
) == 0) {
417 GList
*list
= g_hash_table_lookup(hash
, rdn
->attribute
);
419 EmailKeyValue
*item
= list
->data
;
420 compare
= g_strdup((gchar
*) item
->mail
);
421 if (strcmp(compare
, rdn
->value
) == 0) {
422 update_rdn(rdn
, compare
, rest
);
426 list
= g_list_next(list
);
428 /* if compare and rdn->attribute are equal then last email removed/empty */
429 if (strcmp(compare
, rdn
->attribute
) != 0) {
430 /* RDN changed. Find new */
431 update_rdn(rdn
, compare
, rest
);
436 /* We cannot remove dn */
442 compare
= g_hash_table_lookup(hash
, rdn
->attribute
);
443 /* if compare and rdn->attribute are equal then dn removed/empty */
444 if (strcmp(compare
, rdn
->attribute
) != 0) {
445 update_rdn(rdn
, compare
, rest
);
449 /* We cannot remove dn */
457 * This macro is borrowed from the Balsa project
458 * Creates a LDAPMod structure
460 * \param mods Empty LDAPMod structure
461 * \param modarr Array with values to insert
462 * \param op Operation to perform on LDAP
463 * \param attr Attribute to insert
464 * \param strv Empty array which is NULL terminated
465 * \param val Value for attribute
467 #define SETMOD(mods,modarr,op,attr,strv,val) \
468 do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
469 (strv)[0]=(val); (modarr).mod_values=strv; \
473 * Creates a LDAPMod structure
475 * \param mods Empty LDAPMod structure
476 * \param modarr Array with values to insert
477 * \param op Operation to perform on LDAP
478 * \param attr Attribute to insert
479 * \param strv Array with values to insert. Must be NULL terminated
481 #define SETMODS(mods,modarr,op,attr,strv) \
482 do { (mods) = &(modarr); (modarr).mod_type=attr; \
483 (modarr).mod_op=op; (modarr).mod_values=strv; \
488 * Clean up, close LDAP connection, and refresh cache
490 * \param ld Resource to LDAP
491 * \param server AddressBook resource
492 * \param contact GHashTable with current changed object
494 void clean_up(LDAP
*ld
, LdapServer
*server
, GHashTable
*contact
) {
496 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
499 person
->status
= NONE
;
500 displayName
= g_hash_table_lookup(contact
, "displayName");
502 person
->nickName
= g_strdup(displayName
);
504 if (server
->retVal
!= LDAPRC_SUCCESS
) {
507 addrcache_remove_person(server
->addressCache
, person
);
509 g_critical(N_("ldapsvr_update_book: Could not clean cache\n"));
511 addritem_free_item_person(res
);
515 ldapsvr_disconnect(ld
);
516 /* ldapsvr_force_refresh(server);
517 ldapsvr_free_all_query(server);*/
521 * Get cn attribute from dn
523 * \param dn Distinguesh Name for current object
524 * \return AttrKeyValue, or <i>NULL</i> if none created
526 AttrKeyValue
*get_cn(gchar
*dn
) {
532 g_return_val_if_fail(dn
!= NULL
, NULL
);
534 cn
= attrkeyvalue_create();
535 start
= g_strstr_len(dn
, strlen(dn
), "cn");
538 end
= g_strstr_len(start
, strlen(start
), ",");
539 item
= g_strndup(start
, end
- start
);
542 key_value
= g_strsplit(item
, "=", 2);
543 cn
->key
= g_strdup(key_value
[0]);
544 cn
->value
= g_strdup(key_value
[1]);
545 g_strfreev(key_value
);
551 * Get ou or o attribute from dn
553 * \param dn Distinguesh Name for current object
554 * \return AttrKeyValue, or <i>NULL</i> if none created
556 AttrKeyValue
*get_ou(gchar
*dn
) {
563 g_return_val_if_fail(dn
!= NULL
, NULL
);
564 ou
= attrkeyvalue_create();
565 start
= g_strstr_len(dn
, strlen(dn
), ",o=");
567 start
= g_strstr_len(dn
, strlen(dn
), ",ou=");
571 end
= g_strstr_len(start
, strlen(start
), ",");
572 item
= g_strndup(start
, end
- start
);
575 key_value
= g_strsplit(item
, "=", 2);
576 ou
->key
= g_strdup(key_value
[0]);
577 ou
->value
= g_strdup(key_value
[1]);
578 g_strfreev(key_value
);
584 * Print the contents of a LDAPMod structure for debuging purposes
586 * \param mods LDAPMod structure
588 void ldapsvr_print_ldapmod(LDAPMod
*mods
[]) {
592 g_return_if_fail(mods
!= NULL
);
593 fprintf( stderr
, "Type\n");
594 for (i
= 0; NULL
!= mods
[i
]; i
++) {
595 LDAPMod
*mod
= (LDAPMod
*) mods
[i
];
597 switch (mod
->mod_op
) {
598 case LDAP_MOD_ADD
: mod_op
= g_strdup("ADD"); break;
599 case LDAP_MOD_REPLACE
: mod_op
= g_strdup("MODIFY"); break;
600 case LDAP_MOD_DELETE
: mod_op
= g_strdup("DELETE"); break;
601 default: mod_op
= g_strdup("UNKNOWN");
603 fprintf( stderr
, "Operation: %s\tType:%s\nValues:\n", mod_op
, mod
->mod_type
);
604 vals
= mod
->mod_vals
.modv_strvals
;
606 fprintf( stderr
, "\t%s\n", *vals
++);
612 * Make a compare for every new value we want to store in the
613 * directory with the current values. Great tool for debugging
614 * against invalid syntax in attributes
616 * \param ld AddressBook resource
617 * \param dn dn for the entry
618 * \param cnt Number of attributes to compare
619 * \param mods LDAPMod structure
621 void ldapsvr_compare_attr(LDAP
*ld
, gchar
*dn
, gint cnt
, LDAPMod
*mods
[]) {
624 g_return_if_fail(ld
!= NULL
|| dn
!= NULL
|| cnt
>= 0 || mods
!= NULL
);
625 for (i
= 0; i
< cnt
; i
++) {
626 rc
= ldap_compare_s(ld
, dn
, mods
[i
]->mod_type
, mods
[i
]->mod_vals
.modv_strvals
[0]);
627 fprintf(stderr
, "ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
628 mods
[i
]->mod_type
, mods
[i
]->mod_vals
.modv_strvals
[0], rc
, ldap_err2string(rc
));
633 * Add new contact to LDAP
635 * \param server AddressBook resource
636 * \param contact GHashTable with object to add
638 void ldapsvr_add_contact(LdapServer
*server
, GHashTable
*contact
) {
639 gchar
*email
= NULL
, *param
= NULL
;
641 LDAPMod
*mods
[MODSIZE
];
644 char *cn
[] = {NULL
, NULL
};
645 char *displayName
[] = {NULL
, NULL
};
646 char *givenName
[] = {NULL
, NULL
};
648 char *sn
[] = {NULL
, NULL
};
649 char *org
[] = {NULL
, NULL
};
650 char *obj
[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL
};
653 AttrKeyValue
*ou
, *commonName
;
658 g_return_if_fail(server
!= NULL
|| contact
!= NULL
);
659 node
= g_hash_table_lookup(contact
, "mail");
661 EmailKeyValue
*newEmail
= node
->data
;
662 email
= g_strdup(newEmail
->mail
);
665 server
->retVal
= LDAPRC_NODN
;
666 clean_up(ld
, server
, contact
);
669 base_dn
= g_strdup_printf("mail=%s,%s", email
, server
->control
->baseDN
);
672 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
673 person
->externalID
= g_strdup(base_dn
);
674 debug_print("dn: %s\n", base_dn
);
675 ld
= ldapsvr_connect(server
->control
);
677 clean_up(ld
, server
, contact
);
678 debug_print("no ldap found\n");
681 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "objectClass", obj
);
683 ou
= get_ou(base_dn
);
685 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, ou
->key
, org
, ou
->value
);
689 commonName
= get_cn(base_dn
);
690 if (commonName
== NULL
) {
691 param
= g_hash_table_lookup(contact
, "cn");
693 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "cn", cn
, param
);
696 clean_up(ld
, server
, contact
);
697 debug_print("no CN found\n");
702 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, commonName
->key
, cn
, commonName
->value
);
704 param
= g_hash_table_lookup(contact
, "cn");
705 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "displayName", displayName
, param
);
706 g_hash_table_insert(contact
, "displayName", param
);
709 param
= g_hash_table_lookup(contact
, "givenName");
711 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "givenName", givenName
, param
);
714 mailList
= g_hash_table_lookup(contact
, "mail");
717 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
720 EmailKeyValue
*item
= mailList
->data
;
721 *tmp
++ = g_strdup((gchar
*) item
->mail
);
722 mailList
= g_list_next(mailList
);
725 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "mail", mail
);
728 param
= g_hash_table_lookup(contact
, "sn");
730 param
= g_strdup(N_("Some SN"));
731 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "sn", sn
, param
);
734 if (debug_get_mode()) {
735 ldapsvr_print_ldapmod(mods
);
737 server
->retVal
= LDAPRC_SUCCESS
;
738 rc
= ldap_add_ext_s(ld
, base_dn
, mods
, NULL
, NULL
);
741 case LDAP_ALREADY_EXISTS
:
742 server
->retVal
= LDAPRC_ALREADY_EXIST
;
745 fprintf(stderr
, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",base_dn
, rc
, ldap_err2string(rc
));
747 server
->retVal
= LDAPRC_STRONG_AUTH
;
749 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
753 clean_up(ld
, server
, contact
);
757 * Deside which kind of operation is required to handle
758 * updating the specified attribute
760 * \param ld AddressBook resource
761 * \param dn dn for the entry
762 * \param attr Attribute
763 * \param value New value
764 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
766 int ldapsvr_deside_operation(LDAP
*ld
, char *dn
, char *attr
, char *value
) {
768 gboolean dummy
= FALSE
;
770 g_return_val_if_fail(ld
!= NULL
|| dn
!= NULL
|| attr
!= NULL
, -1);
773 /* value containing empty string cause invalid syntax. A bug in
774 * the LDAP library? Therefore we add a dummy value
776 if (strcmp(value
,"") == 0) {
777 value
= g_strdup("thisisonlyadummy");
780 rc
= ldap_compare_s(ld
, dn
, attr
, value
);
781 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
782 attr
, value
, rc
, ldap_err2string(rc
));
784 case LDAP_COMPARE_FALSE
:
786 return LDAP_MOD_DELETE
;
788 return LDAP_MOD_REPLACE
;
789 case LDAP_COMPARE_TRUE
: return -1;
790 case LDAP_NO_SUCH_ATTRIBUTE
: return LDAP_MOD_ADD
;
791 case LDAP_UNDEFINED_TYPE
: return -2;
792 case LDAP_INVALID_SYNTAX
: return -2;
798 * Update contact to LDAP
800 * \param server AddressBook resource
801 * \param contact GHashTable with object to update
803 void ldapsvr_update_contact(LdapServer
*server
, GHashTable
*contact
) {
805 LDAPMod
*mods
[MODSIZE
];
809 Rdn
*NoRemove
= NULL
;
810 char *cn
[] = {NULL
, NULL
};
811 char *givenName
[] = {NULL
, NULL
};
813 char *sn
[] = {NULL
, NULL
};
817 g_return_if_fail(server
!= NULL
|| contact
!= NULL
);
818 ld
= ldapsvr_connect(server
->control
);
820 clean_up(ld
, server
, contact
);
823 dn
= g_hash_table_lookup(contact
, "dn");
825 clean_up(ld
, server
, contact
);
828 NoRemove
= ldapsvr_modify_dn(contact
, dn
);
830 /* We are trying to change RDN */
831 gchar
*newRdn
= g_strdup_printf("%s=%s", NoRemove
->attribute
, NoRemove
->value
);
832 int rc
= ldap_modrdn2_s(ld
, dn
, newRdn
, 1);
833 if(rc
!= LDAP_SUCCESS
) {
834 if (rc
== LDAP_ALREADY_EXISTS
) {
835 /* We are messing with a contact with more than one listed email
836 * address and the email we are changing is not the one used for dn
838 /* It needs to be able to handle renaming errors to an already defined
839 * dn. For now we just refuse the update. It will be caught later on as
840 * a LDAPRC_NAMING_VIOLATION error.
844 fprintf(stderr
, "Current dn: %s\n", dn
);
845 fprintf(stderr
, "new dn: %s\n", newRdn
);
846 fprintf(stderr
, "LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc
, ldap_err2string(rc
));
848 clean_up(ld
, server
, contact
);
854 dn
= g_strdup(NoRemove
->new_dn
);
858 server
->retVal
= LDAPRC_NODN
;
859 clean_up(ld
, server
, contact
);
862 param
= g_hash_table_lookup(contact
, "cn");
863 mod_op
= ldapsvr_deside_operation(ld
, dn
, "displayName", param
);
864 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("cn", NoRemove
->attribute
) != 0)) {
865 if (mod_op
== LDAP_MOD_DELETE
) {
866 /* Setting param to NULL instructs OpenLDAP to remove any
867 * value stored for this attribute and remove the attribute
868 * completely. Should multiple instances of an attribute be
869 * allowed in the future param is required to have the value
870 * store for the attribute which is going to be deleted
874 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
875 /* Having an empty string is considered a syntax error in
876 * ldap. E.g attributes with empty strings are not allowed
877 * in which case we treate this as a request for deleting
880 mod_op
= LDAP_MOD_DELETE
;
883 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
884 /* Adding an empty string is considered a syntax error in
885 * ldap. E.g attributes with empty strings are not allowed
886 * in which case we silently refuse to add this entry
890 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "displayName", cn
, param
);
892 g_hash_table_insert(contact
, "displayName", param
);
895 param
= g_hash_table_lookup(contact
, "givenName");
896 mod_op
= ldapsvr_deside_operation(ld
, dn
, "givenName", param
);
897 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("givenName", NoRemove
->attribute
) != 0)) {
898 if (mod_op
== LDAP_MOD_DELETE
) {
899 /* Setting param to NULL instructs OpenLDAP to remove any
900 * value stored for this attribute and remove the attribute
901 * completely. Should multiple instances of an attribute be
902 * allowed in the future param is required to have the value
903 * store for the attribute which is going to be deleted
907 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
908 /* Having an empty string is considered a syntax error in
909 * ldap. E.g attributes with empty strings are not allowed
910 * in which case we treate this as a request for deleting
913 mod_op
= LDAP_MOD_DELETE
;
916 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
917 /* Adding an empty string is considered a syntax error in
918 * ldap. E.g attributes with empty strings are not allowed
919 * in which case we silently refuse to add this entry
923 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "givenName", givenName
, param
);
927 mailList
= g_hash_table_lookup(contact
, "mail");
929 debug_print("# of mail: %d\n", g_list_length(mailList
));
930 if (!(strcmp("mail", NoRemove
->attribute
) == 0 && g_list_length(mailList
) == 1)) {
932 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
935 EmailKeyValue
*item
= mailList
->data
;
936 *tmp
++ = g_strdup((gchar
*) item
->mail
);
937 mailList
= g_list_next(mailList
);
941 * At least one email address is required
942 * in which case it will always be a replace
944 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_REPLACE
, "mail", mail
);
950 * an error condition since at least one email adress
951 * is required. Should never occur though.
954 param
= g_hash_table_lookup(contact
, "sn");
955 mod_op
= ldapsvr_deside_operation(ld
, dn
, "sn", param
);
956 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("sn", NoRemove
->attribute
) != 0)) {
957 if (mod_op
== LDAP_MOD_DELETE
) {
958 /* Setting param to NULL instructs OpenLDAP to remove any
959 * value stored for this attribute and remove the attribute
960 * completely. Should multiple instances of an attribute be
961 * allowed in the future param is required to have the value
962 * store for the attribute which is going to be deleted
966 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
967 /* Having an empty string is considered a syntax error in
968 * ldap. E.g attributes with empty strings are not allowed
969 * in which case we treate this as a request for deleting
972 mod_op
= LDAP_MOD_DELETE
;
975 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
976 /* Adding an empty string is considered a syntax error in
977 * ldap. E.g attributes with empty strings are not allowed
978 * in which case we silently refuse to add this entry
982 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "sn", sn
, param
);
986 debug_print("newDN: %s\n", dn
);
989 server
->retVal
= LDAPRC_SUCCESS
;
993 rc
= ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
995 fprintf(stderr
, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
996 dn
, rc
, ldap_err2string(rc
));
997 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
1002 /* If we do not make changes persistent at this point then changes
1003 * will be lost if the user makes new search on the same server since
1004 * changes are only present in Claws' internal cache. This issue has to
1005 * be solved in addressbook.c since this involves access to structures
1006 * which are only accessible in addressbook.c */
1007 clean_up(ld
, server
, contact
);
1011 * Delete contact from LDAP
1013 * \param server AddressBook resource
1014 * \param contact GHashTable with object to delete
1016 void ldapsvr_delete_contact(LdapServer
*server
, GHashTable
*contact
) {
1021 g_return_if_fail(server
!= NULL
|| contact
!= NULL
);
1022 ld
= ldapsvr_connect(server
->control
);
1024 clean_up(ld
, server
, contact
);
1027 dn
= g_hash_table_lookup(contact
, "dn");
1029 clean_up(ld
, server
, contact
);
1032 server
->retVal
= LDAPRC_SUCCESS
;
1033 rc
= ldap_delete_ext_s(ld
, dn
, NULL
, NULL
);
1035 fprintf(stderr
, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1036 dn
, rc
, ldap_err2string(rc
));
1037 server
->retVal
= LDAPRC_NODN
;
1039 clean_up(ld
, server
, contact
);
1043 * Update any changes to the server.
1045 * \param server AddressBook resource.
1046 * \param person ItemPerson holding user input.
1048 void ldapsvr_update_book(LdapServer
*server
, ItemPerson
*item
) {
1050 GHashTable
*contact
= NULL
;
1051 GList
*contacts
= NULL
, *head
= NULL
;
1053 g_return_if_fail(server
!= NULL
);
1054 debug_print("updating ldap addressbook\n");
1056 contact
= g_hash_table_new(g_str_hash
, g_str_equal
);
1058 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1059 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1061 if (debug_get_mode()) {
1062 addritem_print_item_person(item
, stdout
);
1064 contacts
= g_list_append(contacts
, contact
);
1068 ItemFolder
*folder
= server
->addressCache
->rootFolder
;
1069 node
= folder
->listFolder
;
1072 AddrItemObject
*aio
= node
->data
;
1074 if (aio
->type
== ITEMTYPE_FOLDER
) {
1075 ItemFolder
*folder
= (ItemFolder
*) aio
;
1076 GList
*persons
= folder
->listPerson
;
1078 AddrItemObject
*aio
= persons
->data
;
1080 if (aio
->type
== ITEMTYPE_PERSON
) {
1081 ItemPerson
*item
= (ItemPerson
*) aio
;
1082 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1083 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1085 if (debug_get_mode()) {
1086 gchar
*uid
= g_hash_table_lookup(contact
, "uid");
1087 item
= ldapsvr_get_contact(server
, uid
);
1088 addritem_print_item_person(item
, stdout
);
1090 contacts
= g_list_append(contacts
, contact
);
1094 persons
= g_list_next(persons
);
1099 fprintf(stderr
, "\t\tpid : ???\n");
1101 node
= g_list_next(node
);
1106 if (debug_get_mode()) {
1108 debug_print("Contacts which must be updated in LDAP:\n");
1110 debug_print("\tContact:\n");
1111 g_hash_table_foreach(contacts
->data
,
1112 ldapsvr_print_contacts_hashtable
, stderr
);
1113 contacts
= g_list_next(contacts
);
1116 if (contacts
== NULL
)
1120 contact
= (GHashTable
*) contacts
->data
;
1121 status
= (gchar
*) g_hash_table_lookup(contact
, "status");
1123 status
= g_strdup("NULL");
1124 if (g_ascii_strcasecmp(status
, "new") == 0) {
1125 ldapsvr_add_contact(server
, contact
);
1127 else if (g_ascii_strcasecmp(status
, "update") == 0) {
1128 ldapsvr_update_contact(server
, contact
);
1130 else if (g_ascii_strcasecmp(status
, "delete") == 0) {
1131 ldapsvr_delete_contact(server
, contact
);
1134 g_critical(_("ldapsvr_update_book->Unknown status: %s\n"), status
);
1135 contacts
= g_list_next(contacts
);
1137 ldapsvr_free_hashtable(head
);
1140 #endif /* USE_LDAP */