2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2006 Match Grun and the Sylpheed-Claws 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 define and perform LDAP queries.
35 #include "ldapquery.h"
40 #include "addrcache.h"
42 #include "ldapquery.h"
45 * Key for thread specific data.
47 static pthread_key_t _queryThreadKey_;
48 static gboolean _queryThreadInit_ = FALSE;
50 gboolean callbackend (gpointer data)
52 LdapQuery *qry = (LdapQuery *)data;
53 qry->callBackEnd( qry, ADDRQUERY_ID(qry), ADDRQUERY_RETVAL(qry), qry->data );
59 * Create new LDAP query object.
60 * \return Initialized query object.
62 LdapQuery *ldapqry_create( void ) {
65 qry = g_new0( LdapQuery, 1 );
66 ADDRQUERY_TYPE(qry) = ADDRQUERY_LDAP;
67 ADDRQUERY_ID(qry) = 0;
68 ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
69 ADDRQUERY_NAME(qry) = NULL;
70 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
71 ADDRQUERY_FOLDER(qry) = NULL;
72 ADDRQUERY_SEARCHVALUE(qry) = NULL;
77 qry->stopFlag = FALSE;
78 qry->busyFlag = FALSE;
79 qry->agedFlag = FALSE;
80 qry->completed = FALSE;
82 qry->callBackEntry = NULL;
83 qry->callBackEnd = NULL;
87 /* Mutex to protect stop and busy flags */
88 qry->mutexStop = g_malloc0( sizeof( pthread_mutex_t ) );
89 pthread_mutex_init( qry->mutexStop, NULL );
90 qry->mutexBusy = g_malloc0( sizeof( pthread_mutex_t ) );
91 pthread_mutex_init( qry->mutexBusy, NULL );
93 /* Mutex to protect critical section */
94 qry->mutexEntry = g_malloc0( sizeof( pthread_mutex_t ) );
95 pthread_mutex_init( qry->mutexEntry, NULL );
101 * Specify the reference to control data that will be used for the query. The calling
102 * module should be responsible for creating and destroying this control object.
103 * \param qry Query object.
104 * \param ctl Control object.
106 void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
107 g_return_if_fail( qry != NULL );
112 * Specify query name to be used.
113 * \param qry Query object.
116 void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
117 ADDRQUERY_NAME(qry) = mgu_replace_string( ADDRQUERY_NAME(qry), value );
118 g_strstrip( ADDRQUERY_NAME(qry) );
122 * Specify search value to be used.
123 * \param qry Query object.
126 void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
127 ADDRQUERY_SEARCHVALUE(qry) = mgu_replace_string( ADDRQUERY_SEARCHVALUE(qry), value );
128 g_strstrip( ADDRQUERY_SEARCHVALUE(qry) );
132 * Specify error/status.
133 * \param qry Query object.
134 * \param value Status.
136 void ldapqry_set_error_status( LdapQuery* qry, const gint value ) {
137 ADDRQUERY_RETVAL(qry) = value;
141 * Specify query type.
142 * \param qry Query object.
143 * \param value Query type, either:
145 * <li><code>LDAPQUERY_NONE</code></li>
146 * <li><code>LDAPQUERY_STATIC</code></li>
147 * <li><code>LDAPQUERY_DYNAMIC</code></li>
151 void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
152 ADDRQUERY_TYPE(qry) = value;
157 * Specify search type.
158 * \param qry Query object.
161 void ldapqry_set_search_type( LdapQuery *qry, const AddrSearchType value ) {
162 g_return_if_fail( qry != NULL );
163 ADDRQUERY_SEARCHTYPE(qry) = value;
168 * \param qry Query object.
169 * \param value ID for the query.
171 void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
172 ADDRQUERY_ID(qry) = value;
176 * Specify maximum number of LDAP entries to retrieve.
177 * \param qry Query object.
178 * \param value Entries to read.
180 void ldapqry_set_entries_read( LdapQuery* qry, const gint value ) {
182 qry->entriesRead = value;
185 qry->entriesRead = 0;
190 * Register a callback function that will be executed when each entry
191 * has been read and processed. When called, the function will be passed
192 * this query object and a GList of ItemEMail objects as arguments. An
193 * example of typical usage is shown below.
196 * ------------------------------------------------------------
197 * void myCallbackEntry( LdapQuery *qry, GList *listEMail ) {
202 * ItemEMail *email = node->data;
203 * ... process email object ...
204 * node = g_list_next( node );
206 * g_list_free( listEMail );
210 * ldapqry_set_callback_entry( qry, myCallbackEntry );
211 * ------------------------------------------------------------
214 * \param qry Query object.
215 * \param func Function.
217 void ldapqry_set_callback_entry( LdapQuery *qry, void *func ) {
218 pthread_mutex_lock( qry->mutexEntry );
219 qry->callBackEntry = func;
220 pthread_mutex_unlock( qry->mutexEntry );
224 * Register a callback function that will be executed when the search
225 * is complete. When called, the function will be passed this query
226 * object as an argument.
227 * \param qry Query object.
228 * \param func Function.
230 void ldapqry_set_callback_end( LdapQuery *qry, void *func ) {
231 qry->callBackEnd = func;
235 * Notify query to start/stop executing. This method should be called with a
236 * value if <i>TRUE</i> to terminate an existing running query.
238 * \param qry Query object.
239 * \param value Value of stop flag.
241 void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
242 g_return_if_fail( qry != NULL );
244 pthread_mutex_lock( qry->mutexStop );
245 qry->stopFlag = value;
246 pthread_mutex_unlock( qry->mutexStop );
250 * Test value of stop flag. This method should be used to determine whether a
251 * query has stopped running.
252 * \param qry Query object.
253 * \return Value of stop flag.
255 gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
257 g_return_val_if_fail( qry != NULL, TRUE );
259 pthread_mutex_lock( qry->mutexStop );
260 value = qry->stopFlag;
261 pthread_mutex_unlock( qry->mutexStop );
267 * \param qry Query object.
268 * \param value Value of busy flag.
270 void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
271 g_return_if_fail( qry != NULL );
273 pthread_mutex_lock( qry->mutexBusy );
274 qry->busyFlag = value;
275 pthread_mutex_unlock( qry->mutexBusy );
279 * Test value of busy flag. This method will return a value of <i>FALSE</i>
280 * when a query has completed running.
281 * \param qry Query object.
282 * \return Value of busy flag.
284 gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
286 g_return_val_if_fail( qry != NULL, FALSE );
288 pthread_mutex_lock( qry->mutexBusy );
289 value = qry->busyFlag;
290 pthread_mutex_unlock( qry->mutexBusy );
295 * Set query aged flag.
296 * \param qry Query object.
297 * \param value Value of aged flag.
299 void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
300 g_return_if_fail( qry != NULL );
301 qry->agedFlag = value;
305 * Test value of aged flag.
306 * \param qry Query object.
307 * \return <i>TRUE</i> if query has been marked as aged (and can be retired).
309 gboolean ldapqry_get_aged_flag( LdapQuery *qry ) {
310 g_return_val_if_fail( qry != NULL, TRUE );
311 return qry->agedFlag;
315 * Specify user data for query.
316 * \param qry Query object.
317 * \param value Data to set.
319 void ldapqry_set_data( LdapQuery *qry, const gpointer value ) {
320 g_return_if_fail( qry != NULL );
325 * Retrieve user data associated with query.
326 * \param qry Query object.
329 gpointer ldapqry_get_data( LdapQuery *qry ) {
330 g_return_val_if_fail( qry != NULL, NULL );
335 * Release the LDAP control data associated with the query.
336 * \param qry Query object to process.
338 void ldapqry_release_control( LdapQuery *qry ) {
339 g_return_if_fail( qry != NULL );
340 if( qry->control != NULL ) {
341 ldapctl_free( qry->control );
347 * Clear LDAP query member variables.
348 * \param qry Query object.
350 void ldapqry_clear( LdapQuery *qry ) {
351 g_return_if_fail( qry != NULL );
353 /* Free internal stuff */
354 g_free( ADDRQUERY_NAME(qry) );
355 g_free( ADDRQUERY_SEARCHVALUE(qry) );
357 /* Clear pointers and value */
358 ADDRQUERY_NAME(qry) = NULL;
359 ADDRQUERY_SEARCHVALUE(qry) = NULL;
360 ADDRQUERY_ID(qry) = 0;
361 ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
362 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
363 qry->entriesRead = 0;
364 qry->elapsedTime = 0;
365 qry->stopFlag = FALSE;
366 qry->busyFlag = FALSE;
367 qry->agedFlag = FALSE;
368 qry->completed = FALSE;
369 qry->callBackEntry = NULL;
370 qry->callBackEnd = NULL;
376 * Free up LDAP query object by releasing internal memory. Note that
377 * the thread object will be freed by the OS.
378 * \param qry Query object to process.
380 void ldapqry_free( LdapQuery *qry ) {
381 g_return_if_fail( qry != NULL );
383 /* Clear out internal members */
384 ADDRQUERY_TYPE(qry) = ADDRQUERY_NONE;
385 ldapqry_clear( qry );
388 pthread_mutex_destroy( qry->mutexStop );
389 pthread_mutex_destroy( qry->mutexBusy );
390 pthread_mutex_destroy( qry->mutexEntry );
391 g_free( qry->mutexStop );
392 g_free( qry->mutexBusy );
393 g_free( qry->mutexEntry );
394 qry->mutexEntry = NULL;
395 qry->mutexBusy = NULL;
396 qry->mutexStop = NULL;
398 /* Do not free folder - parent server object should free */
399 ADDRQUERY_FOLDER(qry) = NULL;
401 /* Do not free thread - thread should be terminated before freeing */
404 /* Do not free LDAP control - should be destroyed before freeing */
407 /* Now release object */
412 * Display object to specified stream.
413 * \param qry Query object to process.
414 * \param stream Output stream.
416 void ldapqry_print( const LdapQuery *qry, FILE *stream ) {
417 g_return_if_fail( qry != NULL );
419 fprintf( stream, "LdapQuery:\n" );
420 fprintf( stream, " control?: %s\n", qry->control ? "yes" : "no" );
421 fprintf( stream, "err/status: %d\n", ADDRQUERY_RETVAL(qry) );
422 fprintf( stream, "query type: %d\n", ADDRQUERY_TYPE(qry) );
423 fprintf( stream, "searchType: %d\n", ADDRQUERY_SEARCHTYPE(qry) );
424 fprintf( stream, "query name: '%s'\n", ADDRQUERY_NAME(qry) );
425 fprintf( stream, "search val: '%s'\n", ADDRQUERY_SEARCHVALUE(qry) );
426 fprintf( stream, " queryID: %d\n", ADDRQUERY_ID(qry) );
427 fprintf( stream, " entries: %d\n", qry->entriesRead );
428 fprintf( stream, " elapsed: %d\n", qry->elapsedTime );
429 fprintf( stream, " stop flag: %s\n", qry->stopFlag ? "yes" : "no" );
430 fprintf( stream, " busy flag: %s\n", qry->busyFlag ? "yes" : "no" );
431 fprintf( stream, " aged flag: %s\n", qry->agedFlag ? "yes" : "no" );
432 fprintf( stream, " completed: %s\n", qry->completed ? "yes" : "no" );
436 * Free linked lists of character strings.
437 * \param listName List of common names.
438 * \param listAddr List of addresses.
439 * \param listFirst List of first names.
440 * \param listLast List of last names.
442 static void ldapqry_free_lists(
443 GSList *listName, GSList *listAddr, GSList *listFirst,
446 mgu_free_list( listName );
447 mgu_free_list( listAddr );
448 mgu_free_list( listFirst );
449 mgu_free_list( listLast );
453 * Add all LDAP attribute values to a list.
454 * \param ld LDAP handle.
455 * \param entry LDAP entry to process.
456 * \param attr LDAP attribute.
457 * \return List of values.
459 static GSList *ldapqry_add_list_values(
460 LDAP *ld, LDAPMessage *entry, char *attr )
466 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
467 for( i = 0; vals[i] != NULL; i++ ) {
468 /* printf( "lv\t%s: %s\n", attr, vals[i] ); */
469 list = g_slist_append( list, g_strdup( vals[i] ) );
472 ldap_value_free( vals );
477 * Add a single attribute value to a list.
478 * \param ld LDAP handle.
479 * \param entry LDAP entry to process.
480 * \param attr LDAP attribute name to process.
481 * \return List of values; only one value will be present.
483 static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
487 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
488 if( vals[0] != NULL ) {
489 /* printf( "sv\t%s: %s\n", attr, vals[0] ); */
490 list = g_slist_append( list, g_strdup( vals[0] ) );
493 ldap_value_free( vals );
498 * Build an address list entry and append to list of address items. Name is formatted
499 * as "<first-name> <last-name>".
501 * \param cache Address cache to load.
502 * \param qry Query object to process.
503 * \param dn DN for entry found on server.
504 * \param listName List of common names for entry; see notes below.
505 * \param listAddr List of EMail addresses for entry.
506 * \param listFirst List of first names for entry.
507 * \param listLast List of last names for entry.
509 * \return List of ItemEMail objects.
512 * 1) Each LDAP server entry may have multiple LDAP attributes with the same
513 * name. For example, a single entry for a person may have more than one
514 * common name, email address, etc.
516 * 2) The DN for the entry is unique for the server.
518 static GList *ldapqry_build_items_fl(
519 AddressCache *cache, LdapQuery *qry, gchar *dn,
520 GSList *listName, GSList *listAddr, GSList *listFirst,
524 gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
529 GList *listReturn = NULL;
531 folder = ADDRQUERY_FOLDER(qry);
532 if( folder == NULL ) return listReturn;
533 if( listAddr == NULL ) return listReturn;
535 /* Find longest first name in list */
536 firstName = mgu_slist_longest_entry( listFirst );
538 /* Format last name */
540 lastName = listLast->data;
543 /* Find longest common name */
545 fullName = mgu_slist_longest_entry( listName );
546 if( fullName == NULL ) {
547 /* Format a full name from first and last names */
550 fullName = g_strdup_printf( "%s %s", firstName, lastName );
553 fullName = g_strdup_printf( "%s", firstName );
558 fullName = g_strdup_printf( "%s", lastName );
562 g_strchug( fullName ); g_strchomp( fullName );
567 /* Add person into folder */
568 person = addritem_create_item_person();
569 addritem_person_set_common_name( person, fullName );
570 addritem_person_set_first_name( person, firstName );
571 addritem_person_set_last_name( person, lastName );
572 addrcache_id_person( cache, person );
573 addritem_person_set_external_id( person, dn );
574 addrcache_folder_add_person( cache, ADDRQUERY_FOLDER(qry), person );
578 /* Add each address item */
579 nodeAddress = listAddr;
580 while( nodeAddress ) {
581 email = addritem_create_item_email();
582 addritem_email_set_address( email, nodeAddress->data );
583 addrcache_id_email( cache, email );
584 addrcache_person_add_email( cache, person, email );
585 addritem_person_add_email( person, email );
586 listReturn = g_list_append( listReturn, email );
587 nodeAddress = g_slist_next( nodeAddress );
590 /* Free any allocated memory */
594 fullName = firstName = lastName = NULL;
600 * Process a single search entry.
601 * \param cache Address cache to load.
602 * \param qry Query object to process.
603 * \param ld LDAP handle.
604 * \param e LDAP message.
605 * \return List of EMail objects found.
607 static GList *ldapqry_process_single_entry(
608 AddressCache *cache, LdapQuery *qry, LDAP *ld, LDAPMessage *e )
614 GSList *listName = NULL, *listAddress = NULL;
615 GSList *listFirst = NULL, *listLast = NULL;
620 dnEntry = ldap_get_dn( ld, e );
621 /* printf( "DN: %s\n", dnEntry ); */
623 /* Process all attributes */
624 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
625 attribute = ldap_next_attribute( ld, e, ber ) ) {
627 if( strcasecmp( attribute, ctl->attribEMail ) == 0 ) {
628 listAddress = ldapqry_add_list_values( ld, e, attribute );
630 else if( strcasecmp( attribute, ctl->attribCName ) == 0 ) {
631 listName = ldapqry_add_list_values( ld, e, attribute );
633 else if( strcasecmp( attribute, ctl->attribFName ) == 0 ) {
634 listFirst = ldapqry_add_list_values( ld, e, attribute );
636 else if( strcasecmp( attribute, ctl->attribLName ) == 0 ) {
637 listLast = ldapqry_add_single_value( ld, e, attribute );
640 /* Free memory used to store attribute */
641 ldap_memfree( attribute );
644 /* Format and add items to cache */
645 listReturn = ldapqry_build_items_fl(
646 cache, qry, dnEntry, listName, listAddress, listFirst, listLast );
649 ldapqry_free_lists( listName, listAddress, listFirst, listLast );
650 listName = listAddress = listFirst = listLast = NULL;
661 * Check parameters that are required for a search. This should
662 * be called before performing a search.
663 * \param qry Query object to process.
664 * \return <i>TRUE</i> if search criteria appear OK.
666 gboolean ldapqry_check_search( LdapQuery *qry ) {
668 ADDRQUERY_RETVAL(qry) = LDAPRC_CRITERIA;
670 /* Test for control data */
676 /* Test for search value */
677 if( ADDRQUERY_SEARCHVALUE(qry) == NULL ) {
680 if( strlen( ADDRQUERY_SEARCHVALUE(qry) ) < 1 ) {
683 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
688 * Touch the query. This nudges the touch time with the current time.
689 * \param qry Query object to process.
691 void ldapqry_touch( LdapQuery *qry ) {
692 qry->touchTime = time( NULL );
693 qry->agedFlag = FALSE;
697 * Connect to LDAP server.
698 * \param qry Query object to process.
699 * \return Error/status code.
701 static gint ldapqry_connect( LdapQuery *qry ) {
707 /* Initialize connection */
708 /* printf( "===ldapqry_connect===\n" ); */
709 /* ldapqry_print( qry, stdout ); */
711 /* ldapctl_print( ctl, stdout ); */
712 /* printf( "======\n" ); */
713 ldapqry_touch( qry );
714 qry->startTime = qry->touchTime;
715 qry->elapsedTime = -1;
716 ADDRQUERY_RETVAL(qry) = LDAPRC_INIT;
717 if (!ctl->enableSSL) {
718 ld = ldap_init( ctl->hostName, ctl->port );
720 gchar *uri = g_strdup_printf("ldaps://%s:%d",
721 ctl->hostName, ctl->port);
722 ldap_initialize(&ld, uri);
726 return ADDRQUERY_RETVAL(qry);
729 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
730 if( ldapqry_get_stop_flag( qry ) ) {
731 return ADDRQUERY_RETVAL(qry);
733 ldapqry_touch( qry );
736 printf( "connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port );
741 version = LDAP_VERSION3;
742 rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
743 if( rc == LDAP_OPT_SUCCESS ) {
744 ctl->version = LDAP_VERSION3;
747 if( ctl->version == LDAP_VERSION3 ) {
748 if( ctl->enableTLS && !ctl->enableSSL ) {
749 ADDRQUERY_RETVAL(qry) = LDAPRC_TLS;
750 rc = ldap_start_tls_s( ld, NULL, NULL );
752 /* printf( "rc=%d\n", rc );
753 printf( "LDAP Status: set_option: %s\n", ldap_err2string( rc ) ); */
755 if( rc != LDAP_SUCCESS ) {
756 return ADDRQUERY_RETVAL(qry);
762 /* Bind to the server, if required */
763 ADDRQUERY_RETVAL(qry) = LDAPRC_BIND;
765 if( * ctl->bindDN != '\0' ) {
766 /* printf( "binding...\n" ); */
767 rc = ldap_simple_bind_s( ld, ctl->bindDN, ctl->bindPass );
768 /* printf( "rc=%d\n", rc ); */
769 if( rc != LDAP_SUCCESS ) {
771 printf( "LDAP Error: ldap_simple_bind_s: %s\n",
772 ldap_err2string( rc ) );
774 return ADDRQUERY_RETVAL(qry);
778 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
779 if( ldapqry_get_stop_flag( qry ) ) {
780 return ADDRQUERY_RETVAL(qry);
782 ldapqry_touch( qry );
784 ADDRQUERY_RETVAL(qry) = LDAP_SUCCESS;
786 return ADDRQUERY_RETVAL(qry);
790 * Connect to LDAP server.
791 * \param qry Query object to process.
792 * \return Error/status code.
794 static gint ldapqry_disconnect( LdapQuery *qry ) {
796 if( qry->ldap ) ldap_unbind( qry->ldap );
799 ldapqry_touch( qry );
800 qry->elapsedTime = qry->touchTime - qry->startTime;
802 return ADDRQUERY_RETVAL(qry);
806 * Perform the LDAP search, reading LDAP entries into cache.
807 * Note that one LDAP entry can have multiple values for many of its
808 * attributes. If these attributes are E-Mail addresses; these are
809 * broken out into separate address items. For any other attribute,
810 * only the first occurrence is read.
812 * \param qry Query object to process.
813 * \return Error/status code.
815 static gint ldapqry_search_retrieve( LdapQuery *qry ) {
818 LDAPMessage *result, *e = NULL;
822 gboolean entriesFound;
824 struct timeval timeout;
829 /* Initialize some variables */
832 cache = qry->server->addressCache;
833 timeout.tv_sec = ctl->timeOut;
834 timeout.tv_usec = 0L;
835 entriesFound = FALSE;
836 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
838 /* Define all attributes we are interested in. */
839 attribs = ldapctl_attribute_array( ctl );
841 /* Create LDAP search string */
842 criteria = ldapctl_format_criteria( ctl, ADDRQUERY_SEARCHVALUE(qry) );
843 /* printf( "Search criteria ::%s::\n", criteria ); */
846 * Execute the search - this step may take some time to complete
847 * depending on network traffic and server response time.
849 ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
850 rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
851 attribs, 0, NULL, NULL, &timeout, 0, &result );
852 ldapctl_free_attribute_array( attribs );
855 if( rc == LDAP_TIMEOUT ) {
856 return ADDRQUERY_RETVAL(qry);
858 ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
860 /* Test valid returns */
862 if( rc == LDAP_ADMINLIMIT_EXCEEDED ) {
865 else if( rc == LDAP_SUCCESS ) {
868 else if( rc == LDAP_PARTIAL_RESULTS ) {
873 printf( "LDAP Error: ldap_search_st: %d\n", rc );
874 printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
876 return ADDRQUERY_RETVAL(qry);
878 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
881 printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
884 /* Process results */
886 while( searchFlag ) {
887 ldapqry_touch( qry );
888 if( qry->entriesRead >= ctl->maxEntries ) break;
891 if( ldapqry_get_stop_flag( qry ) ) {
898 e = ldap_first_entry( ld, result );
901 e = ldap_next_entry( ld, e );
903 if( e == NULL ) break;
906 /* Setup a critical section here */
907 pthread_mutex_lock( qry->mutexEntry );
910 listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
912 /* Process callback */
913 if( qry->callBackEntry ) {
914 qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data );
917 g_list_free( listEMail );
919 pthread_mutex_unlock( qry->mutexEntry );
922 /* Free up and disconnect */
923 ldap_msgfree( result );
927 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
930 ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
934 return ADDRQUERY_RETVAL(qry);
938 * Connection, perform search and disconnect.
939 * \param qry Query object to process.
940 * \return Error/status code.
942 static gint ldapqry_perform_search( LdapQuery *qry ) {
943 /* Check search criteria */
944 if( ! ldapqry_check_search( qry ) ) {
945 return ADDRQUERY_RETVAL(qry);
950 ldapqry_connect( qry );
951 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
953 ldapqry_search_retrieve( qry );
956 ldapqry_disconnect( qry );
959 return ADDRQUERY_RETVAL(qry);
962 static gint ldapqry_perform_locate( LdapQuery *qry );
965 * Wrapper around search.
966 * \param qry Query object to process.
967 * \return Error/status code.
969 gint ldapqry_search( LdapQuery *qry ) {
972 g_return_val_if_fail( qry != NULL, -1 );
973 g_return_val_if_fail( qry->control != NULL, -1 );
975 ldapqry_touch( qry );
976 qry->completed = FALSE;
978 /* Setup pointer to thread specific area */
979 pthread_setspecific( _queryThreadKey_, qry );
981 pthread_detach( pthread_self() );
983 /* Now perform the search */
984 qry->entriesRead = 0;
985 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
986 ldapqry_set_busy_flag( qry, TRUE );
987 ldapqry_set_stop_flag( qry, FALSE );
988 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) {
989 retVal = ldapqry_perform_locate( qry );
992 retVal = ldapqry_perform_search( qry );
994 if( retVal == LDAPRC_SUCCESS ) {
995 qry->server->addressCache->dataRead = TRUE;
996 qry->server->addressCache->accessFlag = FALSE;
997 if( ldapqry_get_stop_flag( qry ) ) {
999 printf( "Search was terminated prematurely\n" );
1003 ldapqry_touch( qry );
1004 qry->completed = TRUE;
1006 printf( "Search ran to completion\n" );
1010 ldapqry_set_stop_flag( qry, TRUE );
1011 ldapqry_set_busy_flag( qry, FALSE );
1013 /* Process callback */
1014 if( qry->callBackEnd ) {
1015 g_timeout_add(0, callbackend, qry);
1018 return ADDRQUERY_RETVAL(qry);
1022 * Read data into list using a background thread. Callback function will be
1023 * notified when search is complete.
1024 * \param qry Query object to process.
1025 * \return Error/status code.
1027 gint ldapqry_read_data_th( LdapQuery *qry ) {
1028 g_return_val_if_fail( qry != NULL, -1 );
1029 g_return_val_if_fail( qry->control != NULL, -1 );
1031 ldapqry_set_stop_flag( qry, FALSE );
1032 ldapqry_touch( qry );
1033 if( ldapqry_check_search( qry ) ) {
1034 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
1036 printf( "Starting LDAP search thread\n");
1038 ldapqry_set_busy_flag( qry, TRUE );
1039 qry->thread = g_malloc0( sizeof( pthread_t ) );
1042 pthread_create( qry->thread, NULL,
1043 (void *) ldapqry_search, (void *) qry );
1046 return ADDRQUERY_RETVAL(qry);
1050 * Cleanup LDAP thread data. This function will be called when each thread
1051 * exits. Note that the thread object will be freed by the kernel.
1052 * \param ptr Pointer to object being destroyed (a query object in this case).
1054 static void ldapqry_destroyer( void * ptr ) {
1057 qry = ( LdapQuery * ) ptr;
1059 printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), ADDRQUERY_NAME(qry) );
1062 /* Perform any destruction here */
1063 if( qry->control != NULL ) {
1064 ldapctl_free( qry->control );
1066 qry->control = NULL;
1068 ldapqry_set_busy_flag( qry, FALSE );
1072 * Cancel thread associated with query.
1073 * \param qry Query object to process.
1075 void ldapqry_cancel( LdapQuery *qry ) {
1076 g_return_if_fail( qry != NULL );
1079 printf( "cancelling::%d::%s\n", (int) pthread_self(), ADDRQUERY_NAME(qry) );
1081 if( ldapqry_get_busy_flag( qry ) ) {
1083 /* printf( "calling pthread_cancel\n" ); */
1084 pthread_cancel( * qry->thread );
1090 * Initialize LDAP query. This function should be called once before executing
1091 * any LDAP queries to initialize thread specific data.
1093 void ldapqry_initialize( void ) {
1094 /* printf( "ldapqry_initialize...\n" ); */
1095 if( ! _queryThreadInit_ ) {
1097 printf( "ldapqry_initialize::creating thread specific area\n" );
1099 pthread_key_create( &_queryThreadKey_, ldapqry_destroyer );
1100 _queryThreadInit_ = TRUE;
1102 /* printf( "ldapqry_initialize... done!\n" ); */
1106 * Age the query based on LDAP control parameters.
1107 * \param qry Query object to process.
1108 * \param maxAge Maximum age of query (in seconds).
1110 void ldapqry_age( LdapQuery *qry, gint maxAge ) {
1113 g_return_if_fail( qry != NULL );
1115 /* Limit the time that queries can hang around */
1116 if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
1118 /* Check age of query */
1119 age = time( NULL ) - qry->touchTime;
1120 if( age > maxAge ) {
1121 qry->agedFlag = TRUE;
1126 * Delete folder associated with query results.
1127 * \param qry Query object to process.
1129 void ldapqry_delete_folder( LdapQuery *qry ) {
1130 AddressCache *cache;
1133 g_return_if_fail( qry != NULL );
1135 folder = ADDRQUERY_FOLDER(qry);
1137 cache = qry->server->addressCache;
1138 folder = addrcache_remove_folder_delete( cache, folder );
1140 addritem_free_item_folder( folder );
1142 ADDRQUERY_FOLDER(qry) = NULL;
1147 * Create a name/value pair object.
1150 * \return Initialized object.
1152 static NameValuePair *ldapqry_create_name_value( const gchar *n, const gchar *v ) {
1153 NameValuePair *nvp = g_new0( NameValuePair, 1 );
1155 nvp->name = g_strdup( n );
1156 nvp->value = g_strdup( v );
1161 * Free up name/value pair object.
1162 * \param nvp Name/value object.
1164 void ldapqry_free_name_value( NameValuePair *nvp ) {
1166 g_free( nvp->name );
1167 g_free( nvp->value );
1168 nvp->name = nvp->value = NULL;
1174 * Print name/value pair object for debug.
1175 * \param nvp Name/value object.
1176 * \param stream Output stream.
1178 void ldapqry_print_name_value( NameValuePair *nvp, FILE *stream ) {
1180 fprintf( stream, "n/v ::%s::%s::\n", nvp->name, nvp->value );
1185 * Free up a list name/value pair objects.
1186 * \param list List of name/value objects.
1188 void ldapqry_free_list_name_value( GList *list ) {
1193 NameValuePair *nvp = ( NameValuePair * ) node->data;
1194 ldapqry_free_name_value( nvp );
1196 node = g_list_next( node );
1198 g_list_free( list );
1202 * Load a list of name/value pairs from LDAP attributes.
1203 * \param ld LDAP handle.
1204 * \param e LDAP message.
1205 * \param attr Attribute name.
1206 * \param listValues List to populate.
1207 * \return List of attribute name/value pairs.
1209 static GList *ldapqry_load_attrib_values(
1210 LDAP *ld, LDAPMessage *entry, char *attr,
1219 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
1220 for( i = 0; vals[i] != NULL; i++ ) {
1221 nvp = ldapqry_create_name_value( attr, vals[i] );
1222 list = g_list_append( list, nvp );
1225 ldap_value_free( vals );
1230 * Fetch a list of all attributes.
1231 * \param ld LDAP handle.
1232 * \param e LDAP message.
1233 * \return List of attribute name/value pairs.
1235 static GList *ldapqry_fetch_attribs( LDAP *ld, LDAPMessage *e )
1239 GList *listValues = NULL;
1241 /* Process all attributes */
1242 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
1243 attribute = ldap_next_attribute( ld, e, ber ) ) {
1244 listValues = ldapqry_load_attrib_values( ld, e, attribute, listValues );
1245 ldap_memfree( attribute );
1255 #define CRITERIA_SINGLE "(objectclass=*)"
1258 * Perform the data retrieval for a specific LDAP record.
1260 * \param qry Query object to process.
1261 * \return Error/status code.
1263 static gint ldapqry_locate_retrieve( LdapQuery *qry ) {
1266 LDAPMessage *result, *e = NULL;
1267 gboolean entriesFound;
1269 struct timeval timeout;
1274 /* Initialize some variables */
1277 dn = ADDRQUERY_SEARCHVALUE(qry);
1278 timeout.tv_sec = ctl->timeOut;
1279 timeout.tv_usec = 0L;
1280 entriesFound = FALSE;
1283 * Execute the search - this step may take some time to complete
1284 * depending on network traffic and server response time.
1286 ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
1287 rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE, CRITERIA_SINGLE,
1288 NULL, 0, NULL, NULL, &timeout, 0, &result );
1289 if( rc == LDAP_TIMEOUT ) {
1290 return ADDRQUERY_RETVAL(qry);
1292 ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
1293 if( rc != LDAP_SUCCESS ) {
1295 printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
1297 return ADDRQUERY_RETVAL(qry);
1301 printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
1304 /* Process results */
1305 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
1308 ldapqry_touch( qry );
1309 if( qry->entriesRead >= ctl->maxEntries ) break;
1312 if( ldapqry_get_stop_flag( qry ) ) {
1316 /* Retrieve entry */
1319 e = ldap_first_entry( ld, result );
1322 e = ldap_next_entry( ld, e );
1324 if( e == NULL ) break;
1326 entriesFound = TRUE;
1328 /* Setup a critical section here */
1329 pthread_mutex_lock( qry->mutexEntry );
1332 listValues = ldapqry_fetch_attribs( ld, e );
1334 /* Process callback */
1335 if( qry->callBackEntry ) {
1336 qry->callBackEntry( qry, ADDRQUERY_ID(qry), listValues, qry->data );
1338 ldapqry_free_list_name_value( listValues );
1341 pthread_mutex_unlock( qry->mutexEntry );
1344 /* Free up and disconnect */
1345 ldap_msgfree( result );
1347 if( entriesFound ) {
1348 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
1351 ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
1354 return ADDRQUERY_RETVAL(qry);
1358 * Perform the search to locate a specific LDAP record identified by
1359 * distinguished name (dn).
1361 * \param qry Query object to process.
1362 * \return Error/status code.
1364 static gint ldapqry_perform_locate( LdapQuery *qry ) {
1367 ldapqry_connect( qry );
1368 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
1369 /* Perform search */
1370 ldapqry_locate_retrieve( qry );
1373 ldapqry_disconnect( qry );
1376 /* Process callback */
1377 if( qry->callBackEnd ) {
1378 g_timeout_add(0, callbackend, qry);
1381 return ADDRQUERY_RETVAL(qry);
1385 * Remove results (folder and data) for specified LDAP query.
1386 * \param qry Query object to process.
1387 * \return TRUE if folder deleted successfully.
1389 gboolean ldapquery_remove_results( LdapQuery *qry ) {
1390 gboolean retVal = FALSE;
1392 ldapqry_set_aged_flag( qry, TRUE );
1394 if( ldapqry_get_busy_flag( qry ) ) {
1395 ldapqry_set_stop_flag( qry, TRUE );
1398 LdapServer *server = qry->server;
1399 server->listQuery = g_list_remove(server->listQuery, qry);
1406 #endif /* USE_LDAP */