2006-04-06 [mones] 2.1.0cvs7
[claws.git] / src / addrindex.c
index b2c3e2abc46eee9572212154759bf2b51b50240e..96f8e8bcc291e242fec8b464b7f638623e31b5ca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001-2003 Match Grun
+ * Copyright (C) 2001-2006 Match Grun and the Sylpheed-Claws team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 /*
@@ -28,8 +28,8 @@
 #include "defs.h"
 
 #include <glib.h>
+#include <glib/gi18n.h>
 
-#include "intl.h"
 #include "mgutils.h"
 #include "addritem.h"
 #include "addrcache.h"
@@ -37,6 +37,8 @@
 #include "addrindex.h"
 #include "xml.h"
 #include "addrquery.h"
+#include "addr_compl.h"
+#include "utils.h"
 
 #ifndef DEV_STANDALONE
 #include "prefs_gtk.h"
@@ -53,6 +55,7 @@
 #include "ldapserver.h"
 #include "ldapctrl.h"
 #include "ldapquery.h"
+#include "ldaputil.h"
 #endif
 
 #define TAG_ADDRESS_INDEX    "addressbook"
 #define ATTAG_LDAP_TIMEOUT    "timeout"
 #define ATTAG_LDAP_MAX_AGE    "max-age"
 #define ATTAG_LDAP_DYN_SEARCH "dyn-search"
+#define ATTAG_LDAP_MATCH_OPT  "match-opt"
+#define ATTAG_LDAP_ENABLE_TLS "enable-tls"
 
 #define ELTAG_LDAP_ATTR_SRCH  "attribute"
 #define ATTAG_LDAP_ATTR_NAME  "name"
 
+/* Attribute values */
+#define ATVAL_BOOLEAN_YES         "yes"
+#define ATVAL_BOOLEAN_NO          "no"
+#define ATVAL_LDAP_MATCH_BEGIN    "begin-with"
+#define ATVAL_LDAP_MATCH_CONTAINS "contains"
+
 /* New attributes */
 #define ATTAG_LDAP_DEFAULT    "default"
 
-#if 0
-N_("Common address")
-N_("Personal address")
-#endif
-
-#define DISP_NEW_COMMON       _("Common address")
-#define DISP_NEW_PERSONAL     _("Personal address")
+#define DISP_NEW_COMMON       _("Common addresses")
+#define DISP_NEW_PERSONAL     _("Personal addresses")
 
 /* Old address book */
 #define TAG_IF_OLD_COMMON     "common_address"
@@ -115,6 +121,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.
  */
@@ -208,7 +219,7 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        iface->getAllPersons = ( void * ) addrbook_get_all_persons;
        iface->getName       = ( void * ) addrbook_get_name;
        iface->setAccessFlag = ( void * ) addrbook_set_accessed;
-       iface->searchOrder   = 2;
+       iface->searchOrder   = 0;
 
        /* Add to list of interfaces in address book */ 
        addrIndex->interfaceList =
@@ -229,7 +240,7 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        iface->getAllPersons = ( void * ) vcard_get_all_persons;
        iface->getName       = ( void * ) vcard_get_name;
        iface->setAccessFlag = ( void * ) vcard_set_accessed;
-       iface->searchOrder   = 3;
+       iface->searchOrder   = 0;
        addrIndex->interfaceList =
                g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
@@ -252,7 +263,7 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        iface->getAllPersons = ( void * ) jpilot_get_all_persons;
        iface->getName       = ( void * ) jpilot_get_name;
        iface->setAccessFlag = ( void * ) jpilot_set_accessed;
-       iface->searchOrder   = 3;
+       iface->searchOrder   = 0;
 #else
        iface->useInterface = FALSE;
        iface->haveLibrary = FALSE;
@@ -311,7 +322,7 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
  * Free DOM fragment.
  * \param fragment Fragment to free.
  */
