2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003 Match Grun
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Functions necessary to define and perform LDAP queries.
36 #include "ldapquery.h"
41 #include "addrcache.h"
44 * Key for thread specific data.
46 static pthread_key_t _queryThreadKey_;
47 static gboolean _queryThreadInit_ = FALSE;
50 * Create new LDAP query object.
51 * \return Initialized query object.
53 LdapQuery *ldapqry_create( void ) {
56 qry = g_new0( LdapQuery, 1 );
58 qry->retVal = LDAPRC_SUCCESS;
59 qry->queryType = LDAPQUERY_NONE;
60 qry->queryName = NULL;
61 qry->searchValue = NULL;
65 qry->stopFlag = FALSE;
66 qry->busyFlag = FALSE;
67 qry->agedFlag = FALSE;
68 qry->completed = FALSE;
70 qry->callBackStart = NULL;
71 qry->callBackEntry = NULL;
72 qry->callBackEnd = NULL;
76 /* Mutex to protect stop and busy flags */
77 qry->mutexStop = g_malloc0( sizeof( pthread_mutex_t ) );
78 pthread_mutex_init( qry->mutexStop, NULL );
79 qry->mutexBusy = g_malloc0( sizeof( pthread_mutex_t ) );
80 pthread_mutex_init( qry->mutexBusy, NULL );
82 /* Mutex to protect critical section */
83 qry->mutexEntry = g_malloc0( sizeof( pthread_mutex_t ) );
84 pthread_mutex_init( qry->mutexEntry, NULL );
90 * Specify the reference to control data that will be used for the query. The calling
91 * module should be responsible for creating and destroying this control object.
92 * \param qry Query object.
93 * \param ctl Control object.
95 void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
96 g_return_if_fail( qry != NULL );
101 * Specify query name to be used.
102 * \param qry Query object.
105 void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
106 qry->queryName = mgu_replace_string( qry->queryName, value );
107 g_strstrip( qry->queryName );
111 * Specify search value to be used.
112 * \param qry Query object.
115 void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
116 qry->searchValue = mgu_replace_string( qry->searchValue, value );
117 g_strstrip( qry->searchValue );
121 * Specify error/status.
122 * \param qry Query object.
123 * \param value Status.
125 void ldapqry_set_error_status( LdapQuery* qry, const gint value ) {
130 * Specify query type.
131 * \param qry Query object.
132 * \param value Query type, either:
134 * <li><code>LDAPQUERY_NONE</code></li>
135 * <li><code>LDAPQUERY_STATIC</code></li>
136 * <li><code>LDAPQUERY_DYNAMIC</code></li>
139 void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
140 qry->queryType = value;
145 * \param qry Query object.
146 * \param value ID for the query.
148 void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
149 qry->queryID = value;
153 * Specify maximum number of LDAP entries to retrieve.
154 * \param qry Query object.
155 * \param value Entries to read.
157 void ldapqry_set_entries_read( LdapQuery* qry, const gint value ) {
159 qry->entriesRead = value;
162 qry->entriesRead = 0;
167 * Register a callback function that will be executed when the search
168 * starts. When called, the function will be passed this query object
170 * \param qry Query object.
171 * \param func Function.
173 void ldapqry_set_callback_start( LdapQuery *qry, void *func ) {
174 qry->callBackStart = func;
178 * Register a callback function that will be executed when each entry
179 * has been read and processed. When called, the function will be passed
180 * this query object and a GList of ItemEMail objects as arguments. An
181 * example of typical usage is shown below.
184 * ------------------------------------------------------------
185 * void myCallbackEntry( LdapQuery *qry, GList *listEMail ) {
190 * ItemEMail *email = node->data;
191 * ... process email object ...
192 * node = g_list_next( node );
194 * g_list_free( listEMail );
198 * ldapqry_set_callback_entry( qry, myCallbackEntry );
199 * ------------------------------------------------------------
202 * \param qry Query object.
203 * \param func Function.
205 void ldapqry_set_callback_entry( LdapQuery *qry, void *func ) {
206 pthread_mutex_lock( qry->mutexEntry );
207 qry->callBackEntry = func;
208 pthread_mutex_unlock( qry->mutexEntry );
212 * Register a callback function that will be executed when the search
213 * is complete. When called, the function will be passed this query
214 * object as an argument.
215 * \param qry Query object.
216 * \param func Function.
218 void ldapqry_set_callback_end( LdapQuery *qry, void *func ) {
219 qry->callBackEnd = func;
223 * Notify query to start/stop executing. This method should be called with a
224 * value if <i>TRUE</i> to terminate an existing running query.
226 * \param qry Query object.
227 * \param value Value of stop flag.
229 void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
230 g_return_if_fail( qry != NULL );
232 pthread_mutex_lock( qry->mutexStop );
233 qry->stopFlag = value;
234 pthread_mutex_unlock( qry->mutexStop );
238 * Test value of stop flag. This method should be used to determine whether a
239 * query has stopped running.
240 * \param qry Query object.
241 * \return Value of stop flag.
243 gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
245 g_return_if_fail( qry != NULL );
247 pthread_mutex_lock( qry->mutexStop );
248 value = qry->stopFlag;
249 pthread_mutex_unlock( qry->mutexStop );
255 * \param qry Query object.
256 * \param value Value of busy flag.
258 void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
259 g_return_if_fail( qry != NULL );
261 pthread_mutex_lock( qry->mutexBusy );
262 qry->busyFlag = value;
263 pthread_mutex_unlock( qry->mutexBusy );
267 * Test value of busy flag. This method will return a value of <i>FALSE</i>
268 * when a query has completed running.
269 * \param qry Query object.
270 * \return Value of busy flag.
272 gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
274 g_return_if_fail( qry != NULL );
276 pthread_mutex_lock( qry->mutexBusy );
277 value = qry->busyFlag;
278 pthread_mutex_unlock( qry->mutexBusy );
283 * Set query aged flag.
284 * \param qry Query object.
285 * \param value Value of aged flag.
287 void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
288 g_return_if_fail( qry != NULL );
289 qry->agedFlag = value;
293 * Test value of aged flag.
294 * \param qry Query object.
295 * \return <i>TRUE</i> if query has been marked as aged (and can be retired).
297 gboolean ldapqry_get_aged_flag( LdapQuery *qry ) {
298 g_return_if_fail( qry != NULL );
299 return qry->agedFlag;
303 * Release the LDAP control data associated with the query.
304 * \param qry Query object to process.
306 void ldapqry_release_control( LdapQuery *qry ) {
307 g_return_if_fail( qry != NULL );
308 if( qry->control != NULL ) {
309 ldapctl_free( qry->control );
315 * Clear LDAP query member variables.
316 * \param qry Query object.
318 void ldapqry_clear( LdapQuery *qry ) {
319 g_return_if_fail( qry != NULL );
321 /* Free internal stuff */
322 g_free( qry->queryName );
323 g_free( qry->searchValue );
325 /* Clear pointers and value */
326 qry->queryName = NULL;
327 qry->searchValue = NULL;
328 qry->retVal = LDAPRC_SUCCESS;
329 qry->queryType = LDAPQUERY_NONE;
331 qry->entriesRead = 0;
332 qry->elapsedTime = 0;
333 qry->stopFlag = FALSE;
334 qry->busyFlag = FALSE;
335 qry->agedFlag = FALSE;
336 qry->completed = FALSE;
337 qry->callBackStart = NULL;
338 qry->callBackEntry = NULL;
339 qry->callBackEnd = NULL;
343 * Free up LDAP query object by releasing internal memory. Note that
344 * the thread object will be freed by the OS.
345 * \param qry Query object to process.
347 void ldapqry_free( LdapQuery *qry ) {
348 g_return_if_fail( qry != NULL );
350 /* Clear out internal members */
351 ldapqry_clear( qry );
354 pthread_mutex_destroy( qry->mutexStop );
355 pthread_mutex_destroy( qry->mutexBusy );
356 pthread_mutex_destroy( qry->mutexEntry );
357 g_free( qry->mutexStop );
358 g_free( qry->mutexBusy );
359 g_free( qry->mutexEntry );
360 qry->mutexEntry = NULL;
361 qry->mutexBusy = NULL;
362 qry->mutexStop = NULL;
364 /* Do not free folder - parent server object should free */
367 /* Do not free thread - thread should be terminated before freeing */
370 /* Do not free LDAP control - should be destroyed before freeing */
373 /* Now release object */
378 * Display object to specified stream.
379 * \param qry Query object to process.
380 * \param stream Output stream.
382 void ldapqry_print( const LdapQuery *qry, FILE *stream ) {
383 g_return_if_fail( qry != NULL );
385 fprintf( stream, "LdapQuery:\n" );
386 fprintf( stream, " control?: %s\n", qry->control ? "yes" : "no" );
387 fprintf( stream, "err/status: %d\n", qry->retVal );
388 fprintf( stream, "query type: %d\n", qry->queryType );
389 fprintf( stream, "query name: '%s'\n", qry->queryName );
390 fprintf( stream, "search val: '%s'\n", qry->searchValue );
391 fprintf( stream, " queryID: %d\n", qry->queryID );
392 fprintf( stream, " entries: %d\n", qry->entriesRead );
393 fprintf( stream, " elapsed: %d\n", qry->elapsedTime );
394 fprintf( stream, " stop flag: %s\n", qry->stopFlag ? "yes" : "no" );
395 fprintf( stream, " busy flag: %s\n", qry->busyFlag ? "yes" : "no" );
396 fprintf( stream, " aged flag: %s\n", qry->agedFlag ? "yes" : "no" );
397 fprintf( stream, " completed: %s\n", qry->completed ? "yes" : "no" );
401 * Free linked lists of character strings.
402 * \param listName List of common names.
403 * \param listAddr List of addresses.
404 * \param listFirst List of first names.
405 * \param listLast List of last names.
407 static void ldapqry_free_lists(
408 GSList *listName, GSList *listAddr, GSList *listFirst,
411 mgu_free_list( listName );
412 mgu_free_list( listAddr );
413 mgu_free_list( listFirst );
414 mgu_free_list( listLast );
418 * Add all LDAP attribute values to a list.
419 * \param ld LDAP handle.
420 * \param entry LDAP entry to process.
421 * \param attr LDAP attribute.
422 * \return List of values.
424 static GSList *ldapqry_add_list_values(
425 LDAP *ld, LDAPMessage *entry, char *attr )
431 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
432 for( i = 0; vals[i] != NULL; i++ ) {
433 /* printf( "lv\t%s: %s\n", attr, vals[i] ); */
434 list = g_slist_append( list, g_strdup( vals[i] ) );
437 ldap_value_free( vals );
442 * Add a single attribute value to a list.
443 * \param ld LDAP handle.
444 * \param entry LDAP entry to process.
445 * \param attr LDAP attribute name to process.
446 * \return List of values; only one value will be present.
448 static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
452 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
453 if( vals[0] != NULL ) {
454 /* printf( "sv\t%s: %s\n", attr, vals[0] ); */
455 list = g_slist_append( list, g_strdup( vals[0] ) );
458 ldap_value_free( vals );
463 * Build an address list entry and append to list of address items. Name is formatted
464 * as "<first-name> <last-name>".
466 * \param cache Address cache to load.
467 * \param qry Query object to process.
468 * \param dn DN for entry found on server.
469 * \param listName List of common names for entry; see notes below.
470 * \param listAddr List of EMail addresses for entry.
471 * \param listFirst List of first names for entry.
472 * \param listLast List of last names for entry.
474 * \return List of ItemEMail objects.
477 * 1) Each LDAP server entry may have multiple LDAP attributes with the same
478 * name. For example, a single entry for a person may have more than one
479 * common name, email address, etc.
481 * 2) The DN for the entry is unique for the server.
483 static GList *ldapqry_build_items_fl(
484 AddressCache *cache, LdapQuery *qry, gchar *dn,
485 GSList *listName, GSList *listAddr, GSList *listFirst,
489 gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
498 /* Find longest first name in list */
499 firstName = mgu_slist_longest_entry( listFirst );
501 /* Format last name */
503 lastName = listLast->data;
506 /* Find longest common name */
508 fullName = mgu_slist_longest_entry( listName );
509 if( fullName == NULL ) {
510 /* Format a full name from first and last names */
513 fullName = g_strdup_printf( "%s %s", firstName, lastName );
516 fullName = g_strdup_printf( "%s", firstName );
521 fullName = g_strdup_printf( "%s", lastName );
525 g_strchug( fullName ); g_strchomp( fullName );
531 /* Create new folder for results */
532 if( qry->folder == NULL ) {
533 folder = addritem_create_item_folder();
534 addritem_folder_set_name( folder, qry->queryName );
535 addritem_folder_set_remarks( folder, "" );
536 addrcache_id_folder( cache, folder );
537 addrcache_add_folder( cache, folder );
538 qry->folder = folder;
540 /* Specify folder type and back reference */
541 folder->folderType = ADDRFOLDER_LDAP_QUERY;
542 folder->folderData = ( gpointer ) qry;
545 /* Add person into folder */
546 person = addritem_create_item_person();
547 addritem_person_set_common_name( person, fullName );
548 addritem_person_set_first_name( person, firstName );
549 addritem_person_set_last_name( person, lastName );
550 addrcache_id_person( cache, person );
551 addritem_person_set_external_id( person, dn );
552 addrcache_folder_add_person( cache, qry->folder, person );
557 /* Add each address item */
558 nodeAddress = listAddr;
559 while( nodeAddress ) {
560 email = addritem_create_item_email();
561 addritem_email_set_address( email, nodeAddress->data );
562 addrcache_id_email( cache, email );
563 addrcache_person_add_email( cache, person, email );
564 addritem_person_add_email( person, email );
565 listReturn = g_list_append( listReturn, email );
566 nodeAddress = g_slist_next( nodeAddress );
569 /* Free any allocated memory */
573 fullName = firstName = lastName = NULL;
579 * Process a single search entry.
580 * \param cache Address cache to load.
581 * \param qry Query object to process.
582 * \param ld LDAP handle.
583 * \param e LDAP message.
584 * \return List of EMail objects found.
586 static GList *ldapqry_process_single_entry(
587 AddressCache *cache, LdapQuery *qry, LDAP *ld, LDAPMessage *e )
593 GSList *listName = NULL, *listAddress = NULL;
594 GSList *listFirst = NULL, *listLast = NULL;
599 dnEntry = ldap_get_dn( ld, e );
600 /* printf( "DN: %s\n", dnEntry ); */
602 /* Process all attributes */
603 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
604 attribute = ldap_next_attribute( ld, e, ber ) ) {
606 if( strcasecmp( attribute, ctl->attribEMail ) == 0 ) {
607 listAddress = ldapqry_add_list_values( ld, e, attribute );
609 else if( strcasecmp( attribute, ctl->attribCName ) == 0 ) {
610 listName = ldapqry_add_list_values( ld, e, attribute );
612 else if( strcasecmp( attribute, ctl->attribFName ) == 0 ) {
613 listFirst = ldapqry_add_list_values( ld, e, attribute );
615 else if( strcasecmp( attribute, ctl->attribLName ) == 0 ) {
616 listLast = ldapqry_add_single_value( ld, e, attribute );
619 /* Free memory used to store attribute */
620 ldap_memfree( attribute );
623 /* Format and add items to cache */
624 listReturn = ldapqry_build_items_fl(
625 cache, qry, dnEntry, listName, listAddress, listFirst, listLast );
628 ldapqry_free_lists( listName, listAddress, listFirst, listLast );
629 listName = listAddress = listFirst = listLast = NULL;
640 * Check parameters that are required for a search. This should
641 * be called before performing a search.
642 * \param qry Query object to process.
643 * \return <i>TRUE</i> if search criteria appear OK.
645 gboolean ldapqry_check_search( LdapQuery *qry ) {
647 qry->retVal = LDAPRC_CRITERIA;
649 /* Test for control data */
655 /* Test for search value */
656 if( qry->searchValue == NULL ) {
659 if( strlen( qry->searchValue ) < 1 ) {
663 qry->retVal = LDAPRC_SUCCESS;
668 * Touch the query. This nudges the touch time with the current time.
669 * \param qry Query object to process.
671 void ldapqry_touch( LdapQuery *qry ) {
672 qry->touchTime = time( NULL );
673 qry->agedFlag = FALSE;
677 * Perform the LDAP search, reading LDAP entries into cache.
678 * Note that one LDAP entry can have multiple values for many of its
679 * attributes. If these attributes are E-Mail addresses; these are
680 * broken out into separate address items. For any other attribute,
681 * only the first occurrence is read.
683 * \param qry Query object to process.
684 * \return Error/status code.
686 static gint ldapqry_perform_search( LdapQuery *qry ) {
689 LDAPMessage *result, *e;
692 gboolean entriesFound;
694 struct timeval timeout;
700 /* Initialize some variables */
702 cache = qry->server->addressCache;
703 timeout.tv_sec = ctl->timeOut;
704 timeout.tv_usec = 0L;
705 entriesFound = FALSE;
706 qry->elapsedTime = -1;
707 qry->retVal = LDAPRC_SUCCESS;
709 /* Check search criteria */
710 if( ! ldapqry_check_search( qry ) ) {
714 /* Initialize connection */
715 ldapqry_touch( qry );
716 tstart = qry->touchTime;
718 if( ( ld = ldap_init( ctl->hostName, ctl->port ) ) == NULL ) {
719 qry->retVal = LDAPRC_INIT;
722 if( ldapqry_get_stop_flag( qry ) ) {
723 qry->retVal = LDAPRC_SUCCESS;
726 ldapqry_touch( qry );
729 printf( "connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port );
732 /* Bind to the server, if required */
734 if( * ctl->bindDN != '\0' ) {
735 /* printf( "binding...\n" ); */
736 rc = ldap_simple_bind_s( ld, ctl->bindDN, ctl->bindPass );
737 /* printf( "rc=%d\n", rc ); */
738 if( rc != LDAP_SUCCESS ) {
740 printf( "LDAP Error: ldap_simple_bind_s: %s\n",
741 ldap_err2string( rc ) );
744 qry->retVal = LDAPRC_BIND;
749 if( ldapqry_get_stop_flag( qry ) ) {
751 qry->retVal = LDAPRC_SUCCESS;
754 ldapqry_touch( qry );
756 /* Define all attributes we are interested in. */
757 attribs = ldapctl_attribute_array( ctl );
759 /* Create LDAP search string */
760 criteria = ldapctl_format_criteria( ctl, qry->searchValue );
761 /* printf( "Search criteria ::%s::\n", criteria ); */
764 * Execute the search - this step may take some time to complete
765 * depending on network traffic and server response time.
767 rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
768 attribs, 0, NULL, NULL, &timeout, 0, &result );
769 ldapctl_free_attribute_array( attribs );
772 if( rc == LDAP_TIMEOUT ) {
774 qry->retVal = LDAPRC_TIMEOUT;
777 if( rc != LDAP_SUCCESS ) {
779 printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
782 qry->retVal = LDAPRC_SEARCH;
785 if( ldapqry_get_stop_flag( qry ) ) {
786 qry->retVal = LDAPRC_SUCCESS;
789 ldapqry_touch( qry );
792 printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
795 if( ldapqry_get_stop_flag( qry ) ) {
796 qry->retVal = LDAPRC_SUCCESS;
800 /* Process results */
803 ldapqry_touch( qry );
804 if( qry->entriesRead >= ctl->maxEntries ) break;
807 if( ldapqry_get_stop_flag( qry ) ) {
814 e = ldap_first_entry( ld, result );
817 e = ldap_next_entry( ld, e );
819 if( e == NULL ) break;
823 /* Setup a critical section here */
824 pthread_mutex_lock( qry->mutexEntry );
827 listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
829 /* Process callback */
830 if( qry->callBackEntry ) {
831 qry->callBackEntry( qry, listEMail );
834 g_list_free( listEMail );
837 pthread_mutex_unlock( qry->mutexEntry );
840 /* Free up and disconnect */
841 ldap_msgfree( result );
843 ldapqry_touch( qry );
844 tend = qry->touchTime;
845 qry->elapsedTime = tend - tstart;
848 qry->retVal = LDAPRC_SUCCESS;
851 qry->retVal = LDAPRC_NOENTRIES;
858 * Wrapper around search.
859 * \param qry Query object to process.
860 * \return Error/status code.
862 gint ldapqry_search( LdapQuery *qry ) {
865 g_return_val_if_fail( qry != NULL, -1 );
866 g_return_val_if_fail( qry->control != NULL, -1 );
868 ldapqry_touch( qry );
869 qry->completed = FALSE;
871 /* Process callback */
872 if( qry->callBackStart ) {
873 qry->callBackStart( qry );
876 /* Setup pointer to thread specific area */
877 pthread_setspecific( _queryThreadKey_, qry );
879 pthread_detach( pthread_self() );
881 /* Now perform the search */
882 qry->entriesRead = 0;
883 qry->retVal = LDAPRC_SUCCESS;
884 ldapqry_set_busy_flag( qry, TRUE );
885 ldapqry_set_stop_flag( qry, FALSE );
886 retVal = ldapqry_perform_search( qry );
887 if( retVal == LDAPRC_SUCCESS ) {
888 qry->server->addressCache->dataRead = TRUE;
889 qry->server->addressCache->accessFlag = FALSE;
890 if( ldapqry_get_stop_flag( qry ) ) {
892 printf( "Search was terminated prematurely\n" );
896 ldapqry_touch( qry );
897 qry->completed = TRUE;
899 printf( "Search ran to completion\n" );
903 ldapqry_set_stop_flag( qry, TRUE );
904 ldapqry_set_busy_flag( qry, FALSE );
906 /* Process callback */
907 if( qry->callBackEnd ) {
908 qry->callBackEnd( qry );
915 * Read data into list using a background thread. Callback function will be
916 * notified when search is complete.
917 * \param qry Query object to process.
918 * \return Error/status code.
920 gint ldapqry_read_data_th( LdapQuery *qry ) {
921 g_return_val_if_fail( qry != NULL, -1 );
922 g_return_val_if_fail( qry->control != NULL, -1 );
924 ldapqry_set_stop_flag( qry, FALSE );
925 ldapqry_touch( qry );
926 if( ldapqry_check_search( qry ) ) {
927 if( qry->retVal == LDAPRC_SUCCESS ) {
929 printf( "Starting LDAP search thread\n");
931 ldapqry_set_busy_flag( qry, TRUE );
932 qry->thread = g_malloc0( sizeof( pthread_t ) );
935 pthread_create( qry->thread, NULL,
936 (void *) ldapqry_search, (void *) qry );
943 * Join the thread associated with the query. This should probably be removed
944 * to prevent joining threads.
945 * \param qry Query object to process.
947 void ldapqry_join_threadX( LdapQuery *qry ) {
948 g_return_if_fail( qry != NULL );
950 /* Wait for thread */
951 /* printf( "ldapqry_join_thread::Joining thread...\n" ); */
952 pthread_join( * qry->thread, NULL );
953 /* printf( "ldapqry_join_thread::Thread terminated\n" ); */
957 * Cleanup LDAP thread data. This function will be called when each thread
958 * exits. Note that the thread object will be freed by the kernel.
959 * \param ptr Pointer to object being destroyed (a query object in this case).
961 static void ldapqry_destroyer( void * ptr ) {
964 qry = ( LdapQuery * ) ptr;
966 printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), qry->queryName );
969 /* Perform any destruction here */
970 if( qry->control != NULL ) {
971 ldapctl_free( qry->control );
975 ldapqry_set_busy_flag( qry, FALSE );
977 printf( "...destroy exiting\n" );
982 * Cancel thread associated with query.
983 * \param qry Query object to process.
985 void ldapqry_cancel( LdapQuery *qry ) {
986 g_return_if_fail( qry != NULL );
989 printf( "cancelling::%d::%s\n", (int) pthread_self(), qry->queryName );
991 if( ldapqry_get_busy_flag( qry ) ) {
993 pthread_cancel( * qry->thread );
999 * Initialize LDAP query. This function should be called once before executing
1000 * any LDAP queries to initialize thread specific data.
1002 void ldapqry_initialize( void ) {
1003 /* printf( "ldapqry_initialize...\n" ); */
1004 if( ! _queryThreadInit_ ) {
1006 printf( "ldapqry_initialize::creating thread specific area\n" );
1008 pthread_key_create( &_queryThreadKey_, ldapqry_destroyer );
1009 _queryThreadInit_ = TRUE;
1011 /* printf( "ldapqry_initialize... done!\n" ); */
1015 * Age the query based on LDAP control parameters.
1016 * \param qry Query object to process.
1017 * \param maxAge Maximum age of query (in seconds).
1019 void ldapqry_age( LdapQuery *qry, gint maxAge ) {
1022 g_return_if_fail( qry != NULL );
1024 /* Limit the time that queries can hang around */
1025 if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
1027 /* Check age of query */
1028 age = time( NULL ) - qry->touchTime;
1029 if( age > maxAge ) {
1030 qry->agedFlag = TRUE;
1035 * Delete folder associated with query results.
1036 * \param qry Query object to process.
1038 void ldapqry_delete_folder( LdapQuery *qry ) {
1039 AddressCache *cache;
1042 g_return_if_fail( qry != NULL );
1044 folder = qry->folder;
1046 cache = qry->server->addressCache;
1047 folder = addrcache_remove_folder_delete( cache, folder );
1049 addritem_free_item_folder( folder );
1055 #endif /* USE_LDAP */