remove gtk_window_set_wmclass()
[claws.git] / src / addressbook.c
index 5511c0c0529cd517bd9d41b58f2571cfb6cc9ef3..5ce8fca5441fe3befbd884132cf7b6282cfc309a 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
 {
@@ -170,7 +172,11 @@ static void addressbook_to_clicked         (GtkButton      *button,
 static void addressbook_lup_clicked            (GtkButton      *button,
                                                 gpointer       data);
 
-static void addressbook_tree_selected          (GtkCTree       *ctree,
+static gboolean addressbook_tree_selected      (GtkCTree       *ctree,
+                                                GtkCTreeNode   *node,
+                                                gint            column,
+                                                gpointer        data);
+static void addressbook_select_row_tree                (GtkCTree       *ctree,
                                                 GtkCTreeNode   *node,
                                                 gint            column,
                                                 gpointer        data);
@@ -352,6 +358,12 @@ static void addressbook_treenode_cut_cb            ( void );
 static void addressbook_treenode_copy_cb       ( void );
 static void addressbook_treenode_paste_cb      ( void );
 
+static void addressbook_mail_to_cb             ( void );
+
+#ifdef USE_LDAP
+static void addressbook_browse_entry_cb                ( void );
+#endif
+
 static GtkItemFactoryEntry addressbook_entries[] =
 {
        {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
@@ -382,6 +394,8 @@ static GtkItemFactoryEntry addressbook_entries[] =
        {N_("/_Address/---"),           NULL,           NULL, 0, "<Separator>"},
        {N_("/_Address/_Edit"),         "<alt>Return",  addressbook_edit_address_cb,    0, NULL},
        {N_("/_Address/_Delete"),       NULL,           addressbook_delete_address_cb,  0, NULL},
+       {N_("/_Address/---"),           NULL,           NULL, 0, "<Separator>"},
+       {N_("/_Address/_Mail To"),      NULL,           addressbook_mail_to_cb,         0, NULL},
        {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
        {N_("/_Tools/Import _LDIF file..."), NULL,      addressbook_import_ldif_cb,     0, NULL},
        {N_("/_Tools/Import M_utt file..."), NULL,      addressbook_import_mutt_cb,     0, NULL},
@@ -395,13 +409,13 @@ static GtkItemFactoryEntry addressbook_entries[] =
 
 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
 {
-       {N_("/New _Address"),   NULL, addressbook_new_address_cb, 0, NULL},
-       {N_("/New _Group"),     NULL, addressbook_new_group_cb,   0, NULL},
-       {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,  0, NULL},
-       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/_Edit"),          NULL, addressbook_treenode_edit_cb,   0, NULL},
        {N_("/_Delete"),        NULL, addressbook_treenode_delete_cb, 0, NULL},
        {N_("/---"),            NULL, NULL, 0, "<Separator>"},
+       {N_("/New _Address"),   NULL, addressbook_new_address_cb,     0, NULL},
+       {N_("/New _Group"),     NULL, addressbook_new_group_cb,       0, NULL},
+       {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,      0, NULL},
+       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/C_ut"),           NULL, addressbook_treenode_cut_cb,    0, NULL},
        {N_("/_Copy"),          NULL, addressbook_treenode_copy_cb,   0, NULL},
        {N_("/_Paste"),         NULL, addressbook_treenode_paste_cb,  0, NULL}
@@ -409,18 +423,22 @@ static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
 
 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
 {
+       {N_("/_Edit"),          NULL, addressbook_edit_address_cb,   0, NULL},
+       {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL},
+       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/New _Address"),   NULL, addressbook_new_address_cb,    0, NULL},
        {N_("/New _Group"),     NULL, addressbook_new_group_cb,      0, NULL},
        {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,     0, NULL},
        {N_("/---"),            NULL, NULL, 0, "<Separator>"},
-       {N_("/_Edit"),          NULL, addressbook_edit_address_cb,   0, NULL},
-       {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL},
-       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/C_ut"),           NULL, addressbook_clip_cut_cb,       0, NULL},
        {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}
+       {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},
+       {N_("/_Mail To"),       NULL, addressbook_mail_to_cb,            0, NULL},
+#ifdef USE_LDAP
+       {N_("/_Browse Entry"),  NULL, addressbook_browse_entry_cb,       0, NULL},
+#endif 
 };
 
 /**
@@ -458,15 +476,16 @@ 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") },
+       { LDAPRC_TLS,           N_("Error starting TLS connection") },
        { 0,                    NULL }
 };
 #endif
@@ -523,7 +542,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 +555,7 @@ void addressbook_destroy() {
        }
        if( _addressIndex_ != NULL ) {
                addrindex_free_index( _addressIndex_ );
-               addrindex_teardown( _addressIndex_ );
+               addrindex_teardown();
        }
        _addressSelect_ = NULL;
        _clipBoard_ = NULL;
@@ -551,7 +573,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) {
@@ -622,8 +647,7 @@ static void addressbook_create(void)
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
        gtk_widget_set_size_request(window, ADDRESSBOOK_WIDTH, ADDRESSBOOK_HEIGHT);
-       gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
-       gtk_window_set_wmclass(GTK_WINDOW(window), "addressbook", "Sylpheed");
+       gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
        gtk_widget_realize(window);
 
        g_signal_connect(G_OBJECT(window), "delete_event",
@@ -672,6 +696,9 @@ static void addressbook_create(void)
        g_signal_connect(G_OBJECT(ctree), "button_release_event",
                         G_CALLBACK(addressbook_tree_button_released),
                         NULL);
+       /* TEMPORARY */
+       g_signal_connect(G_OBJECT(ctree), "select_row",
+                        G_CALLBACK(addressbook_select_row_tree), NULL);
 
        clist_vbox = gtk_vbox_new(FALSE, 4);
 
@@ -868,12 +895,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(
@@ -1142,8 +1176,7 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data)
        Compose *compose;
        AddrSelectItem *item;
        AddrItemObject *aio;
-       const gchar *addr;
-       gchar *tmpaddr;
+       gchar *addr;
 
        compose = addrbook.target_compose;
        if( ! compose ) return;
@@ -1164,10 +1197,10 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data)
                aio = item->addressItem;
                if( aio->type == ADDR_ITEM_PERSON ||
                    aio->type == ADDR_ITEM_EMAIL ) {
-                       tmpaddr = addressbook_format_address( aio );
+                       addr = addressbook_format_address( aio );
                        compose_entry_append(
-                               compose, tmpaddr, (ComposeEntryType) data );
-                       g_free( tmpaddr );
+                               compose, addr, (ComposeEntryType) data );
+                       g_free( addr );
                }
                else if( aio->type == ADDR_ITEM_GROUP ) {
                        ItemGroup *group = ( ItemGroup * ) aio;
@@ -1175,11 +1208,11 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data)
                        while( nodeMail ) {
                                ItemEMail *email = nodeMail->data;
 
-                               tmpaddr = addressbook_format_address(
+                               addr = addressbook_format_address(
                                                ( AddrItemObject * ) email );
                                compose_entry_append(
-                                       compose, tmpaddr, (ComposeEntryType) data );
-                               g_free( tmpaddr );
+                                       compose, addr, (ComposeEntryType) data );
+                               g_free( addr );
                                nodeMail = g_list_next( nodeMail );
                        }
                }
@@ -1199,6 +1232,7 @@ static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
        menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
        menu_set_sensitive( addrbook.menu_factory, "/Address/New Group",   sensitive );
        menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder",  sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To",     sensitive );
        gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
        gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
 }
@@ -1289,7 +1323,7 @@ static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode
  * \param column Column number where selected occurred.
  * \param data   Pointer to user data.
  */
-static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
+static gboolean addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
                                      gint column, gpointer data)
 {
        AddressObject *obj = NULL;
@@ -1305,7 +1339,7 @@ static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
 
        if( addrbook.clist ) gtk_clist_clear( GTK_CLIST(addrbook.clist) );
        if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
-       if( obj == NULL ) return;
+       if( obj == NULL ) return FALSE;
 
        addrbook.opened = node;
 
@@ -1314,9 +1348,9 @@ static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
                static gboolean tVal = TRUE;
 
                ads = ADAPTER_DSOURCE(obj);
-               if( ads == NULL ) return;
+               if( ads == NULL ) return FALSE;
                ds = ads->dataSource;
-               if( ds == NULL ) return;                
+               if( ds == NULL ) return FALSE;          
 
                if( addrindex_ds_get_modify_flag( ds ) ) {
                        addrindex_ds_read_data( ds );
@@ -1358,13 +1392,14 @@ static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
        addressbook_menuitem_set_sensitive( obj, node );
 
        addressbook_list_select_clear();
+       
+       return FALSE;
 }
 
-/*
-* 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;
@@ -1377,6 +1412,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;
@@ -1388,6 +1424,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;
@@ -1402,14 +1439,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 );
@@ -1418,15 +1458,21 @@ 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;
+       /* Disable edit or browse if more than one row selected */
+       if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
+               canEdit = FALSE;
+               canBrowse = FALSE;
+       }
 
+       /* Now go finalize menu items */
        menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
        menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
 
@@ -1435,19 +1481,26 @@ static void addressbook_list_menu_setup( void ) {
        menu_set_sensitive( addrbook.list_factory, "/Paste",         canPaste );
        menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );
 
+       menu_set_sensitive( addrbook.list_factory, "/Mail To",       canCopy );
+
        menu_set_sensitive( addrbook.menu_factory, "/Edit/Cut",           canCut );
        menu_set_sensitive( addrbook.menu_factory, "/Edit/Copy",          canCopy );
        menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste",         canPaste );
        menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );
 
