Refactor LDAP searches.
authorMatch Grun <match@dimensional.com>
Sun, 2 Nov 2003 03:55:54 +0000 (03:55 +0000)
committerMatch Grun <match@dimensional.com>
Sun, 2 Nov 2003 03:55:54 +0000 (03:55 +0000)
18 files changed:
ChangeLog.claws
configure.ac
src/Makefile.am
src/addr_compl.c
src/addr_compl.h
src/addrbook.c
src/addrcache.c
src/addrcache.h
src/addressbook.c
src/addrindex.c
src/addrindex.h
src/addritem.h
src/addrquery.c
src/addrquery.h
src/ldapquery.c
src/ldapquery.h
src/ldapserver.c
src/ldapserver.h

index 4ec2467b8a8c3275a96da81269be170242d98189..91c07bd1ce36f530b58b97f8118917b637ec3e15 100644 (file)
@@ -1,3 +1,25 @@
+2003-11-01 [match]     0.9.6claws63
+
+       * po/POTFILES.in
+       * src/Makefile.am
+       * src/addr_compl.[ch]
+       * src/addrbook.c
+       * src/addrcache.[ch]
+       * src/addrdefs.h        ** NEW **
+       * src/addressbook.c
+       * src/addressitem.h
+       * src/addrindex.[ch]
+       * src/addritem.h
+       * src/addrquery.[ch]
+       * src/ldapquery.[ch]
+       * src/ldapserver.[ch]
+               refactor LDAP query mechanism.
+
+       * src/browseldap.[ch]   ** NEW **
+       * src/ldaplocate.[ch]   ** NEW **
+               add feature to browse LDAP entry that was retrieved using
+               an explicit LDAP search.
+
 2003-11-01 [alfons]    0.9.6claws62
 
        * src/prefs_gtk.c
index a00f1760d16eeed5a87788c48bf3cd4b3fb0b785..210a5ba88799d613043032242402d77319786a5f 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=6
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=62
+EXTRA_VERSION=63
 if test $EXTRA_VERSION -eq 0; then
     VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}claws
 else
index 5fdc49bcb0a7cd75858e7b7546d51b48b36b6410..db24e26c552c9053d35c9b72b9795ef91196b58d 100644 (file)
@@ -18,6 +18,7 @@ sylpheed_SOURCES = \
        addrquery.c \
        addrselect.c \
        alertpanel.c \
+       browseldap.c \
        codeconv.c \
        compose.c \
        crash.c \
@@ -53,6 +54,7 @@ sylpheed_SOURCES = \
        inputdialog.c \
        jpilot.c \
        ldapctrl.c \
+       ldaplocate.c \
        ldapquery.c \
        ldapserver.c \
        ldaputil.c \
@@ -130,6 +132,7 @@ sylpheedinclude_HEADERS = \
        addrcache.h \
        addrclip.h \
        addr_compl.h \
+       addrdefs.h \
        addressadd.h \
        addressbook.h \
        addressitem.h \
@@ -140,6 +143,7 @@ sylpheedinclude_HEADERS = \
        addrquery.h \
        addrselect.h \
        alertpanel.h \
+       browseldap.h \
        codeconv.h \
        compose.h \
        crash.h \
@@ -175,6 +179,7 @@ sylpheedinclude_HEADERS = \
        inputdialog.h \
        jpilot.h \
        ldapctrl.h \
+       ldaplocate.h \
        ldapquery.h \
        ldapserver.h \
        ldaputil.h \
index de93684449166bf365940240b6a863b1e442e0c4..6e22ff2d29216609fdd90b35a14fbbb2f4a5cfc9 100644 (file)
@@ -40,7 +40,7 @@
 #  include <wctype.h>
 #endif
 
-#include "addressbook.h"
+#include "addrindex.h"
 #include "addr_compl.h"
 #include "utils.h"
 #include <pthread.h>
  * any of those words).
  */ 
        
-/**
- * Reference to address index.
- */
-static AddressIndex *_addressIndex_ = NULL;
-
 /**
  * address_entry - structure which refers to the original address entry in the
  * address book .
@@ -210,7 +205,7 @@ static gint add_address(const gchar *name, const gchar *address, const gchar *al
  * Read address book, creating all entries in the completion index.
  */ 
 static void read_address_book(void) {  
-       addrindex_load_completion( _addressIndex_, add_address );
+       addrindex_load_completion( add_address );
        g_address_list = g_list_reverse(g_address_list);
        g_completion_list = g_list_reverse(g_completion_list);
 }
