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 access LDAP servers.
38 #include "addrcache.h"
40 #include "ldapquery.h"
41 #include "ldapserver.h"
43 #include "adbookbase.h"
46 * Create new LDAP server interface object with no control object.
47 * \return Initialized LDAP server object.
49 LdapServer *ldapsvr_create_noctl( void ) {
52 server = g_new0( LdapServer, 1 );
53 server->type = ADBOOKTYPE_LDAP;
54 server->addressCache = addrcache_create();
55 server->retVal = MGU_SUCCESS;
56 server->control = NULL;
57 server->listQuery = NULL;
58 server->searchFlag = FALSE;
63 * Create new LDAP server interface object.
64 * \return Initialized LDAP server object.
66 LdapServer *ldapsvr_create( void ) {
69 server = ldapsvr_create_noctl();
70 server->control = ldapctl_create();
75 * Return name of server.
76 * \param server Server object.
77 * \return Name for server.
79 gchar *ldapsvr_get_name( LdapServer *server ) {
80 g_return_val_if_fail( server != NULL, NULL );
81 return addrcache_get_name( server->addressCache );
85 * Specify name to be used.
86 * \param server Server object.
87 * \param value Name for server.
89 void ldapsvr_set_name( LdapServer* server, const gchar *value ) {
90 g_return_if_fail( server != NULL );
91 addrcache_set_name( server->addressCache, value );
95 * Refresh internal variables to force a file read.
96 * \param server Server object.
98 void ldapsvr_force_refresh( LdapServer *server ) {
99 addrcache_refresh( server->addressCache );
103 * Return status/error code.
104 * \param server Server object.
105 * \return Status/error code.
107 gint ldapsvr_get_status( LdapServer *server ) {
108 g_return_val_if_fail( server != NULL, -1 );
109 return server->retVal;
113 * Return reference to root level folder.
114 * \param server Server object.
115 * \return Root level folder.
117 ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
118 g_return_val_if_fail( server != NULL, NULL );
120 printf( "ldapsvr_get_root_folder/start\n" );
121 ldapsvr_print_data( server, stdout );
122 printf( "ldapsvr_get_root_folder/done\n" );
124 return addrcache_get_root_folder( server->addressCache );
128 * Test whether server data has been accessed.
129 * \param server Server object.
130 * \return <i>TRUE</i> if data was accessed.
132 gboolean ldapsvr_get_accessed( LdapServer *server ) {
133 g_return_val_if_fail( server != NULL, FALSE );
134 return server->addressCache->accessFlag;
138 * Specify that server's data whas beed accessed.
139 * \param server Server object.
140 * \param value Value for flag.
142 void ldapsvr_set_accessed( LdapServer *server, const gboolean value ) {
143 g_return_if_fail( server != NULL );
144 server->addressCache->accessFlag = value;
148 * Test whether server data has been modified.
149 * \param server Server object.
150 * \return <i>TRUE</i> if data was modified.
152 gboolean ldapsvr_get_modified( LdapServer *server ) {
153 g_return_val_if_fail( server != NULL, FALSE );
154 return server->addressCache->modified;
158 * Specify modify flag.
159 * \param server Server object.
160 * \param value Value for flag.
162 void ldapsvr_set_modified( LdapServer *server, const gboolean value ) {
163 g_return_if_fail( server != NULL );
164 server->addressCache->modified = value;
168 * Test whether data was read from server.
169 * \param server Server object.
170 * \return <i>TRUE</i> if data was read.
172 gboolean ldapsvr_get_read_flag( LdapServer *server ) {
173 g_return_val_if_fail( server != NULL, FALSE );
174 return server->addressCache->dataRead;
178 * Test whether server is to be used for dynamic searches.
179 * \param server Server object.
180 * \return <i>TRUE</i> if server is used for dynamic searches.
182 gboolean ldapsvr_get_search_flag( LdapServer *server ) {
183 g_return_val_if_fail( server != NULL, FALSE );
184 return server->searchFlag;
188 * Specify that server is to be used for dynamic searches.
189 * \param server Server object.
190 * \param value Name for server.
192 void ldapsvr_set_search_flag( LdapServer *server, const gboolean value ) {
193 g_return_if_fail( server != NULL );
194 server->searchFlag = value;
198 * Specify the reference to control data that will be used for the query. The calling
199 * module should be responsible for creating and destroying this control object.
200 * \param server Server object.
201 * \param ctl Control data.
203 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl ) {
204 g_return_if_fail( server != NULL );
205 addrcache_refresh( server->addressCache );
206 server->control = ctl;
211 * \param server Server object.
213 void ldapsvr_free_all_query( LdapServer *server ) {
215 g_return_if_fail( server != NULL );
217 node = server->listQuery;
219 LdapQuery *qry = node->data;
222 node = g_list_next( node );
224 g_list_free( server->listQuery );
225 server->listQuery = NULL;
229 * Add query to server.
230 * \param server Server object.
231 * \param qry Query object.
233 void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
234 g_return_if_fail( server != NULL );
235 g_return_if_fail( qry != NULL );
237 server->listQuery = g_list_append( server->listQuery, qry );
238 qry->server = server;
242 * Free up LDAP server interface object by releasing internal memory.
243 * \param server Server object.
245 void ldapsvr_free( LdapServer *server ) {
246 g_return_if_fail( server != NULL );
248 /* Stop and cancel any queries that may be active */
249 ldapsvr_stop_all_query( server );
250 ldapsvr_cancel_all_query( server );
253 addrcache_clear( server->addressCache );
254 addrcache_free( server->addressCache );
256 /* Free LDAP control block */
257 ldapctl_free( server->control );
258 server->control = NULL;
260 /* Free all queries */
261 ldapsvr_free_all_query( server );
264 server->type = ADBOOKTYPE_NONE;
265 server->addressCache = NULL;
266 server->retVal = MGU_SUCCESS;
267 server->listQuery = NULL;
268 server->searchFlag = FALSE;
270 /* Now release LDAP object */
275 * Display object to specified stream.
276 * \param server Server object.
277 * \param stream Output stream.
279 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
283 g_return_if_fail( server != NULL );
285 fprintf( stream, "LdapServer:\n" );
286 fprintf( stream, " ret val: %d\n", server->retVal );
287 fprintf( stream, "srch flag: %s\n",
288 server->searchFlag ? "yes" : "no" );
289 if( server->control ) {
290 ldapctl_print( server->control, stream );
293 fprintf( stream, " control: NULL\n" );
295 addrcache_print( server->addressCache, stream );
296 addritem_print_item_folder( server->addressCache->rootFolder, stream );
300 node = server->listQuery;
302 LdapQuery *qry = node->data;
303 fprintf( stream, " query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
305 node = g_list_next( node );
310 * Return link list of persons.
311 * \param server Server object.
312 * \return List of persons.
314 GList *ldapsvr_get_list_person( LdapServer *server ) {
315 g_return_val_if_fail( server != NULL, NULL );
316 return addrcache_get_list_person( server->addressCache );
320 * Return link list of folders. There are no "real" folders that are returned
322 * \param server Server object.
323 * \return List of folders.
325 GList *ldapsvr_get_list_folder( LdapServer *server ) {
326 g_return_val_if_fail( server != NULL, NULL );
327 /* return addrcache_get_list_folder( server->addressCache ); */
332 * Execute specified query.
333 * \param server LDAP server.
334 * \param qry LDAP query.
336 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
337 LdapControl *ctlCopy;
339 g_return_if_fail( server != NULL );
340 g_return_if_fail( qry != NULL );
342 /* Copy server's control data to the query */
343 ctlCopy = ldapctl_create();
344 ldapctl_copy( server->control, ctlCopy );
345 ldapqry_set_control( qry, ctlCopy );
346 ldapqry_initialize();
349 /* printf( "ldapsvr_execute_query::checking query...\n" ); */
350 if( ldapqry_check_search( qry ) ) {
351 /* printf( "ldapsvr_execute_query::reading with thread...\n" ); */
352 ldapqry_read_data_th( qry );
354 if( qry->retVal == LDAPRC_SUCCESS ) {
355 printf( "ldapsvr_execute_query::SUCCESS with thread...\n" );
359 /* printf( "ldapsvr_execute_query... terminated\n" ); */
363 * Stop all queries for specified ID.
364 * \param server Server object.
365 * \param queryID Query ID to stop.
367 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
369 g_return_if_fail( server != NULL );
371 node = server->listQuery;
373 LdapQuery *qry = node->data;
374 if( ADDRQUERY_ID(qry) == queryID ) {
375 /* Notify thread to stop */
376 ldapqry_set_stop_flag( qry, TRUE );
378 node = g_list_next( node );
383 * Stop all queries by notifying each thread to stop.
384 * \param server Server object.
386 void ldapsvr_stop_all_query( LdapServer *server ) {
388 g_return_if_fail( server != NULL );
390 node = server->listQuery;
392 LdapQuery *qry = node->data;
393 ldapqry_set_stop_flag( qry, TRUE );
394 node = g_list_next( node );
399 * Cancel all query threads for server.
400 * \param server Server object.
402 void ldapsvr_cancel_all_query( LdapServer *server ) {
404 g_return_if_fail( server != NULL );
406 node = server->listQuery;
408 LdapQuery *qry = node->data;
409 /* Notify thread to stop */
410 ldapqry_set_stop_flag( qry, TRUE );
411 /* Now cancel thread */
412 ldapqry_cancel( qry );
413 node = g_list_next( node );
418 * Search most recent query for specified search term. The most recent
419 * completed query is returned. If no completed query is found, the most recent
420 * incomplete is returned.
421 * \param server LdapServer.
422 * \param searchTerm Search term to locate.
423 * \return Query object, or <i>NULL</i> if none found.
425 static LdapQuery *ldapsvr_locate_query(
426 const LdapServer *server, const gchar *searchTerm )
428 LdapQuery *incomplete = NULL;
430 g_return_val_if_fail( server != NULL, NULL );
432 node = server->listQuery;
433 node = g_list_last( node );
434 /* Search backwards for query */
436 LdapQuery *qry = node->data;
437 if( g_utf8_collate( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
438 if( qry->agedFlag ) continue;
439 if( qry->completed ) {
447 node = g_list_previous( node );
453 * Retire aged queries. Only the following queries are retired:
455 * a) Dynamic queries.
456 * b) Explicit searches that have a hidden folders.
457 * c) Locate searches that have a hidden folder.
459 * \param server LdapServer.
461 void ldapsvr_retire_query( LdapServer *server ) {
469 /* printf( "ldapsvr_retire_query\n" ); */
470 g_return_if_fail( server != NULL );
471 ctl = server->control;
472 maxAge = ctl->maxQueryAge;
474 /* Identify queries to age and move to deletion list */
476 node = server->listQuery;
478 LdapQuery *qry = node->data;
480 node = g_list_next( node );
481 folder = ADDRQUERY_FOLDER(qry);
482 if( folder == NULL ) continue;
483 if( ! folder->isHidden ) {
484 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
485 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
488 ldapqry_age( qry, maxAge );
489 if( qry->agedFlag ) {
490 /* Delete folder associated with query */
492 printf( "deleting folder... ::%s::\n", ADDRQUERY_NAME(qry) );
494 ldapqry_delete_folder( qry );
495 listDelete = g_list_append( listDelete, qry );
500 listQuery = server->listQuery;
503 LdapQuery *qry = node->data;
505 listQuery = g_list_remove( listQuery, qry );
508 node = g_list_next( node );
510 server->listQuery = listQuery;
512 /* Free up deletion list */
513 g_list_free( listDelete );
517 * Return results of a previous query by executing callback for each address
518 * contained in specified folder.
520 * \param folder Address book folder to process.
521 * \param req Address query request object.
523 static void ldapsvr_previous_query(
524 const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
526 AddrSearchCallbackEntry *callBack;
533 callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
536 node = folder->listPerson;
538 AddrItemObject *aio = node->data;
539 if( aio && aio->type == ITEMTYPE_PERSON ) {
540 ItemPerson *person = node->data;
541 nodeEM = person->listEMail;
543 ItemEMail *email = nodeEM->data;
545 nodeEM = g_list_next( nodeEM );
546 listEMail = g_list_append( listEMail, email );
549 node = g_list_next( node );
551 ( callBack ) ( sender, req->queryID, listEMail, NULL );
552 /* // g_list_free( listEMail ); */
557 * Reuse search results from a previous LDAP query. If there is a query that
558 * has the same search term as specified in the query request, then the query
561 * \param server LDAP server object.
562 * \param req Address query object.
563 * \return <i>TRUE</i> if previous query was used.
565 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
570 g_return_val_if_fail( server != NULL, FALSE );
571 g_return_val_if_fail( req != NULL, FALSE );
573 searchTerm = req->searchTerm;
575 /* Test whether any queries for the same term exist */
576 qry = ldapsvr_locate_query( server, searchTerm );
578 /* Touch query to ensure it hangs around for a bit longer */
579 ldapqry_touch( qry );
580 folder = ADDRQUERY_FOLDER(qry);
582 ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
590 * Construct a new LdapQuery object that will be used to perform an dynamic
593 * \param server LdapServer.
594 * \param req Query request.
595 * \return LdapQuery object, or <i>NULL</i> if none created.
597 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
604 g_return_val_if_fail( server != NULL, NULL );
605 g_return_val_if_fail( req != NULL, NULL );
607 /* Retire any aged queries */
608 /* // ldapsvr_retire_query( server ); */
610 /* Name of folder and query */
611 searchTerm = req->searchTerm;
612 name = g_strdup_printf( "Search '%s'", searchTerm );
614 /* Create a folder for the search results */
615 folder = addrcache_add_new_folder( server->addressCache, NULL );
616 addritem_folder_set_name( folder, name );
617 addritem_folder_set_remarks( folder, "" );
619 /* Construct a query */
620 qry = ldapqry_create();
621 ldapqry_set_query_id( qry, req->queryID );
622 ldapqry_set_search_value( qry, searchTerm );
623 ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
624 ldapqry_set_callback_entry( qry, req->callBackEntry );
625 ldapqry_set_callback_end( qry, req->callBackEnd );
627 /* Specify folder type and back reference */
628 ADDRQUERY_FOLDER(qry) = folder;
629 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
630 folder->folderData = ( gpointer ) qry;
631 folder->isHidden = TRUE;
634 ldapqry_set_name( qry, name );
637 /* Add query to request */
638 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
640 /* Now start the search */
641 ldapsvr_add_query( server, qry );
647 * Construct a new LdapQuery object that will be used to perform an explicit
650 * \param server LdapServer.
651 * \param req Query request.
652 * \param folder Folder that will be used to contain search results.
653 * \return LdapQuery object, or <i>NULL</i> if none created.
655 LdapQuery *ldapsvr_new_explicit_search(
656 LdapServer *server, QueryRequest *req, ItemFolder *folder )
662 g_return_val_if_fail( server != NULL, NULL );
663 g_return_val_if_fail( req != NULL, NULL );
664 g_return_val_if_fail( folder != NULL, NULL );
666 /* Retire any aged queries */
667 /* // ldapsvr_retire_query( server ); */
670 searchTerm = req->searchTerm;
671 name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
673 /* Construct a query */
674 qry = ldapqry_create();
675 ldapqry_set_query_id( qry, req->queryID );
676 ldapqry_set_name( qry, name );
677 ldapqry_set_search_value( qry, searchTerm );
678 ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
679 ldapqry_set_callback_end( qry, req->callBackEnd );
680 ldapqry_set_callback_entry( qry, req->callBackEntry );
682 /* Specify folder type and back reference */
683 ADDRQUERY_FOLDER(qry) = folder;
684 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
685 folder->folderData = ( gpointer ) qry;
688 ldapsvr_add_query( server, qry );
690 /* Set up query request */
691 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
698 #endif /* USE_LDAP */