-       menu_set_sensitive( addrbook.tree_factory, "/Cut",           canCut );
-       menu_set_sensitive( addrbook.tree_factory, "/Copy",          canCopy );
-       menu_set_sensitive( addrbook.tree_factory, "/Paste",         canPaste );
+       menu_set_sensitive( addrbook.tree_factory, "/Cut",             canCut );
+       menu_set_sensitive( addrbook.tree_factory, "/Copy",            canCopy );
+       menu_set_sensitive( addrbook.tree_factory, "/Paste",           canPaste );
 
-       menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
-       menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",    canEdit );
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Delete",  canDelete );
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
 
        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,
@@ -1457,17 +1510,24 @@ static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
                /* Handle double click */
                if (prefs_common.add_address_by_click &&
                    addrbook.target_compose)
-                       addressbook_to_clicked(NULL, NULL);
+                       addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
                else
                        addressbook_edit_address_cb(NULL, 0, NULL);
        }
 }
 
-/*
+static void addressbook_select_row_tree        (GtkCTree       *ctree,
+                                        GtkCTreeNode   *node,
+                                        gint            column,
+                                        gpointer        data)
+{
+}
+
+/**
  * 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 )
@@ -1497,9 +1557,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_ );
@@ -1507,9 +1567,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_ );
@@ -1517,9 +1577,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;
@@ -1585,9 +1645,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;
@@ -1650,10 +1710,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;
@@ -1701,9 +1761,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();
@@ -1712,9 +1772,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();
@@ -1723,17 +1783,25 @@ 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_ );
 }
 
+/**
+ * Add specified address item to selected address list.
+ * \param aio Address item object.
+ * \param ds  Datasource.
+ */
 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
        gchar *cacheID;
 