-static addrindex_free_fragment( AddressIfFragment *fragment ) {
+static void addrindex_free_fragment( AddressIfFragment *fragment ) {
        GList *node;
 
        /* Free children */
@@ -369,7 +380,6 @@ AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
  */
 void addrindex_free_datasource( AddressDataSource *ds ) {
        AddressInterface *iface;
-       AddressCache *cache;
 
        g_return_if_fail( ds != NULL );
 
@@ -394,8 +404,6 @@ void addrindex_free_datasource( AddressDataSource *ds ) {
 #ifdef USE_LDAP
                                else if( iface->type == ADDR_IF_LDAP ) {
                                        LdapServer *server = ds->rawDataSource;
-                                       cache = server->addressCache;
-                                       addrcache_use_index( cache, FALSE );
                                        ldapsvr_free( server );
                                }
 #endif
@@ -568,13 +576,11 @@ static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer
  * Free hash table of address cache items.
  */
 static void addrindex_free_cache_hash( GHashTable *table ) {
-       g_hash_table_freeze( table );
        g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
-       g_hash_table_thaw( table );
        g_hash_table_destroy( table );
 }
 
-/*
+/**
  * Remove data source from internal hashtable.
  * \param addrIndex Address index.
  * \param ds        Data source to remove.
@@ -592,32 +598,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_;
 }
 
 /**
@@ -673,19 +691,19 @@ 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();
-} */
+}
 
 /**
  * Perform any other teardown of address index.
- * \param addrIndex Address index.
  */
-/* void addrindex_teardown( AddressIndex *addrIndex ) {
+void addrindex_teardown( void ) {
        addrcompl_teardown();
-} */
+       qrymgr_teardown();
+}
 
 /**
  * Free up address index.
@@ -738,6 +756,8 @@ void addrindex_free_index( AddressIndex *addrIndex ) {
        addrIndex->loadedFlag = FALSE;
 
        g_free( addrIndex );
+       addrIndex = NULL;
+       _addressIndex_ = NULL;
 }
 
 /**
@@ -971,6 +991,8 @@ static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
        guint prevLevel;
        gint rc;
 
+       /* printf( "addrindex_read_fragment\n" ); */
+
        prevLevel = file->level;
 
        /* Get current tag name */
@@ -1053,37 +1075,6 @@ static void addrindex_write_fragment(
        }
 }
 
-/*
-static void addrindex_print_fragment_r(
-               const AddressIfFragment *fragment, FILE *stream, gint lvl )
-{
-       GList *node;
-       gint i;
-
-       for( i = 0; i < lvl; i++ )
-               fprintf( stream, "  " );
-       fprintf( stream, "Element:%s:\n", fragment->name );
-       node = fragment->attributes;
-       while( node ) {
-               AddressIfAttrib *nv = node->data;
-               for( i = 0; i < lvl; i++ )
-                       fprintf( stream, "  " );
-               fprintf( stream, "    %s : %s\n", nv->name, nv->value );
-               node = g_list_next( node );
-       }
-       node = fragment->children;
-       while( node ) {
-               AddressIfFragment *child = node->data;
-               addrindex_print_fragment_r( child, stream, 1+lvl );
-               node = g_list_next( node );
-       }
-}
-
-static void addrindex_print_fragment( const AddressIfFragment *fragment, FILE *stream ) {
-       addrindex_print_fragment_r( fragment, stream, 0 );
-}
-*/
-
 /**
  * Read/parse address index file, creating a data source for a regular
  * intrinsic XML addressbook.
@@ -1215,6 +1206,24 @@ static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
        }
 }
 
+#else
+/*
+ * Just read/write DOM fragments (preserve data found in file).
+ */
+static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
+       AddressDataSource *ds;
+
+       ds = addrindex_create_datasource( ADDR_IF_JPILOT );
+       ds->rawDataSource = addrindex_read_fragment( file );
+       return ds;
+}
+
+static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
+       AddressIfFragment *fragment = ds->rawDataSource;
+       if( fragment ) {
+               addrindex_write_fragment( fp, fragment, lvl );
+       }
+}
 #endif
 
 #ifdef USE_LDAP
@@ -1292,6 +1301,12 @@ static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
 
 }
 
+void ldapsvr_set_control( LdapServer *server, LdapControl *ctl );
+/**
+ * Parse LDAP control data from XML file.
+ * \param  file Index file.
+ * \return Initialized data soruce object.
+ */
 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
        AddressDataSource *ds;
        LdapServer *server;
@@ -1299,8 +1314,15 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
        GList *attr;
        gchar *serverName = NULL;
        gchar *criteria = NULL;
-       gboolean bSearch = FALSE;
-       gboolean cvtFlag = TRUE;
+       gboolean bDynSearch;
+       gboolean bTLS;
+       gint iMatch;
+
+       /* printf( "addrindex_parse_ldap\n" ); */
+       /* Set up some defaults */
+       bDynSearch = FALSE;
+       bTLS = FALSE;
+       iMatch = LDAPCTL_MATCH_BEGINWITH;
 
        ds = addrindex_create_datasource( ADDR_IF_LDAP );
        ctl = ldapctl_create();
@@ -1311,7 +1333,7 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
                gint ivalue = atoi( value );
 
                if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
-                       if( serverName ) g_free( serverName );
+                       g_free( serverName );
                        serverName = g_strdup( value );
                }
                else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
@@ -1330,7 +1352,7 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
                        ldapctl_set_bind_password( ctl, value );
                }
                else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
-                       if( criteria ) g_free( criteria );
+                       g_free( criteria );
                        criteria = g_strdup( value );
                }
                else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
@@ -1343,10 +1365,21 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
                        ldapctl_set_max_query_age( ctl, ivalue );
                }
                else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
