revert last commit because it breaks more than it fixes
[claws.git] / src / ldapctrl.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2003 Match Grun
4  *
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.
9  *
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.
14  *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Functions for LDAP control data.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #ifdef USE_LDAP
29
30 #include <glib.h>
31 #include <sys/time.h>
32 #include <string.h>
33
34 #include "ldapctrl.h"
35 #include "mgutils.h"
36
37 /**
38  * Create new LDAP control block object.
39  * \return Initialized control object.
40  */
41 LdapControl *ldapctl_create( void ) {
42         LdapControl *ctl;
43
44         ctl = g_new0( LdapControl, 1 );
45         ctl->hostName = NULL;
46         ctl->port = LDAPCTL_DFL_PORT;
47         ctl->baseDN = NULL;
48         ctl->bindDN = NULL;
49         ctl->bindPass = NULL;
50         ctl->listCriteria = NULL;
51         ctl->attribEMail = g_strdup( LDAPCTL_ATTR_EMAIL );
52         ctl->attribCName = g_strdup( LDAPCTL_ATTR_COMMONNAME );
53         ctl->attribFName = g_strdup( LDAPCTL_ATTR_GIVENNAME );
54         ctl->attribLName = g_strdup( LDAPCTL_ATTR_SURNAME );
55         ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
56         ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
57         ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
58
59         /* Mutex to protect control block */
60         ctl->mutexCtl = g_malloc0( sizeof( pthread_mutex_t ) );
61         pthread_mutex_init( ctl->mutexCtl, NULL );
62
63         return ctl;
64 }
65
66 /**
67  * Specify hostname to be used.
68  * \param ctl   Control object to process.
69  * \param value Host name.
70  */
71 void ldapctl_set_host( LdapControl* ctl, const gchar *value ) {
72         ctl->hostName = mgu_replace_string( ctl->hostName, value );
73         g_strstrip( ctl->hostName );
74 }
75
76 /**
77  * Specify port to be used.
78  * \param ctl  Control object to process.
79  * \param value Port.
80  */
81 void ldapctl_set_port( LdapControl* ctl, const gint value ) {
82         if( value > 0 ) {
83                 ctl->port = value;
84         }
85         else {
86                 ctl->port = LDAPCTL_DFL_PORT;
87         }
88 }
89
90 /**
91  * Specify base DN to be used.
92  * \param ctl  Control object to process.
93  * \param value Base DN.
94  */
95 void ldapctl_set_base_dn( LdapControl* ctl, const gchar *value ) {
96         ctl->baseDN = mgu_replace_string( ctl->baseDN, value );
97         g_strstrip( ctl->baseDN );
98 }
99
100 /**
101  * Specify bind DN to be used.
102  * \param ctl  Control object to process.
103  * \param value Bind DN.
104  */
105 void ldapctl_set_bind_dn( LdapControl* ctl, const gchar *value ) {
106         ctl->bindDN = mgu_replace_string( ctl->bindDN, value );
107         g_strstrip( ctl->bindDN );
108 }
109
110 /**
111  * Specify bind password to be used.
112  * \param ctl  Control object to process.
113  * \param value Password.
114  */
115 void ldapctl_set_bind_password( LdapControl* ctl, const gchar *value ) {
116         ctl->bindPass = mgu_replace_string( ctl->bindPass, value );
117         g_strstrip( ctl->bindPass );
118 }
119
120 /**
121  * Specify maximum number of entries to retrieve.
122  * \param ctl  Control object to process.
123  * \param value Maximum entries.
124  */
125 void ldapctl_set_max_entries( LdapControl* ctl, const gint value ) {
126         if( value > 0 ) {
127                 ctl->maxEntries = value;
128         }
129         else {
130                 ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
131         }
132 }
133
134 /**
135  * Specify timeout value for LDAP operation (in seconds).
136  * \param ctl  Control object to process.
137  * \param value Timeout.
138  */
139 void ldapctl_set_timeout( LdapControl* ctl, const gint value ) {
140         if( value > 0 ) {
141                 ctl->timeOut = value;
142         }
143         else {
144                 ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
145         }
146 }
147
148 /**
149  * Specify maximum age of query (in seconds) before query is retired.
150  * \param ctl  Control object to process.
151  * \param value Maximum age.
152  */
153 void ldapctl_set_max_query_age( LdapControl* ctl, const gint value ) {
154         if( value > LDAPCTL_MAX_QUERY_AGE ) {
155                 ctl->maxQueryAge = LDAPCTL_MAX_QUERY_AGE;
156         }
157         else if( value < 1 ) {
158                 ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
159         }
160         else {
161                 ctl->maxQueryAge = value;
162         }
163 }
164
165 /**
166  * Specify search criteria list to be used.
167  * \param ctl   Control data object.
168  * \param value Linked list of LDAP attribute names to use for search.
169  */
170 void ldapctl_set_criteria_list( LdapControl* ctl, GList *value ) {
171         g_return_if_fail( ctl != NULL );
172         mgu_free_dlist( ctl->listCriteria );
173         ctl->listCriteria = value;
174 }
175
176 /**
177  * Return search criteria list.
178  * \param  ctl  Control data object.
179  * \return Linked list of character strings containing LDAP attribute names to
180  *         use for a search. This should not be modified directly. Use the
181  *         <code>ldapctl_set_criteria_list()</code>,
182  *         <code>ldapctl_criteria_list_clear()</code> and
183  *         <code>ldapctl_criteria_list_add()</code> functions for this purpose.
184  */
185 GList *ldapctl_get_criteria_list( const LdapControl* ctl ) {
186         g_return_val_if_fail( ctl != NULL, NULL );
187         return ctl->listCriteria;
188 }
189
190 /**
191  * Clear list of LDAP search attributes.
192  * \param  ctl  Control data object.
193  */
194 void ldapctl_criteria_list_clear( LdapControl *ctl ) {
195         g_return_if_fail( ctl != NULL );
196         mgu_free_dlist( ctl->listCriteria );
197         ctl->listCriteria = NULL;
198 }
199
200 /**
201  * Add LDAP attribute to criteria list.
202  * \param ctl  Control object to process.
203  * \param attr Attribute name to append. If not NULL and unique, a copy will
204  *             be appended to the list.
205  */
206 void ldapctl_criteria_list_add( LdapControl *ctl, gchar *attr ) {
207         g_return_if_fail( ctl != NULL );
208         if( attr != NULL ) {
209                 if( mgu_list_test_unq_nc( ctl->listCriteria, attr ) ) {
210                         ctl->listCriteria = g_list_append(
211                                 ctl->listCriteria, g_strdup( attr ) );
212                 }
213         }
214 }
215
216 /**
217  * Build criteria list using default attributes.
218  * \param ctl  Control object to process.
219  */
220 void ldapctl_default_attributes( LdapControl *ctl ) {
221         g_return_if_fail( ctl != NULL );
222
223         ldapctl_criteria_list_clear( ctl );
224         ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_COMMONNAME );
225         ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_GIVENNAME );
226         ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_SURNAME );
227         ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_EMAIL );
228 }
229
230 /**
231  * Clear LDAP server member variables.
232  * \param ctl Control object to clear.
233  */
234 void ldapctl_clear( LdapControl *ctl ) {
235         g_return_if_fail( ctl != NULL );
236
237         /* Free internal stuff */
238         g_free( ctl->hostName );
239         g_free( ctl->baseDN );
240         g_free( ctl->bindDN );
241         g_free( ctl->bindPass );
242         g_free( ctl->attribEMail );
243         g_free( ctl->attribCName );
244         g_free( ctl->attribFName );
245         g_free( ctl->attribLName );
246
247         ldapctl_criteria_list_clear( ctl );
248
249         /* Clear pointers */
250         ctl->hostName = NULL;
251         ctl->port = 0;
252         ctl->baseDN = NULL;
253         ctl->bindDN = NULL;
254         ctl->bindPass = NULL;
255         ctl->attribEMail = NULL;
256         ctl->attribCName = NULL;
257         ctl->attribFName = NULL;
258         ctl->attribLName = NULL;
259         ctl->maxEntries = 0;
260         ctl->timeOut = 0;
261         ctl->maxQueryAge = 0;
262 }
263
264 /**
265  * Free up LDAP server interface object by releasing internal memory.
266  * \param ctl Control object to free.
267  */
268 void ldapctl_free( LdapControl *ctl ) {
269         g_return_if_fail( ctl != NULL );
270
271         /* Free internal stuff */
272         ldapctl_clear( ctl );
273
274         /* Free the mutex */
275         pthread_mutex_destroy( ctl->mutexCtl );
276         g_free( ctl->mutexCtl );
277         ctl->mutexCtl = NULL;
278
279         /* Now release LDAP control object */
280         g_free( ctl );
281 }
282
283 /**
284  * Setup default (empty) values for specified object.
285  * \param ctl  Control object to process.
286  */
287 void ldapctl_default_values( LdapControl *ctl ) {
288         g_return_if_fail( ctl != NULL );
289
290         /* Clear our destination */
291         ldapctl_clear( ctl );
292
293         /* Copy strings */
294         ctl->hostName = g_strdup( "" );
295         ctl->baseDN = g_strdup( "" );
296         ctl->bindDN = g_strdup( "" );
297         ctl->bindPass = g_strdup( "" );
298         ctl->port = LDAPCTL_DFL_PORT;
299         ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
300         ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
301         ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
302
303         ldapctl_default_attributes( ctl );
304 }
305
306 /**
307  * Display object to specified stream.
308  * \param ctl    Control object to process.
309  * \param stream Output stream.
310  */
311 void ldapctl_print( const LdapControl *ctl, FILE *stream ) {
312         g_return_if_fail( ctl != NULL );
313
314         pthread_mutex_lock( ctl->mutexCtl );
315         fprintf( stream, "LdapControl:\n" );
316         fprintf( stream, "host name: '%s'\n", ctl->hostName );
317         fprintf( stream, "     port: %d\n",   ctl->port );
318         fprintf( stream, "  base dn: '%s'\n", ctl->baseDN );
319         fprintf( stream, "  bind dn: '%s'\n", ctl->bindDN );
320         fprintf( stream, "bind pass: '%s'\n", ctl->bindPass );
321         fprintf( stream, "attr mail: '%s'\n", ctl->attribEMail );
322         fprintf( stream, "attr comn: '%s'\n", ctl->attribCName );
323         fprintf( stream, "attr frst: '%s'\n", ctl->attribFName );
324         fprintf( stream, "attr last: '%s'\n", ctl->attribLName );
325         fprintf( stream, "max entry: %d\n",   ctl->maxEntries );
326         fprintf( stream, "  timeout: %d\n",   ctl->timeOut );
327         fprintf( stream, "  max age: %d\n",   ctl->maxQueryAge );
328         fprintf( stream, "crit list:\n" );
329         if( ctl->listCriteria ) {
330                 mgu_print_dlist( ctl->listCriteria, stream );
331         }
332         else {
333                 fprintf( stream, "\t!!!none!!!\n" );
334         }
335         pthread_mutex_unlock( ctl->mutexCtl );
336 }
337
338 /**
339  * Copy member variables to specified object. Mutex lock object is
340  * not copied.
341  * \param ctlFrom Object to copy from.
342  * \param ctlTo   Destination object.
343  */
344 void ldapctl_copy( const LdapControl *ctlFrom, LdapControl *ctlTo ) {
345         GList *node;
346
347         g_return_if_fail( ctlFrom != NULL );
348         g_return_if_fail( ctlTo != NULL );
349
350         /* Lock both objects */
351         pthread_mutex_lock( ctlFrom->mutexCtl );
352         pthread_mutex_lock( ctlTo->mutexCtl );
353
354         /* Clear our destination */
355         ldapctl_clear( ctlTo );
356
357         /* Copy strings */
358         ctlTo->hostName = g_strdup( ctlFrom->hostName );
359         ctlTo->baseDN = g_strdup( ctlFrom->baseDN );
360         ctlTo->bindDN = g_strdup( ctlFrom->bindDN );
361         ctlTo->bindPass = g_strdup( ctlFrom->bindPass );
362         ctlTo->attribEMail = g_strdup( ctlFrom->attribEMail );
363         ctlTo->attribCName = g_strdup( ctlFrom->attribCName );
364         ctlTo->attribFName = g_strdup( ctlFrom->attribFName );
365         ctlTo->attribLName = g_strdup( ctlFrom->attribLName );
366
367         /* Copy search criteria */
368         node = ctlFrom->listCriteria;
369         while( node ) {
370                 ctlTo->listCriteria = g_list_append(
371                         ctlTo->listCriteria, g_strdup( node->data ) );
372                 node = g_list_next( node );
373         }
374
375         /* Copy other members */
376         ctlTo->port = ctlFrom->port;
377         ctlTo->maxEntries = ctlFrom->maxEntries;
378         ctlTo->timeOut = ctlFrom->timeOut;
379         ctlTo->maxQueryAge = ctlFrom->maxQueryAge;
380
381         /* Unlock */
382         pthread_mutex_unlock( ctlTo->mutexCtl );
383         pthread_mutex_unlock( ctlFrom->mutexCtl );
384 }
385
386 /**
387  * Build a formatted LDAP search criteria string from criteria list.
388  * \param ctl  Control object to process.
389  * \param searchVal Value to search for.
390  * \return Formatted string. Should be g_free() when done.
391  */
392 gchar *ldapctl_format_criteria( LdapControl *ctl, const gchar *searchVal ) {
393         GList *node;
394         gchar *p1, *p2, *retVal;
395
396         g_return_val_if_fail( ctl != NULL, NULL );
397
398         /* p1 contains previous formatted criteria */
399         /* p2 contains next formatted criteria */
400         retVal = p1 = p2 = NULL;
401         node = ctl->listCriteria;
402         while( node ) {
403                 gchar *attr, *tmp;
404
405                 attr = node->data;
406                 node = g_list_next( node );
407
408                 /* Switch pointers */
409                 tmp = p1; p1 = p2; p2 = tmp;
410
411                 if( p1 ) {
412                         /* Subsequent time through */
413                         gchar *crit;
414
415                         /* Format query criteria */
416                         crit = g_strdup_printf( "(%s=%s*)", attr, searchVal );
417
418                         /* Append to existing criteria */                       
419                         g_free( p2 );
420                         p2 = g_strdup_printf( "(|%s%s)", p1, crit );
421
422                         g_free( crit );
423                 }
424                 else {
425                         /* First time through - Format query criteria */
426                         p2 = g_strdup_printf( "(%s=%s*)", attr, searchVal );
427                 }
428         }
429
430         if( p2 == NULL ) {
431                 /* Nothing processed - format a default attribute */
432                 retVal = g_strdup_printf( "(%s=*)", LDAPCTL_ATTR_EMAIL );
433         }
434         else {
435                 /* We have something - free up previous result */
436                 retVal = p2;
437                 g_free( p1 );
438         }
439         return retVal;
440 }
441
442 /**
443  * Return array of pointers to attributes for LDAP query.
444  * \param  ctl  Control object to process.
445  * \return NULL terminated list.
446  */
447 char **ldapctl_attribute_array( LdapControl *ctl ) {
448         char **ptrArray;
449         GList *node;
450         gint cnt, i;
451         g_return_val_if_fail( ctl != NULL, NULL );
452
453         cnt = g_list_length( ctl->listCriteria );
454         ptrArray = g_new0( char *, 1 + cnt );
455         i = 0;
456         node = ctl->listCriteria;
457         while( node ) {
458                 ptrArray[ i++ ] = node->data;
459                 node = g_list_next( node );
460         }
461         ptrArray[ i ] = NULL;
462         return ptrArray;
463 }
464
465 /**
466  * Free array of pointers allocated by ldapctl_criteria_array().
467  * param ptrArray Array to clear.
468  */
469 void ldapctl_free_attribute_array( char **ptrArray ) {
470         gint i;
471
472         /* Clear array to NULL's */
473         for( i = 0; ptrArray[i] != NULL; i++ ) {
474                 ptrArray[i] = NULL;
475         }
476         g_free( ptrArray );
477 }       
478
479 /**
480  * Parse LDAP search string, building list of LDAP criteria attributes. This
481  * may be used to convert an old style Sylpheed LDAP search criteria to the
482  * new format. The old style uses a standard LDAP search string, for example:
483  * <pre>
484  *    (&(mail=*)(cn=%s*))
485  * </pre>
486  * This function extracts the two LDAP attributes <code>mail</code> and
487  * <code>cn</code>, adding each to a list.
488  *
489  * \param ctl Control object to process.
490  * \param criteria LDAP search criteria string.
491  */
492 void ldapctl_parse_ldap_search( LdapControl *ctl, gchar *criteria ) {
493         gchar *ptr;
494         gchar *pFrom;
495         gchar *attrib;
496         gint iLen;
497
498         g_return_if_fail( ctl != NULL );
499
500         ldapctl_criteria_list_clear( ctl );
501         if( criteria == NULL ) return;
502
503         pFrom = NULL;
504         ptr = criteria;
505         while( *ptr ) {
506                 if( *ptr == '(' ) {
507                         pFrom = 1 + ptr;
508                 }
509                 if( *ptr == '=' ) {
510                         if( pFrom ) {
511                                 iLen = ptr - pFrom;
512                                 attrib = g_strndup( pFrom, iLen );
513                                 g_strstrip( attrib );
514                                 ldapctl_criteria_list_add( ctl, attrib );
515                                 g_free( attrib );
516                         }
517                         pFrom = NULL;
518                 }
519                 ptr++;
520         }
521 }
522
523 #endif  /* USE_LDAP */
524
525 /*
526  * End of Source.
527  */
528