@@ -1743,10 +1811,28 @@ static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource
        g_free( cacheID );
 }
 
+/**
+ * Remove specified address item from selected address list.
+ * \param aio Address item object.
+ */
 static void addressbook_list_select_remove( AddrItemObject *aio ) {
        addrselect_list_remove( _addressSelect_, aio );
 }
 
+/**
+ * Invoke EMail compose window with addresses in selected address list.
+ */
+static void addressbook_mail_to_cb( void ) {
+       GList *listAddress;
+
+       if( ! addrselect_test_empty( _addressSelect_ ) ) {
+               listAddress = addrselect_build_list( _addressSelect_ );
+               compose_new_with_list( NULL, listAddress );
+               mgu_free_dlist( listAddress );
+               listAddress = NULL;
+       }
+}
+
 static void addressbook_list_row_selected( GtkCTree *clist,
                                           GtkCTreeNode *node,
                                           gint column,
@@ -1818,6 +1904,7 @@ static gboolean addressbook_list_button_released(GtkWidget *widget,
                                                 GdkEventButton *event,
                                                 gpointer data)
 {
+       return FALSE;
 }
 
 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
@@ -1831,6 +1918,7 @@ static gboolean 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;
@@ -1862,6 +1950,7 @@ static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
                ds = ads->dataSource;
                iface = ds->interface;
                canEdit = TRUE;
+               canDelete = TRUE;
                if( iface->readOnly ) {
                        canTreePaste = FALSE;
                }
@@ -1882,6 +1971,7 @@ static gboolean 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 );
@@ -1890,13 +1980,18 @@ static gboolean 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 );
                }
@@ -1913,7 +2008,7 @@ static gboolean 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 );
@@ -1984,9 +2079,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);
        }
 
 }
@@ -2024,7 +2121,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);
        }
 
 }