-                       bSearch = FALSE;
-                       cvtFlag = FALSE;
-                       if( strcmp( value, "yes" ) == 0 ) {
-                               bSearch = TRUE;
+                       bDynSearch = FALSE;
+                       if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
+                               bDynSearch = TRUE;
+                       }
+               }
+               else if( strcmp( name, ATTAG_LDAP_MATCH_OPT ) == 0 ) {
+                       iMatch = LDAPCTL_MATCH_BEGINWITH;
+                       if( strcmp( value, ATVAL_LDAP_MATCH_CONTAINS ) == 0 ) {
+                               iMatch = LDAPCTL_MATCH_CONTAINS;
+                       }
+               }
+               else if( strcmp( name, ATTAG_LDAP_ENABLE_TLS ) == 0 ) {
+                       bTLS = FALSE;
+                       if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
+                               bTLS = TRUE;
                        }
                }
                attr = g_list_next( attr );
@@ -1354,7 +1387,9 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
 
        server = ldapsvr_create_noctl();
        ldapsvr_set_name( server, serverName );
-       ldapsvr_set_search_flag( server, bSearch );
+       ldapsvr_set_search_flag( server, bDynSearch );
+       ldapctl_set_matching_option( ctl, iMatch );
+       ldapctl_set_tls( ctl, bTLS );
        g_free( serverName );
        ldapsvr_set_control( server, ctl );
        ds->rawDataSource = server;
@@ -1371,13 +1406,6 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
                }
                g_free( criteria );
        }
-       /*
-        * If no search flag was found, then we are converting from old format
-        * server data to new format.
-        */
-       if( cvtFlag ) {
-               ldapsvr_set_search_flag( server, TRUE );
-       }
        /* ldapsvr_print_data( server, stdout ); */
 
        return ds;
@@ -1414,7 +1442,16 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
        addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value );
 
        addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
-                       server->searchFlag ? "yes" : "no" );
+                       server->searchFlag ?
+                       ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO );
+
+       addrindex_write_attr( fp, ATTAG_LDAP_MATCH_OPT,
+               ( ctl->matchingOption == LDAPCTL_MATCH_CONTAINS ) ?
+               ATVAL_LDAP_MATCH_CONTAINS : ATVAL_LDAP_MATCH_BEGIN );
+
+       addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_TLS,
+                       ctl->enableTLS ?
+                       ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO );
 
        fputs(" >\n", fp);
 
@@ -1429,7 +1466,25 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
 
        /* End of element */    
        addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP );
+}
+
+#else
+/*
+ * Just read/write DOM fragments (preserve data found in file).
+ */
+static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
+       AddressDataSource *ds;
 
+       ds = addrindex_create_datasource( ADDR_IF_LDAP );
+       ds->rawDataSource = addrindex_read_fragment( file );
+       return ds;
+}
+
+static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
+       AddressIfFragment *fragment = ds->rawDataSource;
+       if( fragment ) {
+               addrindex_write_fragment( fp, fragment, lvl );
+       }
 }
 #endif
 
@@ -1480,16 +1535,12 @@ static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
                                else if( addrIndex->lastType == ADDR_IF_VCARD ) {
                                        ds = addrindex_parse_vcard( file );
                                }
-#ifdef USE_JPILOT
                                else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
                                        ds = addrindex_parse_jpilot( file );
                                }
-#endif
-#ifdef USE_LDAP
                                else if( addrIndex->lastType == ADDR_IF_LDAP ) {
                                        ds = addrindex_parse_ldap( file );
                                }
-#endif
                                if( ds ) {
                                        ds->interface = dsIFace;
                                        addrindex_hash_add_cache( addrIndex, ds );
@@ -1516,7 +1567,6 @@ static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer pt
  * \param addrIndex Address index object.
  */
 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
-       AddressInterface *iface;
        GList *nodeIf;
 
        /* Clear existing list */
@@ -1527,21 +1577,16 @@ static void addrindex_build_search_order( AddressIndex *addrIndex ) {
        nodeIf = addrIndex->interfaceList;
        while( nodeIf ) {
                AddressInterface *iface = nodeIf->data;
-               if( iface->searchOrder > 0 ) {
-                       /* Add to search order list */
-                       addrIndex->searchOrder = g_list_insert_sorted(
-                               addrIndex->searchOrder, iface,
-                               addrindex_search_order_compare );
+               if( iface->useInterface ) {
+                       if( iface->searchOrder > 0 ) {
+                               /* Add to search order list */
+                               addrIndex->searchOrder = g_list_insert_sorted(
+                                       addrIndex->searchOrder, iface,
+                                       addrindex_search_order_compare );
+                       }
                }
                nodeIf = g_list_next( nodeIf );
        }
-
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               AddressInterface *iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
-       }
-
 }
 
 static gint addrindex_read_file( AddressIndex *addrIndex ) {
@@ -1599,16 +1644,12 @@ static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
                                        if( iface->type == ADDR_IF_VCARD ) {
                                                addrindex_write_vcard( fp, ds, lvlItem );
                                        }
-#ifdef USE_JPILOT
                                        if( iface->type == ADDR_IF_JPILOT ) {
                                                addrindex_write_jpilot( fp, ds, lvlItem );
                                        }
-#endif
-#ifdef USE_LDAP
                                        if( iface->type == ADDR_IF_LDAP ) {
                                                addrindex_write_ldap( fp, ds, lvlItem );
                                        }
-#endif
                                }
                                nodeDS = g_list_next( nodeDS );
                        }
