2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2007 Match Grun and the Claws Mail 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 3 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, see <http://www.gnu.org/licenses/>.
21 * Functions necessary to access LDAP servers.
38 #include "addrcache.h"
40 #include "ldapquery.h"
41 #include "ldapserver.h"
44 #include "adbookbase.h"
47 * Create new LDAP server interface object with no control object.
48 * \return Initialized LDAP server object.
50 LdapServer *ldapsvr_create_noctl( void ) {
53 server = g_new0( LdapServer, 1 );
54 server->type = ADBOOKTYPE_LDAP;
55 server->addressCache = addrcache_create();
56 server->retVal = MGU_SUCCESS;
57 server->control = NULL;
58 server->listQuery = NULL;
59 server->searchFlag = FALSE;
64 * Create new LDAP server interface object.
65 * \return Initialized LDAP server object.
67 LdapServer *ldapsvr_create( void ) {
70 server = ldapsvr_create_noctl();
71 server->control = ldapctl_create();
76 * Return name of server.
77 * \param server Server object.
78 * \return Name for server.
80 gchar *ldapsvr_get_name( LdapServer *server ) {
81 g_return_val_if_fail( server != NULL, NULL );
82 return addrcache_get_name( server->addressCache );
86 * Specify name to be used.
87 * \param server Server object.
88 * \param value Name for server.
90 void ldapsvr_set_name( LdapServer* server, const gchar *value ) {
91 g_return_if_fail( server != NULL );
92 addrcache_set_name( server->addressCache, value );
96 * Refresh internal variables to force a file read.
97 * \param server Server object.
99 void ldapsvr_force_refresh( LdapServer *server ) {
100 addrcache_refresh( server->addressCache );
104 * Return status/error code.
105 * \param server Server object.
106 * \return Status/error code.
108 gint ldapsvr_get_status( LdapServer *server ) {
109 g_return_val_if_fail( server != NULL, -1 );
110 return server->retVal;
114 * Return reference to root level folder.
115 * \param server Server object.
116 * \return Root level folder.
118 ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
119 g_return_val_if_fail( server != NULL, NULL );
121 printf( "ldapsvr_get_root_folder/start\n" );
122 ldapsvr_print_data( server, stdout );
123 printf( "ldapsvr_get_root_folder/done\n" );
125 return addrcache_get_root_folder( server->addressCache );
129 * Test whether server data has been accessed.
130 * \param server Server object.
131 * \return <i>TRUE</i> if data was accessed.
133 gboolean ldapsvr_get_accessed( LdapServer *server ) {
134 g_return_val_if_fail( server != NULL, FALSE );
135 return server->addressCache->accessFlag;
139 * Specify that server's data whas beed accessed.
140 * \param server Server object.
141 * \param value Value for flag.
143 void ldapsvr_set_accessed( LdapServer *server, const gboolean value ) {
144 g_return_if_fail( server != NULL );
145 server->addressCache->accessFlag = value;
149 * Test whether server data has been modified.
150 * \param server Server object.
151 * \return <i>TRUE</i> if data was modified.
153 gboolean ldapsvr_get_modified( LdapServer *server ) {
154 g_return_val_if_fail( server != NULL, FALSE );
155 return server->addressCache->modified;
159 * Specify modify flag.
160 * \param server Server object.
161 * \param value Value for flag.
163 void ldapsvr_set_modified( LdapServer *server, const gboolean value ) {
164 g_return_if_fail( server != NULL );
165 server->addressCache->modified = value;
169 * Test whether data was read from server.
170 * \param server Server object.
171 * \return <i>TRUE</i> if data was read.
173 gboolean ldapsvr_get_read_flag( LdapServer *server ) {
174 g_return_val_if_fail( server != NULL, FALSE );
175 return server->addressCache->dataRead;
179 * Test whether server is to be used for dynamic searches.
180 * \param server Server object.
181 * \return <i>TRUE</i> if server is used for dynamic searches.
183 gboolean ldapsvr_get_search_flag( LdapServer *server ) {
184 g_return_val_if_fail( server != NULL, FALSE );
185 return server->searchFlag;
189 * Specify that server is to be used for dynamic searches.
190 * \param server Server object.
191 * \param value Name for server.
193 void ldapsvr_set_search_flag( LdapServer *server, const gboolean value ) {
194 g_return_if_fail( server != NULL );
195 server->searchFlag = value;
199 * Specify the reference to control data that will be used for the query. The calling
200 * module should be responsible for creating and destroying this control object.
201 * \param server Server object.
202 * \param ctl Control data.
204 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl ) {
205 g_return_if_fail( server != NULL );
206 addrcache_refresh( server->addressCache );
207 server->control = ctl;
212 * \param server Server object.
214 void ldapsvr_free_all_query( LdapServer *server ) {
216 g_return_if_fail( server != NULL );
218 node = server->listQuery;
220 LdapQuery *qry = node->data;
223 node = g_list_next( node );
225 g_list_free( server->listQuery );
226 server->listQuery = NULL;
230 * Add query to server.
231 * \param server Server object.
232 * \param qry Query object.
234 void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
235 g_return_if_fail( server != NULL );
236 g_return_if_fail( qry != NULL );
238 server->listQuery = g_list_append( server->listQuery, qry );
239 qry->server = server;
243 * Free up LDAP server interface object by releasing internal memory.
244 * \param server Server object.
246 void ldapsvr_free( LdapServer *server ) {
247 g_return_if_fail( server != NULL );
249 /* Stop and cancel any queries that may be active */
250 ldapsvr_stop_all_query( server );
251 ldapsvr_cancel_all_query( server );
254 addrcache_clear( server->addressCache );
255 addrcache_free( server->addressCache );
257 /* Free LDAP control block */
258 ldapctl_free( server->control );
259 server->control = NULL;
261 /* Free all queries */
262 ldapsvr_free_all_query( server );
265 server->type = ADBOOKTYPE_NONE;
266 server->addressCache = NULL;
267 server->retVal = MGU_SUCCESS;
268 server->listQuery = NULL;
269 server->searchFlag = FALSE;
271 /* Now release LDAP object */
276 * Display object to specified stream.
277 * \param server Server object.
278 * \param stream Output stream.
280 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
284 g_return_if_fail( server != NULL );
286 fprintf( stream, "LdapServer:\n" );
287 fprintf( stream, " ret val: %d\n", server->retVal );
288 fprintf( stream, "srch flag: %s\n",
289 server->searchFlag ? "yes" : "no" );
290 if( server->control ) {
291 ldapctl_print( server->control, stream );
294 fprintf( stream, " control: NULL\n" );
296 addrcache_print( server->addressCache, stream );
297 addritem_print_item_folder( server->addressCache->rootFolder, stream );
301 node = server->listQuery;
303 LdapQuery *qry = node->data;
304 fprintf( stream, " query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
306 node = g_list_next( node );
311 * Return link list of persons.
312 * \param server Server object.
313 * \return List of persons.
315 GList *ldapsvr_get_list_person( LdapServer *server ) {
316 g_return_val_if_fail( server != NULL, NULL );
317 return addrcache_get_list_person( server->addressCache );
321 * Return link list of folders. There are no "real" folders that are returned
323 * \param server Server object.
324 * \return List of folders.
326 GList *ldapsvr_get_list_folder( LdapServer *server ) {
327 g_return_val_if_fail( server != NULL, NULL );
328 /* return addrcache_get_list_folder( server->addressCache ); */
333 * Execute specified query.
334 * \param server LDAP server.
335 * \param qry LDAP query.
337 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
338 LdapControl *ctlCopy;
340 g_return_if_fail( server != NULL );
341 g_return_if_fail( qry != NULL );
343 /* Copy server's control data to the query */
344 ctlCopy = ldapctl_create();
345 ldapctl_copy( server->control, ctlCopy );
346 ldapqry_set_control( qry, ctlCopy );
347 ldapqry_initialize();
350 /* printf( "ldapsvr_execute_query::checking query...\n" ); */
351 if( ldapqry_check_search( qry ) ) {
352 /* printf( "ldapsvr_execute_query::reading with thread...\n" ); */
353 ldapqry_read_data_th( qry );
355 if( qry->retVal == LDAPRC_SUCCESS ) {
356 printf( "ldapsvr_execute_query::SUCCESS with thread...\n" );
360 /* printf( "ldapsvr_execute_query... terminated\n" ); */
364 * Stop all queries for specified ID.
365 * \param server Server object.
366 * \param queryID Query ID to stop.
368 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
370 g_return_if_fail( server != NULL );
372 node = server->listQuery;
374 LdapQuery *qry = node->data;
375 if( ADDRQUERY_ID(qry) == queryID ) {
376 /* Notify thread to stop */
377 ldapqry_set_stop_flag( qry, TRUE );
379 node = g_list_next( node );
384 * Stop all queries by notifying each thread to stop.
385 * \param server Server object.
387 void ldapsvr_stop_all_query( LdapServer *server ) {
389 g_return_if_fail( server != NULL );
391 node = server->listQuery;
393 LdapQuery *qry = node->data;
394 ldapqry_set_stop_flag( qry, TRUE );
395 node = g_list_next( node );
400 * Cancel all query threads for server.
401 * \param server Server object.
403 void ldapsvr_cancel_all_query( LdapServer *server ) {
405 g_return_if_fail( server != NULL );
407 node = server->listQuery;
409 LdapQuery *qry = node->data;
410 /* Notify thread to stop */
411 ldapqry_set_stop_flag( qry, TRUE );
412 /* Now cancel thread */
413 ldapqry_cancel( qry );
414 node = g_list_next( node );
419 * Search most recent query for specified search term. The most recent
420 * completed query is returned. If no completed query is found, the most recent
421 * incomplete is returned.
422 * \param server LdapServer.
423 * \param searchTerm Search term to locate.
424 * \return Query object, or <i>NULL</i> if none found.
426 static LdapQuery *ldapsvr_locate_query(
427 const LdapServer *server, const gchar *searchTerm )
429 LdapQuery *incomplete = NULL;
431 g_return_val_if_fail( server != NULL, NULL );
433 node = server->listQuery;
434 node = g_list_last( node );
435 /* Search backwards for query */
437 LdapQuery *qry = node->data;
438 if( g_utf8_collate( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
439 if( qry->agedFlag ) continue;
440 if( qry->completed ) {
448 node = g_list_previous( node );
454 * Retire aged queries. Only the following queries are retired:
456 * a) Dynamic queries.
457 * b) Explicit searches that have a hidden folders.
458 * c) Locate searches that have a hidden folder.
460 * \param server LdapServer.
462 void ldapsvr_retire_query( LdapServer *server ) {
470 /* printf( "ldapsvr_retire_query\n" ); */
471 g_return_if_fail( server != NULL );
472 ctl = server->control;
473 maxAge = ctl->maxQueryAge;
475 /* Identify queries to age and move to deletion list */
477 node = server->listQuery;
479 LdapQuery *qry = node->data;
481 node = g_list_next( node );
482 folder = ADDRQUERY_FOLDER(qry);
483 if( folder == NULL ) continue;
484 if( ! folder->isHidden ) {
485 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
486 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
489 ldapqry_age( qry, maxAge );
490 if( qry->agedFlag ) {
491 /* Delete folder associated with query */
493 printf( "deleting folder... ::%s::\n", ADDRQUERY_NAME(qry) );
495 ldapqry_delete_folder( qry );
496 listDelete = g_list_append( listDelete, qry );
501 listQuery = server->listQuery;
504 LdapQuery *qry = node->data;
506 listQuery = g_list_remove( listQuery, qry );
509 node = g_list_next( node );
511 server->listQuery = listQuery;
513 /* Free up deletion list */
514 g_list_free( listDelete );
518 * Return results of a previous query by executing callback for each address
519 * contained in specified folder.
521 * \param folder Address book folder to process.
522 * \param req Address query request object.
524 static void ldapsvr_previous_query(
525 const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
527 AddrSearchCallbackEntry *callBack;
534 callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
537 node = folder->listPerson;
539 AddrItemObject *aio = node->data;
540 if( aio && aio->type == ITEMTYPE_PERSON ) {
541 ItemPerson *person = node->data;
542 nodeEM = person->listEMail;
544 ItemEMail *email = nodeEM->data;
546 nodeEM = g_list_next( nodeEM );
547 listEMail = g_list_append( listEMail, email );
550 node = g_list_next( node );
552 ( callBack ) ( sender, req->queryID, listEMail, NULL );
553 /* // g_list_free( listEMail ); */
558 * Reuse search results from a previous LDAP query. If there is a query that
559 * has the same search term as specified in the query request, then the query
562 * \param server LDAP server object.
563 * \param req Address query object.
564 * \return <i>TRUE</i> if previous query was used.
566 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
571 g_return_val_if_fail( server != NULL, FALSE );
572 g_return_val_if_fail( req != NULL, FALSE );
574 searchTerm = req->searchTerm;
576 /* Test whether any queries for the same term exist */
577 qry = ldapsvr_locate_query( server, searchTerm );
579 /* Touch query to ensure it hangs around for a bit longer */
580 ldapqry_touch( qry );
581 folder = ADDRQUERY_FOLDER(qry);
583 ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
591 * Construct a new LdapQuery object that will be used to perform an dynamic
594 * \param server LdapServer.
595 * \param req Query request.
596 * \return LdapQuery object, or <i>NULL</i> if none created.
598 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
605 g_return_val_if_fail( server != NULL, NULL );
606 g_return_val_if_fail( req != NULL, NULL );
608 /* Retire any aged queries */
609 /* // ldapsvr_retire_query( server ); */
611 /* Name of folder and query */
612 searchTerm = req->searchTerm;
613 name = g_strdup_printf( "Search '%s'", searchTerm );
615 /* Create a folder for the search results */
616 folder = addrcache_add_new_folder( server->addressCache, NULL );
617 addritem_folder_set_name( folder, name );
618 addritem_folder_set_remarks( folder, "" );
620 /* Construct a query */
621 qry = ldapqry_create();
622 ldapqry_set_query_id( qry, req->queryID );
623 ldapqry_set_search_value( qry, searchTerm );
624 ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
625 ldapqry_set_callback_entry( qry, req->callBackEntry );
626 ldapqry_set_callback_end( qry, req->callBackEnd );
628 /* Specify folder type and back reference */
629 ADDRQUERY_FOLDER(qry) = folder;
630 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
631 folder->folderData = ( gpointer ) qry;
632 folder->isHidden = TRUE;
635 ldapqry_set_name( qry, name );
638 /* Add query to request */
639 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
641 /* Now start the search */
642 ldapsvr_add_query( server, qry );
648 * Construct a new LdapQuery object that will be used to perform an explicit
651 * \param server LdapServer.
652 * \param req Query request.
653 * \param folder Folder that will be used to contain search results.
654 * \return LdapQuery object, or <i>NULL</i> if none created.
656 LdapQuery *ldapsvr_new_explicit_search(
657 LdapServer *server, QueryRequest *req, ItemFolder *folder )
663 g_return_val_if_fail( server != NULL, NULL );
664 g_return_val_if_fail( req != NULL, NULL );
665 g_return_val_if_fail( folder != NULL, NULL );
667 /* Retire any aged queries */
668 /* // ldapsvr_retire_query( server ); */
671 searchTerm = req->searchTerm;
672 name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
674 /* Construct a query */
675 qry = ldapqry_create();
676 ldapqry_set_query_id( qry, req->queryID );
677 ldapqry_set_name( qry, name );
678 ldapqry_set_search_value( qry, searchTerm );
679 ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
680 ldapqry_set_callback_end( qry, req->callBackEnd );
681 ldapqry_set_callback_entry( qry, req->callBackEntry );
683 /* Specify folder type and back reference */
684 ADDRQUERY_FOLDER(qry) = folder;
685 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
686 folder->folderData = ( gpointer ) qry;
689 ldapsvr_add_query( server, qry );
691 /* Set up query request */
692 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
699 gint ldapsvr_read_data( LdapServer *server )
701 g_return_val_if_fail( server != NULL, -1 );
703 //printf( "...addrbook_read_data :%s:\n", addrcache_get_name( server->addressCache ) );
705 addrcache_clear(server->addressCache);
706 ldapsvr_free_all_query( server );
707 server->listQuery = NULL;
708 server->addressCache->modified = FALSE;
709 server->addressCache->accessFlag = FALSE;
710 server->addressCache->dataRead = TRUE;
711 addrcache_set_dirty(server->addressCache, FALSE);
715 #endif /* USE_LDAP */