@@ -2046,12 +2144,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;
@@ -2153,22 +2251,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;
@@ -2188,57 +2298,108 @@ 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;
+
+               adapter->itemFolder = NULL;
+               /*
+               printf( "remove folder for ::%s::\n", obj->name );
+               printf( "      folder name ::%s::\n", ADDRITEM_NAME(folder) );
+               printf( "-------------- remove results\n" );
+               */
+               addrindex_remove_results( ds, folder );
+               /* printf( "-------------- remove node\n" ); */
+               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;
@@ -2249,7 +2410,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;
@@ -2281,7 +2442,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 );
                        }
                }
        }
@@ -2307,11 +2469,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;
@@ -2680,12 +2842,12 @@ static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFold
        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;
 
@@ -2700,12 +2862,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;
 
@@ -2767,11 +2929,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;
@@ -2795,10 +2957,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);
@@ -2849,13 +3011,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;
 
@@ -3014,11 +3177,13 @@ static gboolean addressbook_convert( AddressIndex *addrIndex ) {
        }
        if( errFlag ) {
                debug_print( "Error\n%s\n", msg );
-               alertpanel( _( "Addressbook conversion error" ), msg, _( "Close" ), NULL, NULL );
+               alertpanel_with_type( _( "Addressbook conversion error" ), msg, _( "Close" ), 
+                                     NULL, NULL, NULL, ALERT_ERROR );
        }
        else if( msg ) {
                debug_print( "Warning\n%s\n", msg );
-               alertpanel( _( "Addressbook conversion" ), msg, _( "Close" ), NULL, NULL );
+               alertpanel_with_type( _( "Addressbook conversion" ), msg, _( "Close" ), 
+                                     NULL, NULL, NULL, ALERT_WARNING );
        }
 
        return retVal;
@@ -3034,7 +3199,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() );
@@ -3054,9 +3219,10 @@ void addressbook_read_file( void ) {
                /* Error reading address book */
                debug_print( "Could not read address index.\n" );
                addrindex_print_index( addrIndex, stdout );
-               alertpanel( _( "Addressbook Error" ),
+               alertpanel_with_type( _( "Addressbook Error" ),
                            _( "Could not read address index" ),
-                           _( "Close" ), NULL, NULL );
+                           _( "Close" ), NULL, NULL, NULL,
+                           ALERT_ERROR);
        }
        debug_print( "done.\n" );
 }
@@ -3111,13 +3277,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 )
@@ -3374,7 +3540,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';
 
@@ -3384,13 +3550,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 );
 }
 
 /**
@@ -3407,7 +3575,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
@@ -3425,25 +3597,61 @@ 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 ID of search request.
+ */
+void addressbook_clear_idler( gint queryID ) {
+       gpointer ptrQID;
+
+       /* Remove idler function */
+       /* printf( "addressbook_clear_idler::%d::\n", queryID ); */
+       ptrQID = GINT_TO_POINTER( queryID );
+       if( ptrQID ) {
+               gtk_idle_remove_by_data( ptrQID );
+       }
+}
+
+/**
+ * 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.
  *
@@ -3455,7 +3663,8 @@ static void addressbook_perform_search(
                AddressDataSource *ds, gchar *searchTerm,
                GtkCTreeNode *pNode )
 {
-       AddressBookFile *abf;
+       AddrBookBase *adbase;
+       AddressCache *cache;
        ItemFolder *folder;
        GtkCTree *ctree;
        GtkCTreeNode *nNode;
@@ -3464,23 +3673,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 );
@@ -3495,8 +3706,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 */
@@ -3505,7 +3716,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,10 +3763,61 @@ static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
                parentNode = node;
        }
        addressbook_perform_search( ds, searchTerm, parentNode );
+       gtk_widget_grab_focus( addrbook.entry );
 
        g_free( searchTerm );
 }
 
+#ifdef USE_LDAP
+/**
+ * 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);
+       if (obj == NULL)
+               return;
+
+       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 ) {
+               browseldap_entry(ds, person->externalID);
+       }
+}
+#endif
+
 /* **********************************************************************
 * Build lookup tables.
 * ***********************************************************************
@@ -3836,10 +4098,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;
@@ -3866,12 +4128,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 ) {
@@ -3881,11 +4145,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 ) {
@@ -3896,10 +4162,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;
@@ -3944,15 +4210,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" );
@@ -3962,33 +4230,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;
@@ -4023,10 +4272,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;
@@ -4061,10 +4310,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;
@@ -4099,11 +4348,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 )
@@ -4136,9 +4385,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;
@@ -4160,9 +4409,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;