@@ -1637,7 +1678,7 @@ gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
        fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
        addrIndex->retVal = MGU_OPEN_FILE;
 #ifdef DEV_STANDALONE
-       fp = fopen( fileSpec, "wb" );
+       fp = g_fopen( fileSpec, "wb" );
        g_free( fileSpec );
        if( fp ) {
                fputs( "<?xml version=\"1.0\" ?>\n", fp );
@@ -1646,8 +1687,7 @@ gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
        g_free( fileSpec );
        if( pfile ) {
                fp = pfile->fp;
-               fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
-                               conv_get_current_charset_str() );
+               fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
 #endif
                addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX );
                fputs( ">\n", fp );
@@ -1776,6 +1816,7 @@ static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
                if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
                        nn->remarks = g_strdup( element );
                }
+               g_free(element);
                xml_parse_next_tag(file);
        }
 }
@@ -2293,6 +2334,10 @@ gint addrindex_ds_read_data( AddressDataSource *ds ) {
        iface = ds->interface;
        if( iface == NULL ) return retVal;
        if( iface->getReadData ) {
+               /*
+               gchar *name = ( iface->getName ) ( ds->rawDataSource );
+               printf( "addrindex_ds_read_data...reading:::%s:::\n", name );
+               */
                retVal = ( iface->getReadData ) ( ds->rawDataSource );
        }
        return retVal;
@@ -2425,324 +2470,333 @@ 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
+
+/*
+ * Function prototypes (not in header file or circular reference errors are
+ * encountered!)
+ */
+LdapQuery *ldapsvr_new_dynamic_search( 
+               LdapServer *server, QueryRequest *req );
+LdapQuery *ldapsvr_new_explicit_search(
+               LdapServer *server, QueryRequest *req, ItemFolder *folder );
+void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry );
+
+#endif
+
 /**
- * Perform the search for specified address cache.
- * \param cache Cache to be searched.
- * \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.
  */
-static void addrindex_search_cache( AddressCache *cache, const gint queryID ) {
-       AddrCacheIndex *index;
-       GList *listEMail;
+static gboolean addrindex_start_dynamic( QueryRequest *req ) {
+       AddressInterface *iface;
+       AddressDataSource *ds;
+       GList *nodeIf;
+       GList *nodeDS;
+       gint type;
 
-       index = cache->searchIndex;
-       if( index == NULL ) return;
-       if( index->invalid ) {
-               addrcache_build_index( cache );
-       }
+       /* printf( "addrindex_start_dynamic::%d::\n", req->queryID ); */
+       nodeIf = _addressIndex_->searchOrder;
+       while( nodeIf ) {
+               iface = nodeIf->data;
+               nodeIf = g_list_next( nodeIf );
 
-       /*
-       printf( "query ::%d:: searching index for ::%s::\n", queryID, _searchTerm_ );
-       */
-       listEMail = addrcindex_search( index, _searchTerm_ );
-       ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
-       g_list_free( listEMail );
-       listEMail = NULL;
-       /* printf( "searching index done\n" ); */
-}
+               if( ! iface->useInterface ) {
+                       continue;
+               }
+               if( ! iface->externalQuery ) {
+                       continue;
+               }
 
+               type = iface->type;
+               nodeDS = iface->listSource;
+               while( nodeDS ) {
+                       ds = nodeDS->data;
+                       nodeDS = g_list_next( nodeDS );
 #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;
+                       if( type == ADDR_IF_LDAP ) {
+                               LdapServer *server;
+                               LdapQuery *qry;
 
-       /*
-       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 );
-}
+                               server = ds->rawDataSource;
+                               if( ! server->searchFlag ) {
+                                       continue;
+                               }
+                               if( ldapsvr_reuse_previous( server, req ) ) {
+                                       continue;
+                               }
 
-/**
- * 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 ); */
+                               /* Start a new dynamic search */
+                               qry = ldapsvr_new_dynamic_search( server, req );
+                               if( qry ) {
+                                       ldapsvr_execute_query( server, qry );
+                               }
+                       }
+#endif
+               }
+       }
+       return TRUE;
 }
 
 /**
- * Return results of previous query.
- * \param folder.
- * \return List of ItemEMail objects.
+ * Stop the previously registered search.
+ *
+ * \param queryID ID of search query to stop.
  */