@@ -609,6 +604,9 @@ static CompletionWindow *addrcompl_create_window( void ) {
  * \param cw Window to destroy.
  */
 static void addrcompl_destroy_window( CompletionWindow *cw ) {
+       /* Stop all searches currently in progress */
+       addrindex_stop_search( _queryID_ );
+
        /* Remove idler function... or application may not terminate */
        if( _completionIdleID_ != 0 ) {
                gtk_idle_remove( _completionIdleID_ );
@@ -762,17 +760,15 @@ static void addrcompl_add_entry( CompletionWindow *cw, gchar *address ) {
 static gboolean addrcompl_idle( gpointer data ) {
        GList *node;
        gchar *address;
-       CompletionWindow *cw;
 
        /* Process all entries in display queue */
        pthread_mutex_lock( & _completionMutex_ );
        if( _displayQueue_ ) {
-               cw = data;
                node = _displayQueue_;
                while( node ) {
                        address = node->data;
                        /* printf( "address ::: %s :::\n", address ); */
-                       addrcompl_add_entry( cw, address );
+                       addrcompl_add_entry( _compWindow_, address );
                        g_free( address );
                        node = g_list_next( node );
                }
@@ -787,35 +783,34 @@ static gboolean addrcompl_idle( gpointer data ) {
 /**
  * Callback entry point. The background thread (if any) appends the address
  * list to the display queue.
+ * \param sender     Sender of query.
  * \param queryID    Query ID of search request.
  * \param listEMail  List of zero of more email objects that met search
  *                   criteria.
- * \param target     Target object to received data.
+ * \param data       Query data.
  */
-static gint addrcompl_callback(
-       gint queryID, GList *listEMail, gpointer target )
+static gint addrcompl_callback_entry(
+       gpointer sender, gint queryID, GList *listEMail, gpointer data )
 {
        GList *node;
        gchar *address;
 
-       /* printf( "addrcompl_callback::queryID=%d\n", queryID ); */
+       /* printf( "addrcompl_callback_entry::queryID=%d\n", queryID ); */
        pthread_mutex_lock( & _completionMutex_ );
-       if( target ) {
-               if( queryID == _queryID_ ) {
-                       /* Append contents to end of display queue */
-                       node = listEMail;
-                       while( node ) {
-                               ItemEMail *email = node->data;
-
-                               address = addritem_format_email( email );
-                               /* printf( "\temail/address ::%s::\n", address ); */
-                               _displayQueue_ = g_list_append( _displayQueue_, address );
-                               node = g_list_next( node );
-                       }
+       if( queryID == _queryID_ ) {
+               /* Append contents to end of display queue */
+               node = listEMail;
+               while( node ) {
+                       ItemEMail *email = node->data;
+
+                       address = addritem_format_email( email );
+                       /* printf( "\temail/address ::%s::\n", address ); */
+                       _displayQueue_ = g_list_append( _displayQueue_, address );
+                       node = g_list_next( node );
                }
        }
+       g_list_free( listEMail );
        pthread_mutex_unlock( & _completionMutex_ );
-       /* printf( "addrcompl_callback...done\n" ); */
 
        return 0;
 }
@@ -845,9 +840,8 @@ static void addrcompl_add_queue( gchar *address ) {
 
 /**
  * Load list with entries from local completion index.
- * \param cw Completion window.
  */
-static void addrcompl_load_local( CompletionWindow *cw ) {
+static void addrcompl_load_local( void ) {
        guint count = 0;
 
        for (count = 0; count < get_completion_count(); count++) {
@@ -871,19 +865,19 @@ static void addrcompl_start_search( void ) {
 
        /* Setup the search */
        _queryID_ = addrindex_setup_search(
-               _addressIndex_, searchTerm, _compWindow_, addrcompl_callback );
+               searchTerm, NULL, addrcompl_callback_entry );
        g_free( searchTerm );
        /* printf( "addrcompl_start_search::queryID=%d\n", _queryID_ ); */
 
        /* Load local stuff */
-       addrcompl_load_local( _compWindow_ );
+       addrcompl_load_local();
 
        /* Sit back and wait until something happens */
        _completionIdleID_ =
-               gtk_idle_add( ( GtkFunction ) addrcompl_idle, _compWindow_ );
+               gtk_idle_add( ( GtkFunction ) addrcompl_idle, NULL );
        /* printf( "addrindex_start_search::queryID=%d\n", _queryID_ ); */
 
-       addrindex_start_search( _addressIndex_, _queryID_ );
+       addrindex_start_search( _queryID_ );
 }
 
 /**
@@ -1387,12 +1381,8 @@ static gboolean completion_window_key_press(GtkWidget *widget,
 
 /**
  * Setup completion object.
- * \param addrIndex Address index object.
  */
-void addrcompl_initialize( AddressIndex *addrIndex ) {
-       g_return_if_fail( addrIndex != NULL );
-       _addressIndex_ = addrIndex;
-
+void addrcompl_initialize( void ) {
        /* printf( "addrcompl_initialize...\n" ); */
        if( ! _compWindow_ ) {
                _compWindow_ = addrcompl_create_window();
@@ -1414,7 +1404,6 @@ void addrcompl_teardown( void ) {
        }
        _displayQueue_ = NULL;
        _completionIdleID_ = 0;
-       _addressIndex_ = NULL;
        /* printf( "addrcompl_teardown...done\n" ); */
 }
 
index c81cf12e8a3f1b40ae5cf5c18e0cbd424f60ac6d..d11b73b9dd237b9597ec25d4aee0716669d67112 100644 (file)
 
 #include <gtk/gtk.h>
 
-#include "addrindex.h"
-
 gint start_address_completion          (void);
 guint complete_address                 (const gchar *str);
-gchar *get_complete_address            (gint        index);
+gchar *get_complete_address            (gint index);
 gint invalidate_address_completion     (void);
 gint end_address_completion            (void);
 
@@ -37,7 +35,7 @@ void address_completion_register_entry        (GtkEntry  *entry);
 void address_completion_unregister_entry(GtkEntry  *entry);
 void address_completion_end            (GtkWidget *mainwindow);
 
-void addrcompl_initialize      ( AddressIndex *addrIndex );
+void addrcompl_initialize      ( void );
 void addrcompl_teardown                ( void );
 
 #endif /* __ADDR_COMPL_H__ */
index 21055a5deb1e40804b8b7a6c00608da2edf49c14..b7ced22f79988d72dbd31f01d8f4d51b35bef3cb 100644 (file)
@@ -1720,6 +1720,11 @@ ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
  *         <code>g_free()</code> when done.
  */
 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
+{
+       g_return_val_if_fail(book != NULL, NULL);
+       return addrcache_add_new_folder( book->addressCache, parent );
+}
+#if 0
 {
        ItemFolder *folder = NULL;
        ItemFolder *p = parent;
@@ -1741,6 +1746,7 @@ ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
        }
        return folder;
 }
+#endif
 
 /**
  * Update address book attribute list for specified person. Note: The existing
index 1edf82ab4853bf5397221daafbb543db6144ee5c..1943ae3e2444e02b0f9c7220fae07aa457143a96 100644 (file)
@@ -1326,17 +1326,19 @@ ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *fol
        return NULL;
 }
 
-/*
-* Add person and address data to cache.
-* Enter: cache     Cache.
-*        folder    Folder where to add person, or NULL for root folder.
-*        name      Common name.
-*        address   EMail address.
-*        remarks   Remarks.
-* Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
-* this will destroy the address book data.
-*/
-ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, const gchar *name,
+/**
+ * Add person and address data to cache.
+ * \param cache     Cache.
+ * \param folder    Folder where to add person, or NULL for root folder.
+ * \param name      Common name.
+ * \param address   EMail address.
+ * \param remarks   Remarks.
+ * \return Person added. Do not *NOT* to use the 
+ *         <code>addrbook_free_xxx()</code> functions...; this will destroy
+ *         the address book data.
+ */
+ItemPerson *addrcache_add_contact(
+               AddressCache *cache, ItemFolder *folder, const gchar *name,
                const gchar *address, const gchar *remarks )
 {
        ItemPerson *person = NULL;
@@ -1364,6 +1366,36 @@ ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, cons
        return person;
 }
 
+/**
+ * Create a new folder and add to address cache.
+ * \param  cache  Address cache.
+ * \param  folder Parent folder where to add folder, or <i>NULL</i> for
+ *                root folder.
+ * \return Folder that was created. This should <b>*NOT*</b> be
+ *         <code>g_free()</code> when done.
+ */
+ItemFolder *addrcache_add_new_folder( AddressCache *cache, ItemFolder *parent )
+{
+       ItemFolder *folder;
+       ItemFolder *p = parent;
+
+       g_return_val_if_fail( cache != NULL, NULL );
+
+       if( !p ) p = cache->rootFolder;
+       folder = addritem_create_item_folder();
+       addrcache_id_folder( cache, folder );
+       if( addrcache_hash_add_folder( cache, folder ) ) {
+               p->listFolder = g_list_append( p->listFolder, folder );
+               ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
+               addrcache_set_dirty( cache, TRUE );
+       }
+       else {
+               addritem_free_item_folder( folder );
+               folder = NULL;
+       }
+       return folder;
+}
+
 /*
 * End of Source.
 */
index 951a30664c9ae5cb5c42a86667730c6b958e859c..092c5d34c4c5975d0c5a0a80ccaa5b831ba2729b 100644 (file)
@@ -170,4 +170,7 @@ ItemPerson *addrcache_add_contact   ( AddressCache *cache,
                                          const gchar *address,
                                          const gchar *remarks ); 
 
+ItemFolder *addrcache_add_new_folder   ( AddressCache *cache,
+                                         ItemFolder *parent );
+
 #endif /* __ADDRCACHE_H__ */
index 7616785bea62f2bbe2066790cd815f85a5e3c01b..e345f141dee111f992a19730eb3973008271dbed 100644 (file)
 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
 #endif
 
+#include "addrquery.h"
 #include "addrselect.h"
 #include "addrclip.h"
 #include "addrgather.h"
 #include "adbookbase.h"
 #include "exphtmldlg.h"
 #include "expldifdlg.h"
+#include "browseldap.h"
 
 typedef enum
 {
@@ -352,6 +354,10 @@ static void addressbook_treenode_cut_cb            ( void );
 static void addressbook_treenode_copy_cb       ( void );
 static void addressbook_treenode_paste_cb      ( void );
 
+#ifdef USE_LDAP
+static void addressbook_browse_entry_cb                ( void );
+#endif
+
 static GtkItemFactoryEntry addressbook_entries[] =
 {
        {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
@@ -420,7 +426,12 @@ static GtkItemFactoryEntry addressbook_list_popup_entries[] =
        {N_("/_Copy"),          NULL, addressbook_clip_copy_cb,      0, NULL},
        {N_("/_Paste"),         NULL, addressbook_clip_paste_cb,     0, NULL},
        {N_("/---"),            NULL, NULL, 0, "<Separator>"},
-       {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb,     0, NULL}
+#ifdef USE_LDAP
+       {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},
+       {N_("/_Browse Entry"),  NULL, addressbook_browse_entry_cb,       0, NULL}
+#else
+       {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL}
+#endif 
 };
 
 /**
@@ -458,15 +469,15 @@ static ErrMsgTableEntry _lutErrorsGeneral_[] = {
  * Lookup table of error messages for LDAP errors.
  */
 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
-       { MGU_SUCCESS,          N_("Success") },
-       { MGU_LDAP_CONNECT,     N_("Error connecting to LDAP server") },
-       { MGU_LDAP_INIT,        N_("Error initializing LDAP") },
-       { MGU_LDAP_BIND,        N_("Error binding to LDAP server") },
-       { MGU_LDAP_SEARCH,      N_("Error searching LDAP database") },
-       { MGU_LDAP_TIMEOUT,     N_("Timeout performing LDAP operation") },
-       { MGU_LDAP_CRITERIA,    N_("Error in LDAP search criteria") },
-       { MGU_LDAP_CRITERIA,    N_("Error in LDAP search criteria") },
-       { MGU_LDAP_NOENTRIES,   N_("No LDAP entries found for search criteria") },
+       { LDAPRC_SUCCESS,       N_("Success") },
+       { LDAPRC_CONNECT,       N_("Error connecting to LDAP server") },
+       { LDAPRC_INIT,          N_("Error initializing LDAP") },
+       { LDAPRC_BIND,          N_("Error binding to LDAP server") },
+       { LDAPRC_SEARCH,        N_("Error searching LDAP database") },
+       { LDAPRC_TIMEOUT,       N_("Timeout performing LDAP operation") },
+       { LDAPRC_CRITERIA,      N_("Error in LDAP search criteria") },
+       { LDAPRC_NOENTRIES,     N_("No LDAP entries found for search criteria") },
+       { LDAPRC_STOP_FLAG,     N_("LDAP search terminated on request") },
        { 0,                    NULL }
 };
 #endif
@@ -523,7 +534,10 @@ void addressbook_open(Compose *target)
        addressbook_set_target_compose(target);
 }
 
-void addressbook_destroy() {
+/**
+ * Destroy addressbook.
+ */
+void addressbook_destroy( void ) {
        /* Free up address stuff */
        if( _addressSelect_ != NULL ) {
                addrselect_list_free( _addressSelect_ );
@@ -533,7 +547,7 @@ void addressbook_destroy() {
        }
        if( _addressIndex_ != NULL ) {
                addrindex_free_index( _addressIndex_ );
-               addrindex_teardown( _addressIndex_ );
+               addrindex_teardown();
        }
        _addressSelect_ = NULL;
        _clipBoard_ = NULL;
@@ -551,7 +565,10 @@ Compose *addressbook_get_target_compose(void)
        return addrbook.target_compose;
 }
 
-void addressbook_refresh(void)
+/**
+ * Refresh addressbook and save to file(s).
+ */
+void addressbook_refresh( void )
 {
        if (addrbook.window) {
                if (addrbook.treeSelected) {
@@ -868,12 +885,19 @@ static void addressbook_create(void)
 
 }
 
+/**
+ * Close address book window and save to file(s).
+ */
 static gint addressbook_close( void ) {
        gtk_widget_hide(addrbook.window);
        addressbook_export_to_file();
        return TRUE;
 }
 
+/**
+ * Display message in status line.
+ * \param msg Message to display.
+ */
 static void addressbook_status_show( gchar *msg ) {
        if( addrbook.statusbar != NULL ) {
                gtk_statusbar_pop(
@@ -1359,11 +1383,10 @@ static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
        addressbook_list_select_clear();
 }
 
-/*
-* Setup address list popup menu.
-* Enter: pobj  Parent address object in address tree.
-*        obj   Address object in address list.
-*/
+/**
+ * Setup address list popup menu items. Items are enabled or disabled as
+ * required.
+ */
 static void addressbook_list_menu_setup( void ) {
        GtkCTree *clist = NULL;
        AddressObject *pobj = NULL;
@@ -1376,6 +1399,7 @@ static void addressbook_list_menu_setup( void ) {
        gboolean canCut = FALSE;
        gboolean canCopy = FALSE;
        gboolean canPaste = FALSE;
+       gboolean canBrowse = FALSE;
 
        pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
        if( pobj == NULL ) return;
@@ -1387,6 +1411,7 @@ static void addressbook_list_menu_setup( void ) {
        menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
 
        if( pobj->type == ADDR_DATASOURCE ) {
+               /* Parent object is a data source */
                ads = ADAPTER_DSOURCE(pobj);
                ds = ads->dataSource;
                iface = ds->interface;
@@ -1401,14 +1426,17 @@ static void addressbook_list_menu_setup( void ) {
                }
        }
        else if( pobj->type != ADDR_INTERFACE ) {
+               /* Parent object is not an interface */
                ds = addressbook_find_datasource( addrbook.treeSelected );
                iface = ds->interface;
                if( ! iface->readOnly ) {
+                       /* Folder or group */
                        if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
                                menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
                                gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                                if( obj ) canEdit = TRUE;
                        }
+                       /* Folder */
                        if( pobj->type == ADDR_ITEM_FOLDER ) {
                                menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
                                menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
@@ -1417,15 +1445,18 @@ static void addressbook_list_menu_setup( void ) {
                        if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
                        if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
                }
+               if( iface->type == ADDR_IF_LDAP ) {
+                       if( obj ) canBrowse = TRUE;
+               }
        }
        if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
 
-       canDelete = canEdit;
        canDelete = canEdit;
 
        /* Disable edit if more than one row selected */
        if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE;
 
+       /* Now go finalize menu items */
        menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
        menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
 
@@ -1447,6 +1478,10 @@ static void addressbook_list_menu_setup( void ) {
        menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
 
        gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
+
+#ifdef USE_LDAP
+       menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
+#endif
 }
 
 static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
@@ -1462,11 +1497,11 @@ static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
        }
 }
 
-/*
+/**
  * Add list of items into tree node below specified tree node.
- * Enter: treeNode  Tree node.
- *        ds        Data source.
- *        listItems List of items.
+ * \param treeNode  Tree node.
+ * \param ds        Data source.
+ * \param listItems List of items.
  */
 static void addressbook_treenode_add_list(
        GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
@@ -1496,9 +1531,9 @@ static void addressbook_treenode_add_list(
        }
 }
 
-/*
-* Cut from address list widget.
-*/
+/**
+ * Cut from address list widget.
+ */
 static void addressbook_clip_cut_cb( void ) {
        _clipBoard_->cutFlag = TRUE;
        addrclip_clear( _clipBoard_ );
@@ -1506,9 +1541,9 @@ static void addressbook_clip_cut_cb( void ) {
        /* addrclip_list_show( _clipBoard_, stdout ); */
 }
 
-/*
-* Copy from address list widget.
-*/
+/**
+ * Copy from address list widget.
+ */
 static void addressbook_clip_copy_cb( void ) {
        _clipBoard_->cutFlag = FALSE;
        addrclip_clear( _clipBoard_ );
@@ -1516,9 +1551,9 @@ static void addressbook_clip_copy_cb( void ) {
        /* addrclip_list_show( _clipBoard_, stdout ); */
 }
 
-/*
-* Paste clipboard into address list widget.
-*/
+/**
+ * Paste clipboard into address list widget.
+ */
 static void addressbook_clip_paste_cb( void ) {
        GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
        AddressObject *pobj = NULL;
@@ -1584,9 +1619,9 @@ static void addressbook_clip_paste_cb( void ) {
 
 }
 
-/*
-* Paste clipboard email addresses only into address list widget.
-*/
+/**
+ * Paste clipboard email addresses only into address list widget.
+ */
 static void addressbook_clip_paste_address_cb( void ) {
        GtkCTree *clist = GTK_CTREE(addrbook.clist);
        GtkCTree *ctree;
@@ -1649,10 +1684,10 @@ static void addressbook_clip_paste_address_cb( void ) {
        }
 }
 
-/*
-* Add current treenode object to clipboard. Note that widget only allows
-* one entry from the tree list to be selected.
-*/
+/**
+ * Add current treenode object to clipboard. Note that widget only allows
+ * one entry from the tree list to be selected.
+ */
 static void addressbook_treenode_to_clipboard( void ) {
        AddressObject *obj = NULL;
        AddressDataSource *ds = NULL;
@@ -1700,9 +1735,9 @@ static void addressbook_treenode_to_clipboard( void ) {
        }
 }
 
-/*
-* Cut from tree widget.
-*/
+/**
+ * Cut from tree widget.
+ */
 static void addressbook_treenode_cut_cb( void ) {
        _clipBoard_->cutFlag = TRUE;
        addressbook_treenode_to_clipboard();
@@ -1711,9 +1746,9 @@ static void addressbook_treenode_cut_cb( void ) {
        /* addrclip_list_show( _clipBoard_, stdout ); */
 }
 
-/*
-* Copy from tree widget.
-*/
+/**
+ * Copy from tree widget.
+ */
 static void addressbook_treenode_copy_cb( void ) {
        _clipBoard_->cutFlag = FALSE;
        addressbook_treenode_to_clipboard();
@@ -1722,13 +1757,16 @@ static void addressbook_treenode_copy_cb( void ) {
        /* addrclip_list_show( _clipBoard_, stdout ); */
 }
 
-/*
-* Paste clipboard into address tree widget.
-*/
+/**
+ * Paste clipboard into address tree widget.
+ */
 static void addressbook_treenode_paste_cb( void ) {
        addressbook_clip_paste_cb();
 }
 
+/**
+ * Clear selected entries in clipboard.
+ */
 static void addressbook_list_select_clear( void ) {
        addrselect_list_clear( _addressSelect_ );
 }
@@ -1829,6 +1867,7 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
        AddressInterface *iface = NULL;
        AddressDataSource *ds = NULL;
        gboolean canEdit = FALSE;
+       gboolean canDelete = FALSE;
        gboolean canCut = FALSE;
        gboolean canCopy = FALSE;
        gboolean canPaste = FALSE;
@@ -1860,6 +1899,7 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
                ds = ads->dataSource;
                iface = ds->interface;
                canEdit = TRUE;
+               canDelete = TRUE;
                if( iface->readOnly ) {
                        canTreePaste = FALSE;
                }
@@ -1880,6 +1920,7 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
                }
                else {
                        canEdit = TRUE;
+                       canDelete = TRUE;
                        canTreeCut = TRUE;
                        menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
                        menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
@@ -1888,13 +1929,18 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
                }
                canTreeCopy = TRUE;
                iface = ds->interface;
-               if( iface->externalQuery ) canLookup = TRUE;
+               if( iface->externalQuery ) {
+                       /* Enable deletion of LDAP folder */
+                       canLookup = TRUE;
+                       canDelete = TRUE;
+               }
        }
        else if (obj->type == ADDR_ITEM_GROUP) {
                ds = addressbook_find_datasource( addrbook.treeSelected );
                iface = ds->interface;
                if( ! iface->readOnly ) {
                        canEdit = TRUE;
+                       canDelete = TRUE;
                        menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
                        gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                }
@@ -1911,7 +1957,7 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
 
        /* Enable edit */
        menu_set_sensitive( addrbook.tree_factory, "/Edit",   canEdit );
-       menu_set_sensitive( addrbook.tree_factory, "/Delete", canEdit );
+       menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
        menu_set_sensitive( addrbook.tree_factory, "/Cut",    canTreeCut );
        menu_set_sensitive( addrbook.tree_factory, "/Copy",   canTreeCopy );
        menu_set_sensitive( addrbook.tree_factory, "/Paste",  canTreePaste );
@@ -1980,9 +2026,11 @@ static void addressbook_new_folder_cb(gpointer data, guint action,
        folder = addressbook_edit_folder( abf, parentFolder, NULL );
        if( folder ) {
                GtkCTreeNode *nn;
-               nn = addressbook_node_add_folder( addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
+               nn = addressbook_node_add_folder(
+                       addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
                gtk_ctree_expand( ctree, addrbook.treeSelected );
-               if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj);
+               if( addrbook.treeSelected == addrbook.opened )
+                       addressbook_set_clist(obj);
        }
 
 }
@@ -2020,7 +2068,8 @@ static void addressbook_new_group_cb(gpointer data, guint action,
                GtkCTreeNode *nn;
                nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
                gtk_ctree_expand( ctree, addrbook.treeSelected );
-               if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj);
+               if( addrbook.treeSelected == addrbook.opened )
+                       addressbook_set_clist(obj);
        }
 
 }
@@ -2042,12 +2091,12 @@ static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
                                is_leaf, expanded);
 }
 
-/*
-* Edit data source.
-* Enter: obj   Address object to edit.
-*        node  Node in tree.
-* Return: New name of data source.
-*/
+/**
+ * Edit data source.
+ * \param obj  Address object to edit.
+ * \param node Node in tree.
+ * \return New name of data source.
+ */
 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
        gchar *newName = NULL;
        AddressDataSource *ds = NULL;
@@ -2149,22 +2198,34 @@ static void addressbook_treenode_edit_cb(gpointer data, guint action,
        }
 }
 
-/*
-* Delete an item from the tree widget.
-*/
-static void addressbook_treenode_delete_cb(gpointer data, guint action,
-                                        GtkWidget *widget)
+typedef enum {
+       ADDRTREE_DEL_NONE,
+       ADDRTREE_DEL_DATA,
+       ADDRTREE_DEL_FOLDER_ONLY,
+       ADDRTREE_DEL_FOLDER_ADDR
+} TreeItemDelType ;
+
+/**
+ * Delete an item from the tree widget.
+ * \param data   Data passed in.
+ * \param action Action.
+ * \param widget Widget issuing callback.
+ */
+static void addressbook_treenode_delete_cb(
+               gpointer data, guint action, GtkWidget *widget )
 {
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
        GtkCTreeNode *node = NULL;
        AddressObject *obj;
        gchar *message;
        AlertValue aval;
-       AddressBookFile *abf = NULL;
+       AddrBookBase *adbase;
+       AddressCache *cache;
        AdapterDSource *ads = NULL;
        AddressInterface *iface = NULL;
        AddressDataSource *ds = NULL;
        gboolean remFlag = FALSE;
+       TreeItemDelType delType;
 
        if( ! addrbook.treeSelected ) return;
        node = addrbook.treeSelected;
@@ -2184,57 +2245,101 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
                ds = addressbook_find_datasource( node );
                if( ds == NULL ) return;
 
-               /* Only allow deletion from non-readOnly data sources */
+               /* Only allow deletion from non-readOnly */
                iface = ds->interface;
-               if( iface->readOnly ) return;
+               if( iface->readOnly ) {
+                       /* Allow deletion of query results */
+                       if( ! iface->externalQuery ) return;
+               }
        }
 
        /* Confirm deletion */
+       delType = ADDRTREE_DEL_NONE;
        if( obj->type == ADDR_ITEM_FOLDER ) {
-               message = g_strdup_printf( _(
-                       "Do you want to delete the folder AND all addresses in `%s' ? \n" \
-                       "If deleting the folder only, addresses will be moved into parent folder." ),
-                       obj->name );
-               aval = alertpanel( _("Delete"), message,
-                       _("Folder only"), _("Folder and Addresses"), _("Cancel") );
-               g_free(message);
-               if( aval == G_ALERTOTHER ) return;
+               if( iface->externalQuery ) {
+                       message = g_strdup_printf( _(
+                               "Do you want to delete the query " \
+                               "results and addresses in `%s' ?" ),
+                               obj->name );
+                       aval = alertpanel( _("Delete"), message,
+                               _("Yes"), _("No"), NULL );
+                       g_free(message);
+                       if( aval == G_ALERTDEFAULT ) {
+                               delType = ADDRTREE_DEL_FOLDER_ADDR;
+                       }
+               }
+               else {
+                       message = g_strdup_printf( _(
+                               "Do you want to delete the folder " \
+                               "AND all addresses in `%s' ? \n" \
+                               "If deleting the folder only, addresses " \
+                               "will be moved into parent folder." ),
+                               obj->name );
+                       aval = alertpanel( _("Delete"), message,
+                               _("Folder only"),
+                               _("Folder and Addresses"),
+                               _("Cancel") );
+                       g_free(message);
+                       if( aval == G_ALERTDEFAULT ) {
+                               delType = ADDRTREE_DEL_FOLDER_ONLY;
+                       }
+                       else if( aval == G_ALERTALTERNATE ) {
+                               delType = ADDRTREE_DEL_FOLDER_ADDR;
+                       }
+               }
        }
        else {
                message = g_strdup_printf(_("Really delete `%s' ?"), obj->name);
                aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL);
                g_free(message);
-               if (aval != G_ALERTDEFAULT) return;
+               if( aval == G_ALERTDEFAULT ) delType = ADDRTREE_DEL_DATA;
        }
+       if( delType == ADDRTREE_DEL_NONE ) return;
 
        /* Proceed with deletion */
        if( obj->type == ADDR_DATASOURCE ) {
+               /* Remove node from tree */
+               gtk_ctree_remove_node( ctree, node );
+       
                /* Remove data source. */
                if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
                        addrindex_free_datasource( ds );
-                       remFlag = TRUE;
                }
+               return;
        }
-       else {
-               abf = addressbook_get_book_file();
-               if( abf == NULL ) return;
+
+       /* Get reference to cache */
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       if( adbase == NULL ) return;
+       cache = adbase->addressCache;
+
+       /* Remove query results folder */
+       if( iface->externalQuery ) {
+               AdapterFolder *adapter = ADAPTER_FOLDER(obj);
+               ItemFolder *folder = adapter->itemFolder;
+
+               addrindex_remove_results( ds, folder );
+               gtk_ctree_remove_node( ctree, node );
+               return;
        }
 
+       /* Code below is valid for regular address book deletion */
        if( obj->type == ADDR_ITEM_FOLDER ) {
                AdapterFolder *adapter = ADAPTER_FOLDER(obj);
                ItemFolder *item = adapter->itemFolder;
-               if( aval == G_ALERTDEFAULT ) {
+
+               if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
                        /* Remove folder only */
-                       item = addrbook_remove_folder( abf, item );
+                       item = addrcache_remove_folder( cache, item );
                        if( item ) {
                                addritem_free_item_folder( item );
                                addressbook_move_nodes_up( ctree, node );
                                remFlag = TRUE;
                        }
                }
-               else if( aval == G_ALERTALTERNATE ) {
+               else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
                        /* Remove folder and addresses */
-                       item = addrbook_remove_folder_delete( abf, item );
+                       item = addrcache_remove_folder_delete( cache, item );
                        if( item ) {
                                addritem_free_item_folder( item );
                                remFlag = TRUE;
@@ -2245,7 +2350,7 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
                AdapterGroup *adapter = ADAPTER_GROUP(obj);
                ItemGroup *item = adapter->itemGroup;
 
-               item = addrbook_remove_group( abf, item );
+               item = addrcache_remove_group( cache, item );
                if( item ) {
                        addritem_free_item_group( item );
                        remFlag = TRUE;
@@ -2277,7 +2382,8 @@ static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *
                        ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE );
                        if( person && addrbook.treeSelected == addrbook.opened ) {
                                gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
-                               addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
+                               addressbook_folder_refresh_one_person(
+                                       GTK_CTREE(addrbook.clist), person );
                        }
                }
        }
@@ -2303,11 +2409,11 @@ static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *
        }
 }
 
-/*
-* Search for specified child group node in address index tree.
-* Enter: parent Parent node.
-*        group  Group to find.
-*/
+/**
+ * Search for specified child group node in address index tree.
+ * \param parent Parent node.
+ * \param group  Group to find.
+ */
 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
        GtkCTreeNode *node = NULL;
        GtkCTreeRow *currRow;
@@ -2669,20 +2775,19 @@ static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFold
                                      atci->iconXpmOpen, atci->maskXpmOpen,
                                      FALSE, FALSE);
                gtk_ctree_node_set_row_data(clist, nodeGroup, group );
+               gtk_sctree_sort_node(clist, NULL);
        }
-       gtk_sctree_sort_node(clist, NULL);
-
        /* Free up the list */
        mgu_clear_list( items );
        g_list_free( items );
 }
 
-/*
-* Search ctree widget callback function.
-* Enter: pA Pointer to node.
-*        pB Pointer to data item being sought.
-* Return: Zero (0) if group found.
-*/
+/**
+ * Search ctree widget callback function.
+ * \param  pA Pointer to node.
+ * \param  pB Pointer to data item being sought.
+ * \return Zero (0) if group found.
+ */
 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
        AddressObject *aoA;
 
@@ -2697,12 +2802,12 @@ static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer p
        return 1;
 }
 
-/*
-* Search ctree widget callback function.
-* Enter: pA Pointer to node.
-*        pB Pointer to data item being sought.
-* Return: Zero (0) if folder found.
-*/
+/**
+ * Search ctree widget callback function.
+ * \param  pA Pointer to node.
+ * \param  pB Pointer to data item being sought.
+ * \return Zero (0) if folder found.
+ */
 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
        AddressObject *aoA;
 
@@ -2764,11 +2869,11 @@ static void addressbook_treenode_remove_item( void ) {
        }
 }
 
-/*
-* Find parent datasource for specified tree node.
-* Enter: node Node to test.
-* Return: Data source, or NULL if not found.
-*/
+/**
+ * Find parent datasource for specified tree node.
+ * \param  node Node to test.
+ * \return Data source, or NULL if not found.
+ */
 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
        AddressDataSource *ds = NULL;
        AddressObject *ao;
@@ -2792,10 +2897,10 @@ static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
        return ds;
 }
 
-/*
-* Load address list widget with children of specified object.
-* Enter: obj   Parent object to be loaded.
-*/
+/**
+ * Load address list widget with children of specified object.
+ * \param obj Parent object to be loaded.
+ */
 static void addressbook_set_clist( AddressObject *obj ) {
        GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
        GtkCList *clist = GTK_CLIST(addrbook.clist);
@@ -2846,13 +2951,14 @@ static void addressbook_set_clist( AddressObject *obj ) {
        gtk_clist_thaw(clist);
 }
 
-/*
-* Call back function to free adaptor. Call back is setup by function
-* gtk_ctree_node_set_row_data_full() when node is populated. This function is
-* called when the address book tree widget node is removed by calling
-* function gtk_ctree_remove_node().
-* Enter: data Tree node's row data.
-*/
+/**
+ * Call back function to free adaptor. Call back is setup by function
+ * gtk_ctree_node_set_row_data_full() when node is populated. This function is
+ * called when the address book tree widget node is removed by calling
+ * function gtk_ctree_remove_node().
+ * 
+ * \param data Tree node's row data.
+ */
 static void addressbook_free_treenode( gpointer data ) {
        AddressObject *ao;
 
@@ -3031,7 +3137,7 @@ void addressbook_read_file( void ) {
        }
 
        addrIndex = addrindex_create_index();
-       addrindex_initialize( addrIndex );
+       addrindex_initialize();
 
        /* Use new address book index. */
        addrindex_set_file_path( addrIndex, get_rc_dir() );
@@ -3108,13 +3214,13 @@ static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
        return added;
 }
 
-/*
-* Add group into the address index tree.
-* Enter: node     Parent node.
-*        ds        Data source.
-*        itemGroup Group to add.
-* Return: Inserted node.
-*/
+/**
+ * Add group into the address index tree.
+ * \param  node      Parent node.
+ * \param  ds        Data source.
+ * \param  itemGroup Group to add.
+ * \return Inserted node.
+ */
 static GtkCTreeNode *addressbook_node_add_group(
                GtkCTreeNode *node, AddressDataSource *ds,
                ItemGroup *itemGroup )
@@ -3370,7 +3476,7 @@ static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *wid
  * \param queryType Query type.
  * \param status    Status/Error code.
  */
-static void addressbook_search_message( AddrQueryType queryType, gint sts ) {
+static void addressbook_search_message( gint queryType, gint sts ) {
        gchar *desc = NULL;
        *addressbook_msgbuf = '\0';
 
@@ -3380,13 +3486,15 @@ static void addressbook_search_message( AddrQueryType queryType, gint sts ) {
                        desc = addressbook_err2string( _lutErrorsLDAP_, sts );
 #endif
                }
-               else {
-                       desc = NULL;
-               }
+       }
+       if( desc ) {
                g_snprintf( addressbook_msgbuf,
                        sizeof(addressbook_msgbuf), "%s", desc );
+               addressbook_status_show( addressbook_msgbuf );
+       }
+       else {
+               addressbook_status_show( "" );
        }
-       addressbook_status_show( addressbook_msgbuf );
 }
 
 /**
@@ -3403,7 +3511,11 @@ static void addressbook_refresh_current( void ) {
        addressbook_set_clist( obj );
 }
 
-static gchar *_tempMessage_ = N_("Busy searching...");
+/**
+ * Message that is displayed whilst a query is executing in a background
+ * thread.
+ */
+static gchar *_tempMessage_ = N_( "Busy searching..." );
 
 /**
  * Address search idle function. This function is called during UI idle time
@@ -3421,25 +3533,44 @@ static void addressbook_search_idle( gpointer data ) {
 }
 
 /**
- * Search completion function. This removes the query from the idle list.
+ * Search completion callback function. This removes the query from the idle
+ * list.
  *
- * \param queryID   Query to be removed.
- * \param queryType Query type being removed.
- * \param status    Search status.
+ * \param sender  Sender of query.
+ * \param queryID Query ID of search request.
+ * \param status  Search status.
+ * \param data    Query data.
  */
-static void addressbook_search_idle_end(
-               gint queryID, AddrQueryType queryType, gint status )
+static void addressbook_search_callback_end(
+               gpointer sender, gint queryID, gint status, gpointer data )
 {
-       gpointer data;
+       gpointer ptrQID;
+       QueryRequest *req;
+       AddrQueryObject *aqo;
 
-       data = GINT_TO_POINTER( queryID );
-       if( data ) {
-               gtk_idle_remove_by_data( data );
+       /* Remove idler function */
+       ptrQID = GINT_TO_POINTER( queryID );
+       if( ptrQID ) {
+               gtk_idle_remove_by_data( ptrQID );
        }
+
+       /* Refresh addressbook contents */
        addressbook_refresh_current();
-       addressbook_search_message( queryType, status );
+       req = qrymgr_find_request( queryID );
+       if( req != NULL ) {
+               aqo = ( AddrQueryObject * ) req->queryList->data;
+               addressbook_search_message( aqo->queryType, status );
+       }
+
+       /* Stop the search */
+       addrindex_stop_search( queryID );
 }
 
+/**
+ * Label (a format string) that is used to name each folder.
+ */
+static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
+
 /**
  * Perform search.
  *
@@ -3451,7 +3582,8 @@ static void addressbook_perform_search(
                AddressDataSource *ds, gchar *searchTerm,
                GtkCTreeNode *pNode )
 {
-       AddressBookFile *abf;
+       AddrBookBase *adbase;
+       AddressCache *cache;
        ItemFolder *folder;
        GtkCTree *ctree;
        GtkCTreeNode *nNode;
@@ -3460,23 +3592,25 @@ static void addressbook_perform_search(
        guint idleID;
        AddressObjectType aoType;
 
+       /* Setup a query */
+       if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
+
        if( ds->type == ADDR_IF_LDAP ) {
-#ifdef USE_LDAP
+#if USE_LDAP
                aoType = ADDR_LDAP_QUERY;
 #endif
        }
        else {
                return;
        }
-       abf = ds->rawDataSource;
-
-       /* Setup a query */
-       if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
 
+       /* Get reference to address cache */    
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       cache = adbase->addressCache;
 
        /* Create a folder for the search results */
-       folder = addrbook_add_new_folder( abf, NULL );
-       name = g_strdup_printf( "Search '%s'", searchTerm );
+       folder = addrcache_add_new_folder( cache, NULL );
+       name = g_strdup_printf( _queryFolderLabel_, searchTerm );
        addritem_folder_set_name( folder, name );
        addritem_folder_set_remarks( folder, "" );
        g_free( name );
@@ -3491,8 +3625,8 @@ static void addressbook_perform_search(
        }
 
        /* Setup the search */
-       queryID = addrindex_setup_static_search(
-                       ds, searchTerm, folder, addressbook_search_idle_end );
+       queryID = addrindex_setup_explicit_search(
+               ds, searchTerm, folder, addressbook_search_callback_end, NULL );
        if( queryID == 0 ) return;
 
        /* Set up idler function */
@@ -3501,7 +3635,7 @@ static void addressbook_perform_search(
                        GINT_TO_POINTER( queryID ) );
 
        /* Start search, sit back and wait for something to happen */
-       addrindex_start_static_search( queryID, idleID );
+       addrindex_start_search( queryID );
 
        addressbook_status_show( _tempMessage_ );
 }
@@ -3552,6 +3686,47 @@ static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
        g_free( searchTerm );
 }
 
+/**
+ * Browse address entry for highlighted entry.
+ */
+static void addressbook_browse_entry_cb( void ) {
+       GtkCTree *clist = GTK_CTREE(addrbook.clist);
+       AddressObject *obj;
+       AddressDataSource *ds;
+       AddressInterface *iface;
+       ItemPerson *person;
+       ItemEMail *email;
+
+       if( addrbook.listSelected == NULL ) return;
+       obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
+       g_return_if_fail(obj != NULL);
+
+       ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
+       if( ds == NULL ) return;
+       iface = ds->interface;
+       if( ! iface->haveLibrary ) return;
+
+       person = NULL;
+       if( obj->type == ADDR_ITEM_EMAIL ) {
+               email = ( ItemEMail * ) obj;
+               if( email == NULL ) return;
+               person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+       }
+       else if( obj->type == ADDR_ITEM_PERSON ) {
+               person = ( ItemPerson * ) obj;
+       }
+       else {
+               /* None of these */
+               return;
+       }
+
+       if( iface->type == ADDR_IF_LDAP ) {
+#ifdef USE_LDAP
+               browseldap_entry( ds, person->externalID );
+#endif
+       }
+}
+
 /* **********************************************************************
 * Build lookup tables.
 * ***********************************************************************
@@ -3832,10 +4007,10 @@ static void addrbookctl_free_group( AdapterGroup *adapter ) {
        g_free( adapter );
 }
 
-/*
+/**
  * Build GUI interface list.
  */
-void addrbookctl_build_iflist() {
+void addrbookctl_build_iflist( void ) {
        AddressTypeControlItem *atci;
        AdapterInterface *adapter;
        GList *list = NULL;
@@ -3862,12 +4037,14 @@ void addrbookctl_build_iflist() {
                        adapter->haveLibrary = interface->haveLibrary;
                        ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
                        ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
-                       _addressInterfaceList_ = g_list_append( _addressInterfaceList_, adapter );
+                       _addressInterfaceList_ =
+                               g_list_append( _addressInterfaceList_, adapter );
                }
                list = g_list_next( list );
        }
 }
 
+#if 0
 void addrbookctl_free_selection( GList *list ) {
        GList *node = list;
        while( node ) {
@@ -3877,11 +4054,13 @@ void addrbookctl_free_selection( GList *list ) {
        }
        g_list_free( list );
 }
+#endif
 
-/*
-* Find GUI interface type specified interface type.
-* Return: Interface item, or NULL if not found.
-*/
+/**
+ * Find GUI interface type specified interface type.
+ * \param  ifType Interface type.
+ * \return Interface item, or NULL if not found.
+ */
 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
        GList *node = _addressInterfaceList_;
        while( node ) {
@@ -3892,10 +4071,10 @@ AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
        return NULL;
 }
 
-/*
-* Build interface list selection.
-*/
-void addrbookctl_build_ifselect() {
+/**
+ * Build interface list selection.
+ */
+void addrbookctl_build_ifselect( void ) {
        GList *newList = NULL;
        gchar *selectStr;
        gchar **splitStr;
@@ -3940,15 +4119,17 @@ void addrbookctl_build_ifselect() {
        newList = NULL;
 }
 
-/* **********************************************************************
-* Add sender to address book.
-* ***********************************************************************
-*/
+/* ***********************************************************************
+ * Add sender to address book.
+ * ***********************************************************************
+ */
 
 /*
  * This function is used by the Add sender to address book function.
  */
-gboolean addressbook_add_contact( const gchar *name, const gchar *address, const gchar *remarks ) {
+gboolean addressbook_add_contact(
+               const gchar *name, const gchar *address, const gchar *remarks )
+{
        debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
        if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
                debug_print( "addressbook_add_contact - added\n" );
@@ -3958,33 +4139,14 @@ gboolean addressbook_add_contact( const gchar *name, const gchar *address, const
 }
 
 /* **********************************************************************
-* Address completion support.
-* ***********************************************************************
-*/
-
-/*
-* This function is used by the address completion function to load
-* addresses.
-* Enter: callBackFunc Function to be called when an address is
-*                     to be loaded.
-* Return: TRUE if data loaded, FALSE if address index not loaded.
-*/
-gboolean addressbook_load_completion(
-               gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) )
-{
-       debug_print( "addressbook_load_completion\n" );
-       return addrindex_load_completion( _addressIndex_, callBackFunc );
-}
-
-/* **********************************************************************
-* Address Import.
-* ***********************************************************************
-*/
+ * Address Import.
+ * ***********************************************************************
+ */
 
-/*
-* Import LDIF file.
-*/
-static void addressbook_import_ldif_cb() {
+/**
+ * Import LDIF file.
+ */
+static void addressbook_import_ldif_cb( void ) {
        AddressDataSource *ds = NULL;
        AdapterDSource *ads = NULL;
        AddressBookFile *abf = NULL;
@@ -4019,10 +4181,10 @@ static void addressbook_import_ldif_cb() {
        }
 }
 
-/*
-* Import MUTT file.
-*/
-static void addressbook_import_mutt_cb() {
+/**
+ * Import MUTT file.
+ */
+static void addressbook_import_mutt_cb( void ) {
        AddressDataSource *ds = NULL;
        AdapterDSource *ads = NULL;
        AddressBookFile *abf = NULL;
@@ -4057,10 +4219,10 @@ static void addressbook_import_mutt_cb() {
        }
 }
 
-/*
-* Import Pine file.
-*/
-static void addressbook_import_pine_cb() {
+/**
+ * Import Pine file.
+ */
+static void addressbook_import_pine_cb( void ) {
        AddressDataSource *ds = NULL;
        AdapterDSource *ads = NULL;
        AddressBookFile *abf = NULL;
@@ -4095,11 +4257,11 @@ static void addressbook_import_pine_cb() {
        }
 }
 
-/*
+/**
  * Harvest addresses.
- * Enter: folderItem Folder to import.
- *        sourceInd  Source indicator: FALSE - Folder, TRUE - Messages.
- *        msgList    List of message numbers, or NULL to process folder.
+ * \param folderItem Folder to import.
+ * \param sourceInd  Source indicator: FALSE - Folder, TRUE - Messages.
+ * \param msgList    List of message numbers, or NULL to process folder.
  */
 void addressbook_harvest(
        FolderItem *folderItem, gboolean sourceInd, GList *msgList )
@@ -4132,9 +4294,9 @@ void addressbook_harvest(
        }
 }
 
-/*
-* Export HTML file.
-*/
+/**
+ * Export HTML file.
+ */
 static void addressbook_export_html_cb( void ) {
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
        AddressObject *obj;
@@ -4156,9 +4318,9 @@ static void addressbook_export_html_cb( void ) {
        addressbook_exp_html( cache );
 }
 
-/*
-* Export LDIF file.
-*/
+/**
+ * Export LDIF file.
+ */
 static void addressbook_export_ldif_cb( void ) {
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
        AddressObject *obj;
index a1d2f33af8be6cb3085a9a8d854293c9326fde19..89a7f4c3c5b0fd17554fa6ee8ee0cfd34ead0276 100644 (file)
@@ -116,6 +116,11 @@ N_("Personal address")
 #define DISP_OLD_COMMON       _("Common address")
 #define DISP_OLD_PERSONAL     _("Personal address")
 
+/**
+ * Singleton object.
+ */
+static AddressIndex *_addressIndex_ = NULL;
+
 /*
  * Define attribute name-value pair.
  */
@@ -572,7 +577,7 @@ static void addrindex_free_cache_hash( GHashTable *table ) {
        g_hash_table_destroy( table );
 }
 
-/*
+/**
  * Remove data source from internal hashtable.
  * \param addrIndex Address index.
  * \param ds        Data source to remove.
@@ -590,32 +595,44 @@ static void addrindex_hash_remove_cache(
        }
 }
 
-/*
- * Create a new address index.
+/**
+ * Create a new address index. This is created as a singleton object.
  * \return Initialized address index object.
  */
 AddressIndex *addrindex_create_index( void ) {
-       AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
+       AddressIndex *index;
+
+       if( _addressIndex_ == NULL ) {
+               index = g_new0( AddressIndex, 1 );
+               ADDRITEM_TYPE(index) = ITEMTYPE_INDEX;
+               ADDRITEM_ID(index) = NULL;
+               ADDRITEM_NAME(index) = g_strdup( "Address Index" );
+               ADDRITEM_PARENT(index) = NULL;
+               ADDRITEM_SUBTYPE(index) = 0;
+               index->filePath = NULL;
+               index->fileName = NULL;
+               index->retVal = MGU_SUCCESS;
+               index->needsConversion = FALSE;
+               index->wasConverted = FALSE;
+               index->conversionError = FALSE;
+               index->interfaceList = NULL;
+               index->lastType = ADDR_IF_NONE;
+               index->dirtyFlag = FALSE;
+               index->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
+               index->loadedFlag = FALSE;
+               index->searchOrder = NULL;
+               addrindex_build_if_list( index );
+               _addressIndex_ = index;
+       }
+       return _addressIndex_;
+}
 
-       ADDRITEM_TYPE(addrIndex) = ITEMTYPE_INDEX;
-       ADDRITEM_ID(addrIndex) = NULL;
-       ADDRITEM_NAME(addrIndex) = g_strdup( "Address Index" );
-       ADDRITEM_PARENT(addrIndex) = NULL;
-       ADDRITEM_SUBTYPE(addrIndex) = 0;
-       addrIndex->filePath = NULL;
-       addrIndex->fileName = NULL;
-       addrIndex->retVal = MGU_SUCCESS;
-       addrIndex->needsConversion = FALSE;
-       addrIndex->wasConverted = FALSE;
-       addrIndex->conversionError = FALSE;
-       addrIndex->interfaceList = NULL;
-       addrIndex->lastType = ADDR_IF_NONE;
-       addrIndex->dirtyFlag = FALSE;
-       addrIndex->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
-       addrIndex->loadedFlag = FALSE;
-       addrIndex->searchOrder = NULL;
-       addrindex_build_if_list( addrIndex );
-       return addrIndex;
+/**
+ * Return reference to address index.
+ * \return Address index object.
+ */
+AddressIndex *addrindex_get_object( void ) {
+       return _addressIndex_;
 }
 
 /**
@@ -671,18 +688,16 @@ GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
 
 /**
  * Perform any other initialization of address index.
- * \param addrIndex Address index.
  */
-void addrindex_initialize( AddressIndex *addrIndex ) {
+void addrindex_initialize( void ) {
        qrymgr_initialize();
-       addrcompl_initialize( addrIndex );
+       addrcompl_initialize();
 }
 
 /**
  * Perform any other teardown of address index.
- * \param addrIndex Address index.
  */
-void addrindex_teardown( AddressIndex *addrIndex ) {
+void addrindex_teardown( void ) {
        addrcompl_teardown();
        qrymgr_teardown();
 }
@@ -738,6 +753,8 @@ void addrindex_free_index( AddressIndex *addrIndex ) {
        addrIndex->loadedFlag = FALSE;
 
        g_free( addrIndex );
+       addrIndex = NULL;
+       _addressIndex_ = NULL;
 }
 
 /**
@@ -1055,7 +1072,7 @@ static void addrindex_write_fragment(
        }
 }
 
-/*
+#if 0
 static void addrindex_print_fragment_r(
                const AddressIfFragment *fragment, FILE *stream, gint lvl )
 {
@@ -1084,7 +1101,7 @@ static void addrindex_print_fragment_r(
 static void addrindex_print_fragment( const AddressIfFragment *fragment, FILE *stream ) {
        addrindex_print_fragment_r( fragment, stream, 0 );
 }
-*/
+#endif
 
 /**
  * Read/parse address index file, creating a data source for a regular
@@ -2456,174 +2473,60 @@ GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
 */
 
 /**
- * Current query ID. This is incremented for each query created.
- */
-static gint _currentQueryID_ = 0;
-
-/*
- * Variables for the search that is being performed.
- */
-static gchar *_searchTerm_ = NULL;
-static gpointer _searchTarget_ = NULL;
-static AddrSearchCallbackFunc *_searchCallback_ = NULL;
-
-/**
- * Setup or register the search that will be performed.
- * \param addrIndex  Address index object.
- * \param searchTerm Search term. A private copy will be made.
- * \param target     Target object that will receive data.
- * \param callBack   Callback function.
+ * Setup or register the dynamic search that will be performed. The search
+ * is registered with the query manager.
+ *
+ * \param searchTerm    Search term. A private copy will be made.
+ * \param callBackEntry Callback function that should be called when
+ *                     each entry is received.
+ * \param callBackEnd   Callback function that should be called when
+ *                     search has finished running.
  * \return ID allocated to query that will be executed.
  */
 gint addrindex_setup_search(
-       AddressIndex *addrIndex, const gchar *searchTerm,
-       const gpointer target, AddrSearchCallbackFunc callBack )
+       const gchar *searchTerm, void *callBackEnd, void *callBackEntry )
 {
+       QueryRequest *req;
        gint queryID;
 
-       /* printf( "search term ::%s::\n", searchTerm ); */
-       g_free( _searchTerm_ );
-       _searchTerm_ = g_strdup( searchTerm );
+       /* Set up a dynamic address query */
+       req = qrymgr_add_request( searchTerm, callBackEnd, callBackEntry );
+       queryID = req->queryID;
+       qryreq_set_search_type( req, ADDRSEARCH_DYNAMIC );
 
-       queryID = ++_currentQueryID_;
-       _searchTarget_ = target;
-       _searchCallback_ = callBack;
-       /* printf( "query ID ::%d::\n", queryID ); */
+       /* printf( "***> query ID ::%d::\n", queryID ); */
        return queryID;
 }
 
 #ifdef USE_LDAP
-/**
- * LDAP callback entry point for each address entry found.
- * \param qry       LDAP query.
- * \param listEMail List of Item EMail objects found.
- */
-static void addrindex_ldap_entry_cb( LdapQuery *qry, GList *listEMail ) {
-       /*
-       GList *node;
-
-       printf( "\naddrindex::addrindex_ldap_entry_cb ::%s::\n", qry->queryName );
-       node = listEMail;
-       while( node ) {
-               ItemEMail *email = node->data;
-               printf( "\temail ::%s::\n", email->address );
-               node = g_list_next( node );
-       }
-       */
-       if( _searchCallback_ ) {
-               ( _searchCallback_ ) ( qry->queryID, listEMail, _searchTarget_ );
-       }
-       g_list_free( listEMail );
-}
-
-/**
- * LDAP callback entry point for completion of search.
- * \param qry LDAP query.
- */
-static void addrindex_ldap_end_cb( LdapQuery *qry ) {
-       /* printf( "\naddrindex::addrindex_ldap_end_cb ::%s::\n", qry->queryName ); */
-}
-
-/**
- * Return results of previous query.
- * \param folder.
- * \return List of ItemEMail objects.
- */
-static void addrindex_ldap_use_previous(
-       const ItemFolder *folder, const gint queryID )
-{
-       GList *listEMail;
-       GList *node;
-       GList *nodeEM;
-
-       listEMail = NULL;
-       if( _searchCallback_ ) {
-               node = folder->listPerson;
-               while( node ) {
-                       AddrItemObject *aio = node->data;
-                       if( aio &&  aio->type == ITEMTYPE_PERSON ) {
-                               ItemPerson *person = node->data;
-                               nodeEM = person->listEMail;
-                               while( nodeEM ) {
-                                       ItemEMail *email = nodeEM->data;
-                                       nodeEM = g_list_next( nodeEM );
-                                       listEMail = g_list_append( listEMail, email );
-                               }
-                       }
-                       node = g_list_next( node );
-               }
-               ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
-               g_list_free( listEMail );
-       }
-}
 
 /*
- * Function prototype (not in header file or circular reference encountered!)
- */
-LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
-
-/**
- * Construct an LDAP query and initiate an LDAP dynamic search.
- * \param server  LDAP server object.
- * \param queryID ID of search query to be executed.
+ * Function prototypes (not in header file or circular reference errors are
+ * encountered!)
  */
-static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
-       LdapQuery *qry;
-       gchar *name;
-
-       if( ! server->searchFlag ) return;
-
-       /* Retire any aged queries */
-       ldapsvr_retire_query( server );
-
-       /* Test whether any queries for the same term exist */
-       qry = ldapsvr_locate_query( server, _searchTerm_ );
-       if( qry ) {
-               ItemFolder *folder = qry->folder;
-
-               /* Touch query to ensure it hangs around for a bit longer */
-               ldapqry_touch( qry );
-               if( folder ) {
-                       addrindex_ldap_use_previous( folder, queryID );
-                       return;
-               }
-       }
-
-       /* Construct a query */
-       qry = ldapqry_create();
-       ldapqry_set_query_id( qry, queryID );
-       ldapqry_set_search_value( qry, _searchTerm_ );
-       ldapqry_set_query_type( qry, LDAPQUERY_DYNAMIC );
-       ldapqry_set_callback_entry( qry, addrindex_ldap_entry_cb );
-       ldapqry_set_callback_end( qry, addrindex_ldap_end_cb );
-
-       /* Name the query */
-       name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
-       ldapqry_set_name( qry, name );
-       g_free( name );
-
-       ldapsvr_add_query( server, qry );
-       ldapsvr_execute_query( server, qry );
-}
+LdapQuery *ldapsvr_new_dynamic_search( 
+               LdapServer *server, QueryRequest *req );
+LdapQuery *ldapsvr_new_explicit_search(
+               LdapServer *server, QueryRequest *req, ItemFolder *folder );
 
 #endif
 
 /**
- * Perform the previously registered search.
- * \param  addrIndex  Address index object.
- * \param  queryID    ID of search query to be executed.
+ * Execute the previously registered dynamic search.
+ *
+ * \param  req Address query object to execute.
  * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
  *         failed.
  */
-gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
+static gboolean addrindex_start_dynamic( QueryRequest *req ) {
        AddressInterface *iface;
        AddressDataSource *ds;
        GList *nodeIf;
        GList *nodeDS;
        gint type;
 
-       /* printf( "addrindex_start_search::%d::\n", queryID ); */
-       nodeIf = addrIndex->searchOrder;
+       /* printf( "addrindex_start_dynamic::%d::\n", req->queryID ); */
+       nodeIf = _addressIndex_->searchOrder;
        while( nodeIf ) {
                iface = nodeIf->data;
                nodeIf = g_list_next( nodeIf );
@@ -2631,7 +2534,6 @@ gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
                if( ! iface->useInterface ) {
                        continue;
                }
-
                if( ! iface->externalQuery ) {
                        continue;
                }
@@ -2643,8 +2545,22 @@ gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
                        nodeDS = g_list_next( nodeDS );
 #ifdef USE_LDAP
                        if( type == ADDR_IF_LDAP ) {
-                               LdapServer *server = ds->rawDataSource;
-                               addrindex_search_ldap( server, queryID );
+                               LdapServer *server;
+                               LdapQuery *qry;
+
+                               server = ds->rawDataSource;
+                               if( ! server->searchFlag ) {
+                                       continue;
+                               }
+                               if( ldapsvr_reuse_previous( server, req ) ) {
+                                       continue;
+                               }
+
+                               /* Start a new dynamic search */
+                               qry = ldapsvr_new_dynamic_search( server, req );
+                               if( qry ) {
+                                       ldapsvr_execute_query( server, qry );
+                               }
                        }
 #endif
                }
@@ -2654,230 +2570,193 @@ gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
 
 /**
  * Stop the previously registered search.
- * \param addrIndex Address index object.
+ *
  * \param queryID ID of search query to stop.
  */
-void addrindex_stop_search( AddressIndex *addrIndex, const gint queryID ){
-#ifdef USE_LDAP
-       AddressInterface *iface;
-       AddressDataSource *ds;
-       GList *nodeIf;
-       GList *nodeDS;
-       gint type;
+void addrindex_stop_search( const gint queryID ){
+       QueryRequest *req;
+       AddrQueryObject *aqo;
+       GList *node;
 
+       /* printf( "addrindex_stop_search/queryID=%d\n", queryID ); */
        /* If query ID does not match, search has not been setup */
-       /* if( queryID != _queryID_ ) return; */
-
-       /* printf( "addrindex_stop_search::%d::\n", queryID ); */
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
-
-               if( ! iface->useInterface ) {
-                       continue;
-               }
-
-               type = iface->type;
-               nodeDS = iface->listSource;
-               while( nodeDS ) {
-                       ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
-                       if( type == ADDR_IF_LDAP ) {
-                               LdapServer *server = ds->rawDataSource;
-                               ldapsvr_stop_all_query( server );
-                       }
-               }
+       req = qrymgr_find_request( queryID );
+       if( req == NULL ) {
+               return;
        }
-#endif
-}
 
+       /* Stop all queries that were associated with request */
+       node = req->queryList;
+       while( node ) {
+               aqo = node->data;
 #ifdef USE_LDAP
-/**
- * LDAP callback entry point for completion of search.
- * \param qry LDAP query.
- */
-static void addrindex_ldap_end_static_cb( LdapQuery *qry ) {
-       AddrQuery *addrQry;
-       gint queryID;
-       AddrQueryType queryType;
-       AddrSearchStaticFunc *callBack;
-
-       queryID = qry->queryID;
-       queryType = qry->queryType;
-       addrQry = qrymgr_find_query( queryID );
-       if( addrQry == NULL ) {
-               return;
+               if( aqo->queryType == ADDRQUERY_LDAP ) {
+                       LdapQuery *qry = ( LdapQuery * ) aqo;
+                       ldapqry_set_stop_flag( qry, TRUE );
+               }
+#endif
+               node->data = NULL;
+               node = g_list_next( node );
        }
-       callBack = addrQry->callBack;
-
-       /* Delete query */
-       qrymgr_delete_query( queryID );
 
-       /* Execute callback function */
-       callBack( queryID, queryType, qry->retVal );
+       /* Delete query request */
+       qrymgr_delete_request( queryID );
 }
-#endif
 
 /**
- * Setup the explicit search that will be performed. The search is registered with
- * the query manager.
+ * Setup or register the explicit search that will be performed. The search is
+ * registered with the query manager.
  *
- * \param  ds          Data source to search.
- * \param  searchTerm  Search term to locate.
- * \param  folder      Folder to receive search results; may be NULL.
- * \param  callbackEnd Function to call when search has terminated.
+ * \param  ds            Data source to search.
+ * \param  searchTerm    Search term to locate.
+ * \param  folder        Folder to receive search results; may be NULL.
+ * \param  callbackEnd   Function to call when search has terminated.
+ * \param  callbackEntry Function to called for each entry processed.
  * \return ID allocated to query that will be executed.
  */
-gint addrindex_setup_static_search(
+gint addrindex_setup_explicit_search(
        AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder,
-       void *callbackEnd )
+       void *callBackEnd, void *callBackEntry )
 {
-       AddrQuery *addrQry;
+       QueryRequest *req;
        gint queryID;
        gchar *name;
 
-       queryID = ++_currentQueryID_;
-
        /* Name the query */
        name = g_strdup_printf( "Search '%s'", searchTerm );
 
-       /* Set up a generic address query */
-       addrQry = qrymgr_add_query( queryID, searchTerm, callbackEnd, NULL );
+       /* Set up query request */
+       req = qrymgr_add_request( searchTerm, callBackEnd, callBackEntry );
+       qryreq_set_search_type( req, ADDRSEARCH_EXPLICIT );
+       queryID = req->queryID;
 
        if( ds->type == ADDR_IF_LDAP ) {
 #ifdef USE_LDAP
                LdapServer *server;
-               LdapQuery *qry;
 
                server = ds->rawDataSource;
-
-               /* Construct a query */
-               qry = ldapqry_create();
-               ldapqry_set_query_id( qry, queryID );
-               ldapqry_set_name( qry, name );
-               ldapqry_set_search_value( qry, searchTerm );
-               ldapqry_set_query_type( qry, LDAPQUERY_STATIC );
-               ldapqry_set_callback_end( qry, addrindex_ldap_end_static_cb );
-
-               /* Specify folder type and back reference */
-               qry->folder = folder;
-               folder->folderType = ADDRFOLDER_LDAP_QUERY;
-               folder->folderData = ( gpointer ) qry;
-
-               /* Setup server */
-               ldapsvr_add_query( server, qry );
-
-               /* Set up generic query */
-               addrqry_set_query_type( addrQry, ADDRQUERY_LDAP );
-               addrqry_set_server( addrQry, server );
-               addrqry_set_query( addrQry, qry );
+               ldapsvr_new_explicit_search( server, req, folder );
 #endif
        }
        else {
-               qrymgr_delete_query( queryID );
+               qrymgr_delete_request( queryID );
                queryID = 0;
        }
-
        g_free( name );
 
        return queryID;
 }
 
 /**
- * Perform the previously registered explicit search.
- * \param  queryID    ID of search query to be executed.
- * \param  idleID     Idler ID.
+ * Execute the previously registered explicit search.
+ *
+ * \param  req Address query request object to execute.
  * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
  *         failed.
  */
-gboolean addrindex_start_static_search( const gint queryID, const guint idleID )
-{
+static gboolean addrindex_start_explicit( QueryRequest *req ) {
        gboolean retVal;
-       AddrQuery *addrQry;
+       AddrQueryObject *aqo;
 
        retVal = FALSE;
-       addrQry = qrymgr_find_query( queryID );
-       if( addrQry == NULL ) {
-               return retVal;
-       }
 
-       if( addrQry->queryType == ADDRQUERY_LDAP ) {
+       /* Note: there should only be one query in the list. */
+       aqo = req->queryList->data;
 #ifdef USE_LDAP
+       if( aqo->queryType == ADDRQUERY_LDAP ) {
                LdapServer *server;
                LdapQuery *qry;
 
-               server = ( LdapServer * ) addrQry->serverObject;
-               qry = ( LdapQuery * ) addrQry->queryObject;
-
-               /* Retire any aged queries */
-               ldapsvr_retire_query( server );
+               qry = ( LdapQuery * ) aqo;
+               server = qry->server;
 
                /* Start the search */
-               ldapsvr_execute_query( server, qry );
                retVal = TRUE;
+               ldapsvr_execute_query( server, qry );
+       }
 #endif
+       return retVal;
+}
+
+/**
+ * Start the previously registered search.
+ *
+ * \param  queryID    ID of search query to be executed.
+ * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
+ *         failed.
+ */
+gboolean addrindex_start_search( const gint queryID ) {
+       gboolean retVal;
+       QueryRequest *req;
+       AddrSearchType searchType;
+
+       retVal = FALSE;
+       /* printf( "addrindex_start_search/queryID=%d\n", queryID ); */
+       req = qrymgr_find_request( queryID );
+       if( req == NULL ) {
+               return retVal;
        }
 
-       if( retVal ) {
-               addrqry_set_idle_id( addrQry, idleID );
+       searchType = req->searchType;
+       if( searchType == ADDRSEARCH_DYNAMIC ) {
+               retVal = addrindex_start_dynamic( req );
+       }
+       else if( searchType == ADDRSEARCH_EXPLICIT ) {
+               retVal = addrindex_start_explicit( req );
        }
 
        return retVal;
 }
 
 /**
- * Read all address books that do not support dynamic queries.
- * \param addrIndex Address index object.
+ * Remove results (folder and data) for specified data source and folder.
+ * \param ds     Data source to process.
+ * \param folder Results folder to remove.
  */
-void addrindex_read_all( AddressIndex *addrIndex ) {
-       AddressInterface *iface;
-       AddressDataSource *ds;
-       GList *nodeIf;
-       GList *nodeDS;
+void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) {
+       AddrBookBase *adbase;
+       AddressCache *cache;
+       gint queryID = 0;
 
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
+       /* Test for folder */
+       if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return;
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       if( adbase == NULL ) return;
+       cache = adbase->addressCache;
 
-               if( ! iface->useInterface ) {
-                       continue;
-               }
-               if( iface->externalQuery ) {
-                       continue;
-               }
-               nodeDS = iface->listSource;
-               while( nodeDS ) {
-                       ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
+       /* Hide folder to prevent re-display */
+       addritem_folder_set_hidden( folder, TRUE );
 
-                       /* Read address book */
-                       if( addrindex_ds_get_modify_flag( ds ) ) {
-                               addrindex_ds_read_data( ds );
-                               continue;
-                       }
+       if( ds->type == ADDR_IF_LDAP ) {
+#ifdef USE_LDAP
+               LdapQuery  *qry;
 
-                       if( ! addrindex_ds_get_read_flag( ds ) ) {
-                               addrindex_ds_read_data( ds );
-                               continue;
-                       }
-               }
+               qry = ( LdapQuery * ) folder->folderData;
+               queryID = ADDRQUERY_ID(qry);
+               ldapquery_remove_results( qry );
+#endif
+       }
+
+       /* Delete query request */
+       if( queryID > 0 ) {
+               qrymgr_delete_request( queryID );
        }
-       addrIndex->loadedFlag = TRUE;
 }
 
+/* **********************************************************************
+* Address completion stuff.
+* ***********************************************************************
+*/
+
 /**
  * This function is used by the address completion function to load
  * addresses for all non-external address book interfaces.
  *
- * \param addrIndex Address index object.
  * \param callBackFunc Function to be called when an address is
  *                     to be loaded.
  * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded.
  */
 gboolean addrindex_load_completion(
-               AddressIndex *addrIndex,
                gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) )
 {
        AddressDataSource *ds;
@@ -2886,9 +2765,7 @@ gboolean addrindex_load_completion(
        GList *nodeM;
        gchar *sName, *sAddress, *sAlias, *sFriendly;
 
-       if( addrIndex == NULL ) return FALSE;
-
-       nodeIf = addrindex_get_interface_list( addrIndex );
+       nodeIf = addrindex_get_interface_list( _addressIndex_ );
        while( nodeIf ) {
                AddressInterface *iface = nodeIf->data;
 
index ae227e90642e2a52544f401f024aa6a1959cb020..ef928d040f3ca03a218bd6c8846eec6795660d9e 100644 (file)
@@ -99,10 +99,11 @@ struct _AddressDataSource {
        gpointer rawDataSource;
 };
 
-void addrindex_initialize              ( AddressIndex *addrIndex );
-void addrindex_teardown                        ( AddressIndex *addrIndex );
+void addrindex_initialize              ( void );
+void addrindex_teardown                        ( void );
 
 AddressIndex *addrindex_create_index   ( void );
+AddressIndex *addrindex_get_object     ( void );
 void addrindex_set_file_path           ( AddressIndex *addrIndex,
                                          const gchar *value );
 void addrindex_set_file_name           ( AddressIndex *addrIndex,
@@ -157,18 +158,22 @@ GList *addrindex_ds_get_all_persons       ( AddressDataSource *ds );
 GList *addrindex_ds_get_all_groups     ( AddressDataSource *ds );
 
 /* Search support */
-gint addrindex_setup_search    ( AddressIndex *addrIndex,
-                                 const gchar *searchTerm,
-                                 const gpointer target,
-                                 AddrSearchCallbackFunc callBack );
-gboolean addrindex_start_search        ( AddressIndex *addrIndex,
-                                 const gint queryID );
-void addrindex_stop_search     ( AddressIndex *addrIndex,
-                                 const gint queryID );
-
-void addrindex_read_all                ( AddressIndex *addrIndex );
+gint addrindex_setup_search            ( const gchar *searchTerm,
+                                         void *callBackEnd,
+                                         void *callBackEntry );
+
+gint addrindex_setup_static_search     ( AddressDataSource *ds,
+                                         const gchar *searchTerm,
+                                         ItemFolder *folder,
+                                         void *callBackEnd,
+                                         void *callBackEntry );
+
+gboolean addrindex_start_search                ( const gint queryID );
+void addrindex_stop_search             ( const gint queryID );
+void addrindex_remove_results          ( AddressDataSource *ds,
+                                         ItemFolder *folder );
+
 gboolean addrindex_load_completion(
-               AddressIndex *addrIndex,
                gint (*callBackFunc)
                        ( const gchar *, const gchar *, const gchar * ) );
 
index e2a24a671e0e054d8504a162f024d4677d4e8afa..6c2fbab2dd877f5d571acc974eed89a823ce40a0 100644 (file)
@@ -50,7 +50,7 @@ typedef enum {
        ADDRFOLDER_ROOT,
        ADDRFOLDER_REGULAR,
        ADDRFOLDER_CATEGORY,
-       ADDRFOLDER_LDAP_QUERY
+       ADDRFOLDER_QUERY_RESULTS
 } AddressFolderType;
 
 typedef struct _AddrItemObject AddrItemObject;
index 049e8e11412e74efa973093a25d0dba62143c565..410cb6a333bd9048d5c5acf045384ac3b4c56181 100644 (file)
 /**
  * Query list for tracking current queries.
  */
-static GList *_queryList_ = NULL;
+static GList *_requestList_ = NULL;
 
 /**
  * Mutex to protect list from multiple threads.
  */
-static pthread_mutex_t _queryListMutex_ = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _requestListMutex_ = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Current query ID. This is incremented for each query request created.
+ */
+static gint _currentQueryID_ = 0;
 
 /**
  * Create new address query.
  * \return Initialized address query object.
  */
-AddrQuery *addrqry_create( void ) {
-       AddrQuery *qry;
-
-       qry = g_new0( AddrQuery, 1 );
-       qry->queryType = ADDRQUERY_NONE;
-       qry->queryID = 0;
-       qry->idleID = 0;
-       qry->searchTerm = NULL;
-       qry->callBack = NULL;
-       qry->target = NULL;
-       qry->serverObject = NULL;
-       qry->queryObject = NULL;
-       return qry;
+QueryRequest *reqreq_create( void ) {
+       QueryRequest *req;
+
+       req = g_new0( QueryRequest, 1 );
+       req->queryID = 0;
+       req->searchType = ADDRSEARCH_NONE;
+       req->searchTerm = NULL;
+       req->callBackEnd = NULL;
+       req->callBackEntry = NULL;
+       req->queryList = NULL;
+       return req;
 }
 
 /**
  * Clear the query.
- * \param qry Address query object.
+ * \param req Request query object.
  */
-void addrqry_clear( AddrQuery *qry ) {
-       g_return_if_fail( qry != NULL );
-       g_free( qry->searchTerm );
-       qry->queryType = ADDRQUERY_NONE;
-       qry->queryID = 0;
-       qry->idleID = 0;
-       qry->searchTerm = NULL;
-       qry->callBack = NULL;
-       qry->target = NULL;
-       qry->serverObject = NULL;
-       qry->queryObject = NULL;
+void qryreq_clear( QueryRequest *req ) {
+       GList *node;
+
+       g_return_if_fail( req != NULL );
+       g_free( req->searchTerm );
+       req->queryID = 0;
+       req->searchType = ADDRSEARCH_NONE;
+       req->searchTerm = NULL;
+       req->callBackEnd = NULL;
+       req->callBackEntry = NULL;
+
+       /* Empty the list */
+       node = req->queryList;
+       while( node ) {
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( req->queryList );
+       req->queryList = NULL;
 }
 
 /**
  * Free query.
- * \param qry Address query object.
+ * \param req Request query object.
  */
-void addrqry_free( AddrQuery *qry ) {
-       g_return_if_fail( qry != NULL );
-       addrqry_clear( qry );
-       g_free( qry );
+void qryreq_free( QueryRequest *req ) {
+       g_return_if_fail( req != NULL );
+       qryreq_clear( req );
+       g_free( req );
 }
 
 /**
- * Specify query type.
- * \param qry   Address query object.
+ * Specify search type.
+ * \param req   Request query object.
  * \param value Type.
  */
-void addrqry_set_query_type( AddrQuery *qry, const AddrQueryType value ) {
-       g_return_if_fail( qry != NULL );
-       qry->queryType = value;
-}
-
-/**
- * Specify idle ID.
- * \param qry   Address query object.
- * \param value Idle ID.
- */
-void addrqry_set_idle_id( AddrQuery *qry, const guint value ) {
-       g_return_if_fail( qry != NULL );
-       qry->idleID = value;
+void qryreq_set_search_type( QueryRequest *req, const AddrSearchType value ) {
+       g_return_if_fail( req != NULL );
+       req->searchType = value;
 }
 
 /**
  * Specify search term to be used.
- * \param qry   Address query object.
+ * \param req   Request query object.
  * \param value Search term.
  */
-void addrqry_set_search_term( AddrQuery* qry, const gchar *value ) {
-       qry->searchTerm = mgu_replace_string( qry->searchTerm, value );
-       g_return_if_fail( qry != NULL );
-       g_strstrip( qry->searchTerm );
-}
-
-/**
- * Specify server object to be used.
- * \param qry   Address query object.
- * \param value Server object that performs the search.
- */
-void addrqry_set_server( AddrQuery* qry, const gpointer value ) {
-       g_return_if_fail( qry != NULL );
-       qry->serverObject = value;
+void qryreq_set_search_term( QueryRequest *req, const gchar *value ) {
+       req->searchTerm = mgu_replace_string( req->searchTerm, value );
+       g_return_if_fail( req != NULL );
+       g_strstrip( req->searchTerm );
 }
 
 /**
- * Specify query object to be used.
- * \param qry   Address query object.
- * \param value Query object that performs the search.
+ * Add address query object to request.
+ * \param req  Request query object.
+ * \param aqo  Address query object that performs the search.
  */
-void addrqry_set_query( AddrQuery* qry, const gpointer value ) {
-       g_return_if_fail( qry != NULL );
-       qry->queryObject = value;
+void qryreq_add_query( QueryRequest *req, AddrQueryObject *aqo ) {
+       g_return_if_fail( req != NULL );
+       g_return_if_fail( aqo != NULL );
+       req->queryList = g_list_append( req->queryList, aqo );
 }
 
 /**
  * Display object to specified stream.
- * \param qry    Address query object.
+ * \param req    Request query object.
  * \param stream Output stream.
  */
-void addrqry_print( const AddrQuery *qry, FILE *stream ) {
-       g_return_if_fail( qry != NULL );
+void qryreq_print( const QueryRequest *req, FILE *stream ) {
+       GList *node;
+       g_return_if_fail( req != NULL );
 
-       fprintf( stream, "AddressQuery:\n" );
-       fprintf( stream, "     queryID: %d\n",   qry->queryID );
-       fprintf( stream, "      idleID: %d\n",   qry->idleID );
-       fprintf( stream, "  searchTerm: '%s'\n", qry->searchTerm );
+       fprintf( stream, "QueryRequest:\n" );
+       fprintf( stream, "     queryID: %d\n",   req->queryID );
+       fprintf( stream, "  searchType: %d\n",   req->searchType );
+       fprintf( stream, "  searchTerm: '%s'\n", req->searchTerm );
+       node = req->queryList;
+       while( node ) {
+               AddrQueryObject *aqo = node->data;
+               fprintf( stream, "    --- type: %d\n", aqo->queryType );
+               node = g_list_next( node );
+       }
 }
 
 /**
  * Add query to list.
- * \param queryID    ID of query being executed.
- * \param searchTerm Search term. A private copy will be made.
- * \param callBack   Callback function.
- * \param target     Target object to receive data.
+ *
+ * \param searchTerm    Search term. A private copy will be made.
+ * \param callBackEnd   Callback function that will be called when query
+ *                     terminates.
+ * \param callBackEntry Callback function that will be called after each
+ *                     address entry has been read.
+ * \return Initialize query request object.                    
  */
-AddrQuery *qrymgr_add_query(
-       const gint queryID, const gchar *searchTerm, void *callBack,
-       gpointer target )
+QueryRequest *qrymgr_add_request(
+       const gchar *searchTerm, void *callBackEnd, void *callBackEntry )
 {
-       AddrQuery *qry;
-
-       qry = g_new0( AddrQuery, 1 );
-       qry->queryType = ADDRQUERY_NONE;
-       qry->queryID = queryID;
-       qry->idleID = 0;
-       qry->searchTerm = g_strdup( searchTerm );
-       qry->callBack = callBack;
-       qry->target = NULL;
-       qry->timeStart = time( NULL );
-       qry->serverObject = NULL;
-       qry->queryObject = NULL;
+       QueryRequest *req;
+
+       req = g_new0( QueryRequest, 1 );
+       req->searchTerm = g_strdup( searchTerm );
+       req->callBackEnd = callBackEnd;
+       req->callBackEntry = callBackEntry;
+       req->timeStart = time( NULL );
+       req->queryList = NULL;
 
        /* Insert in head of list */
-       pthread_mutex_lock( & _queryListMutex_ );
-       _queryList_ = g_list_prepend( _queryList_, qry );
-       pthread_mutex_unlock( & _queryListMutex_ );
+       pthread_mutex_lock( & _requestListMutex_ );
+       req->queryID = ++_currentQueryID_;
+       _requestList_ = g_list_prepend( _requestList_, req );
+       pthread_mutex_unlock( & _requestListMutex_ );
 
-       return qry;
+       return req;
 }
 
 /**
@@ -187,45 +185,45 @@ AddrQuery *qrymgr_add_query(
  * \param  queryID ID of query to find.
  * \return Query object, or <i>NULL</i> if not found.
  */
-AddrQuery *qrymgr_find_query( const gint queryID ) {
-       AddrQuery *qry;
-       AddrQuery *q;
+QueryRequest *qrymgr_find_request( const gint queryID ) {
+       QueryRequest *req;
+       QueryRequest *q;
        GList *node;
 
-       pthread_mutex_lock( & _queryListMutex_ );
-       qry = NULL;
-       node = _queryList_;
+       pthread_mutex_lock( & _requestListMutex_ );
+       req = NULL;
+       node = _requestList_;
        while( node ) {
                q = node->data;
                if( q->queryID == queryID ) {
-                       qry = q;
+                       req = q;
                        break;
                }
                node = g_list_next( node );
        }
-       pthread_mutex_unlock( & _queryListMutex_ );
+       pthread_mutex_unlock( & _requestListMutex_ );
 
-       return qry;
+       return req;
 }
 
 /**
  * Delete specified query.
  * \param  queryID ID of query to retire.
  */
-void qrymgr_delete_query( const gint queryID ) {
-       AddrQuery *qry;
+void qrymgr_delete_request( const gint queryID ) {
+       QueryRequest *req;
        GList *node, *nf;
 
-       pthread_mutex_lock( & _queryListMutex_ );
+       pthread_mutex_lock( & _requestListMutex_ );
 
        /* Find node */
        nf = NULL;
-       node = _queryList_;
+       node = _requestList_;
        while( node ) {
-               qry = node->data;
-               if( qry->queryID == queryID ) {
+               req = node->data;
+               if( req->queryID == queryID ) {
                        nf = node;
-                       addrqry_free( qry );
+                       qryreq_free( req );
                        break;
                }
                node = g_list_next( node );
@@ -233,45 +231,45 @@ void qrymgr_delete_query( const gint queryID ) {
 
        /* Free link element and associated query */
        if( nf ) {
-               _queryList_ = g_list_remove_link( _queryList_, nf );
+               _requestList_ = g_list_remove_link( _requestList_, nf );
                g_list_free_1( nf );
        }
 
-       pthread_mutex_unlock( & _queryListMutex_ );
+       pthread_mutex_unlock( & _requestListMutex_ );
 }
 
 /**
  * Initialize query manager.
  */
 void qrymgr_initialize( void ) {
-       _queryList_ = NULL;
+       _requestList_ = NULL;
 }
 
 /**
  * Free all queries.
  */
-static void qrymgr_free_all_query( void ) {
-       AddrQuery *qry;
+static void qrymgr_free_all_request( void ) {
+       QueryRequest *req;
        GList *node;
 
-       pthread_mutex_lock( & _queryListMutex_ );
-       node = _queryList_;
+       pthread_mutex_lock( & _requestListMutex_ );
+       node = _requestList_;
        while( node ) {
-               qry = node->data;
-               addrqry_free( qry );
+               req = node->data;
+               qryreq_free( req );
                node->data = NULL;
                node = g_list_next( node );
        }
-       g_list_free( _queryList_ );
-       _queryList_ = NULL;
-       pthread_mutex_unlock( & _queryListMutex_ );
+       g_list_free( _requestList_ );
+       _requestList_ = NULL;
+       pthread_mutex_unlock( & _requestListMutex_ );
 }
 
 /**
  * Teardown query manager.
  */
 void qrymgr_teardown( void ) {
-       qrymgr_free_all_query();
+       qrymgr_free_all_request();
 }
 
 /**
@@ -279,19 +277,19 @@ void qrymgr_teardown( void ) {
  * \param stream Output stream.
  */
 void qrymgr_print( FILE *stream ) {
-       AddrQuery *qry;
+       QueryRequest *req;
        GList *node;
 
-       pthread_mutex_lock( & _queryListMutex_ );
+       pthread_mutex_lock( & _requestListMutex_ );
        fprintf( stream, "=== Query Manager ===\n" );
-       node = _queryList_;
+       node = _requestList_;
        while( node ) {
-               qry = node->data;
-               addrqry_print( qry, stream );
+               req = node->data;
+               qryreq_print( req, stream );
                fprintf( stream, "---\n" );
                node = g_list_next( node );
        }
-       pthread_mutex_unlock( & _queryListMutex_ );
+       pthread_mutex_unlock( & _requestListMutex_ );
 }
 
 /*
index 5e288d609b14ddfa13cb37d9d750765e97cef107..217367dc79b49b44e046d37208fb1c396b62ea83 100644 (file)
 #include <glib.h>
 #include <stdio.h>
 #include <sys/time.h>
+#include "addritem.h"
 
 /* Query types */
-typedef enum {
-       ADDRQUERY_NONE,
-       ADDRQUERY_LDAP
-} AddrQueryType;
-
-/* Address search call back function */
-typedef gint ( AddrSearchCallbackFunc ) ( gint cacheID,
-                                         GList *listEMail,
-                                         gpointer target );
+#define ADDRQUERY_NONE  0
+#define ADDRQUERY_LDAP  1
 
-typedef void ( AddrSearchStaticFunc ) ( gint qid, AddrQueryType qty, gint status );
+/* Search type */
+typedef enum {
+       ADDRSEARCH_NONE,
+       ADDRSEARCH_DYNAMIC,
+       ADDRSEARCH_EXPLICIT,
+       ADDRSEARCH_LOCATE
+} AddrSearchType;
 
 /* Data structures */
 typedef struct {
-       AddrQueryType queryType;
-       gint     queryID;
-       gint     idleID;
-       gchar    *searchTerm;
-       time_t   timeStart;
-       AddrSearchStaticFunc *callBack;
-       gpointer target;
-       gpointer serverObject;
-       gpointer queryObject;
+       gint           queryID;
+       AddrSearchType searchType;
+       gchar          *searchTerm;
+       time_t         timeStart;
+       void           ( *callBackEnd ) ( void * );
+       void           ( *callBackEntry ) ( void * );
+       GList          *queryList;
 }
-AddrQuery;
+QueryRequest;
+
+/* Some macros */
+#define ADDRQUERY_OBJECT(obj)          ((AddrQueryObject *)obj)
+#define ADDRQUERY_TYPE(obj)            (ADDRQUERY_OBJECT(obj)->queryType)
+#define ADDRQUERY_ID(obj)              (ADDRQUERY_OBJECT(obj)->queryID)
+#define ADDRQUERY_SEARCHTYPE(obj)      (ADDRQUERY_OBJECT(obj)->searchType)
+#define ADDRQUERY_NAME(obj)            (ADDRQUERY_OBJECT(obj)->queryName)
+#define ADDRQUERY_RETVAL(obj)          (ADDRQUERY_OBJECT(obj)->retVal)
+#define ADDRQUERY_FOLDER(obj)          (ADDRQUERY_OBJECT(obj)->folder)
+#define ADDRQUERY_SEARCHVALUE(obj)     (ADDRQUERY_OBJECT(obj)->searchValue)
+
+/* Generic address query (base class) */
+typedef struct _AddrQueryObject AddrQueryObject;
+struct _AddrQueryObject {
+       gint           queryType;
+       gint           queryID;
+       AddrSearchType searchType;
+       gchar          *queryName;
+       gint           retVal;
+       ItemFolder     *folder;         /* Reference to folder in cache */
+       gchar          *searchValue;
+};
+
+/* Address search call back functions */
+typedef gint ( AddrSearchCallbackEntry ) ( gpointer sender,
+                                          gint queryID,
+                                          GList *listEMail,
+                                          gpointer data );
+
+typedef void ( AddrSearchCallbackEnd ) ( gpointer sender,
+                                        gint queryID,
+                                        gint status,
+                                        gpointer data );
 
 /* Function prototypes */
-AddrQuery *addrqry_create      ( void );
-void addrqry_clear             ( AddrQuery *qry );
-void addrqry_free              ( AddrQuery *qry );
-void addrqry_set_query_type    ( AddrQuery *qry, const AddrQueryType value );
-void addrqry_set_idle_id       ( AddrQuery *qry, const guint value );
-void addrqry_set_search_term   ( AddrQuery* qry, const gchar *value );
-void addrqry_set_server                ( AddrQuery* qry, const gpointer server );
-void addrqry_set_query         ( AddrQuery* qry, const gpointer query );
-void addrqry_print             ( const AddrQuery *qry, FILE *stream );
+QueryRequest *qryreq_create    ( void );
+void qryreq_clear              ( QueryRequest *req );
+void qryreq_free               ( QueryRequest *req );
+void qryreq_set_search_type    ( QueryRequest *req, const AddrSearchType value );
+void qryreq_set_search_term    ( QueryRequest *req, const gchar *value );
+void qryreq_add_query          ( QueryRequest *req, AddrQueryObject *aqo );
+void qryreq_print              ( const QueryRequest *req, FILE *stream );
 
 void qrymgr_initialize         ( void );
 void qrymgr_teardown           ( void );
-AddrQuery *qrymgr_add_query(
-               const gint queryID, const gchar *searchTerm,
-               void *callBack, gpointer target );
+QueryRequest *qrymgr_add_request( const gchar *searchTerm,
+                                 void *callBackEnd,
+                                 void *callBackEntry );
 
-AddrQuery *qrymgr_find_query   ( const gint queryID );
-void qrymgr_delete_query       ( const gint queryID );
+QueryRequest *qrymgr_find_request( const gint queryID );
+void qrymgr_delete_request     ( const gint queryID );
 void qrymgr_print              ( FILE *stream );
 
 #endif /* __ADDRQUERY_H__ */
index 6ef4bbacc32fa9cdabd86b0b57cbd3cee4bd545e..a04b77934b2afe58963685ecba96ac263a27bc90 100644 (file)
@@ -30,7 +30,6 @@
 #include <glib.h>
 #include <sys/time.h>
 #include <string.h>
-#include <ldap.h>
 #include <lber.h>
 
 #include "ldapquery.h"
@@ -40,6 +39,8 @@
 #include "addritem.h"
 #include "addrcache.h"
 
+#include "ldapquery.h"
+
 /*
  * Key for thread specific data.
  */
@@ -54,12 +55,15 @@ LdapQuery *ldapqry_create( void ) {
        LdapQuery *qry;
 
        qry = g_new0( LdapQuery, 1 );
+       ADDRQUERY_TYPE(qry) = ADDRQUERY_LDAP;
+       ADDRQUERY_ID(qry) = 0;
+       ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
+       ADDRQUERY_NAME(qry) = NULL;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
+       ADDRQUERY_FOLDER(qry) = NULL;
+       ADDRQUERY_SEARCHVALUE(qry) = NULL;
        qry->control = NULL;
-       qry->retVal = LDAPRC_SUCCESS;
-       qry->queryType = LDAPQUERY_NONE;
-       qry->queryName = NULL;
-       qry->searchValue = NULL;
-       qry->queryID = 0;
+       qry->server = NULL;
        qry->entriesRead = 0;
        qry->elapsedTime = 0;
        qry->stopFlag = FALSE;
@@ -67,11 +71,10 @@ LdapQuery *ldapqry_create( void ) {
        qry->agedFlag = FALSE;
        qry->completed = FALSE;
        qry->thread = NULL;
-       qry->callBackStart = NULL;
        qry->callBackEntry = NULL;
        qry->callBackEnd = NULL;
-       qry->folder = NULL;
-       qry->server = NULL;
+       qry->ldap = NULL;
+       qry->data = NULL;
 
        /* Mutex to protect stop and busy flags */
        qry->mutexStop = g_malloc0( sizeof( pthread_mutex_t ) );
@@ -103,8 +106,8 @@ void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
  * \param value Name.
  */
 void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
-       qry->queryName = mgu_replace_string( qry->queryName, value );
-       g_strstrip( qry->queryName );
+       ADDRQUERY_NAME(qry) = mgu_replace_string( ADDRQUERY_NAME(qry), value );
+       g_strstrip( ADDRQUERY_NAME(qry) );
 }
 
 /**
@@ -113,8 +116,8 @@ void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
  * \param value 
  */
 void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
-       qry->searchValue = mgu_replace_string( qry->searchValue, value );
-       g_strstrip( qry->searchValue );
+       ADDRQUERY_SEARCHVALUE(qry) = mgu_replace_string( ADDRQUERY_SEARCHVALUE(qry), value );
+       g_strstrip( ADDRQUERY_SEARCHVALUE(qry) );
 }
 
 /**
@@ -123,7 +126,7 @@ void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
  * \param value Status.
  */
 void ldapqry_set_error_status( LdapQuery* qry, const gint value ) {
-       qry->retVal = value;
+       ADDRQUERY_RETVAL(qry) = value;
 }
 
 /**
@@ -136,8 +139,20 @@ void ldapqry_set_error_status( LdapQuery* qry, const gint value ) {
  * <li><code>LDAPQUERY_DYNAMIC</code></li>
  * </ul>
  */
+/*
 void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
-       qry->queryType = value;
+       ADDRQUERY_TYPE(qry) = value;
+}
+*/
+
+/**
+ * Specify search type.
+ * \param qry   Query object.
+ * \param value Type.
+ */
+void ldapqry_set_search_type( LdapQuery *qry, const AddrSearchType value ) {
+       g_return_if_fail( qry != NULL );
+       ADDRQUERY_SEARCHTYPE(qry) = value;
 }
 
 /**
@@ -146,7 +161,7 @@ void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
  * \param value ID for the query.
  */
 void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
-       qry->queryID = value;
+       ADDRQUERY_ID(qry) = value;
 }
 
 /**
@@ -163,17 +178,6 @@ void ldapqry_set_entries_read( LdapQuery* qry, const gint value ) {
        }
 }
 
-/**
- * Register a callback function that will be executed when the search
- * starts. When called, the function will be passed this query object
- * as an argument.
- * \param qry Query object.
- * \param func Function.
- */
-void ldapqry_set_callback_start( LdapQuery *qry, void *func ) {
-       qry->callBackStart = func;
-}
-
 /**
  * Register a callback function that will be executed when each entry
  * has been read and processed. When called, the function will be passed
@@ -299,6 +303,26 @@ gboolean ldapqry_get_aged_flag( LdapQuery *qry ) {
        return qry->agedFlag;
 }
 
+/**
+ * Specify user data for query.
+ * \param qry Query object.
+ * \param value Data to set.
+ */
+void ldapqry_set_data( LdapQuery *qry, const gpointer value ) {
+       g_return_if_fail( qry != NULL );
+       qry->data = value;
+}
+
+/**
+ * Retrieve user data associated with query.
+ * \param qry Query object.
+ * \return Data.
+ */
+gpointer ldapqry_get_data( LdapQuery *qry ) {
+       g_return_if_fail( qry != NULL );
+       return qry->data;
+}
+
 /**
  * Release the LDAP control data associated with the query.
  * \param qry Query object to process.
@@ -319,24 +343,25 @@ void ldapqry_clear( LdapQuery *qry ) {
        g_return_if_fail( qry != NULL );
 
        /* Free internal stuff */
-       g_free( qry->queryName );
-       g_free( qry->searchValue );
+       g_free( ADDRQUERY_NAME(qry) );
+       g_free( ADDRQUERY_SEARCHVALUE(qry) );
 
        /* Clear pointers and value */
-       qry->queryName = NULL;
-       qry->searchValue = NULL;
-       qry->retVal = LDAPRC_SUCCESS;
-       qry->queryType = LDAPQUERY_NONE;
-       qry->queryID = 0;
+       ADDRQUERY_NAME(qry) = NULL;
+       ADDRQUERY_SEARCHVALUE(qry) = NULL;
+       ADDRQUERY_ID(qry) = 0;
+       ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
        qry->entriesRead = 0;
        qry->elapsedTime = 0;
        qry->stopFlag = FALSE;
        qry->busyFlag = FALSE;
        qry->agedFlag = FALSE;
        qry->completed = FALSE;
-       qry->callBackStart = NULL;
        qry->callBackEntry = NULL;
        qry->callBackEnd = NULL;
+       qry->ldap = NULL;
+       qry->data = NULL;
 }
 
 /**
@@ -348,6 +373,7 @@ void ldapqry_free( LdapQuery *qry ) {
        g_return_if_fail( qry != NULL );
 
        /* Clear out internal members */
+       ADDRQUERY_TYPE(qry) = ADDRQUERY_NONE;
        ldapqry_clear( qry );
 
        /* Free the mutex */
@@ -362,7 +388,7 @@ void ldapqry_free( LdapQuery *qry ) {
        qry->mutexStop = NULL;
 
        /* Do not free folder - parent server object should free */     
-       qry->folder = NULL;
+       ADDRQUERY_FOLDER(qry) = NULL;
 
        /* Do not free thread - thread should be terminated before freeing */
        qry->thread = NULL;
@@ -384,11 +410,12 @@ void ldapqry_print( const LdapQuery *qry, FILE *stream ) {
 
        fprintf( stream, "LdapQuery:\n" );
        fprintf( stream, "  control?: %s\n",   qry->control ? "yes" : "no" );
-       fprintf( stream, "err/status: %d\n",   qry->retVal );
-       fprintf( stream, "query type: %d\n",   qry->queryType );
-       fprintf( stream, "query name: '%s'\n", qry->queryName );
-       fprintf( stream, "search val: '%s'\n", qry->searchValue );
-       fprintf( stream, "   queryID: %d\n",   qry->queryID );
+       fprintf( stream, "err/status: %d\n",   ADDRQUERY_RETVAL(qry) );
+       fprintf( stream, "query type: %d\n",   ADDRQUERY_TYPE(qry) );
+       fprintf( stream, "searchType: %d\n",   ADDRQUERY_SEARCHTYPE(qry) );
+       fprintf( stream, "query name: '%s'\n", ADDRQUERY_NAME(qry) );
+       fprintf( stream, "search val: '%s'\n", ADDRQUERY_SEARCHVALUE(qry) );
+       fprintf( stream, "   queryID: %d\n",   ADDRQUERY_ID(qry) );
        fprintf( stream, "   entries: %d\n",   qry->entriesRead );
        fprintf( stream, "   elapsed: %d\n",   qry->elapsedTime );
        fprintf( stream, " stop flag: %s\n",   qry->stopFlag  ? "yes" : "no" );
@@ -529,16 +556,16 @@ static GList *ldapqry_build_items_fl(
        }
 
        /* Create new folder for results */
-       if( qry->folder == NULL ) {
+       if( ADDRQUERY_FOLDER(qry) == NULL ) {
                folder = addritem_create_item_folder();
-               addritem_folder_set_name( folder, qry->queryName );
+               addritem_folder_set_name( folder, ADDRQUERY_NAME(qry) );
                addritem_folder_set_remarks( folder, "" );
                addrcache_id_folder( cache, folder );
                addrcache_add_folder( cache, folder );
-               qry->folder = folder;
+               ADDRQUERY_FOLDER(qry) = folder;
 
                /* Specify folder type and back reference */                    
-               folder->folderType = ADDRFOLDER_LDAP_QUERY;
+               folder->folderType = ADDRFOLDER_QUERY_RESULTS;
                folder->folderData = ( gpointer ) qry;
                folder->isHidden = TRUE;
        }
@@ -550,7 +577,7 @@ static GList *ldapqry_build_items_fl(
        addritem_person_set_last_name( person, lastName );
        addrcache_id_person( cache, person );
        addritem_person_set_external_id( person, dn );
-       addrcache_folder_add_person( cache, qry->folder, person );
+       addrcache_folder_add_person( cache, ADDRQUERY_FOLDER(qry), person );
 
        qry->entriesRead++;
 
@@ -644,7 +671,7 @@ static GList *ldapqry_process_single_entry(
  */
 gboolean ldapqry_check_search( LdapQuery *qry ) {
        LdapControl *ctl;
-       qry->retVal = LDAPRC_CRITERIA;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_CRITERIA;
 
        /* Test for control data */
        ctl = qry->control;
@@ -653,14 +680,13 @@ gboolean ldapqry_check_search( LdapQuery *qry ) {
        }
 
        /* Test for search value */
-       if( qry->searchValue == NULL ) {
+       if( ADDRQUERY_SEARCHVALUE(qry) == NULL ) {
                return FALSE;
        }
-       if( strlen( qry->searchValue ) < 1 ) {
+       if( strlen( ADDRQUERY_SEARCHVALUE(qry) ) < 1 ) {
                return FALSE;
        }
-
-       qry->retVal = LDAPRC_SUCCESS;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
        return TRUE;
 }
 
@@ -674,54 +700,28 @@ void ldapqry_touch( LdapQuery *qry ) {
 }
 
 /**
- * Perform the LDAP search, reading LDAP entries into cache.
- * Note that one LDAP entry can have multiple values for many of its
- * attributes. If these attributes are E-Mail addresses; these are
- * broken out into separate address items. For any other attribute,
- * only the first occurrence is read.
- * 
+ * Connect to LDAP server.
  * \param  qry Query object to process.
  * \return Error/status code.
  */
-static gint ldapqry_perform_search( LdapQuery *qry ) {
+static gint ldapqry_connect( LdapQuery *qry ) {
        LdapControl *ctl;
        LDAP *ld;
-       LDAPMessage *result, *e;
-       char **attribs;
-       gchar *criteria;
-       gboolean entriesFound;
-       gboolean first;
-       struct timeval timeout;
        gint rc;
-       time_t tstart, tend;
-       AddressCache *cache;
-       GList *listEMail;
-
-       /* Initialize some variables */
-       ctl = qry->control;
-       cache = qry->server->addressCache;
-       timeout.tv_sec = ctl->timeOut;
-       timeout.tv_usec = 0L;
-       entriesFound = FALSE;
-       qry->elapsedTime = -1;
-       qry->retVal = LDAPRC_SUCCESS;
-
-       /* Check search criteria */     
-       if( ! ldapqry_check_search( qry ) ) {
-               return qry->retVal;
-       }
 
        /* Initialize connection */
+       ctl = qry->control;
        ldapqry_touch( qry );
-       tstart = qry->touchTime;
-       tend = tstart - 1;
+       qry->startTime = qry->touchTime;
+       qry->elapsedTime = -1;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_INIT;
        if( ( ld = ldap_init( ctl->hostName, ctl->port ) ) == NULL ) {
-               qry->retVal = LDAPRC_INIT;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
+       qry->ldap = ld;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
        if( ldapqry_get_stop_flag( qry ) ) {
-               qry->retVal = LDAPRC_SUCCESS;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
        ldapqry_touch( qry );
 
@@ -730,6 +730,7 @@ static gint ldapqry_perform_search( LdapQuery *qry ) {
        */
 
        /* Bind to the server, if required */
+       ADDRQUERY_RETVAL(qry) = LDAPRC_BIND;
        if( ctl->bindDN ) {
                if( * ctl->bindDN != '\0' ) {
                        /* printf( "binding...\n" ); */
@@ -740,51 +741,99 @@ static gint ldapqry_perform_search( LdapQuery *qry ) {
                                printf( "LDAP Error: ldap_simple_bind_s: %s\n",
                                        ldap_err2string( rc ) );
                                */
-                               ldap_unbind( ld );
-                               qry->retVal = LDAPRC_BIND;
-                               return qry->retVal;
+                               return ADDRQUERY_RETVAL(qry);
                        }
                }
        }
+       ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
        if( ldapqry_get_stop_flag( qry ) ) {
-               ldap_unbind( ld );
-               qry->retVal = LDAPRC_SUCCESS;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
        ldapqry_touch( qry );
 
+       ADDRQUERY_RETVAL(qry) = LDAP_SUCCESS;
+
+       return ADDRQUERY_RETVAL(qry);
+}
+
+/**
+ * Connect to LDAP server.
+ * \param  qry Query object to process.
+ * \return Error/status code.
+ */
+static gint ldapqry_disconnect( LdapQuery *qry ) {
+       /* Disconnect */
+       if( qry->ldap ) ldap_unbind( qry->ldap );
+       qry->ldap = NULL;
+
+       ldapqry_touch( qry );
+       qry->elapsedTime = qry->touchTime - qry->startTime;
+
+       return ADDRQUERY_RETVAL(qry);
+}
+
+/**
+ * Perform the LDAP search, reading LDAP entries into cache.
+ * Note that one LDAP entry can have multiple values for many of its
+ * attributes. If these attributes are E-Mail addresses; these are
+ * broken out into separate address items. For any other attribute,
+ * only the first occurrence is read.
+ * 
+ * \param  qry Query object to process.
+ * \return Error/status code.
+ */
+static gint ldapqry_search_retrieve( LdapQuery *qry ) {
+       LdapControl *ctl;
+       LDAP *ld;
+       LDAPMessage *result, *e;
+       char **attribs;
+       gchar *criteria;
+       gboolean entriesFound;
+       gboolean first;
+       struct timeval timeout;
+       gint rc;
+       AddressCache *cache;
+       GList *listEMail;
+
+       /* Initialize some variables */
+       ld = qry->ldap;
+       ctl = qry->control;
+       cache = qry->server->addressCache;
+       timeout.tv_sec = ctl->timeOut;
+       timeout.tv_usec = 0L;
+       entriesFound = FALSE;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
+
        /* Define all attributes we are interested in. */
        attribs = ldapctl_attribute_array( ctl );
 
        /* Create LDAP search string */
-       criteria = ldapctl_format_criteria( ctl, qry->searchValue );
+       criteria = ldapctl_format_criteria( ctl, ADDRQUERY_SEARCHVALUE(qry) );
        /* printf( "Search criteria ::%s::\n", criteria ); */
 
        /*
         * Execute the search - this step may take some time to complete
         * depending on network traffic and server response time.
         */
+       ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
        rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
                attribs, 0, NULL, NULL, &timeout, 0, &result );
        ldapctl_free_attribute_array( attribs );
        g_free( criteria );
        criteria = NULL;
        if( rc == LDAP_TIMEOUT ) {
-               ldap_unbind( ld );
-               qry->retVal = LDAPRC_TIMEOUT;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
        if( rc != LDAP_SUCCESS ) {
                /*
                printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
                */
-               ldap_unbind( ld );
-               qry->retVal = LDAPRC_SEARCH;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
+       ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
        if( ldapqry_get_stop_flag( qry ) ) {
-               qry->retVal = LDAPRC_SUCCESS;
-               return qry->retVal;
+               return ADDRQUERY_RETVAL(qry);
        }
        ldapqry_touch( qry );
 
@@ -792,11 +841,6 @@ static gint ldapqry_perform_search( LdapQuery *qry ) {
        printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
        */
 
-       if( ldapqry_get_stop_flag( qry ) ) {
-               qry->retVal = LDAPRC_SUCCESS;
-               return qry->retVal;
-       }
-
        /* Process results */
        first = TRUE;
        while( TRUE ) {
@@ -828,7 +872,7 @@ static gint ldapqry_perform_search( LdapQuery *qry ) {
 
                /* Process callback */
                if( qry->callBackEntry ) {
-                       qry->callBackEntry( qry, listEMail );
+                       qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data );
                }
                else {
                        g_list_free( listEMail );
@@ -839,19 +883,40 @@ static gint ldapqry_perform_search( LdapQuery *qry ) {
 
        /* Free up and disconnect */
        ldap_msgfree( result );
-       ldap_unbind( ld );
-       ldapqry_touch( qry );
-       tend = qry->touchTime;
-       qry->elapsedTime = tend - tstart;
 
        if( entriesFound ) {
-               qry->retVal = LDAPRC_SUCCESS;
+               ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
        }
        else {
-               qry->retVal = LDAPRC_NOENTRIES;
+               ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
        }
 
-       return qry->retVal;
+       return ADDRQUERY_RETVAL(qry);
+}
+
+/**
+ * Connection, perform search and disconnect.
+ * \param  qry Query object to process.
+ * \return Error/status code.
+ */
+static gint ldapqry_perform_search( LdapQuery *qry ) {
+       /* Check search criteria */     
+       if( ! ldapqry_check_search( qry ) ) {
+               return ADDRQUERY_RETVAL(qry);
+       }
+
+       /* Connect */
+       qry->ldap = NULL;
+       ldapqry_connect( qry );
+       if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
+               /* Perform search */
+               ldapqry_search_retrieve( qry );
+       }
+       /* Disconnect */
+       ldapqry_disconnect( qry );
+       qry->ldap = NULL;
+
+       return ADDRQUERY_RETVAL(qry);
 }
 
 /**
@@ -868,11 +933,6 @@ gint ldapqry_search( LdapQuery *qry ) {
        ldapqry_touch( qry );
        qry->completed = FALSE;
 
-       /* Process callback */  
-       if( qry->callBackStart ) {
-               qry->callBackStart( qry );
-       }
-
        /* Setup pointer to thread specific area */
        pthread_setspecific( _queryThreadKey_, qry );
 
@@ -880,10 +940,15 @@ gint ldapqry_search( LdapQuery *qry ) {
        
        /* Now perform the search */
        qry->entriesRead = 0;
-       qry->retVal = LDAPRC_SUCCESS;
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
        ldapqry_set_busy_flag( qry, TRUE );
        ldapqry_set_stop_flag( qry, FALSE );
-       retVal = ldapqry_perform_search( qry );
+       if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) {
+               retVal = ldapqry_perform_locate( qry );
+       }
+       else {
+               retVal = ldapqry_perform_search( qry );
+       }
        if( retVal == LDAPRC_SUCCESS ) {
                qry->server->addressCache->dataRead = TRUE;
                qry->server->addressCache->accessFlag = FALSE;
@@ -905,10 +970,10 @@ gint ldapqry_search( LdapQuery *qry ) {
 
        /* Process callback */  
        if( qry->callBackEnd ) {
-               qry->callBackEnd( qry );
+               qry->callBackEnd( qry, ADDRQUERY_ID(qry), ADDRQUERY_RETVAL(qry), qry->data );
        }
 
-       return qry->retVal;
+       return ADDRQUERY_RETVAL(qry);
 }
 
 /**
@@ -924,7 +989,7 @@ gint ldapqry_read_data_th( LdapQuery *qry ) {
        ldapqry_set_stop_flag( qry, FALSE );
        ldapqry_touch( qry );
        if( ldapqry_check_search( qry ) ) {
-               if( qry->retVal == LDAPRC_SUCCESS ) {
+               if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
                        /*
                        printf( "Starting LDAP search thread\n");
                        */
@@ -936,21 +1001,7 @@ gint ldapqry_read_data_th( LdapQuery *qry ) {
                                (void *) ldapqry_search, (void *) qry );
                }
        }
-       return qry->retVal;
-}
-
-/**
- * Join the thread associated with the query. This should probably be removed
- * to prevent joining threads.
- * \param qry Query object to process.
- */
-void ldapqry_join_threadX( LdapQuery *qry ) {
-       g_return_if_fail( qry != NULL );
-
-       /* Wait for thread */
-       /* printf( "ldapqry_join_thread::Joining thread...\n" ); */
-       pthread_join( * qry->thread, NULL );
-       /* printf( "ldapqry_join_thread::Thread terminated\n" ); */
+       return ADDRQUERY_RETVAL(qry);
 }
 
 /**
@@ -963,7 +1014,7 @@ static void ldapqry_destroyer( void * ptr ) {
 
        qry = ( LdapQuery * ) ptr;
        /*
-       printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), qry->queryName );
+       printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), ADDRQUERY_NAME(qry) );
        */
 
        /* Perform any destruction here */
@@ -986,7 +1037,7 @@ void ldapqry_cancel( LdapQuery *qry ) {
        g_return_if_fail( qry != NULL );
 
        /*
-       printf( "cancelling::%d::%s\n", (int) pthread_self(), qry->queryName );
+       printf( "cancelling::%d::%s\n", (int) pthread_self(), ADDRQUERY_NAME(qry) );
        */
        if( ldapqry_get_busy_flag( qry ) ) {
                if( qry->thread ) {
@@ -1041,14 +1092,276 @@ void ldapqry_delete_folder( LdapQuery *qry ) {
 
        g_return_if_fail( qry != NULL );
 
-       folder = qry->folder;
+       folder = ADDRQUERY_FOLDER(qry);
        if( folder ) {
                cache = qry->server->addressCache;
                folder = addrcache_remove_folder_delete( cache, folder );
                if( folder ) {
                        addritem_free_item_folder( folder );
                }
-               qry->folder = NULL;
+               ADDRQUERY_FOLDER(qry) = NULL;
+       }
+}
+
+/**
+ * Create a name/value pair object.
+ * \param n Name.
+ * \param v Value.
+ * \return Initialized object.
+ */
+static NameValuePair *ldapqry_create_name_value( const gchar *n, const gchar *v ) {
+       NameValuePair *nvp = g_new0( NameValuePair, 1 );
+
+       nvp->name = g_strdup( n );
+       nvp->value = g_strdup( v );
+       return nvp;
+}
+
+/**
+ * Free up name/value pair object.
+ * \param nvp Name/value object.
+ */
+void ldapqry_free_name_value( NameValuePair *nvp ) {
+       if( nvp ) {
+               g_free( nvp->name );
+               g_free( nvp->value );
+               nvp->name = nvp->value = NULL;
+               g_free( nvp );
+       }
+}
+
+/**
+ * Print name/value pair object for debug.
+ * \param nvp    Name/value object.
+ * \param stream Output stream.
+ */
+void ldapqry_print_name_value( NameValuePair *nvp, FILE *stream ) {
+       if( nvp ) {
+               fprintf( stream, "n/v ::%s::%s::\n", nvp->name, nvp->value );
+       }
+}
+
+/**
+ * Free up a list name/value pair objects.
+ * \param list List of name/value objects.
+ */
+void ldapqry_free_list_name_value( GList *list ) {
+       GList *node;
+
+       node = list;
+       while( node ) {
+               NameValuePair *nvp = ( NameValuePair * ) node->data;
+               ldapqry_free_name_value( nvp );
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( list );
+}
+
+/**
+ * Load a list of name/value pairs from LDAP attributes.
+ * \param  ld          LDAP handle.
+ * \param  e          LDAP message.
+ * \param  attr       Attribute name.
+ * \param  listValues List to populate.
+ * \return List of attribute name/value pairs.
+ */
+static GList *ldapqry_load_attrib_values(
+               LDAP *ld, LDAPMessage *entry, char *attr,
+               GList *listValues )
+{
+       GList *list = NULL;
+       gint i;
+       gchar **vals;
+       NameValuePair *nvp;
+
+       list = listValues;
+       if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+               for( i = 0; vals[i] != NULL; i++ ) {
+                       nvp = ldapqry_create_name_value( attr, vals[i] );
+                       list = g_list_append( list, nvp );
+               }
+       }
+       ldap_value_free( vals );
+       return list;
+}
+
+/**
+ * Fetch a list of all attributes.
+ * \param  ld    LDAP handle.
+ * \param  e     LDAP message.
+ * \return List of attribute name/value pairs.
+ */
+static GList *ldapqry_fetch_attribs( LDAP *ld, LDAPMessage *e )
+{
+       char *attribute;
+       BerElement *ber;
+       GList *listValues = NULL;
+
+       /* Process all attributes */
+       for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+               attribute = ldap_next_attribute( ld, e, ber ) ) {
+               listValues = ldapqry_load_attrib_values( ld, e, attribute, listValues );
+               ldap_memfree( attribute );
+       }
+
+       /* Free up */
+       if( ber != NULL ) {
+               ber_free( ber, 0 );
+       }
+       return listValues;
+}
+
+#define CRITERIA_SINGLE "(objectclass=*)"
+
+/**
+ * Perform the data retrieval for a specific LDAP record.
+ * 
+ * \param  qry Query object to process.
+ * \return Error/status code.
+ */
+static gint ldapqry_locate_retrieve( LdapQuery *qry ) {
+       LdapControl *ctl;
+       LDAP *ld;
+       LDAPMessage *result, *e;
+       gboolean entriesFound;
+       gboolean first;
+       struct timeval timeout;
+       gint rc;
+       gchar *dn;
+       GList *listValues;
+
+       /* Initialize some variables */
+       ld = qry->ldap;
+       ctl = qry->control;
+       dn = ADDRQUERY_SEARCHVALUE(qry);
+       timeout.tv_sec = ctl->timeOut;
+       timeout.tv_usec = 0L;
+       entriesFound = FALSE;
+
+       /*
+        * Execute the search - this step may take some time to complete
+        * depending on network traffic and server response time.
+        */
+       ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
+       rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE, CRITERIA_SINGLE,
+               NULL, 0, NULL, NULL, &timeout, 0, &result );
+       if( rc == LDAP_TIMEOUT ) {
+               return ADDRQUERY_RETVAL(qry);
+       }
+       ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
+       if( rc != LDAP_SUCCESS ) {
+               /*
+               printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
+               */
+               return ADDRQUERY_RETVAL(qry);
+       }
+       ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
+       if( ldapqry_get_stop_flag( qry ) ) {
+               return ADDRQUERY_RETVAL(qry);
+       }
+       ldapqry_touch( qry );
+
+       /*
+       printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
+       */
+
+       /* Process results */
+       first = TRUE;
+       while( TRUE ) {
+               ldapqry_touch( qry );
+               if( qry->entriesRead >= ctl->maxEntries ) break;                
+
+               /* Test for stop */
+               if( ldapqry_get_stop_flag( qry ) ) {
+                       break;
+               }
+
+               /* Retrieve entry */            
+               if( first ) {
+                       first = FALSE;
+                       e = ldap_first_entry( ld, result );
+               }
+               else {
+                       e = ldap_next_entry( ld, e );
+               }
+               if( e == NULL ) break;
+
+               entriesFound = TRUE;
+
+               /* Setup a critical section here */
+               pthread_mutex_lock( qry->mutexEntry );
+
+               /* Process entry */
+               listValues = ldapqry_fetch_attribs( ld, e );
+
+               /* Process callback */
+               if( qry->callBackEntry ) {
+                       qry->callBackEntry( qry, ADDRQUERY_ID(qry), listValues, qry->data );
+               }
+               ldapqry_free_list_name_value( listValues );
+               listValues = NULL;
+
+               pthread_mutex_unlock( qry->mutexEntry );
+       }
+
+       /* Free up and disconnect */
+       ldap_msgfree( result );
+
+       if( entriesFound ) {
+               ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
+       }
+       else {
+               ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
+       }
+
+       return ADDRQUERY_RETVAL(qry);
+}
+
+/**
+ * Perform the search to locate a specific LDAP record identified by
+ * distinguished name (dn).
+ * 
+ * \param  qry Query object to process.
+ * \return Error/status code.
+ */
+gint ldapqry_perform_locate( LdapQuery *qry ) {
+       /* Connect */
+       qry->ldap = NULL;
+       ldapqry_connect( qry );
+       if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
+               /* Perform search */
+               ldapqry_locate_retrieve( qry );
+       }
+       /* Disconnect */
+       ldapqry_disconnect( qry );
+       qry->ldap = NULL;
+
+       /* Process callback */  
+       if( qry->callBackEnd ) {
+               qry->callBackEnd( qry, ADDRQUERY_ID(qry), ADDRQUERY_RETVAL(qry), qry->data );
+       }
+
+       return ADDRQUERY_RETVAL(qry);
+}
+
+/**
+ * Remove results (folder and data) for specified LDAP query.
+ * \param  qry Query object to process.
+ */
+void ldapquery_remove_results( LdapQuery *qry ) {
+       /* Set query as aged - will be retired on a later call */
+       ldapqry_set_aged_flag( qry, TRUE );
+       if( ldapqry_get_busy_flag( qry ) ) {
+               /* Query is still busy - cancel query */
+               /* printf( "\tquery is still busy running...\n" ); */
+               ldapqry_set_stop_flag( qry, TRUE );
+               ldapqry_cancel( qry );
+       }
+       else {
+               /* Delete folder */
+               /* printf( "\tquery can be deleted!\n" ); */
+               ldapqry_delete_folder( qry );
        }
 }
 
index 9a9d2a359b29dd292aa9ea69c43a6088b36a4f2e..59b28cf2549da65c97709708f25846a04c45723a 100644 (file)
 #include <stdio.h>
 #include <sys/time.h>
 #include <pthread.h>
+#include <ldap.h>
 
+#include "addrquery.h"
 #include "ldapctrl.h"
 #include "ldapserver.h"
 #include "addritem.h"
 #include "addrcache.h"
 
-/*
- * Constants.
- */
-#define LDAPQUERY_NONE     0
-#define LDAPQUERY_STATIC   1
-#define LDAPQUERY_DYNAMIC  2
-
-/* Error codes */
-#define LDAPRC_SUCCESS    0
-#define LDAPRC_CONNECT    -1
-#define LDAPRC_INIT       -2
-#define LDAPRC_BIND       -3
-#define LDAPRC_SEARCH     -4
-#define LDAPRC_TIMEOUT    -5
-#define LDAPRC_CRITERIA   -6
-#define LDAPRC_NOENTRIES  -7
-
 typedef struct _LdapQuery LdapQuery;
 struct _LdapQuery {
-       LdapControl *control;
-       gint        retVal;
-       gint        queryType;
-       gchar       *queryName;
-       gchar       *searchValue;
-       gint        queryID;
-       gint        entriesRead;
-       gint        elapsedTime;
-       gboolean    stopFlag;
-       gboolean    busyFlag;
-       gboolean    agedFlag;
-       gboolean    completed;
-       time_t      touchTime;
-       pthread_t   *thread;
+       AddrQueryObject obj;
+       LdapControl     *control;
+       LdapServer      *server;        /* Reference to (parent) LDAP server */
+       gint            entriesRead;
+       gint            elapsedTime;
+       gboolean        stopFlag;
+       gboolean        busyFlag;
+       gboolean        agedFlag;
+       gboolean        completed;
+       time_t          startTime;
+       time_t          touchTime;
+       pthread_t       *thread;
        pthread_mutex_t *mutexStop;
        pthread_mutex_t *mutexBusy;
        pthread_mutex_t *mutexEntry;
-       void        (*callBackStart)( void * );
-       void        (*callBackEntry)( void *, void * );
-       void        (*callBackEnd)( void * );
-       ItemFolder  *folder;            /* Reference to folder in cache */
-       LdapServer  *server;            /* Reference to (parent) LDAP server */
+       void            (*callBackEntry)( void *, gint, void *, void * );
+       void            (*callBackEnd)( void *, gint, gint, void * );
+       LDAP            *ldap;
+       gpointer        data;
+};
+
+typedef struct _NameValuePair NameValuePair;
+struct _NameValuePair {
+       gchar *name;
+       gchar *value;
 };
 
 /* Function prototypes */
@@ -86,7 +74,7 @@ void ldapqry_set_control      ( LdapQuery *qry, LdapControl *ctl );
 void ldapqry_set_name          ( LdapQuery* qry, const gchar *value );
 void ldapqry_set_search_value  ( LdapQuery *qry, const gchar *value );
 void ldapqry_set_error_status  ( LdapQuery* qry, const gint value );
-void ldapqry_set_query_type    ( LdapQuery* qry, const gint value );
+void ldapqry_set_search_type   ( LdapQuery *qry, const AddrSearchType value );
 void ldapqry_set_query_id      ( LdapQuery* qry, const gint value );
 void ldapqry_set_entries_read  ( LdapQuery* qry, const gint value );
 void ldapqry_set_callback_start        ( LdapQuery *qry, void *func );
@@ -101,15 +89,17 @@ void ldapqry_set_busy_flag ( LdapQuery *qry, const gboolean value );
 gboolean ldapqry_get_busy_flag ( LdapQuery *qry );
 void ldapqry_set_aged_flag     ( LdapQuery *qry, const gboolean value );
 gboolean ldapqry_get_aged_flag ( LdapQuery *qry );
+void ldapqry_set_data          ( LdapQuery *qry, const gpointer value );
+gpointer ldapqry_get_data      ( LdapQuery *qry );
 
 gboolean ldapqry_check_search  ( LdapQuery *qry );
 void ldapqry_touch             ( LdapQuery *qry );
 gint ldapqry_search            ( LdapQuery *qry );
 gint ldapqry_read_data_th      ( LdapQuery *qry );
-void ldapqry_join_thread       ( LdapQuery *qry );
 void ldapqry_cancel            ( LdapQuery *qry );
 void ldapqry_age               ( LdapQuery *qry, gint maxAge );
 void ldapqry_delete_folder     ( LdapQuery *qry );
+void ldapquery_remove_results  ( LdapQuery *qry );
 
 #endif /* USE_LDAP */
 
index f3a31ab4cac06f61cf2490d6fc19fac3dbb4e1aa..51615824f5f6e74f8e465ccbea8ecb813a2579d4 100644 (file)
@@ -310,7 +310,7 @@ void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
        node = server->listQuery;
        while( node ) {
                LdapQuery *qry = node->data;
-               fprintf( stream, "    query: %2d : %s\n", i, qry->queryName );
+               fprintf( stream, "    query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
                i++;
                node = g_list_next( node );
        }
@@ -356,8 +356,9 @@ void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
        ldapqry_initialize();
 
        /* Perform query */     
-       /* printf( "ldapsvr_execute_query::reading with thread...\n" ); */
+       /* printf( "ldapsvr_execute_query::checking query...\n" ); */
        if( ldapqry_check_search( qry ) ) {
+               /* printf( "ldapsvr_execute_query::reading with thread...\n" ); */
                ldapqry_read_data_th( qry );
                /*
                if( qry->retVal == LDAPRC_SUCCESS ) {
@@ -380,7 +381,7 @@ void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
        node = server->listQuery;
        while( node ) {
                LdapQuery *qry = node->data;
-               if( qry->queryID == queryID ) {
+               if( ADDRQUERY_ID(qry) == queryID ) {
                        /* Notify thread to stop */
                        ldapqry_set_stop_flag( qry, TRUE );
                }
@@ -431,7 +432,8 @@ void ldapsvr_cancel_all_query( LdapServer *server ) {
  * \param searchTerm Search term to locate.
  * \return Query object, or <i>NULL</i> if none found.
  */
-LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm )
+static LdapQuery *ldapsvr_locate_query(
+       const LdapServer *server, const gchar *searchTerm )
 {
        LdapQuery *incomplete = NULL;
        GList *node;    
@@ -442,7 +444,7 @@ LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm )
        /* Search backwards for query */
        while( node ) {
                LdapQuery *qry = node->data;
-               if( g_strcasecmp( qry->searchValue, searchTerm ) == 0 ) {
+               if( g_strcasecmp( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
                        if( qry->agedFlag ) continue;
                        if( qry->completed ) {
                                /* Found */
@@ -458,7 +460,12 @@ LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm )
 }
 
 /**
- * Retire aged queries. Only dynamic queries are retired.
+ * Retire aged queries. Only the following queries are retired:
+ *
+ * a) Dynamic queries.
+ * b) Explicit searches that have a hidden folders.
+ * c) Locate searches that have a hidden folder.
+ *
  * \param server LdapServer.
  */
 void ldapsvr_retire_query( LdapServer *server ) {
@@ -467,6 +474,7 @@ void ldapsvr_retire_query( LdapServer *server ) {
        GList *listQuery;
        gint maxAge;
        LdapControl *ctl;
+       ItemFolder *folder;
 
        /* printf( "ldapsvr_retire_query\n" ); */
        g_return_if_fail( server != NULL );
@@ -480,14 +488,18 @@ void ldapsvr_retire_query( LdapServer *server ) {
                LdapQuery *qry = node->data;
 
                node = g_list_next( node );
-               if( qry->queryType == LDAPQUERY_STATIC ) continue;
+               folder = ADDRQUERY_FOLDER(qry);
+               if( folder == NULL ) continue;
+               if( ! folder->isHidden ) {
+                       if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
+                       if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
+               }
 
-               /* Only dynamic queries are retired */
                ldapqry_age( qry, maxAge );
                if( qry->agedFlag ) {
                        /* Delete folder associated with query */
                        /*
-                       printf( "deleting folder... ::%s::\n", qry->queryName );
+                       printf( "deleting folder... ::%s::\n", ADDRQUERY_NAME(qry) );
                        */
                        ldapqry_delete_folder( qry );
                        listDelete = g_list_append( listDelete, qry );
@@ -511,6 +523,176 @@ void ldapsvr_retire_query( LdapServer *server ) {
        g_list_free( listDelete );
 }
 
+/**
+ * Return results of a previous query by executing callback for each address
+ * contained in specified folder.
+ * 
+ * \param folder  Address book folder to process.
+ * \param req Address query request object.
+ */
+static void ldapsvr_previous_query(
+       const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
+{
+       AddrSearchCallbackEntry *callBack;
+       GList *listEMail;
+       GList *node;
+       GList *nodeEM;
+       gpointer sender;
+
+       sender = aqo;
+       callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
+       if( callBack ) {
+               listEMail = NULL;
+               node = folder->listPerson;
+               while( node ) {
+                       AddrItemObject *aio = node->data;
+                       if( aio &&  aio->type == ITEMTYPE_PERSON ) {
+                               ItemPerson *person = node->data;
+                               nodeEM = person->listEMail;
+                               while( nodeEM ) {
+                                       ItemEMail *email = nodeEM->data;
+
+                                       nodeEM = g_list_next( nodeEM );
+                                       listEMail = g_list_append( listEMail, email );
+                               }
+                       }
+                       node = g_list_next( node );
+               }
+               ( callBack ) ( sender, req->queryID, listEMail, NULL );
+               /* // g_list_free( listEMail ); */
+       }
+}
+
+/**
+ * Reuse search results from a previous LDAP query. If there is a query that
+ * has the same search term as specified in the query request, then the query
+ * will be reused.
+ *
+ * \param server  LDAP server object.
+ * \param req Address query object.
+ * \return <i>TRUE</i> if previous query was used.
+ */
+gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
+       LdapQuery *qry;
+       gchar *searchTerm;
+       ItemFolder *folder;
+
+       g_return_val_if_fail( server != NULL, FALSE );
+       g_return_val_if_fail( req != NULL, FALSE );
+
+       searchTerm = req->searchTerm;
+
+       /* Test whether any queries for the same term exist */
+       qry = ldapsvr_locate_query( server, searchTerm );
+       if( qry ) {
+               /* Touch query to ensure it hangs around for a bit longer */
+               ldapqry_touch( qry );
+               folder = ADDRQUERY_FOLDER(qry);
+               if( folder ) {
+                       ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+/**
+ * Construct a new LdapQuery object that will be used to perform an dynamic
+ * search request.
+ *
+ * \param server LdapServer.
+ * \param req    Query request.
+ * \return LdapQuery object, or <i>NULL</i> if none created.
+ */
+LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
+{
+       LdapQuery *qry;
+       gchar *name;
+       gchar *searchTerm;
+
+       g_return_val_if_fail( server != NULL, NULL );
+       g_return_val_if_fail( req != NULL, NULL );
+
+       /* Retire any aged queries */
+       /* // ldapsvr_retire_query( server ); */
+
+       searchTerm = req->searchTerm;
+
+       /* Construct a query */
+       qry = ldapqry_create();
+       ldapqry_set_query_id( qry, req->queryID );
+       ldapqry_set_search_value( qry, searchTerm );
+       ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
+       ldapqry_set_callback_entry( qry, req->callBackEntry );
+       ldapqry_set_callback_end( qry, req->callBackEnd );
+
+       /* Name the query */
+       name = g_strdup_printf( "Search for '%s'", searchTerm );
+       ldapqry_set_name( qry, name );
+       g_free( name );
+
+       /* Add query to request */
+       qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
+
+       /* Now start the search */
+       ldapsvr_add_query( server, qry );
+
+       return qry;     
+}
+
+/**
+ * Construct a new LdapQuery object that will be used to perform an explicit
+ * search request.
+ *
+ * \param server LdapServer.
+ * \param req    Query request.
+ * \param folder Folder that will be used to contain search results; may be NULL.
+ * \return LdapQuery object, or <i>NULL</i> if none created.
+ */
+LdapQuery *ldapsvr_new_explicit_search(
+               LdapServer *server, QueryRequest *req, ItemFolder *folder )
+{
+       LdapQuery *qry;
+       gchar *searchTerm;
+       gchar *name;
+
+       g_return_val_if_fail( server != NULL, NULL );
+       g_return_val_if_fail( req != NULL, NULL );
+       searchTerm = req->searchTerm;
+
+       /* Retire any aged queries */
+       /* // ldapsvr_retire_query( server ); */
+
+       /* Name the query */
+       name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
+
+       /* Construct a query */
+       qry = ldapqry_create();
+       ldapqry_set_query_id( qry, req->queryID );
+       ldapqry_set_name( qry, name );
+       ldapqry_set_search_value( qry, searchTerm );
+       ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
+       ldapqry_set_callback_end( qry, req->callBackEnd );
+       ldapqry_set_callback_entry( qry, req->callBackEntry );
+
+       if( folder ) {
+               /* Specify folder type and back reference */
+               ADDRQUERY_FOLDER(qry) = folder;
+               folder->folderType = ADDRFOLDER_QUERY_RESULTS;
+               folder->folderData = ( gpointer ) qry;
+       }
+
+       /* Setup server */
+       ldapsvr_add_query( server, qry );
+
+       /* Set up query request */
+       qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
+
+       g_free( name );
+
+       return qry;
+}
+
 #endif /* USE_LDAP */
 
 /*
index aa72775be608bbe6e7ac2468fe4d6722131c08df..21a64f5d68900355978200fbce32e710ac73ff35 100644 (file)
 #include "addritem.h"
 #include "addrcache.h"
 #include "adbookbase.h"
+#include "addrquery.h"
 
-#define MGU_LDAP_CONNECT   -51
-#define MGU_LDAP_INIT      -52
-#define MGU_LDAP_BIND      -53
-#define MGU_LDAP_SEARCH    -54
-#define MGU_LDAP_TIMEOUT   -55
-#define MGU_LDAP_CRITERIA  -56
-#define MGU_LDAP_NOENTRIES -57
+/* Error codes */
+#define LDAPRC_SUCCESS    0
+#define LDAPRC_CONNECT    -1
+#define LDAPRC_INIT       -2
+#define LDAPRC_BIND       -3
+#define LDAPRC_SEARCH     -4
+#define LDAPRC_TIMEOUT    -5
+#define LDAPRC_CRITERIA   -6
+#define LDAPRC_NOENTRIES  -7
+#define LDAPRC_STOP_FLAG  -8
 
 typedef struct _LdapServer LdapServer;
 struct _LdapServer {
@@ -80,6 +84,9 @@ void ldapsvr_stop_all_query   ( LdapServer *server );
 void ldapsvr_cancel_all_query  ( LdapServer *server );
 void ldapsvr_retire_query      ( LdapServer *server );
 
+gboolean ldapsvr_reuse_previous        ( const LdapServer *server,
+                                 const QueryRequest *req );
+
 #endif /* USE_LDAP */
 
 #endif /* __LDAPSERVER_H__ */