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 thread associated with the query.
304 * \param qry Query object to process.
306 void ldapqry_release_thread( LdapQuery *qry ) {
307 g_return_if_fail( qry != NULL );
308 printf( "ldapqry_release_thread...\n" );
309 if( qry->thread != NULL ) {
310 g_free( qry->thread );
311 printf( "\t===========>done\n" );
317 * Release the LDAP control data associated with the query.
318 * \param qry Query object to process.
320 void ldapqry_release_control( LdapQuery *qry ) {
321 g_return_if_fail( qry != NULL );
322 if( qry->control != NULL ) {
323 ldapctl_free( qry->control );
329 * Clear LDAP query member variables.
330 * \param qry Query object.
332 void ldapqry_clear( LdapQuery *qry ) {
333 g_return_if_fail( qry != NULL );
335 /* Free internal stuff */
336 g_free( qry->queryName );
337 g_free( qry->searchValue );
339 /* Clear pointers and value */
340 qry->queryName = NULL;
341 qry->searchValue = NULL;
342 qry->retVal = LDAPRC_SUCCESS;
343 qry->queryType = LDAPQUERY_NONE;
345 qry->entriesRead = 0;
346 qry->elapsedTime = 0;
347 qry->stopFlag = FALSE;
348 qry->busyFlag = FALSE;
349 qry->agedFlag = FALSE;
350 qry->completed = FALSE;
351 qry->callBackStart = NULL;
352 qry->callBackEntry = NULL;
353 qry->callBackEnd = NULL;
357 * Free up LDAP query object by releasing internal memory.
358 * \param qry Query object to process.
360 void ldapqry_free( LdapQuery *qry ) {
361 g_return_if_fail( qry != NULL );
363 /* Clear out internal members */
364 ldapqry_clear( qry );
367 pthread_mutex_destroy( qry->mutexStop );
368 pthread_mutex_destroy( qry->mutexBusy );
369 pthread_mutex_destroy( qry->mutexEntry );
370 g_free( qry->mutexStop );
371 g_free( qry->mutexBusy );
372 g_free( qry->mutexEntry );
373 qry->mutexEntry = NULL;
374 qry->mutexBusy = NULL;
375 qry->mutexStop = NULL;
377 /* Do not free folder - parent server object should free */
380 /* Do not free thread - thread should be terminated before freeing */
383 /* Do not free LDAP control - should be destroyed before freeing */
386 /* Now release object */
391 * Display object to specified stream.
392 * \param qry Query object to process.
393 * \param stream Output stream.
395 void ldapqry_print( const LdapQuery *qry, FILE *stream ) {
396 g_return_if_fail( qry != NULL );
398 fprintf( stream, "LdapQuery:\n" );
399 fprintf( stream, " control?: %s\n", qry->control ? "yes" : "no" );
400 fprintf( stream, "err/status: %d\n", qry->retVal );
401 fprintf( stream, "query type: %d\n", qry->queryType );
402 fprintf( stream, "query name: '%s'\n", qry->queryName );
403 fprintf( stream, "search val: '%s'\n", qry->searchValue );
404 fprintf( stream, " queryID: %d\n", qry->queryID );
405 fprintf( stream, " entries: %d\n", qry->entriesRead );
406 fprintf( stream, " elapsed: %d\n", qry->elapsedTime );
407 fprintf( stream, " stop flag: %s\n", qry->stopFlag ? "yes" : "no" );
408 fprintf( stream, " busy flag: %s\n", qry->busyFlag ? "yes" : "no" );
409 fprintf( stream, " aged flag: %s\n", qry->agedFlag ? "yes" : "no" );
410 fprintf( stream, " completed: %s\n", qry->completed ? "yes" : "no" );
414 * Free linked lists of character strings.
415 * \param listName List of common names.
416 * \param listAddr List of addresses.
417 * \param listFirst List of first names.
418 * \param listLast List of last names.
420 static void ldapqry_free_lists(
421 GSList *listName, GSList *listAddr, GSList *listFirst,
424 mgu_free_list( listName );
425 mgu_free_list( listAddr );
426 mgu_free_list( listFirst );
427 mgu_free_list( listLast );
431 * Add all LDAP attribute values to a list.
432 * \param ld LDAP handle.
433 * \param entry LDAP entry to process.
434 * \param attr LDAP attribute.
435 * \return List of values.
437 static GSList *ldapqry_add_list_values(
438 LDAP *ld, LDAPMessage *entry, char *attr )
444 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
445 for( i = 0; vals[i] != NULL; i++ ) {
446 /* printf( "lv\t%s: %s\n", attr, vals[i] ); */
447 list = g_slist_append( list, g_strdup( vals[i] ) );
450 ldap_value_free( vals );
455 * Add a single attribute value to a list.
456 * \param ld LDAP handle.
457 * \param entry LDAP entry to process.
458 * \param attr LDAP attribute name to process.
459 * \return List of values; only one value will be present.
461 static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
465 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
466 if( vals[0] != NULL ) {
467 /* printf( "sv\t%s: %s\n", attr, vals[0] ); */
468 list = g_slist_append( list, g_strdup( vals[0] ) );
471 ldap_value_free( vals );
476 * Build an address list entry and append to list of address items. Name is formatted
477 * as "<first-name> <last-name>".
479 * \param cache Address cache to load.
480 * \param qry Query object to process.
481 * \param dn DN for entry found on server.
482 * \param listName List of common names for entry; see notes below.
483 * \param listAddr List of EMail addresses for entry.
484 * \param listFirst List of first names for entry.
485 * \param listLast List of last names for entry.
487 * \return List of ItemEMail objects.
490 * 1) Each LDAP server entry may have multiple LDAP attributes with the same
491 * name. For example, a single entry for a person may have more than one
492 * common name, email address, etc.
494 * 2) The DN for the entry is unique for the server.
496 static GList *ldapqry_build_items_fl(
497 AddressCache *cache, LdapQuery *qry, gchar *dn,
498 GSList *listName, GSList *listAddr, GSList *listFirst,
502 gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
511 /* Find longest first name in list */
512 firstName = mgu_slist_longest_entry( listFirst );
514 /* Format last name */
516 lastName = listLast->data;
519 /* Find longest common name */
521 fullName = mgu_slist_longest_entry( listName );
522 if( fullName == NULL ) {
523 /* Format a full name from first and last names */
526 fullName = g_strdup_printf( "%s %s", firstName, lastName );
529 fullName = g_strdup_printf( "%s", firstName );
534 fullName = g_strdup_printf( "%s", lastName );
538 g_strchug( fullName ); g_strchomp( fullName );
544 /* Create new folder for results */
545 if( qry->folder == NULL ) {
546 folder = addritem_create_item_folder();
547 addritem_folder_set_name( folder, qry->queryName );
548 addritem_folder_set_remarks( folder, "" );
549 addrcache_id_folder( cache, folder );
550 addrcache_add_folder( cache, folder );
551 qry->folder = folder;
553 /* Specify folder type and back reference */
554 folder->folderType = ADDRFOLDER_LDAP_QUERY;
555 folder->folderData = ( gpointer ) qry;
558 /* Add person into folder */
559 person = addritem_create_item_person();
560 addritem_person_set_common_name( person, fullName );
561 addritem_person_set_first_name( person, firstName );
562 addritem_person_set_last_name( person, lastName );
563 addrcache_id_person( cache, person );
564 addritem_person_set_external_id( person, dn );
565 addrcache_folder_add_person( cache, qry->folder, person );
570 /* Add each address item */
571 nodeAddress = listAddr;
572 while( nodeAddress ) {
573 email = addritem_create_item_email();
574 addritem_email_set_address( email, nodeAddress->data );
575 addrcache_id_email( cache, email );
576 addrcache_person_add_email( cache, person, email );
577 addritem_person_add_email( person, email );
578 listReturn = g_list_append( listReturn, email );
579 nodeAddress = g_slist_next( nodeAddress );
582 /* Free any allocated memory */
586 fullName = firstName = lastName = NULL;
592 * Process a single search entry.
593 * \param cache Address cache to load.
594 * \param qry Query object to process.
595 * \param ld LDAP handle.
596 * \param e LDAP message.
597 * \return List of EMail objects found.
599 static GList *ldapqry_process_single_entry(
600 AddressCache *cache, LdapQuery *qry, LDAP *ld, LDAPMessage *e )
606 GSList *listName = NULL, *listAddress = NULL;
607 GSList *listFirst = NULL, *listLast = NULL;
612 dnEntry = ldap_get_dn( ld, e );
613 /* printf( "DN: %s\n", dnEntry ); */
615 /* Process all attributes */
616 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
617 attribute = ldap_next_attribute( ld, e, ber ) ) {
619 if( strcasecmp( attribute, ctl->attribEMail ) == 0 ) {
620 listAddress = ldapqry_add_list_values( ld, e, attribute );
622 else if( strcasecmp( attribute, ctl->attribCName ) == 0 ) {
623 listName = ldapqry_add_list_values( ld, e, attribute );
625 else if( strcasecmp( attribute, ctl->attribFName ) == 0 ) {
626 listFirst = ldapqry_add_list_values( ld, e, attribute );
628 else if( strcasecmp( attribute, ctl->attribLName ) == 0 ) {
629 listLast = ldapqry_add_single_value( ld, e, attribute );
632 /* Free memory used to store attribute */
633 ldap_memfree( attribute );
636 /* Format and add items to cache */
637 listReturn = ldapqry_build_items_fl(
638 cache, qry, dnEntry, listName, listAddress, listFirst, listLast );
641 ldapqry_free_lists( listName, listAddress, listFirst, listLast );
642 listName = listAddress = listFirst = listLast = NULL;
653 * Check parameters that are required for a search. This should
654 * be called before performing a search.
655 * \param qry Query object to process.
656 * \return <i>TRUE</i> if search criteria appear OK.
658 gboolean ldapqry_check_search( LdapQuery *qry ) {
660 qry->retVal = LDAPRC_CRITERIA;
662 /* Test for control data */
668 /* Test for search value */
669 if( qry->searchValue == NULL ) {
672 if( strlen( qry->searchValue ) < 1 ) {
676 qry->retVal = LDAPRC_SUCCESS;
681 * Touch the query. This nudges the touch time with the current time.
682 * \param qry Query object to process.
684 void ldapqry_touch( LdapQuery *qry ) {
685 qry->touchTime = time( NULL );
686 qry->agedFlag = FALSE;
690 * Perform the LDAP search, reading LDAP entries into cache.
691 * Note that one LDAP entry can have multiple values for many of its
692 * attributes. If these attributes are E-Mail addresses; these are
693 * broken out into separate address items. For any other attribute,
694 * only the first occurrence is read.
696 * \param qry Query object to process.
697 * \return Error/status code.
699 static gint ldapqry_perform_search( LdapQuery *qry ) {
702 LDAPMessage *result, *e;
705 gboolean entriesFound;
707 struct timeval timeout;
713 /* Initialize some variables */
715 cache = qry->server->addressCache;
716 timeout.tv_sec = ctl->timeOut;
717 timeout.tv_usec = 0L;
718 entriesFound = FALSE;
719 qry->elapsedTime = -1;
720 qry->retVal = LDAPRC_SUCCESS;
722 /* Check search criteria */
723 if( ! ldapqry_check_search( qry ) ) {
727 /* Initialize connection */
728 ldapqry_touch( qry );
729 tstart = qry->touchTime;
731 if( ( ld = ldap_init( ctl->hostName, ctl->port ) ) == NULL ) {
732 qry->retVal = LDAPRC_INIT;
735 if( ldapqry_get_stop_flag( qry ) ) {
736 qry->retVal = LDAPRC_SUCCESS;
739 ldapqry_touch( qry );
742 printf( "connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port );
745 /* Bind to the server, if required */
747 if( * ctl->bindDN != '\0' ) {
748 /* printf( "binding...\n" ); */
749 rc = ldap_simple_bind_s( ld, ctl->bindDN, ctl->bindPass );
750 /* printf( "rc=%d\n", rc ); */
751 if( rc != LDAP_SUCCESS ) {
753 printf( "LDAP Error: ldap_simple_bind_s: %s\n",
754 ldap_err2string( rc ) );
757 qry->retVal = LDAPRC_BIND;
762 if( ldapqry_get_stop_flag( qry ) ) {
764 qry->retVal = LDAPRC_SUCCESS;
767 ldapqry_touch( qry );
769 /* Define all attributes we are interested in. */
770 attribs = ldapctl_attribute_array( ctl );
772 /* Create LDAP search string */
773 criteria = ldapctl_format_criteria( ctl, qry->searchValue );
774 /* printf( "Search criteria ::%s::\n", criteria ); */
777 * Execute the search - this step may take some time to complete
778 * depending on network traffic and server response time.
780 rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
781 attribs, 0, NULL, NULL, &timeout, 0, &result );
782 ldapctl_free_attribute_array( attribs );
785 if( rc == LDAP_TIMEOUT ) {
787 qry->retVal = LDAPRC_TIMEOUT;
790 if( rc != LDAP_SUCCESS ) {
792 printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
795 qry->retVal = LDAPRC_SEARCH;
798 if( ldapqry_get_stop_flag( qry ) ) {
799 qry->retVal = LDAPRC_SUCCESS;
802 ldapqry_touch( qry );
805 printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
808 if( ldapqry_get_stop_flag( qry ) ) {
809 qry->retVal = LDAPRC_SUCCESS;
813 /* Process results */
816 ldapqry_touch( qry );
817 if( qry->entriesRead >= ctl->maxEntries ) break;
820 if( ldapqry_get_stop_flag( qry ) ) {
827 e = ldap_first_entry( ld, result );
830 e = ldap_next_entry( ld, e );
832 if( e == NULL ) break;
836 /* Setup a critical section here */
837 pthread_mutex_lock( qry->mutexEntry );
840 listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
842 /* Process callback */
843 if( qry->callBackEntry ) {
844 qry->callBackEntry( qry, listEMail );
847 g_list_free( listEMail );
850 pthread_mutex_unlock( qry->mutexEntry );
853 /* Free up and disconnect */
854 ldap_msgfree( result );
856 ldapqry_touch( qry );
857 tend = qry->touchTime;
858 qry->elapsedTime = tend - tstart;
861 qry->retVal = LDAPRC_SUCCESS;
864 qry->retVal = LDAPRC_NOENTRIES;
871 * Wrapper around search.
872 * \param qry Query object to process.
873 * \return Error/status code.
875 gint ldapqry_search( LdapQuery *qry ) {
878 g_return_val_if_fail( qry != NULL, -1 );
879 g_return_val_if_fail( qry->control != NULL, -1 );
881 ldapqry_touch( qry );
882 qry->completed = FALSE;
884 /* Process callback */
885 if( qry->callBackStart ) {
886 qry->callBackStart( qry );
889 /* Setup pointer to thread specific area */
890 pthread_setspecific( _queryThreadKey_, qry );
892 pthread_detach( pthread_self() );
894 /* Now perform the search */
895 qry->entriesRead = 0;
896 qry->retVal = LDAPRC_SUCCESS;
897 ldapqry_set_busy_flag( qry, TRUE );
898 ldapqry_set_stop_flag( qry, FALSE );
899 retVal = ldapqry_perform_search( qry );
900 if( retVal == LDAPRC_SUCCESS ) {
901 qry->server->addressCache->dataRead = TRUE;
902 qry->server->addressCache->accessFlag = FALSE;
903 if( ldapqry_get_stop_flag( qry ) ) {
905 printf( "Search was terminated prematurely\n" );
909 ldapqry_touch( qry );
910 qry->completed = TRUE;
912 printf( "Search ran to completion\n" );
916 ldapqry_set_stop_flag( qry, TRUE );
917 ldapqry_set_busy_flag( qry, FALSE );
919 /* Process callback */
920 if( qry->callBackEnd ) {
921 qry->callBackEnd( qry );
928 * Read data into list using a background thread. Callback function will be
929 * notified when search is complete.
930 * \param qry Query object to process.
931 * \return Error/status code.
933 gint ldapqry_read_data_th( LdapQuery *qry ) {
934 g_return_val_if_fail( qry != NULL, -1 );
935 g_return_val_if_fail( qry->control != NULL, -1 );
937 ldapqry_set_stop_flag( qry, FALSE );
938 ldapqry_touch( qry );
939 if( ldapqry_check_search( qry ) ) {
940 if( qry->retVal == LDAPRC_SUCCESS ) {
942 printf( "Starting LDAP search thread\n");
944 ldapqry_set_busy_flag( qry, TRUE );
945 qry->thread = g_malloc0( sizeof( pthread_t ) );
948 pthread_create( qry->thread, NULL,
949 (void *) ldapqry_search, (void *) qry );
956 * Join the thread associated with the query. This should probably be removed
957 * to prevent joining threads.
958 * \param qry Query object to process.
960 void ldapqry_join_thread( LdapQuery *qry ) {
961 g_return_if_fail( qry != NULL );
963 /* Wait for thread */
964 /* printf( "ldapqry_join_thread::Joining thread...\n" ); */
965 pthread_join( * qry->thread, NULL );
966 /* printf( "ldapqry_join_thread::Thread terminated\n" ); */
970 * Cleanup LDAP thread data. This function will be called when each thread
972 * \param ptr Pointer to object being destroyed (a query object in this case).
974 static void ldapqry_destroyer( void * ptr ) {
977 qry = ( LdapQuery * ) ptr;
979 printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), qry->queryName );
982 /* Perform any destruction here */
983 if( qry->control != NULL ) {
984 ldapctl_free( qry->control );
989 g_free( qry->thread );
992 ldapqry_set_busy_flag( qry, FALSE );
994 printf( "...destroy exiting\n" );
999 * Cancel thread associated with query.
1000 * \param qry Query object to process.
1002 void ldapqry_cancel( LdapQuery *qry ) {
1003 g_return_if_fail( qry != NULL );
1006 printf( "cancelling::%d::%s\n", (int) pthread_self(), qry->queryName );
1008 if( ldapqry_get_busy_flag( qry ) ) {
1010 pthread_cancel( * qry->thread );
1016 * Initialize LDAP query. This function should be called once before executing
1017 * any LDAP queries to initialize thread specific data.
1019 void ldapqry_initialize( void ) {
1020 /* printf( "ldapqry_initialize...\n" ); */
1021 if( ! _queryThreadInit_ ) {
1023 printf( "ldapqry_initialize::creating thread specific area\n" );
1025 pthread_key_create( &_queryThreadKey_, ldapqry_destroyer );
1026 _queryThreadInit_ = TRUE;
1028 /* printf( "ldapqry_initialize... done!\n" ); */
1032 * Age the query based on LDAP control parameters.
1033 * \param qry Query object to process.
1034 * \param maxAge Maximum age of query (in seconds).
1036 void ldapqry_age( LdapQuery *qry, gint maxAge ) {
1039 g_return_if_fail( qry != NULL );
1041 /* Limit the time that queries can hang around */
1042 if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
1044 /* Check age of query */
1045 age = time( NULL ) - qry->touchTime;
1046 if( age > maxAge ) {
1047 qry->agedFlag = TRUE;
1052 * Delete folder associated with query results.
1053 * \param qry Query object to process.
1055 void ldapqry_delete_folder( LdapQuery *qry ) {
1056 AddressCache *cache;
1059 g_return_if_fail( qry != NULL );
1061 folder = qry->folder;
1063 cache = qry->server->addressCache;
1064 folder = addrcache_remove_folder_delete( cache, folder );
1066 addritem_free_item_folder( folder );
1072 #endif /* USE_LDAP */