-static void addrindex_ldap_use_previous( const ItemFolder *folder, const gint queryID )
-{
-       GList *listEMail;
+void addrindex_stop_search( const gint queryID ){
+       QueryRequest *req;
+       AddrQueryObject *aqo;
        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 );
+       /* printf( "addrindex_stop_search/queryID=%d\n", queryID ); */
+       /* If query ID does not match, search has not been setup */
+       req = qrymgr_find_request( queryID );
+       if( req == NULL ) {
+               return;
+       }
+
+       /* Stop all queries that were associated with request */
+       node = req->queryList;
+       while( node ) {
+               aqo = node->data;
+#ifdef USE_LDAP
+               if( aqo->queryType == ADDRQUERY_LDAP ) {
+                       LdapQuery *qry = ( LdapQuery * ) aqo;
+                       ldapqry_set_stop_flag( qry, TRUE );
                }
-               ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
-               g_list_free( listEMail );
+#endif
+               node->data = NULL;
+               node = g_list_next( node );
        }
-}
 
-LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
+       /* Delete query request */
+       qrymgr_delete_request( queryID );
+}
 
 /**
- * Construct an LDAP query and initiate an LDAP search.
- * \param server  LDAP server object.
- * \param queryID ID of search query to be executed.
+ * 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  callbackEntry Function to called for each entry processed.
+ * \return ID allocated to query that will be executed.
  */
-static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
-       LdapQuery *qry;
+gint addrindex_setup_explicit_search(
+       AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder,
+       void *callBackEnd, void *callBackEntry )
+{
+       QueryRequest *req;
+       gint queryID;
        gchar *name;
+       gchar *mySearch;
 
-       if( ! server->searchFlag ) return;
-       /* printf( "Searching ::%s::\n", ldapsvr_get_name( server ) ); */
+       /* Name the query */
+       name = g_strdup_printf( "Search '%s'", searchTerm );
 
-       /* Retire any aged queries */
-       ldapsvr_retire_query( server );
+       /* Set up query request */
+       if (!strcmp(searchTerm, "*"))
+               mySearch = g_strdup("*@");
+       else
+               mySearch = g_strdup(searchTerm);
+       
+       req = qrymgr_add_request( mySearch, callBackEnd, callBackEntry );
 
-       /* Test whether any queries for the same term exist */
-       qry = ldapsvr_locate_query( server, _searchTerm_ );
-       if( qry ) {
-               ItemFolder *folder = qry->folder;
+       g_free(mySearch);
 
-               /* Touch query to ensure it hangs around for a bit longer */            
-               ldapqry_touch( qry );
-               if( folder ) {
-                       addrindex_ldap_use_previous( folder, queryID );
-                       return;
-               }
-       }
+       qryreq_set_search_type( req, ADDRSEARCH_EXPLICIT );
+       queryID = req->queryID;
 
-       /* 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 );
+       if( ds->type == ADDR_IF_LDAP ) {
+#ifdef USE_LDAP
+               LdapServer *server;
 
-       /* Name the query */
-       name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
-       ldapqry_set_name( qry, name );
+               server = ds->rawDataSource;
+               ldapsvr_new_explicit_search( server, req, folder );
+#endif
+       }
+       else {
+               qrymgr_delete_request( queryID );
+               queryID = 0;
+       }
        g_free( name );
 
-       ldapsvr_add_query( server, qry );
-       /* printf( "addrindex_search_ldap::executing dynamic search...\n" ); */
-       ldapsvr_execute_query( server, qry );
+       return queryID;
 }
 
 /**
- * Construct an LDAP query and initiate an LDAP search.
- * \param server      LDAP server object to search.
- * \param searchTerm  Search term to locate.
- * \param callbackEnd Function to call when search has terminated.
+ * 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.
  */
-void addrindex_search_ldap_noid(
-       LdapServer *server, const gchar *searchTerm, void * callbackEnd )
-{
-       LdapQuery *qry;
-       gchar *name;
+static gboolean addrindex_start_explicit( QueryRequest *req ) {
+       gboolean retVal;
+       AddrQueryObject *aqo;
 
-       /* Construct a query */
-       qry = ldapqry_create();
-       ldapqry_set_search_value( qry, searchTerm );
-       ldapqry_set_query_type( qry, LDAPQUERY_STATIC );
-       ldapqry_set_callback_end( qry, callbackEnd );
+       retVal = FALSE;
 
-       /* Name the query */
-       name = g_strdup_printf( "Static Search for '%s'", searchTerm );
-       ldapqry_set_name( qry, name );
-       g_free( name );
+       /* 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;
 
-       ldapsvr_add_query( server, qry );
-       /* printf( "addrindex_search_ldap_noid::executing static search...\n" ); */
-       ldapsvr_execute_query( server, qry );
-}
+               qry = ( LdapQuery * ) aqo;
+               server = qry->server;
+
+               /* Start the search */
+               retVal = TRUE;
+               ldapsvr_execute_query( server, qry );
+       }
 #endif
+       return retVal;
+}
 
 /**
- * Perform the previously registered search.
- * \param  addrIndex  Address index object.
+ * 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( AddressIndex *addrIndex, const gint queryID ) {
-       AddressInterface *iface;
-       AddressDataSource *ds;
-       AddressCache *cache;
-       GList *nodeIf;
-       GList *nodeDS;
-       gint type;
-
-       /* printf( "addrindex_start_search::%d::\n", queryID ); */
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
-
-               if( ! iface->useInterface ) {
-                       continue;
-               }
+gboolean addrindex_start_search( const gint queryID ) {
+       gboolean retVal;
+       QueryRequest *req;
+       AddrSearchType searchType;
 
-               type = iface->type;
-               nodeDS = iface->listSource;
-               while( nodeDS ) {
-                       ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
-                       cache = NULL;
+       retVal = FALSE;
+       /* printf( "addrindex_start_search/queryID=%d\n", queryID ); */
+       req = qrymgr_find_request( queryID );
+       if( req == NULL ) {
+               return retVal;
+       }
 
-                       if( type == ADDR_IF_BOOK ) {
-                               AddressBookFile *abf = ds->rawDataSource;
-                               cache = abf->addressCache;
-                       }
-                       else if( type == ADDR_IF_VCARD ) {
-                               VCardFile *vcf = ds->rawDataSource;
-                               cache = vcf->addressCache;
-                       }
-#ifdef USE_JPILOT
-                       else if( type == ADDR_IF_JPILOT ) {
-                               JPilotFile *jpf = ds->rawDataSource;
-                               cache = jpf->addressCache;
-                       }
-#endif
-#ifdef USE_LDAP
-                       else if( type == ADDR_IF_LDAP ) {
-                               LdapServer *server = ds->rawDataSource;
-                               addrindex_search_ldap( server, queryID );
-                       }
-#endif
-                       if( cache ) {
-                               addrindex_search_cache( cache, queryID );
-                       }
-               }
+       searchType = req->searchType;
+       if( searchType == ADDRSEARCH_DYNAMIC ) {
+               retVal = addrindex_start_dynamic( req );
        }
-       return TRUE;
+       else if( searchType == ADDRSEARCH_EXPLICIT ) {
+               retVal = addrindex_start_explicit( req );
+       }
+
+       return retVal;
 }
 
 /**
- * Stop the previously registered search.
- * \param addrIndex Address index object.
- * \param queryID ID of search query to stop.
+ * 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_stop_search( AddressIndex *addrIndex, const gint queryID ){
-#ifdef USE_LDAP
-       AddressInterface *iface;
-       AddressDataSource *ds;
-       GList *nodeIf;
-       GList *nodeDS;
-       gint type;
+void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) {
+       AddrBookBase *adbase;
+       AddressCache *cache;
+       gint queryID = 0;
 
-       /* If query ID does not match, search has not been setup */
-       /* if( queryID != _queryID_ ) return; */
+       /* printf( "addrindex_remove_results/start\n" ); */
 
-       /* printf( "addrindex_stop_search::%d::\n", queryID ); */
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
+       /* Test for folder */
+       if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return;
+       /* printf( "folder name ::%s::\n", ADDRITEM_NAME(folder) ); */
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       if( adbase == NULL ) return;
+       cache = adbase->addressCache;
 
-               if( ! iface->useInterface ) {
-                       continue;
-               }
+       /* Hide folder to prevent re-display */
+       addritem_folder_set_hidden( folder, TRUE );
 
-               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 );
-                       }
+       if( ds->type == ADDR_IF_LDAP ) {
+#ifdef USE_LDAP
+               LdapQuery *qry;
+               gboolean  delFlag;
+
+               qry = ( LdapQuery * ) folder->folderData;
+               queryID = ADDRQUERY_ID(qry);
+               /* printf( "calling ldapquery_remove_results...queryID=%d\n", queryID ); */
+               delFlag = ldapquery_remove_results( qry );
+               if (delFlag) {
+                       ldapqry_free( qry );
                }
-       }
+               /* printf( "calling ldapquery_remove_results...done\n" ); */
+               /*
+               if( delFlag ) {
+                       printf( "delFlag IS-TRUE\n" );
+               }
+               else {
+                       printf( "delFlag IS-FALSE\n" );
+                       addressbook_clear_idler( queryID );
+               }
+               */
 #endif
+       }
+       /* printf( "addrindex_remove_results/end\n" ); */
+
+       /* Delete query request */
+       if( queryID > 0 ) {
+               qrymgr_delete_request( queryID );
+       }
 }
 
+/* **********************************************************************
+* Address completion stuff.
+* ***********************************************************************
+*/
+
 /**
- * Read all address books that do not support dynamic queries.
- * \param addrIndex Address index object.
+ * This function is used by the address completion function to load
+ * addresses for all non-external address book interfaces.
+ *
+ * \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.
  */
-void addrindex_read_all( AddressIndex *addrIndex ) {
-       AddressInterface *iface;
+gboolean addrindex_load_completion(
+               gint (*callBackFunc) ( const gchar *, const gchar *, 
+                                      const gchar *, const gchar * ) )
+{
        AddressDataSource *ds;
-       GList *nodeIf;
-       GList *nodeDS;
+       GList *nodeIf, *nodeDS;
+       GList *listP, *nodeP;
+       GList *nodeM;
+       gchar *sName;
 
-       nodeIf = addrIndex->searchOrder;
+       nodeIf = addrindex_get_interface_list( _addressIndex_ );
        while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
+               AddressInterface *iface = nodeIf->data;
 
+               nodeIf = g_list_next( nodeIf );
                if( ! iface->useInterface ) {
                        continue;
                }
@@ -2752,189 +2806,130 @@ void addrindex_read_all( AddressIndex *addrIndex ) {
                nodeDS = iface->listSource;
                while( nodeDS ) {
                        ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
 
                        /* Read address book */
                        if( addrindex_ds_get_modify_flag( ds ) ) {
                                addrindex_ds_read_data( ds );
-                               continue;
                        }
 
                        if( ! addrindex_ds_get_read_flag( ds ) ) {
                                addrindex_ds_read_data( ds );
-                               continue;
                        }
-               }
-       }
-       addrIndex->loadedFlag = TRUE;
-}
-
-/**
- * Perform a simple search of all non-query type data sources for specified
- * search term. If several entries are found, only the first item is
- * returned. Interfaces that require a time-consuming "external query" are
- * ignored for this search.
- *
- * \param  addrIndex  Address index object.
- * \param  searchTerm Search term to find. Typically an email address.
- * \return List of references to zero or mail E-Mail object that was found in
- *         the address books, or <i>NULL</i> if nothing found. This list
- *         *SHOULD* be freed when done.
- */
-GList *addrindex_quick_search_list(
-               AddressIndex *addrIndex, const gchar *searchTerm )
-{
-       GList *listRet = NULL;
-       GList *listEMail;
-       AddressInterface *iface;
-       AddressDataSource *ds;
-       AddressCache *cache;
-       AddrCacheIndex *index;
-       ItemEMail *email;
-       GList *nodeIf;
-       GList *nodeDS;
-       GList *nodeEM;
-       gint type;
-
-       nodeIf = addrIndex->searchOrder;
-       while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
-
-               if( ! iface->useInterface ) {
-                       /* Ignore interfaces that don't have a library */
-                       continue;
-               }
-               if( iface->externalQuery ) {
-                       /* Ignore interfaces that require a "query" */
-                       continue;
-               }
-
-               type = iface->type;
-               nodeDS = iface->listSource;
-               while( nodeDS ) {
-                       ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
-                       cache = NULL;
 
-                       if( type == ADDR_IF_BOOK ) {
-                               AddressBookFile *abf = ds->rawDataSource;
-                               cache = abf->addressCache;
-                       }
-                       else if( type == ADDR_IF_VCARD ) {
-                               VCardFile *vcf = ds->rawDataSource;
-                               cache = vcf->addressCache;
-                       }
-#ifdef USE_JPILOT
-                       else if( type == ADDR_IF_JPILOT ) {
-                               JPilotFile *jpf = ds->rawDataSource;
-                               cache = jpf->addressCache;
-                       }
-#endif
-                       if( cache ) {
-                               index = cache->searchIndex;
-                               if( index == NULL ) {
-                                       continue;
-                               }
-                               if( index->invalid ) {
-                                       addrcache_build_index( cache );
+                       /* Get all persons */
+                       listP = addrindex_ds_get_all_persons( ds );
+                       nodeP = listP;
+                       while( nodeP ) {
+                               ItemPerson *person = nodeP->data;
+                               nodeM = person->listEMail;
+
+                               /* Figure out name to use */
+                               sName = ADDRITEM_NAME(person);
+                               if( sName == NULL || *sName == '\0' ) {
+                                       sName = person->nickName;
                                }
-                               listEMail = addrcindex_search( index, searchTerm );
-                               nodeEM = listEMail;
-                               while( nodeEM ) {
-                                       email = listEMail->data;
-                                       listRet = g_list_append( listRet, email );
-                                       nodeEM = g_list_next( nodeEM );
+
+                               /* Process each E-Mail address */
+                               while( nodeM ) {
+                                       ItemEMail *email = nodeM->data;
+                                       
+                                       callBackFunc( sName, email->address, person->nickName, 
+                                                     ADDRITEM_NAME(email) );
+                                       
+                                       nodeM = g_list_next( nodeM );
                                }
-                               g_list_free( listEMail );
+                               nodeP = g_list_next( nodeP );
                        }
+                       /* Free up the list */
+                       g_list_free( listP );
+
+                       nodeDS = g_list_next( nodeDS );
                }
        }
-       return listRet;
+
+       return TRUE;
 }
 
 /**
- * Perform a simple search of all non-query type data sources for specified
- * search term. If several entries are found, only the first item is
- * returned. Interfaces that require a time-consuming "external query" are
- * ignored for this search.
+ * This function can be used to collect information about
+ * addressbook entries that contain a specific attribute.
  *
- * \param  addrIndex  Address index object.
- * \param  searchTerm Search term to find. Typically an email address.
- * \return Reference to a single E-Mail object that was found in the address
- *         book, or <i>NULL</i> if nothing found. This should *NOT* be freed
- *         when done.
+ * \param attr         Name of attribute to look for
+ * \param callBackFunc Function to be called when a matching attribute was found
+ * \return <i>TRUE</i>
  */
-ItemEMail *addrindex_quick_search_single(
-               AddressIndex *addrIndex, const gchar *searchTerm )
+gboolean addrindex_load_person_attribute(
+               const gchar *attr,
+               gint (*callBackFunc) ( ItemPerson *, const gchar * ) )
 {
-       ItemEMail *email = NULL;
-       AddressInterface *iface;
        AddressDataSource *ds;
-       AddressCache *cache;
-       AddrCacheIndex *index;
-       GList *listEMail;
-       GList *nodeIf;
-       GList *nodeDS;
-       gint type;
+       GList *nodeIf, *nodeDS;
+       GList *listP, *nodeP;
+       GList *nodeA;
 
-       /* printf( "addrindex_quick_search::%s::\n", searchTerm ); */
-       nodeIf = addrIndex->searchOrder;
+       nodeIf = addrindex_get_interface_list( _addressIndex_ );
        while( nodeIf ) {
-               iface = nodeIf->data;
-               nodeIf = g_list_next( nodeIf );
+               gchar *cur_bname;
+               AddressInterface *iface = nodeIf->data;
 
+               nodeIf = g_list_next( nodeIf );
                if( ! iface->useInterface ) {
                        continue;
                }
                if( iface->externalQuery ) {
                        continue;
                }
-
-               type = iface->type;
                nodeDS = iface->listSource;
                while( nodeDS ) {
                        ds = nodeDS->data;
-                       nodeDS = g_list_next( nodeDS );
-                       cache = NULL;
 
-                       if( type == ADDR_IF_BOOK ) {
-                               AddressBookFile *abf = ds->rawDataSource;
-                               cache = abf->addressCache;
-                       }
-                       else if( type == ADDR_IF_VCARD ) {
-                               VCardFile *vcf = ds->rawDataSource;
-                               cache = vcf->addressCache;
+                       /* Read address book */
+                       if( addrindex_ds_get_modify_flag( ds ) ) {
+                               addrindex_ds_read_data( ds );
                        }
-#ifdef USE_JPILOT
-                       else if( type == ADDR_IF_JPILOT ) {
-                               JPilotFile *jpf = ds->rawDataSource;
-                               cache = jpf->addressCache;
+
+                       if( ! addrindex_ds_get_read_flag( ds ) ) {
+                               addrindex_ds_read_data( ds );
                        }
-#endif
-                       if( cache ) {
-                               index = cache->searchIndex;
-                               if( index == NULL ) {
-                                       continue;
-                               }
-                               if( index->invalid ) {
-                                       addrcache_build_index( cache );
+
+                       /* Check addressbook name */
+                       cur_bname = addrindex_ds_get_name( ds );
+
+                       /* Get all persons */
+                       listP = addrindex_ds_get_all_persons( ds );
+                       nodeP = listP;
+                       while( nodeP ) {
+                               ItemPerson *person = nodeP->data;
+
+                               /* Return all ItemPerson's if attr is NULL */
+                               if( attr == NULL ) {
+                                       callBackFunc(person, cur_bname);
                                }
 
-                               listEMail = addrcindex_search( index, searchTerm );
-                               if( listEMail ) {
-                                       email = listEMail->data;
+                               /* Return ItemPerson's with specific attribute */
+                               else {
+                                       nodeA = person->listAttrib;
+                                       /* Process each User Attribute */
+                                       while( nodeA ) {
+                                               UserAttribute *attrib = nodeA->data;
+                                               if( attrib->name && 
+                                                   !strcmp( attrib->name,attr ) ) {
+                                                       callBackFunc(person, cur_bname);
+                                               }
+                                               nodeA = g_list_next( nodeA );
+                                       }
                                }
-                               g_list_free( listEMail );
-                               if( email ) break;
+                               nodeP = g_list_next( nodeP );
                        }
+                       /* Free up the list */
+                       g_list_free( listP );
+
+                       nodeDS = g_list_next( nodeDS );
                }
        }
-       return email;
+       return TRUE;
 }
 
 /*
  * End of Source.
  */
-
-