reimplement new dynamic LDAP search.
authorMatch Grun <match@dimensional.com>
Sat, 21 Jun 2003 06:23:00 +0000 (06:23 +0000)
committerMatch Grun <match@dimensional.com>
Sat, 21 Jun 2003 06:23:00 +0000 (06:23 +0000)
21 files changed:
ChangeLog.claws
configure.ac
src/Makefile.am
src/addr_compl.c
src/addr_compl.h
src/addrbook.c
src/addressbook.c
src/addressbook.h
src/addrindex.c
src/addrindex.h
src/addritem.c
src/addritem.h
src/editaddress.c
src/editaddress.h
src/editgroup.c
src/editgroup.h
src/editldap.c
src/editldap.h
src/editldap_basedn.c
src/editldap_basedn.h
src/ldapquery.h

index ddeee43..f7e33dd 100644 (file)
@@ -1,3 +1,18 @@
+2003-06-19 [match]     0.9.0claws50
+
+       * src/addressbook.[ch]
+       * src/addrindex.[ch]
+       * src/addr_compl.[ch]
+       * src/editldap.[ch]
+       * src/editldap_basedn.[ch]
+       * src/addritem.[ch]
+       * src/ldapquery.h
+               re-implemented dynamic LDAP search. works without
+               slowdown on display sender with addressbook
+               option.
+       * src/addrbook.c
+               documented code.
+
 2003-06-19 [paul]      0.9.0claws49
 
        * src/compose.c
index a9d69fc..6967048 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=claws49
+EXTRA_VERSION=claws50
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
index 362572d..4fb351d 100644 (file)
@@ -49,7 +49,10 @@ sylpheed_SOURCES = \
        pine.c pine.h \
        importpine.c importpine.h \
        jpilot.c jpilot.h \
-       syldap.c syldap.h \
+       ldapctrl.c ldapctrl.h \
+       ldapquery.c ldapquery.h \
+       ldapserver.c ldapserver.h \
+       ldaputil.c ldaputil.h \
        editbook.c editbook.h \
        editgroup.c editgroup.h \
        editaddress.c editaddress.h \
index 3403ce3..15e9781 100644 (file)
 #include "addressbook.h"
 #include "addr_compl.h"
 #include "utils.h"
+#include <pthread.h>
 
-/* How it works:
+/*
+ * How it works:
  *
  * The address book is read into memory. We set up an address list
  * containing all address book entries. Next we make the completion
  * any of those words).
  */ 
        
-/* address_entry - structure which refers to the original address entry in the
- * address book 
+/**
+ * Reference to address index.
+ */
+static AddressIndex *_addressIndex_ = NULL;
+
+/**
+ * address_entry - structure which refers to the original address entry in the
+ * address book .
  */
 typedef struct
 {
@@ -70,7 +78,8 @@ typedef struct
        gchar *address;
 } address_entry;
 
-/* completion_entry - structure used to complete addresses, with a reference
+/**
+ * completion_entry - structure used to complete addresses, with a reference
  * the the real address information.
  */
 typedef struct
@@ -99,8 +108,9 @@ static gchar    *g_completion_prefix;        /* last prefix. (this is cached here
 
 /*******************************************************************************/
 
-/* completion_func() - used by GTK to find the string data to be used for 
- * completion 
+/**
+ * Function used by GTK to find the string data to be used for completion.
+ * \param data Pointer to data being processed.
  */
 static gchar *completion_func(gpointer data)
 {
@@ -109,12 +119,18 @@ static gchar *completion_func(gpointer data)
        return ((completion_entry *)data)->string;
 } 
 
+/**
+ * Initialize all completion index data.
+ */
 static void init_all(void)
 {
        g_completion = g_completion_new(completion_func);
        g_return_if_fail(g_completion != NULL);
 }
 
+/**
+ * Free up all completion index data.
+ */
 static void free_all(void)
 {
        GList *walk;
@@ -142,6 +158,11 @@ static void free_all(void)
        g_completion = NULL;
 }
 
+/**
+ * Append specified address entry to the index.
+ * \param str Index string value.
+ * \param ae  Entry containing address data.
+ */
 static void add_address1(const char *str, address_entry *ae)
 {
        completion_entry *ce1;
@@ -154,8 +175,14 @@ static void add_address1(const char *str, address_entry *ae)
        g_completion_list = g_list_prepend(g_completion_list, ce1);
 }
 
-/* add_address() - adds address to the completion list. this function looks
- * complicated, but it's only allocation checks.
+/**
+ * Adds address to the completion list. This function looks complicated, but
+ * it's only allocation checks. Each value will be included in the index.
+ * \param name    Recipient name.
+ * \param address EMail address.
+ * \param alias   Alias to append.
+ * \return <code>0</code> if entry appended successfully, or <code>-1</code>
+ *         if failure.
  */
 static gint add_address(const gchar *name, const gchar *address, const gchar *alias)
 {
@@ -170,7 +197,7 @@ static gint add_address(const gchar *name, const gchar *address, const gchar *al
        ae->name    = g_strdup(name);
        ae->address = g_strdup(address);                
 
-       g_address_list    = g_list_prepend(g_address_list,    ae);
+       g_address_list = g_list_prepend(g_address_list, ae);
 
        add_address1(name, ae);
        add_address1(address, ae);
@@ -179,16 +206,48 @@ static gint add_address(const gchar *name, const gchar *address, const gchar *al
        return 0;
 }
 
-/* read_address_book()
+/**
+ * Read address book, creating all entries in the completion index.
  */ 
 static void read_address_book(void) {  
-       addressbook_load_completion( add_address );
+       addrindex_load_completion( _addressIndex_, add_address );
        g_address_list = g_list_reverse(g_address_list);
        g_completion_list = g_list_reverse(g_completion_list);
 }
 
-/* start_address_completion() - returns the number of addresses 
- * that should be matched for completion.
+/**
+ * Test whether there is a completion pending.
+ * \return <code>TRUE</code> if pending.
+ */
+static gboolean is_completion_pending(void)
+{
+       /* check if completion pending, i.e. we might satisfy a request for the next
+        * or previous address */
+        return g_completion_count;
+}
+
+/**
+ * Clear the completion cache.
+ */
+static void clear_completion_cache(void)
+{
+       if (is_completion_pending()) {
+               if (g_completion_prefix)
+                       g_free(g_completion_prefix);
+
+               if (g_completion_addresses) {
+                       g_slist_free(g_completion_addresses);
+                       g_completion_addresses = NULL;
+               }
+
+               g_completion_count = g_completion_next = 0;
+       }
+}
+
+/**
+ * Prepare completion index. This function should be called prior to attempting
+ * address completion.
+ * \return The number of addresses in the completion list.
  */
 gint start_address_completion(void)
 {
@@ -207,12 +266,16 @@ gint start_address_completion(void)
        return g_list_length(g_completion_list);
 }
 
-/* get_address_from_edit() - returns a possible address (or a part)
- * from an entry box. To make life easier, we only look at the last valid address 
- * component; address completion only works at the last string component in
- * the entry box. 
- */ 
-gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
+/**
+ * Retrieve a possible address (or a part) from an entry box. To make life
+ * easier, we only look at the last valid address component; address
+ * completion only works at the last string component in the entry box.
+ *
+ * \param entry Address entry field.
+ * \param start_pos Address of start position of address.
+ * \return Possible address.
+ */
+static gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
 {
        const gchar *edit_text;
        gint cur_pos;
@@ -281,23 +344,29 @@ gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
        return str;
 } 
 
-/* replace_address_in_edit() - replaces an incompleted address with a completed one.
+/**
+ * Replace an incompleted address with a completed one.
+ * \param entry     Address entry field.
+ * \param newtext   New text.
+ * \param start_pos Insertion point in entry field.
  */
-void replace_address_in_edit(GtkEntry *entry, const gchar *newtext,
+static void replace_address_in_edit(GtkEntry *entry, const gchar *newtext,
                             gint start_pos)
 {
        if (!newtext) return;
-
        gtk_editable_delete_text(GTK_EDITABLE(entry), start_pos, -1);
        gtk_editable_insert_text(GTK_EDITABLE(entry), newtext, strlen(newtext),
                                 &start_pos);
        gtk_editable_set_position(GTK_EDITABLE(entry), -1);
 }
 
-/* complete_address() - tries to complete an addres, and returns the
- * number of addresses found. use get_complete_address() to get one.
- * returns zero if no match was found, otherwise the number of addresses,
- * with the original prefix at index 0. 
+/**
+ * Attempt to complete an address, and returns the number of addresses found.
+ * Use <code>get_complete_address()</code> to get an entry from the index.
+ *
+ * \param  str Search string to find.
+ * \return Zero if no match was found, otherwise the number of addresses; the
+ *         original prefix (search string) will appear at index 0. 
  */
 guint complete_address(const gchar *str)
 {
@@ -343,8 +412,11 @@ guint complete_address(const gchar *str)
        return count;
 }
 
-/* get_complete_address() - returns a complete address. the returned
- * string should be freed 
+/**
+ * Return a complete address from the index.
+ * \param index Index of entry that was found (by the previous call to
+ *              <code>complete_address()</code>
+ * \return Completed address string; this should be freed when done.
  */
 gchar *get_complete_address(gint index)
 {
@@ -361,8 +433,7 @@ gchar *get_complete_address(gint index)
                        if (p != NULL) {
                                if (!p->name || p->name[0] == '\0')
                                        address = g_strdup_printf(p->address);
-                               else if (p->name[0] != '"' &&
-                                        strpbrk(p->name, ",.[]<>") != NULL)
+                               else if (strchr_with_skip_quote(p->name, '"', ','))
                                        address = g_strdup_printf
                                                ("\"%s\" <%s>", p->name, p->address);
                                else
@@ -375,7 +446,11 @@ gchar *get_complete_address(gint index)
        return address;
 }
 
-gchar *get_next_complete_address(void)
+/**
+ * Return the next complete address match from the completion index.
+ * \return Completed address string; this should be freed when done.
+ */
+static gchar *get_next_complete_address(void)
 {
        if (is_completion_pending()) {
                gchar *res;
@@ -390,7 +465,11 @@ gchar *get_next_complete_address(void)
                return NULL;
 }
 
-gchar *get_prev_complete_address(void)
+/**
+ * Return the previous complete address match from the completion index.
+ * \return Completed address string; this should be freed when done.
+ */
+static gchar *get_prev_complete_address(void)
 {
        if (is_completion_pending()) {
                int n = g_completion_next - 2;
@@ -407,7 +486,11 @@ gchar *get_prev_complete_address(void)
                return NULL;
 }
 
-guint get_completion_count(void)
+/**
+ * Return a count of the completed matches in the completion index.
+ * \return Number of matched entries.
+ */
+static guint get_completion_count(void)
 {
        if (is_completion_pending())
                return g_completion_count;
@@ -415,31 +498,11 @@ guint get_completion_count(void)
                return 0;
 }
 
-/* should clear up anything after complete_address() */
-void clear_completion_cache(void)
-{
-       if (is_completion_pending()) {
-               if (g_completion_prefix)
-                       g_free(g_completion_prefix);
-
-               if (g_completion_addresses) {
-                       g_slist_free(g_completion_addresses);
-                       g_completion_addresses = NULL;
-               }
-
-               g_completion_count = g_completion_next = 0;
-       }
-}
-
-gboolean is_completion_pending(void)
-{
-       /* check if completion pending, i.e. we might satisfy a request for the next
-        * or previous address */
-        return g_completion_count;
-}
-
-/* invalidate_address_completion() - should be called if address book
- * changed; 
+/**
+ * Invalidate address completion index. This function should be called whenever
+ * the address book changes. This forces data to be read into the completion
+ * data.
+ * \return Number of entries in index.
  */
 gint invalidate_address_completion(void)
 {
@@ -449,14 +512,18 @@ gint invalidate_address_completion(void)
                free_all();
                init_all();
                read_address_book();
-               if (g_completion_list)
-                       g_completion_add_items(g_completion, g_completion_list);
+               g_completion_add_items(g_completion, g_completion_list);
                clear_completion_cache();
        }
 
        return g_list_length(g_completion_list);
 }
 
+/**
+ * Finished with completion index. This function should be called after
+ * matching addresses.
+ * \return Reference count.
+ */
 gint end_address_completion(void)
 {
        clear_completion_cache();
@@ -469,14 +536,49 @@ gint end_address_completion(void)
        return g_ref_count; 
 }
 
+/*
+ * Define the structure of the completion window.
+ */
+typedef struct _CompletionWindow CompletionWindow;
+struct _CompletionWindow {
+       gint      listCount;
+       gchar     *searchTerm;
+       GtkWidget *window;
+       GtkWidget *entry;
+       GtkWidget *clist;
+};
+
+/**
+ * Completion window.
+ */
+static CompletionWindow *_compWindow_ = NULL;
+
+/**
+ * Mutex to protect callback from multiple threads.
+ */
+static pthread_mutex_t _completionMutex_ = PTHREAD_MUTEX_INITIALIZER;
 
-/* address completion entry ui. the ui (completion list was inspired by galeon's
+/**
+ * Completion queue list.
+ */
+static GList *_displayQueue_ = NULL;
+
+/**
+ * Current query ID.
+ */
+static gint _queryID_ = 0;
+
+/**
+ * Completion idle ID.
+ */
+static gint _completionIdleID_ = 0;
+
+/*
+ * address completion entry ui. the ui (completion list was inspired by galeon's
  * auto completion list). remaining things powered by sylpheed's completion engine.
  */
 
-#define ENTRY_DATA_TAB_HOOK    "tab_hook"                      /* used to lookup entry */
-#define WINDOW_DATA_COMPL_ENTRY        "compl_entry"   /* used to store entry for compl. window */
-#define WINDOW_DATA_COMPL_CLIST "compl_clist"  /* used to store clist for compl. window */
+#define ENTRY_DATA_TAB_HOOK    "tab_hook"      /* used to lookup entry */
 
 static void address_completion_mainwindow_set_focus    (GtkWindow   *window,
                                                         GtkWidget   *widget,
@@ -493,38 +595,111 @@ static void completion_window_select_row(GtkCList         *clist,
                                         gint             row,
                                         gint             col,
                                         GdkEvent        *event,
-                                        GtkWidget      **completion_window);
+                                        CompletionWindow *compWin );
+
 static gboolean completion_window_button_press
                                        (GtkWidget       *widget,
                                         GdkEventButton  *event,
-                                        GtkWidget      **completion_window);
+                                        CompletionWindow *compWin );
+
 static gboolean completion_window_key_press
                                        (GtkWidget       *widget,
                                         GdkEventKey     *event,
-                                        GtkWidget      **completion_window);
+                                        CompletionWindow *compWin );
+static void address_completion_create_completion_window( GtkEntry *entry_ );
+
+/**
+ * Create a completion window object.
+ * \return Initialized completion window.
+ */
+static CompletionWindow *addrcompl_create_window( void ) {
+       CompletionWindow *cw;
+
+       cw = g_new0( CompletionWindow, 1 );
+       cw->listCount = 0;
+       cw->searchTerm = NULL;
+       cw->window = NULL;
+       cw->entry = NULL;
+       cw->clist = NULL;
 
+       return cw;      
+}
+
+/**
+ * Destroy completion window.
+ * \param cw Window to destroy.
+ */
+static void addrcompl_destroy_window( CompletionWindow *cw ) {
+       /* Remove idler function... or application may not terminate */
+       if( _completionIdleID_ != 0 ) {
+               gtk_idle_remove( _completionIdleID_ );
+               _completionIdleID_ = 0;
+       }
+
+       /* Now destroy window */        
+       if( cw ) {
+               /* Clear references to widgets */
+               cw->entry = NULL;
+               cw->clist = NULL;
+
+               /* Free objects */
+               if( cw->window ) {
+                       gtk_widget_hide( cw->window );
+                       gtk_widget_destroy( cw->window );
+               }
+               cw->window = NULL;
+       }
+}
+
+/**
+ * Free up completion window.
+ * \param cw Window to free.
+ */
+static void addrcompl_free_window( CompletionWindow *cw ) {
+       if( cw ) {
+               addrcompl_destroy_window( cw );
 
+               g_free( cw->searchTerm );
+               cw->searchTerm = NULL;
+
+               /* Clear references */          
+               cw->listCount = 0;
+
+               /* Free object */               
+               g_free( cw );
+       }
+}
+
+/**
+ * Select specified row in list.
+ * \param clist List to process.
+ * \param row   Row to select.
+ */
 static void completion_window_advance_to_row(GtkCList *clist, gint row)
 {
        g_return_if_fail(row < g_completion_count);
        gtk_clist_select_row(clist, row, 0);
 }
 
+/**
+ * Advance selection to previous/next item in list.
+ * \param clist   List to process.
+ * \param forward Set to <i>TRUE</i> to select next or <i>FALSE</i> for
+ *                previous entry.
+ */
 static void completion_window_advance_selection(GtkCList *clist, gboolean forward)
 {
        int row;
 
        g_return_if_fail(clist != NULL);
-       g_return_if_fail(clist->selection != NULL);
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-
-       row = forward ? (row + 1) % g_completion_count :
-                       (row - 1) < 0 ? g_completion_count - 1 : row - 1;
-
-       gtk_clist_freeze(clist);
-       completion_window_advance_to_row(clist, row);                                   
-       gtk_clist_thaw(clist);
+       if( clist->selection ) {
+               row = GPOINTER_TO_INT(clist->selection->data);
+               row = forward ? ( row + 1 ) : ( row - 1 );
+               gtk_clist_freeze(clist);
+               gtk_clist_select_row(clist, row, 0);
+               gtk_clist_thaw(clist);
+       }
 }
 
 #if 0
@@ -558,27 +733,230 @@ static void completion_window_accept_selection(GtkWidget **window,
 }
 #endif
 
-/* completion_window_apply_selection() - apply the current selection in the
- * clist */
+/**
+ * Resize window to accommodate maximum number of address entries.
+ * \param cw Completion window.
+ */
+static void addrcompl_resize_window( CompletionWindow *cw ) {
+       GtkRequisition r;
+       gint x, y, width, height, depth;
+
+       /* Get current geometry of window */
+       gdk_window_get_geometry( cw->window->window, &x, &y, &width, &height, &depth );
+
+       gtk_widget_size_request( cw->clist, &r );
+       gtk_widget_set_usize( cw->window, width, r.height );
+       gtk_widget_show_all( cw->window );
+       gtk_widget_size_request( cw->clist, &r );
+
+       /* Adjust window height to available screen space */
+       if( ( y + r.height ) > gdk_screen_height() ) {
+               gtk_window_set_policy( GTK_WINDOW( cw->window ), TRUE, FALSE, FALSE );
+               gtk_widget_set_usize( cw->window, width, gdk_screen_height() - y );
+       }
+}
+
+/**
+ * Add an address the completion window address list.
+ * \param cw      Completion window.
+ * \param address Address to add.
+ */
+static void addrcompl_add_entry( CompletionWindow *cw, gchar *address ) {
+       gchar *text[] = { NULL, NULL };
+
+       /* printf( "\t\tAdding :%s\n", address ); */
+       text[0] = address;
+       gtk_clist_append( GTK_CLIST(cw->clist), text );
+       cw->listCount++;
+
+       /* Resize window */
+       addrcompl_resize_window( cw );
+       gtk_grab_add( cw->window );
+
+       if( cw->listCount == 1 ) {
+               /* Select first row for now */
+               gtk_clist_select_row( GTK_CLIST(cw->clist), 0, 0);
+       }
+       else if( cw->listCount == 2 ) {
+               /* Move off first row */
+               gtk_clist_select_row( GTK_CLIST(cw->clist), 1, 0);
+       }
+}
+
+/**
+ * Completion idle function. This function is called by the main (UI) thread
+ * during UI idle time while an address search is in progress. Items from the
+ * display queue are processed and appended to the address list.
+ *
+ * \param data Target completion window to receive email addresses.
+ * \return <i>TRUE</i> to ensure that idle event do not get ignored.
+ */
+static gboolean addrcompl_idle( gpointer data ) {
+       GList *node;
+       gchar *address;
+       CompletionWindow *cw;
+
+       /* Process all entries in display queue */
+       pthread_mutex_lock( & _completionMutex_ );
+       if( _displayQueue_ ) {
+               cw = data;
+               node = _displayQueue_;
+               while( node ) {
+                       address = node->data;
+                       /* printf( "address ::: %s :::\n", address ); */
+                       addrcompl_add_entry( cw, address );
+                       g_free( address );
+                       node = g_list_next( node );
+               }
+               g_list_free( _displayQueue_ );
+               _displayQueue_ = NULL;
+       }
+       pthread_mutex_unlock( & _completionMutex_ );
+
+       return TRUE;
+}
+
+/**
+ * Callback entry point. The background thread (if any) appends the address
+ * list to the display queue.
+ * \param queryID    Query ID of search request.
+ * \param listEMail  List of zero of more email objects that met search
+ *                   criteria.
+ * \param target     Target object to received data.
+ */
+static gint addrcompl_callback(
+       gint queryID, GList *listEMail, gpointer target )
+{
+       GList *node;
+       gchar *address;
+
+       /* printf( "addrcompl_callback::queryID=%d\n", queryID ); */
+       pthread_mutex_lock( & _completionMutex_ );
+       if( queryID == _queryID_ ) {
+               /* Append contents to end of display queue */
+               node = listEMail;
+               while( node ) {
+                       ItemEMail *email = node->data;
+                       if( target ) {
+                               address = addritem_format_email( email );
+                               /* printf( "\temail/address ::%s::\n", address ); */
+                               _displayQueue_ = g_list_append( _displayQueue_, address );
+                       }
+                       node = g_list_next( node );
+               }
+       }
+       pthread_mutex_unlock( & _completionMutex_ );
+       /* printf( "addrcompl_callback...done\n" ); */
+}
+
+/**
+ * Clear the display queue.
+ */
+static void addrcompl_clear_queue( void ) {
+       /* Clear out display queue */
+       pthread_mutex_lock( & _completionMutex_ );
+
+       g_list_free( _displayQueue_ );
+       _displayQueue_ = NULL;
+
+       pthread_mutex_unlock( & _completionMutex_ );
+}
+
+/**
+ * Add a single address entry into the display queue.
+ * \param address Address to append.
+ */
+static void addrcompl_add_queue( gchar *address ) {
+       pthread_mutex_lock( & _completionMutex_ );
+       _displayQueue_ = g_list_append( _displayQueue_, address );
+       pthread_mutex_unlock( & _completionMutex_ );
+}
+
+/**
+ * Load list with entries from local completion index.
+ * \param cw Completion window.
+ */
+static void addrcompl_load_local( CompletionWindow *cw ) {
+       guint count = 0;
+
+       for (count = 0; count < get_completion_count(); count++) {
+               gchar *address;
+
+               address = get_complete_address( count );
+               /* printf( "\taddress ::%s::\n", address ); */
+
+               /* Append contents to end of display queue */
+               addrcompl_add_queue( address );
+       }
+}
+
+/**
+ * Start the search.
+ */
+static void addrcompl_start_search( void ) {
+       gchar *searchTerm;
+
+       searchTerm = g_strdup( _compWindow_->searchTerm );
+
+       /* Setup the search */
+       _queryID_ = addrindex_setup_search(
+               _addressIndex_, searchTerm, _compWindow_, addrcompl_callback );
+       g_free( searchTerm );
+       /* printf( "addrcompl_start_search::queryID=%d\n", _queryID_ ); */
+
+       /* Load local stuff */
+       addrcompl_load_local( _compWindow_ );
+
+       /* Sit back and wait until something happens */
+       _completionIdleID_ =
+               gtk_idle_add( ( GtkFunction ) addrcompl_idle, _compWindow_ );
+       /* printf( "addrindex_start_search::queryID=%d\n", _queryID_ ); */
+
+       addrindex_start_search( _addressIndex_, _queryID_ );
+}
+
+/**
+ * Apply the current selection in the list to the entry field. Focus is also
+ * moved to the next widget so that Tab key works correctly.
+ * \param clist List to process.
+ * \param entry Address entry field.
+ */
 static void completion_window_apply_selection(GtkCList *clist, GtkEntry *entry)
 {
        gchar *address = NULL, *text = NULL;
        gint   cursor_pos, row;
+       GtkWidget *parent;
 
        g_return_if_fail(clist != NULL);
        g_return_if_fail(entry != NULL);
        g_return_if_fail(clist->selection != NULL);
 
+       /* First remove the idler */
+       if( _completionIdleID_ != 0 ) {
+               gtk_idle_remove( _completionIdleID_ );
+               _completionIdleID_ = 0;
+       }
+
+       /* Process selected item */
        row = GPOINTER_TO_INT(clist->selection->data);
 
        address = get_address_from_edit(entry, &cursor_pos);
        g_free(address);
        gtk_clist_get_text(clist, row, 0, &text);
        replace_address_in_edit(entry, text, cursor_pos);
+
+       /* Move focus to next widget */
+       parent = GTK_WIDGET(entry)->parent;
+       if( parent ) {
+               gtk_container_focus( GTK_CONTAINER(parent), GTK_DIR_TAB_FORWARD );
+       }
 }
 
-/* should be called when creating the main window containing address
- * completion entries */
+/**
+ * Start address completion. Should be called when creating the main window
+ * containing address completion entries.
+ * \param mainwindow Main window.
+ */
 void address_completion_start(GtkWidget *mainwindow)
 {
        start_address_completion();
@@ -589,10 +967,16 @@ void address_completion_start(GtkWidget *mainwindow)
                           mainwindow);
 }
 
-/* Need unique data to make unregistering signal handler possible for the auto
- * completed entry */
+/**
+ * Need unique data to make unregistering signal handler possible for the auto
+ * completed entry.
+ */
 #define COMPLETION_UNIQUE_DATA (GINT_TO_POINTER(0xfeefaa))
 
+/**
+ * Register specified entry widget for address completion.
+ * \param entry Address entry field.
+ */
 void address_completion_register_entry(GtkEntry *entry)
 {
        g_return_if_fail(entry != NULL);
@@ -611,6 +995,10 @@ void address_completion_register_entry(GtkEntry *entry)
                                0); /* magic */
 }
 
+/**
+ * Unregister specified entry widget from address completion operations.
+ * \param entry Address entry field.
+ */
 void address_completion_unregister_entry(GtkEntry *entry)
 {
        GtkObject *entry_obj;
@@ -631,10 +1019,12 @@ void address_completion_unregister_entry(GtkEntry *entry)
                COMPLETION_UNIQUE_DATA);
 }
 
-/* should be called when main window with address completion entries
- * terminates.
- * NOTE: this function assumes that it is called upon destruction of
- * the window */
+/**
+ * End address completion. Should be called when main window with address
+ * completion entries terminates. NOTE: this function assumes that it is
+ * called upon destruction of the window.
+ * \param mainwindow Main window.
+ */
 void address_completion_end(GtkWidget *mainwindow)
 {
        /* if address_completion_end() is really called on closing the window,
@@ -651,15 +1041,21 @@ static void address_completion_mainwindow_set_focus(GtkWindow *window,
                clear_completion_cache();
 }
 
-/* watch for tabs in one of the address entries. if no tab then clear the
- * completion cache */
+/**
+ * Listener that watches for tab or other keystroke in address entry field.
+ * \param entry Address entry field.
+ * \param ev    Event object.
+ * \param data  User data.
+ * \return <i>TRUE</i>.
+ */
 static gboolean address_completion_entry_key_pressed(GtkEntry    *entry,
                                                     GdkEventKey *ev,
                                                     gpointer     data)
 {
        if (ev->keyval == GDK_Tab) {
-               if (address_completion_complete_address_in_entry(entry, TRUE)) {
-                       address_completion_create_completion_window(entry);
+               addrcompl_clear_queue();
+
+               if( address_completion_complete_address_in_entry( entry, TRUE ) ) {
                        /* route a void character to the default handler */
                        /* this is a dirty hack; we're actually changing a key
                         * reported by the system. */
@@ -667,7 +1063,14 @@ static gboolean address_completion_entry_key_pressed(GtkEntry    *entry,
                        ev->state &= ~GDK_SHIFT_MASK;
                        gtk_signal_emit_stop_by_name(GTK_OBJECT(entry),
                                                     "key_press_event");
-               } else {
+
+                       /* Create window */                     
+                       address_completion_create_completion_window(entry);
+
+                       /* Start remote queries */
+                       addrcompl_start_search();
+               }
+               else {
                        /* old behaviour */
                }
        } else if (ev->keyval == GDK_Shift_L
@@ -686,174 +1089,168 @@ static gboolean address_completion_entry_key_pressed(GtkEntry    *entry,
 
        return TRUE;
 }
-
-/* initialize the completion cache and put first completed string
- * in entry. this function used to do back cycling but this is not
- * currently used. since the address completion behaviour has been
- * changed regularly, we keep the feature in case someone changes
- * his / her mind again. :) */
+/**
+ * Initialize search term for address completion.
+ * \param entry Address entry field.
+ */
 static gboolean address_completion_complete_address_in_entry(GtkEntry *entry,
                                                             gboolean  next)
 {
        gint ncount, cursor_pos;
-       gchar *address, *new = NULL;
-       gboolean completed = FALSE;
+       gchar *searchTerm, *new = NULL;
 
        g_return_val_if_fail(entry != NULL, FALSE);
 
        if (!GTK_WIDGET_HAS_FOCUS(entry)) return FALSE;
 
        /* get an address component from the cursor */
-       address = get_address_from_edit(entry, &cursor_pos);
-       if (!address) return FALSE;
+       searchTerm = get_address_from_edit( entry, &cursor_pos );
+       if( ! searchTerm ) return FALSE;
+       /* printf( "search for :::%s:::\n", searchTerm ); */
 
-       /* still something in the cache */
-       if (is_completion_pending()) {
-               new = next ? get_next_complete_address() :
-                       get_prev_complete_address();
-       } else {
-               if (0 < (ncount = complete_address(address)))
-                       new = get_next_complete_address();
+       /* Clear any existing search */
+       if( _compWindow_->searchTerm ) {
+               g_free( _compWindow_->searchTerm );
        }
+       _compWindow_->searchTerm = g_strdup( searchTerm );
 
-       if (new) {
-               /* prevent "change" signal */
-               /* replace_address_in_edit(entry, new, cursor_pos); */
-               g_free(new);
-               completed = TRUE;
+       /* Perform search on local completion index */
+       ncount = complete_address( searchTerm );
+       if( 0 < ncount ) {
+               new = get_next_complete_address();
+               g_free( new );
        }
 
-       g_free(address);
+       /* Make sure that drop-down appears uniform! */
+       if( ncount == 0 ) {
+               addrcompl_add_queue( g_strdup( searchTerm ) );
+       }
+       g_free( searchTerm );
 
-       return completed;
+       return TRUE;
 }
 
-static void address_completion_create_completion_window(GtkEntry *entry_)
+/**
+ * Create new address completion window for specified entry.
+ * \param entry_ Entry widget to associate with window.
+ */
+static void address_completion_create_completion_window( GtkEntry *entry_ )
 {
-       static GtkWidget *completion_window;
        gint x, y, height, width, depth;
        GtkWidget *scroll, *clist;
        GtkRequisition r;
-       guint count = 0;
+       GtkWidget *window;
        GtkWidget *entry = GTK_WIDGET(entry_);
 
-       if (completion_window) {
-               gtk_widget_destroy(completion_window);
-               completion_window = NULL;
-       }
-
-       scroll = gtk_scrolled_window_new(NULL, NULL);
+       /* Create new window and list */
+       window = gtk_window_new(GTK_WINDOW_POPUP);
        clist  = gtk_clist_new(1);
-       gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE);
-       
-       completion_window = gtk_window_new(GTK_WINDOW_POPUP);
 
+       /* Destroy any existing window */
+       addrcompl_destroy_window( _compWindow_ );
+
+       /* Create new object */
+       _compWindow_->window = window;
+       _compWindow_->entry = entry;
+       _compWindow_->clist = clist;
+       _compWindow_->listCount = 0;
+
+       scroll = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
                                       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-       gtk_container_add(GTK_CONTAINER(completion_window), scroll);
+       gtk_container_add(GTK_CONTAINER(window), scroll);
        gtk_container_add(GTK_CONTAINER(scroll), clist);
+       gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE);
 
-       /* set the unique data so we can always get back the entry and
-        * clist window to which this completion window has been attached */
-       gtk_object_set_data(GTK_OBJECT(completion_window),
-                           WINDOW_DATA_COMPL_ENTRY, entry_);
-       gtk_object_set_data(GTK_OBJECT(completion_window),
-                           WINDOW_DATA_COMPL_CLIST, clist);
-
-       gtk_signal_connect(GTK_OBJECT(clist), "select_row",
-                          GTK_SIGNAL_FUNC(completion_window_select_row),
-                          &completion_window);
-
-       for (count = 0; count < get_completion_count(); count++) {
-               gchar *text[] = {NULL, NULL};
-
-               text[0] = get_complete_address(count);
-               gtk_clist_append(GTK_CLIST(clist), text);
-               g_free(text[0]);
-       }
-
+       /* Use entry widget to create initial window */
        gdk_window_get_geometry(entry->window, &x, &y, &width, &height, &depth);
        gdk_window_get_deskrelative_origin (entry->window, &x, &y);
        y += height;
-       gtk_widget_set_uposition(completion_window, x, y);
-
-       gtk_widget_size_request(clist, &r);
-       gtk_widget_set_usize(completion_window, width, r.height);
-       gtk_widget_show_all(completion_window);
-       gtk_widget_size_request(clist, &r);
+       gtk_widget_set_uposition(window, x, y);
 
-       if ((y + r.height) > gdk_screen_height()) {
-               gtk_window_set_policy(GTK_WINDOW(completion_window),
-                                     TRUE, FALSE, FALSE);
-               gtk_widget_set_usize(completion_window, width,
-                                    gdk_screen_height () - y);
-       }
+       /* Resize window to fit initial (empty) address list */
+       gtk_widget_size_request( clist, &r );
+       gtk_widget_set_usize( window, width, r.height );
+       gtk_widget_show_all( window );
+       gtk_widget_size_request( clist, &r );
 
-       gtk_signal_connect(GTK_OBJECT(completion_window),
+       /* Setup handlers */
+       gtk_signal_connect(GTK_OBJECT(clist), "select_row",
+                          GTK_SIGNAL_FUNC(completion_window_select_row),
+                          _compWindow_ );
+       gtk_signal_connect(GTK_OBJECT(window),
                           "button-press-event",
                           GTK_SIGNAL_FUNC(completion_window_button_press),
-                          &completion_window);
-       gtk_signal_connect(GTK_OBJECT(completion_window),
+                          _compWindow_ );
+       gtk_signal_connect(GTK_OBJECT(window),
                           "key-press-event",
                           GTK_SIGNAL_FUNC(completion_window_key_press),
-                          &completion_window);
-       gdk_pointer_grab(completion_window->window, TRUE,
+                          _compWindow_ );
+       gdk_pointer_grab(window->window, TRUE,
                         GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
                         GDK_BUTTON_RELEASE_MASK,
                         NULL, NULL, GDK_CURRENT_TIME);
-       gtk_grab_add(completion_window);
+       gtk_grab_add( window );
 
        /* this gets rid of the irritating focus rectangle that doesn't
         * follow the selection */
        GTK_WIDGET_UNSET_FLAGS(clist, GTK_CAN_FOCUS);
-       gtk_clist_select_row(GTK_CLIST(clist), 1, 0);
 }
 
-
-/* row selection sends completed address to entry.
- * note: event is NULL if selected by anything else than a mouse button. */
+/**
+ * Respond to select row event in clist object. selection sends completed
+ * address to entry. Note: event is NULL if selected by anything else than a
+ * mouse button.
+ * \param widget   Window object.
+ * \param event    Event.
+ * \param compWind Reference to completion window.
+ */
 static void completion_window_select_row(GtkCList *clist, gint row, gint col,
                                         GdkEvent *event,
-                                        GtkWidget **completion_window)
+                                        CompletionWindow *compWin )
 {
        GtkEntry *entry;
 
-       g_return_if_fail(completion_window != NULL);
-       g_return_if_fail(*completion_window != NULL);
+       g_return_if_fail(compWin != NULL);
 
-       entry = GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(*completion_window),
-                                             WINDOW_DATA_COMPL_ENTRY));
+       entry = GTK_ENTRY(compWin->entry);
        g_return_if_fail(entry != NULL);
 
-       completion_window_apply_selection(clist, entry);
-
+       /* Don't update unless user actually selects ! */
        if (!event || event->type != GDK_BUTTON_RELEASE)
                return;
 
+       /* User selected address by releasing the mouse in drop-down list*/
+       completion_window_apply_selection( clist, entry );
+
        clear_completion_cache();
-       gtk_widget_destroy(*completion_window);
-       *completion_window = NULL;
+       addrcompl_destroy_window( _compWindow_ );
 }
 
-/* completion_window_button_press() - check is mouse click is anywhere
- * else (not in the completion window). in that case the completion
- * window is destroyed, and the original prefix is restored */
+/**
+ * Respond to button press in completion window. Check if mouse click is
+ * anywhere outside the completion window. In that case the completion
+ * window is destroyed, and the original searchTerm is restored.
+ *
+ * \param widget   Window object.
+ * \param event    Event.
+ * \param compWin  Reference to completion window.
+ */
 static gboolean completion_window_button_press(GtkWidget *widget,
                                               GdkEventButton *event,
-                                              GtkWidget **completion_window)
+                                              CompletionWindow *compWin )
 {
        GtkWidget *event_widget, *entry;
-       gchar *prefix;
+       gchar *searchTerm;
        gint cursor_pos;
        gboolean restore = TRUE;
 
-       g_return_val_if_fail(completion_window != NULL, FALSE);
-       g_return_val_if_fail(*completion_window != NULL, FALSE);
+       g_return_val_if_fail(compWin != NULL, FALSE);
 
-       entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(*completion_window),
-                                              WINDOW_DATA_COMPL_ENTRY));
+       entry = compWin->entry;
        g_return_val_if_fail(entry != NULL, FALSE);
 
+       /* Test where mouse was clicked */
        event_widget = gtk_get_event_widget((GdkEvent *)event);
        if (event_widget != widget) {
                while (event_widget) {
@@ -863,41 +1260,43 @@ static gboolean completion_window_button_press(GtkWidget *widget,
                                restore = FALSE;
                                break;
                        }
-                   event_widget = event_widget->parent;
+                       event_widget = event_widget->parent;
                }
        }
 
        if (restore) {
-               prefix = get_complete_address(0);
+               /* Clicked outside of completion window - restore */
+               searchTerm = _compWindow_->searchTerm;
                g_free(get_address_from_edit(GTK_ENTRY(entry), &cursor_pos));
-               replace_address_in_edit(GTK_ENTRY(entry), prefix, cursor_pos);
-               g_free(prefix);
+               replace_address_in_edit(GTK_ENTRY(entry), searchTerm, cursor_pos);
        }
 
        clear_completion_cache();
-       gtk_widget_destroy(*completion_window);
-       *completion_window = NULL;
+       addrcompl_destroy_window( _compWindow_ );
 
        return TRUE;
 }
 
+/**
+ * Respond to key press in completion window.
+ * \param widget   Window object.
+ * \param event    Event.
+ * \param compWind Reference to completion window.
+ */
 static gboolean completion_window_key_press(GtkWidget *widget,
                                            GdkEventKey *event,
-                                           GtkWidget **completion_window)
+                                           CompletionWindow *compWin )
 {
        GdkEventKey tmp_event;
        GtkWidget *entry;
-       gchar *prefix;
+       gchar *searchTerm;
        gint cursor_pos;
        GtkWidget *clist;
 
-       g_return_val_if_fail(completion_window != NULL, FALSE);
-       g_return_val_if_fail(*completion_window != NULL, FALSE);
+       g_return_val_if_fail(compWin != NULL, FALSE);
 
-       entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(*completion_window),
-                                              WINDOW_DATA_COMPL_ENTRY));
-       clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(*completion_window),
-                                              WINDOW_DATA_COMPL_CLIST));
+       entry = compWin->entry;
+       clist = compWin->clist;
        g_return_val_if_fail(entry != NULL, FALSE);
 
        /* allow keyboard navigation in the alternatives clist */
@@ -925,9 +1324,15 @@ static gboolean completion_window_key_press(GtkWidget *widget,
 
        /* look for presses that accept the selection */
        if (event->keyval == GDK_Return || event->keyval == GDK_space) {
+               /* User selected address with a key press */
+
+               /* Display selected address in entry field */           
+               completion_window_apply_selection(
+                       GTK_CLIST(clist), GTK_ENTRY(entry) );
+
+               /* Discard the window */
                clear_completion_cache();
-               gtk_widget_destroy(*completion_window);
-               *completion_window = NULL;
+               addrcompl_destroy_window( _compWindow_ );
                return FALSE;
        }
 
@@ -945,12 +1350,10 @@ static gboolean completion_window_key_press(GtkWidget *widget,
                return FALSE;
        }
 
-       /* other key, let's restore the prefix (orignal text) */
-       prefix = get_complete_address(0);
+       /* some other key, let's restore the searchTerm (orignal text) */
+       searchTerm = _compWindow_->searchTerm;
        g_free(get_address_from_edit(GTK_ENTRY(entry), &cursor_pos));
-       replace_address_in_edit(GTK_ENTRY(entry), prefix, cursor_pos);
-       g_free(prefix);
-       clear_completion_cache();
+       replace_address_in_edit(GTK_ENTRY(entry), searchTerm, cursor_pos);
 
        /* make sure anything we typed comes in the edit box */
        tmp_event.type       = event->type;
@@ -964,8 +1367,52 @@ static gboolean completion_window_key_press(GtkWidget *widget,
        gtk_widget_event(entry, (GdkEvent *)&tmp_event);
 
        /* and close the completion window */
-       gtk_widget_destroy(*completion_window);
-       *completion_window = NULL;
+       clear_completion_cache();
+       addrcompl_destroy_window( _compWindow_ );
 
        return TRUE;
 }
+
+/*
+ * ============================================================================
+ * Publically accessible functions.
+ * ============================================================================
+ */
+
+/**
+ * Setup completion object.
+ * \param addrIndex Address index object.
+ */
+void addrcompl_initialize( AddressIndex *addrIndex ) {
+       g_return_if_fail( addrIndex != NULL );
+       _addressIndex_ = addrIndex;
+
+       /* printf( "addrcompl_initialize...\n" ); */
+       if( ! _compWindow_ ) {
+               _compWindow_ = addrcompl_create_window();
+       }
+       _queryID_ = 0;
+       _completionIdleID_ = 0;
+       /* printf( "addrcompl_initialize...done\n" ); */
+}
+
+/**
+ * Teardown completion object.
+ */
+void addrcompl_teardown( void ) {
+       /* printf( "addrcompl_teardown...\n" ); */
+       addrcompl_free_window( _compWindow_ );
+       _compWindow_ = NULL;
+       if( _displayQueue_ ) {
+               g_list_free( _displayQueue_ );
+       }
+       _displayQueue_ = NULL;
+       _completionIdleID_ = 0;
+       _addressIndex_ = NULL;
+       /* printf( "addrcompl_teardown...done\n" ); */
+}
+
+/*
+ * End of Source.
+ */
+
index 7439cc9..19a141d 100644 (file)
 #ifndef __ADDR_COMPL_H__
 #define __ADDR_COMPL_H__
 
-gint start_address_completion          (void);
-gint invalidate_address_completion     (void);
-
-guint complete_address                 (const gchar    *str);
-
-gchar *get_address_from_edit           (GtkEntry       *entry,
-                                        gint           *start_pos);
-void replace_address_in_edit           (GtkEntry       *entry,
-                                        const gchar    *newtext,
-                                        gint            start_pos);
-
-gchar *get_complete_address            (gint            index);
-
-gchar *get_next_complete_address       (void);
-gchar *get_prev_complete_address       (void);
-guint get_completion_count             (void);
-
-gboolean is_completion_pending         (void);
-
-void clear_completion_cache            (void);
+#include "addrindex.h"
 
+gint start_address_completion          (void);
+guint complete_address                 (const gchar *str);
+gchar *get_complete_address            (gint        index);
 gint end_address_completion            (void);
 
 /* ui functions */
+void address_completion_start          (GtkWidget *mainwindow);
+void address_completion_register_entry (GtkEntry  *entry);
+void address_completion_unregister_entry(GtkEntry  *entry);
+void address_completion_end            (GtkWidget *mainwindow);
 
-void address_completion_start  (GtkWidget *mainwindow);
-void address_completion_register_entry (GtkEntry *entry);
-void address_completion_unregister_entry (GtkEntry *entry);
-void address_completion_end    (GtkWidget *mainwindow);
+void addrcompl_initialize      ( AddressIndex *addrIndex );
+void addrcompl_teardown                ( void );
 
 #endif /* __ADDR_COMPL_H__ */
index 839ee55..21055a5 100644 (file)
 
 #define ID_TIME_OFFSET            998000000
 
-/* Create new address book */
+/**
+ * Create new address book
+ * \return Address book.
+ */
 AddressBookFile *addrbook_create_book()
 {
        AddressBookFile *book;
@@ -61,10 +64,15 @@ AddressBookFile *addrbook_create_book()
        book->tempList = NULL;
        book->tempHash = NULL;
        book->addressCache->modified = TRUE;
+
        return book;
 }
 
-/* Specify name to be used */
+/**
+ * Specify name to be used
+ * \param book  Address book.
+ * \param value Name.
+ */
 void addrbook_set_name(AddressBookFile *book, const gchar *value)
 {
        g_return_if_fail(book != NULL);
@@ -77,6 +85,11 @@ gchar *addrbook_get_name(AddressBookFile *book)
        return addrcache_get_name(book->addressCache);
 }
 
+/**
+ * Specify path to address book file.
+ * \param book  Address book.
+ * \param value Path.
+ */
 void addrbook_set_path(AddressBookFile *book, const gchar *value)
 {
        g_return_if_fail(book != NULL);
@@ -84,6 +97,11 @@ void addrbook_set_path(AddressBookFile *book, const gchar *value)
        addrcache_set_dirty(book->addressCache, TRUE);
 }
 
+/**
+ * Specify filename to be used
+ * \param book  Address book.
+ * \param value Filename.
+ */
 void addrbook_set_file(AddressBookFile *book, const gchar *value)
 {
        g_return_if_fail(book != NULL);
@@ -97,6 +115,11 @@ gboolean addrbook_get_modified(AddressBookFile *book)
        return book->addressCache->modified;
 }
 
+/**
+ * Specify book as modified.
+ * \param book  Address book.
+ * \param value Indicator.
+ */
 void addrbook_set_modified(AddressBookFile *book, const gboolean value)
 {
        g_return_if_fail(book != NULL);
@@ -109,6 +132,11 @@ gboolean addrbook_get_accessed(AddressBookFile *book)
        return book->addressCache->accessFlag;
 }
 
+/**
+ * Specify address book as accessed.
+ * \param book  Address book.
+ * \param value Value.
+ */
 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
 {
        g_return_if_fail(book != NULL);
@@ -121,6 +149,11 @@ gboolean addrbook_get_read_flag(AddressBookFile *book)
        return book->addressCache->dataRead;
 }
 
+/**
+ * Specify address book as read.
+ * \param book  Address book.
+ * \param value Value.
+ */
 void addrbook_set_read_flag(AddressBookFile *book, const gboolean value)
 {
        g_return_if_fail(book != NULL);
@@ -157,13 +190,21 @@ gboolean addrbook_get_dirty(AddressBookFile *book)
        return addrcache_get_dirty(book->addressCache);
 }
 
+/**
+ * Set address book as dirty (needs to be written to file).
+ * \param book  Address book.
+ * \param value Dirty flag.
+ */
 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
 {
        g_return_if_fail(book != NULL);
        addrcache_set_dirty(book->addressCache, value);
 }
 
-/* Empty address book */
+/**
+ * Empty address book contents.
+ * \param book Address book.
+ */
 void addrbook_empty_book(AddressBookFile *book)
 {
        g_return_if_fail(book != NULL);
@@ -182,13 +223,15 @@ void addrbook_empty_book(AddressBookFile *book)
        book->retVal = MGU_SUCCESS;
 }
 
-/* Free address book */
+/**
+ * Free address book.
+ * \param book Address book.
+ */
 void addrbook_free_book(AddressBookFile *book)
 {
        g_return_if_fail(book != NULL);
 
        /* Clear cache */
-       addrcache_clear(book->addressCache);
        addrcache_free(book->addressCache);
 
        /* Free up internal objects */
@@ -209,7 +252,11 @@ void addrbook_free_book(AddressBookFile *book)
        g_free(book);
 }
 
-/* Print list of items */
+/**
+ * Print list of items.
+ * \param book   Address book.
+ * \param stream Output stream.
+ */
 void addrbook_print_item_list(GList *list, FILE *stream)
 {
        GList *node = list;
@@ -227,7 +274,11 @@ void addrbook_print_item_list(GList *list, FILE *stream)
        fprintf(stream, "\t---\n");
 }
 
-/* Print address book */
+/**
+ * Print address book header.
+ * \param book   Address book.
+ * \param stream Output stream.
+ */
 void addrbook_print_book(AddressBookFile *book, FILE *stream)
 {
        g_return_if_fail(book != NULL);
@@ -239,7 +290,11 @@ void addrbook_print_book(AddressBookFile *book, FILE *stream)
        addrcache_print(book->addressCache, stream);
 }
 
-/* Dump entire address book traversing folders */
+/**
+ * Dump entire address book traversing folders.
+ * \param book   Address book.
+ * \param stream Output stream.
+ */
 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
 {
        ItemFolder *folder;
@@ -251,31 +306,42 @@ void addrbook_dump_book(AddressBookFile *book, FILE *stream)
        addritem_print_item_folder(folder, stream);
 }
 
-/* Remove group from address book.
-   param: group        Group to remove.
-   return: Group, or NULL if not found. 
-   Note that object should still be freed */
+/**
+ * Remove specified group from address book. Note that object should still
+ * be freed.
+ * Specify name to be used
+ * \param book  Address book.
+ * \param group Group to remove.
+ * \param value Name.
+ * \return Group, or NULL if not found. 
+ */
 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
 {
        g_return_val_if_fail(book != NULL, NULL);
        return addrcache_remove_group(book->addressCache, group);
 }
 
-/* Remove specified person from address book.
-   param: person       Person to remove.
-  return: Person, or NULL if not found. 
-  Note that object should still be freed */
+/**
+ * Remove specified person from address book. Note that object should still
+ * be freed.
+ * \param  book   Address book.
+ * \param  person Person to remove.
+ * \return Person, or NULL if not found.
+ */
 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
 {
        g_return_val_if_fail(book != NULL, NULL);
        return addrcache_remove_person(book->addressCache, person);
 }
 
-/* Remove email address in address book for specified person.
-   param: person       Person.
-          email                EMail to remove.
-  return: EMail object, or NULL if not found. 
-  Note that object should still be freed */
+/**
+ * Remove specified email address in address book for specified person.
+ * Note that object should still be freed.
+ * \param  book   Address book.
+ * \param  person Person.
+ * \param  email  EMail to remove.
+ * \return EMail object, or NULL if not found.
+ */
 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
                                        ItemPerson *person, ItemEMail *email)
 {
@@ -283,7 +349,8 @@ ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
        return addrcache_person_remove_email(book->addressCache, person, email);
 }
 
-/* **********************************************************************
+/*
+* ***********************************************************************
 * Read/Write XML data file...
 * ===========================
 * Notes:
@@ -348,7 +415,12 @@ ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
 #define AB_ATTAG_VAL_GROUP       "group"
 #define AB_ATTAG_VAL_FOLDER      "folder"
 
-/* Parse address item for person */
+/**
+ * Parse address item for person from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param person Person.
+ */
 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file, 
                                   ItemPerson *person)
 {
@@ -384,7 +456,12 @@ static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse email address list */
+/**
+ * Parse list of email address for person from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param person Person.
+ */
 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file, 
                                     ItemPerson *person)
 {
@@ -405,7 +482,12 @@ static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse attibute for person */
+/**
+ * Parse attribute for person from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param person Person.
+ */
 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
 {
        GList *attr;
@@ -439,7 +521,12 @@ static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
        }
 }
 
-/* Parse attribute list */
+/**
+ * Parse list of attributes for person from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param person Person.
+ */
 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file, 
                                     ItemPerson *person)
 {
@@ -460,7 +547,11 @@ static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse person */
+/**
+ * Parse person from XML file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -502,23 +593,33 @@ static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Parse group member */
+/**
+ * Parse group member from XML file.
+ * \param book  Address book.
+ * \param file  XML file handle.
+ * \param group Group.
+ */
 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file, 
                                  ItemGroup *group)
 {
        GList *attr;
        gchar *name, *value;
-       gchar *pid = NULL, *eid = NULL;
+       gchar *eid = NULL;
+       /* gchar *pid = NULL; */
        ItemEMail *email = NULL;
 
        attr = xml_get_current_tag_attr(file);
        while (attr) {
                name = ((XMLAttr *)attr->data)->name;
                value = ((XMLAttr *)attr->data)->value;
+               /*
                if (strcmp(name, AB_ATTAG_PID) == 0)
                        pid = g_strdup(value);
                else if (strcmp(name, AB_ATTAG_EID) == 0)
                        eid = g_strdup(value);
+               */
+               if( strcmp( name, AB_ATTAG_EID ) == 0 )
+                       eid = g_strdup( value );
                attr = g_list_next(attr);
        }
        /* email = addrcache_get_email( book->addressCache, pid, eid ); */
@@ -535,7 +636,12 @@ static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse group member list */
+/**
+ * Parse list of group members from XML file.
+ * \param book  Address book.
+ * \param file  XML file handle.
+ * \param group Group.
+ */
 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file, 
                                       ItemGroup *group)
 {
@@ -560,7 +666,11 @@ static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse group */
+/**
+ * Parse group object from XML file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -592,7 +702,12 @@ static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Parse folder item */
+/**
+ * Parse folder item from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param folder Folder.
+ */
 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file, 
                                       ItemFolder *folder)
 {
@@ -616,7 +731,12 @@ static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse folder item list */
+/**
+ * Parse list of folder items from XML file.
+ * \param book   Address book.
+ * \param file   XML file handle.
+ * \param folder Folder.
+ */
 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
                                       ItemFolder *folder)
 {
@@ -641,7 +761,11 @@ static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
        }
 }
 
-/* Parse folder */
+/**
+ * Parse folder from XML file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file) 
 {
        GList *attr;
@@ -679,8 +803,13 @@ static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Parse address book.
-   Return: TRUE if data read successfully, FALSE if error reading data */
+/**
+ * Read address book (DOM) tree from file.
+ * \param  book Address book.
+ * \param  file XML file handle.
+ * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
+ *         reading data.
+ */
 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
 {
        gboolean retVal;
@@ -723,7 +852,12 @@ static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
                return retVal;
 }
 
-/* Resolve folder items visitor function */
+/**
+ * Resolve folder items callback function.
+ * \param key   Table key.
+ * \param value Reference to object contained in folder.
+ * \param data  Reference to address book.
+ */
 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
 {
        AddressBookFile *book = data;
@@ -743,8 +877,11 @@ static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
        }
 }
 
-/* Resolve folder items. Lists of UID's are replaced with pointers to 
-   data items */
+/**
+ * Resolve folder items. Lists of UID's are replaced with pointers to
+ * data items.
+ * \param  book Address book.
+ */
 static void addrbook_resolve_folder_items(AddressBookFile *book)
 {
        GList *nodeFolder = NULL;
@@ -839,7 +976,11 @@ static void addrbook_resolve_folder_items(AddressBookFile *book)
        book->tempList = NULL;
 }
 
-/* Read address book file */
+/**
+ * Read address book.
+ * \param  book Address book.
+ * \return Status code.
+ */
 gint addrbook_read_data(AddressBookFile *book)
 {
        XMLFile *file = NULL;
@@ -879,6 +1020,12 @@ gint addrbook_read_data(AddressBookFile *book)
        return book->retVal;
 }
 
+/**
+ * Write start element to file.
+ * \param fp   File handle.
+ * \param lvl  Indent level.
+ * \param name Element name.
+ */
 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
 {
        gint i;
@@ -888,6 +1035,12 @@ static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
        fputs(name, fp);
 }
 
+/**
+ * Write end element to file.
+ * \param fp   File handle.
+ * \param lvl  Indent level.
+ * \param name Element name.
+ */
 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
 {
        gint i;
@@ -898,6 +1051,12 @@ static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
        fputs(">\n", fp);
 }
 
+/**
+ * Write attribute name/value pair to file.
+ * \param fp    File handle.
+ * \param name  Attribute name.
+ * \param value Attribute value.
+ */
 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
 {
        fputs(" ", fp);
@@ -907,7 +1066,13 @@ static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
        fputs("\"", fp);
 }
 
-/* Write file hash table visitor function */
+/**
+ * Write person and associated addresses and attributes to file.
+ * file hash table visitor function.
+ * \param key   Table key.
+ * \param value Reference to person.
+ * \param data  File pointer.
+ */
 static void addrbook_write_item_person_vis(gpointer key, gpointer value, 
                                           gpointer data)
 {
@@ -964,7 +1129,13 @@ static void addrbook_write_item_person_vis(gpointer key, gpointer value,
        }
 }
 
-/* Write file hash table visitor function */
+/**
+ * Write group and associated references to addresses to file.
+ * file hash table visitor function.
+ * \param key   Table key.
+ * \param value Reference to group.
+ * \param data  File pointer.
+ */
 static void addrbook_write_item_group_vis(gpointer key, gpointer value, 
                                          gpointer data)
 {
@@ -1002,7 +1173,13 @@ static void addrbook_write_item_group_vis(gpointer key, gpointer value,
        }
 }
 
-/* Write file hash table visitor function */
+/**
+ * Write folder and associated references to addresses to file.
+ * file hash table visitor function.
+ * \param key   Table key.
+ * \param value Reference to folder.
+ * \param data  File pointer.
+ */
 static void addrbook_write_item_folder_vis(gpointer key, gpointer value, 
                                           gpointer data)
 {
@@ -1061,8 +1238,12 @@ static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
        }
 }
 
-/* Output address book data to specified file.
-  return: Status code */
+/**
+ * Output address book data to specified file.
+ * \param  book Address book.
+ * \param  newFile Filename of new file (in book's filepath).
+ * \return Status code.
+ */
 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
 {
        FILE *fp;
@@ -1121,8 +1302,11 @@ gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
        return book->retVal;
 }
 
-/* Output address book data to original file.
-   return: Status code */
+/**
+ * Output address book data to original file.
+ * \param  book Address book.
+ * \return Status code.
+ */
 gint addrbook_save_data(AddressBookFile *book)
 {
        g_return_val_if_fail(book != NULL, -1);
@@ -1139,14 +1323,20 @@ gint addrbook_save_data(AddressBookFile *book)
        return book->retVal;
 }
 
-/* **********************************************************************
-   Address book edit interface functions...
-   ***********************************************************************
-  Move person's email item.
-  param: book       Address book.
-         person     Person.
-         itemMove   Item to move.
-         itemTarget Target item before which to move item */
+/*
+ * **********************************************************************
+ * Address book edit interface functions.
+ * **********************************************************************
+ */
+
+/**
+ * Move email item within list of person's email items.
+ * \param  book       Address book.
+ * \param  person     Person.
+ * \param  itemMove   EMail item to move.
+ * \param  itemTarget EMail item to move before.
+ * \return Moved item.
+ */
 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
                                      ItemEMail *itemMove, ItemEMail *itemTarget)
 {
@@ -1160,11 +1350,14 @@ ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
        return email;
 }
 
-/* Move person's email item.
-   param: book       Address book.
-          person     Person.
-         itemMove   Item to move.
-         itemTarget Target item after which to move item */
+/**
+ * Move email item within list of person's email items.
+ * \param  book       Address book.
+ * \param  person     Person.
+ * \param  itemMove   EMail item to move.
+ * \param  itemTarget EMail item after which to move.
+ * \return Moved item.
+ */
 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
                                     ItemEMail *itemMove, ItemEMail *itemTarget)
 {
@@ -1178,7 +1371,13 @@ ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
        return email;
 }
 
-/* Hash table visitor function for deletion of hashtable entries */
+/**
+ * Hash table callback function for simple deletion of hashtable entries.
+ * \param  key   Table key (will be freed).
+ * \param  value Value stored in table.
+ * \param  data  User data.
+ * \return <i>TRUE</i> to indicate that entry freed.
+ */
 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value, 
                                              gpointer *data)
 {
@@ -1188,13 +1387,15 @@ static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
        return TRUE;
 }
 
-/* Update address book email list for specified person.
-   Enter: book      Address book.
-          person    Person to update.
-          listEMail List of new email addresses.
-  Note: The existing email addresses are replaced with the new addresses. Any references
-  to old addresses in the groups are re-linked to the new addresses. All old addresses
-  linked to the person are removed */
+/**
+ * Update address book email list for specified person. Note: The existing
+ * email addresses are replaced with the new addresses. Any references to
+ * old addresses in the groups are re-linked to the new addresses. All old
+ * addresses linked to the person are removed.
+ * \param book      Address book.
+ * \param person    Person to update.
+ * \param listEMail List of new email addresses.
+ */
 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person, 
                                  GList *listEMail)
 {
@@ -1341,13 +1542,17 @@ void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
 
 }
 
-/* Add person and address data to address book.
-   Enter: book      Address book.
-          folder    Folder where to add person, or NULL for root folder.
-          listEMail New list of email addresses.
-   Return: Person added.
-   Note: A new person is created with specified list of email addresses. All objects inserted
-   into address book */
+/**
+ * Create person object and add person with specified address data to address
+ * book. Note: A new person is created with specified list of email addresses.
+ * All objects inserted into address book.
+ *
+ * \param  book      Address book.
+ * \param  folder    Parent folder where to add person, or <i>NULL</i> for
+ *                   root folder.
+ * \param  listEMail List of new email addresses to associate with person.
+ * \return Person object created.
+ */
 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
                                      GList *listEMail)
 {
@@ -1375,7 +1580,12 @@ ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
        return person;
 }
 
-/* Build available email list visitor function */
+/**
+ * Build available email list visitor function.
+ * \param  key   Table key.
+ * \param  value Value stored in table.
+ * \param  data  Reference to address book.
+ */
 static void addrbook_build_avail_email_vis(gpointer key, gpointer value, 
                                           gpointer data)
 {
@@ -1398,11 +1608,17 @@ static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
        }
 }
 
-/* Return link list of available email items (which have not already been linked to
-   groups). Note that the list contains references to items and should be g_free()
-   when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
-   destroy the addressbook data!
-   Return: List of items, or NULL if none */
+/**
+ * Return link list of available email items that have not already been linked
+ * to groups. Note that the list contains references to items and should be
+ * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
+ * <code>addrbook_free_xxx()<code> functions... this will destroy the
+ * addressbook data!
+ *
+ * \param  book  Address book.
+ * \param  group Group to process.
+ * \return List of items, or <i>NULL</i> if none.
+ */
 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
 {
        GList *list = NULL;
@@ -1437,13 +1653,17 @@ GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group
        return list;
 }
 
-/* Update address book email list for specified group.
-   Enter: book      Address book.
-          group     group to update.
-          listEMail New list of email addresses. This should *NOT* be g_free() when done.
-  Note: The existing email addresses are replaced with the new addresses. Any references
-  to old addresses in the groups are re-linked to the new addresses. All old addresses
-  linked to the person are removed */
+/**
+ * Update address book email list for specified group. Note: The existing email
+ * addresses are replaced with the new addresses. Any references to old addresses
+ * in the groups are re-linked to the new addresses. All old addresses linked to
+ * the person are removed.
+ *
+ * \param book      Address book.
+ * \param group     Group to process.
+ * \param listEMail List of email items. This should <b>*NOT*</b> be
+ *                  <code>g_free()</code> when done.
+ */
 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group, 
                                GList *listEMail)
 {
@@ -1461,14 +1681,19 @@ void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
        oldData = NULL;
 }
 
-/* Add group and email list to address book.
-   Enter: book      Address book.
-          folder    Parent folder, or NULL for root folder.
-          listEMail New list of email addresses. This should *NOT* be g_free() when done.
-   Return: Group object.
-   Note: The existing email addresses are replaced with the new addresses. Any references
-   to old addresses in the groups are re-linked to the new addresses. All old addresses
-   linked to the person are removed */
+/**
+ * Create group object and add with specifed list of email addresses to
+ * address book. Note: The existing email addresses are replaced with the new
+ * addresses. Any references to old addresses in the groups are re-linked to
+ * the new addresses. All old addresses linked to the person are removed.
+ *
+ * \param  book      Address book.
+ * \param  folder    Parent folder where to add group, or <i>NULL</i> for
+ *                   root folder.
+ * \param  listEMail List of email items. This should <b>*NOT*</b> be
+ *                  <code>g_free()</code> when done.
+ * \return Group object created.
+ */
 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
                                   GList *listEMail)
 {
@@ -1486,10 +1711,14 @@ ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
        return group;
 }
 
-/* Add new folder to address book.
-   Enter: book   Address book.
-          parent       Parent folder.
-   Return: Folder that was added. This should *NOT* be g_free() when done */
+/**
+ * Create a new folder and add to address book.
+ * \param  book   Address book.
+ * \param  folder Parent folder where to add folder, or <i>NULL</i> for
+ *                root folder.
+ * \return Folder that was created. This should <b>*NOT*</b> be
+ *         <code>g_free()</code> when done.
+ */
 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
 {
        ItemFolder *folder = NULL;
@@ -1513,12 +1742,15 @@ ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
        return folder;
 }
 
-/* Update address book attribute list for specified person.
-   Enter: book       Address book.
-          person     Person to update.
-          listAttrib New list of attributes.
-   Note: The existing email addresses are replaced with the new addresses. All old attributes
-   linked to the person are removed */
+/**
+ * Update address book attribute list for specified person. Note: The existing
+ * attributes are replaced with the new addresses. All old attributes linked
+ * to the person are removed.
+ *
+ * \param book       Address book.
+ * \param person     Person to receive attributes.
+ * \param listAttrib New list of attributes.
+ */
 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
                                 GList *listAttrib)
 {
@@ -1549,13 +1781,13 @@ void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
        oldData = NULL;
 }
 
-/*
-* Add attribute data for person to address book.
-* Enter: book       Address book.
-*        person     New person object.
-*        listAttrib New list of attributes.
-* Note: Only attributes are inserted into address book.
-*/
+/**
+ * Add attribute data for specified person to address book. Note: Only
+ * attributes are inserted into address book.
+ * \param book       Address book.
+ * \param person     Person to receive attributes.
+ * \param listAttrib List of attributes.
+ */
 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
        GList *node;
 
@@ -1574,9 +1806,13 @@ void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList
        addrcache_set_dirty( book->addressCache, TRUE );
 }
 
-/* Return address book file for specified object.
-   Enter: aio Book item object.
-   Return: Address book, or NULL if not found */
+/*
+ * Return reference to address book file for specified object by traversing up
+ * address book heirarchy.
+ *
+ * \param aio Book item object.
+ * \return Address book, or <i>NULL</i> if not found.
+ */
 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
 {
        AddressBookFile *book = NULL;
@@ -1600,9 +1836,14 @@ AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
        return book;
 }
 
-/* Remove folder from address book. Children are re-parented to parent folder.
-   param: folder Folder to remove.
-   return: Folder, or NULL if not found. Note that object should still be freed */
+/**
+ * Remove folder from address book. Children are re-parented to the parent
+ * folder.
+ * \param  book   Address book.
+ * \param  folder Folder to remove.
+ * \return Folder, or <i>NULL</i> if not found. Note that object should still
+ *         be freed.
+ */
 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
 {
        ItemFolder *f;
@@ -1613,9 +1854,13 @@ ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
        return f;
 }
 
-/* Remove folder from address book. Children are deleted.
-   param: folder Folder to remove.
-   return: Folder, or NULL if not found. Note that object should still be freed */
+/**
+ * Remove folder from address book. Children are deleted.
+ * \param  book   Address book.
+ * \param  folder Folder to remove.
+ * \return Folder, or <i>NULL</i> if not found. Note that object should still
+ *         be freed.
+ */
 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book, 
                                          ItemFolder *folder)
 {
@@ -1630,9 +1875,11 @@ ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
 #define WORK_BUFLEN     1024
 #define ADDRBOOK_DIGITS "0123456789"
 
-/* Return list of existing address book files.
-   Enter: book Address book file.
-   Return: File list */
+/**
+ * Return list of existing address book files.
+ * \param  book Address book.
+ * \return List of files (as strings).
+ */
 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
        gchar *adbookdir;
        DIR *dp;
@@ -1683,9 +1930,17 @@ GList *addrbook_get_bookfile_list(AddressBookFile *book) {
                strcat(buf, entry->d_name);
                stat(buf, &statbuf);
                if (S_IFREG & statbuf.st_mode) {
-                       if (strncmp(entry->d_name, ADDRBOOK_PREFIX, lenpre) == 0) {
-                               if (strncmp((entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf) == 0) {
-                                       strncpy(numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS);
+                       if (strncmp(
+                               entry->d_name,
+                               ADDRBOOK_PREFIX, lenpre) == 0)
+                       {
+                               if (strncmp(
+                                       (entry->d_name) + lennum,
+                                       ADDRBOOK_SUFFIX, lensuf) == 0)
+                               {
+                                       strncpy(numbuf,
+                                               (entry->d_name) + lenpre,
+                                               FILE_NUMDIGITS);
                                        numbuf[FILE_NUMDIGITS] = '\0';
                                        flg = TRUE;
                                        for(i = 0; i < FILE_NUMDIGITS; i++) {
@@ -1699,7 +1954,9 @@ GList *addrbook_get_bookfile_list(AddressBookFile *book) {
                                                val = strtol(numbuf, &endptr, 10);
                                                if (endptr  && val > -1) {
                                                        if (val > maxval) maxval = val;
-                                                       fileList = g_list_append(fileList, g_strdup(entry->d_name));
+                                                       fileList = g_list_append(
+                                                               fileList,
+                                                               g_strdup(entry->d_name));
                                                }
                                        }
                                }
@@ -1714,9 +1971,12 @@ GList *addrbook_get_bookfile_list(AddressBookFile *book) {
        return fileList;
 }
 
-/* Return file name for specified file number.
-   Enter:  fileNum File number.
-   Return: File name, or NULL if file number too large. Should be g_free() when done */
+/**
+ * Return file name for specified file number.
+ * \param  fileNum File number.
+ * \return File name, or <i>NULL</i> if file number too large. Should be
+ *         <code>g_free()</code> when done.
+ */
 gchar *addrbook_gen_new_file_name(gint fileNum) {
        gchar fmt[30];
        gchar buf[WORK_BUFLEN];
@@ -1733,14 +1993,17 @@ gchar *addrbook_gen_new_file_name(gint fileNum) {
        return g_strdup(buf);
 }
 
-/* **********************************************************************
-   Address book test functions...
-   **********************************************************************
-*/
-
 /*
-* Test email address list.
-*/
+ * **********************************************************************
+ * Address book test functions...
+ * **********************************************************************
+ */
+
+/**
+ * Attempt to parse list of email address from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
        guint prev_level;
        GList *attr;
@@ -1758,7 +2021,11 @@ static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
        }
 }
 
-/* Test user attributes for person */
+/**
+ * Attempt to parse attributes for person address from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1770,7 +2037,11 @@ static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
        /* printf( "\t\tattrib value : %s\n", element ); */
 }
 
-/* Test attribute list */
+/**
+ * Attempt to parse list of attributes for person address from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
 {
        guint prev_level;
@@ -1788,7 +2059,11 @@ static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Test person */
+/**
+ * Attempt to parse person from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1808,7 +2083,11 @@ static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
                addrbook_chkparse_attr_list(book, file);
 }
 
-/* Test group member list */
+/**
+ * Attempt to parse list of members from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1834,7 +2113,11 @@ static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Test group */
+/**
+ * Attempt to parse group from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1848,7 +2131,11 @@ static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
                addrbook_chkparse_member_list(book, file);
 }
 
-/* Test folder item list */
+/**
+ * Attempt to parse list of folders from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1874,7 +2161,11 @@ static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
        }
 }
 
-/* Test folder */
+/**
+ * Attempt to parse a folder from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1888,7 +2179,11 @@ static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
                addrbook_chkparse_folder_list(book, file);
 }
 
-/* Test address book */
+/**
+ * Attempt to parse (DOM) tree from file.
+ * \param book Address book.
+ * \param file XML file handle.
+ */
 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
 {
        GList *attr;
@@ -1925,10 +2220,12 @@ static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
        return retVal;
 }
 
-/* Test address book file by parsing contents.
-   Enter: book     Address book file to check.
-          fileName File name to check.
-   Return: MGU_SUCCESS if file appears to be valid format */
+/**
+ * Test address book file by parsing contents.
+ * \param  book     Address book.
+ * \param  fileName Filename of XML file.
+ * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
+ */
 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
 {
        XMLFile *file = NULL;
@@ -1955,37 +2252,49 @@ gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
        return book->retVal;
 }
 
-/* Return link list of all persons in address book.  Note that the list contains
-   references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
-   this will destroy the addressbook data!
-   Return: List of items, or NULL if none */
+/**
+ * Return link list of all persons in address book.  Note that the list
+ * contains references to items. Do <b>*NOT*</b> attempt to use the
+ * <code>addrbook_free_xxx()</code> functions... this will destroy the
+ * addressbook data!
+ * \param  book     Address book.
+ * \return List of persons, or NULL if none.
+ */
 GList *addrbook_get_all_persons(AddressBookFile *book)
 {
        g_return_val_if_fail(book != NULL, NULL);
        return addrcache_get_all_persons(book->addressCache);
 }
 
-/* Add person and address data to address book.
-   Enter: book      Address book.
-          folder    Folder where to add person, or NULL for root folder.
-          name      Common name.
-          address   EMail address.
-          remarks   Remarks.
-   Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
-   this will destroy the address book data */
+/**
+ * Add person and address data to address book.
+ * \param  book    Address book.
+ * \param  folder  Folder where to add person, or NULL for root folder.
+ * \param  name    Common name.
+ * \param  address EMail address.
+ * \param  remarks Remarks.
+ * \return Person added. Do not <b>*NOT*</b> to use the
+ *         <code>addrbook_free_xxx()</code> functions... this will destroy
+ *         the address book data.
+ */
 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder, 
                                 const gchar *name,const gchar *address, 
                                 const gchar *remarks)
 {
+       ItemPerson *person;
+
        g_return_val_if_fail(book != NULL, NULL);
-       return addrcache_add_contact(book->addressCache, folder, name, address, 
-                                    remarks);
+       person = addrcache_add_contact(
+                       book->addressCache, folder, name, address, remarks );
+       return person;
 }
 
-/* Return file name for next address book file.
-   Enter:  book Address book.
-   Return: File name, or NULL if could not create. This should be g_free()
-           when done */
+/**
+ * Return file name for next address book file.
+ * \param  book Address book.
+ * \return File name, or <i>NULL</i> if could not create. This should be
+ *         <code>g_free()</code> when done.
+ */
 gchar *addrbook_guess_next_file(AddressBookFile *book)
 {
        gchar *newFile = NULL;
@@ -2000,3 +2309,9 @@ gchar *addrbook_guess_next_file(AddressBookFile *book)
        fileList = NULL;
        return newFile;
 }
+
+/*
+* End of Source.
+*/
+
+
index 608b801..f3d4a94 100644 (file)
@@ -85,7 +85,7 @@
 
 #ifdef USE_LDAP
 #include <pthread.h>
-#include "syldap.h"
+#include "ldapserver.h"
 #include "editldap.h"
 
 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
@@ -313,7 +313,7 @@ static void addressbook_folder_remove_node  (GtkCTree *clist,
                                                 GtkCTreeNode *node);
 
 #ifdef USE_LDAP
-static void addressbook_ldap_show_message      (SyldapServer *server);
+static void addressbook_ldap_show_message      ( LdapServer *server );
 #endif
 
 /* LUT's and IF stuff */
@@ -527,7 +527,8 @@ void addressbook_destroy() {
                addrclip_free( _clipBoard_ );
        }
        if( _addressIndex_ != NULL ) {
-              addrindex_free_index( _addressIndex_ );
+               addrindex_free_index( _addressIndex_ );
+               addrindex_teardown( _addressIndex_ );
        }
        _addressSelect_ = NULL;
        _clipBoard_ = NULL;
@@ -1116,7 +1117,7 @@ gchar *addressbook_format_address( AddrItemObject * aio ) {
        }
        if( address ) {
                if( name && name[0] != '\0' ) {
-                       if( name[0] != '"' && strpbrk( name, ",.[]<>" ) != NULL )
+                       if( strchr_with_skip_quote( name, '"', ',' ) )
                                buf = g_strdup_printf( "\"%s\" <%s>", name, address );
                        else
                                buf = g_strdup_printf( "%s <%s>", name, address );
@@ -2484,9 +2485,11 @@ static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
        }
 }
 
-static void addressbook_folder_load_one_person( GtkCTree *clist, ItemPerson *person,  
-                                               AddressTypeControlItem *atci, AddressTypeControlItem *atciMail) {
-       
+static void addressbook_folder_load_one_person(
+               GtkCTree *clist, ItemPerson *person,
+               AddressTypeControlItem *atci,
+               AddressTypeControlItem *atciMail )
+{
        GtkCTreeNode *nodePerson = NULL;
        GtkCTreeNode *nodeEMail = NULL;
        gchar *text[N_COLS];
@@ -2578,8 +2581,10 @@ static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node
        addrbook.listSelected = NULL;
        gtk_ctree_remove_node( clist, node );
        addressbook_menubar_set_sensitive( FALSE );
-       addressbook_menuitem_set_sensitive( gtk_ctree_node_get_row_data( 
-                                               GTK_CTREE(clist), addrbook.treeSelected ), addrbook.treeSelected );
+       addressbook_menuitem_set_sensitive(
+               gtk_ctree_node_get_row_data(
+                       GTK_CTREE(clist), addrbook.treeSelected ),
+               addrbook.treeSelected );
 }
 
 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
@@ -2789,8 +2794,10 @@ static void addressbook_set_clist( AddressObject *obj ) {
                        /* Load root folder */
                        ItemFolder *rootFolder = NULL;
                        rootFolder = addrindex_ds_get_root_folder( ds );
-                       addressbook_folder_load_person( ctreelist, addrindex_ds_get_root_folder( ds ) );
-                       addressbook_folder_load_group( ctreelist, addrindex_ds_get_root_folder( ds ) );
+                       addressbook_folder_load_person(
+                               ctreelist, addrindex_ds_get_root_folder( ds ) );
+                       addressbook_folder_load_group(
+                               ctreelist, addrindex_ds_get_root_folder( ds ) );
                }
        }
        else {
@@ -2855,7 +2862,8 @@ AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
 }
 
 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
-       ADDRESS_OBJECT_NAME(adapter) = mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
+       ADDRESS_OBJECT_NAME(adapter) =
+               mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
 }
 
 /*
@@ -2886,8 +2894,10 @@ static void addressbook_load_tree( void ) {
                                        ds = nodeDS->data;
                                        newNode = NULL;
                                        name = addrindex_ds_get_name( ds );
-                                       ads = addressbook_create_ds_adapter( ds, atci->objectType, name );
-                                       newNode = addressbook_add_object( node, ADDRESS_OBJECT(ads) );
+                                       ads = addressbook_create_ds_adapter(
+                                                       ds, atci->objectType, name );
+                                       newNode = addressbook_add_object(
+                                                       node, ADDRESS_OBJECT(ads) );
                                        nodeDS = g_list_next( nodeDS );
                                }
                                gtk_ctree_expand( ctree, node );
@@ -2992,6 +3002,7 @@ void addressbook_read_file( void ) {
        }
 
        addrIndex = addrindex_create_index();
+       addrindex_initialize( addrIndex );
 
        /* Use new address book index. */
        addrindex_set_file_path( addrIndex, get_rc_dir() );
@@ -3112,7 +3123,8 @@ static GtkCTreeNode *addressbook_node_add_group( GtkCTreeNode *node, AddressData
 * Return: Inserted node.
 */
 static GtkCTreeNode *addressbook_node_add_folder(
-               GtkCTreeNode *node, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype )
+               GtkCTreeNode *node, AddressDataSource *ds,
+               ItemFolder *itemFolder, AddressObjectType otype )
 {
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
        GtkCTreeNode *newNode = NULL;
@@ -3313,43 +3325,36 @@ static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *wid
        }
 }
 
-static void addressbook_ldap_show_message( SyldapServer *svr ) {
+static void addressbook_ldap_show_message( LdapServer *svr ) {
        gchar *name;
        gchar *desc;
        *addressbook_msgbuf = '\0';
        if( svr ) {
-               name = syldap_get_name( svr );
-               if( svr->busyFlag ) {
+               name = ldapsvr_get_name( svr );
+               if( svr->retVal == MGU_SUCCESS ) {
                        g_snprintf( addressbook_msgbuf,
-                                   sizeof(addressbook_msgbuf), "%s: %s", name,
-                                   ADDRESSBOOK_LDAP_BUSYMSG );
+                                   sizeof(addressbook_msgbuf), "%s",
+                                   name );
                }
                else {
-                       if( svr->retVal == MGU_SUCCESS ) {
-                               g_snprintf( addressbook_msgbuf,
-                                           sizeof(addressbook_msgbuf), "%s",
-                                           name );
-                       }
-                       else {
-                               desc = addressbook_err2string(
-                                               _lutErrorsLDAP_, svr->retVal );
-                               g_snprintf( addressbook_msgbuf,
-                                           sizeof(addressbook_msgbuf),
-                                           "%s: %s", name, desc );
-                       }
+                       desc = addressbook_err2string(
+                                       _lutErrorsLDAP_, svr->retVal );
+                       g_snprintf( addressbook_msgbuf,
+                                   sizeof(addressbook_msgbuf),
+                                   "%s: %s", name, desc );
                }
        }
        addressbook_status_show( addressbook_msgbuf );
 }
 
-static void addressbook_ldap_show_results( SyldapServer *sls ) {
+static void addressbook_ldap_show_results( LdapServer *server ) {
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
        AddressObject *obj;
        AdapterDSource *ads = NULL;
        AddressDataSource *ds = NULL;
        AddressInterface *iface = NULL;
 
-       if( sls == NULL ) return;
+       if( server == NULL ) return;
        if( ! addrbook.treeSelected ) return;
        if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
 
@@ -3358,18 +3363,18 @@ static void addressbook_ldap_show_results( SyldapServer *sls ) {
        if( obj->type == ADDR_DATASOURCE ) {
                ads = ADAPTER_DSOURCE(obj);
                if( ads->subType == ADDR_LDAP ) {
-                       SyldapServer *server;
+                       LdapServer *ldapSvr;
 
                        ds = ads->dataSource;
                        if( ds == NULL ) return;
                        iface = ds->interface;
                        if( ! iface->haveLibrary ) return;
                        server = ds->rawDataSource;
-                       if( server == sls ) {
+                       if( ldapSvr == server ) {
                                /* Read from cache */
                                gtk_widget_show_all(addrbook.window);
                                addressbook_set_clist( obj );
-                               addressbook_ldap_show_message( sls );
+                               addressbook_ldap_show_message( server );
                                gtk_widget_show_all(addrbook.window);
                                gtk_entry_set_text( GTK_ENTRY(addrbook.entry), "" );
                        }
@@ -3377,24 +3382,27 @@ static void addressbook_ldap_show_results( SyldapServer *sls ) {
        }
 }
 
+static gint _idleID_ = 0;
+static gchar *_tempMessage_ = "Busy searching LDAP...";
+
 /*
  * LDAP idle function. This function is called during UI idle time while
  * an LDAP search is in progress.
  * Enter: data Reference to LDAP server object.
  */
 static void addressbook_ldap_idle( gpointer data ) {
-       SyldapServer *server;
-
-       server = ( SyldapServer * ) data;       
-       if( ! server->busyFlag ) {
-               /* Server has completed search - remove from idle list */
-               gtk_idle_remove( server->idleId );
+}
 
-               /* Process callback and free up the thread */
-               addressbook_ldap_show_results( server );
-               g_free( server->thread );
-               server->thread = NULL;
+/*
+ * LDAP search completion function.
+ */
+static void addressbook_ldap_idle_end( void ) {
+       /* Server has completed search - remove from idle list */
+       printf( "addressbook_ldap_idle_end... completed" );
+       if( _idleID_ != 0 ) {
+               gtk_idle_remove( _idleID_ );
        }
+       _idleID_ = 0;
 }
 
 /*
@@ -3405,21 +3413,26 @@ static void addressbook_ldap_idle( gpointer data ) {
 static void addressbook_ldap_lookup( AdapterDSource *ads, gchar *sLookup ) {
        AddressDataSource *ds = NULL;
        AddressInterface *iface = NULL;
-       SyldapServer *server;
+       LdapServer *server;
 
+       printf( "addressbook_ldap_lookup/Searching for '%s'\n", sLookup );
        ds = ads->dataSource;
        if( ds == NULL ) return;
        iface = ds->interface;
        if( ! iface->haveLibrary ) return;
        server = ds->rawDataSource;
        if( server ) {
-               syldap_cancel_read( server );
+               printf( "addressbook_ldap_lookup/Starting.../1\n" );
                if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return;
-               syldap_set_search_value( server, sLookup );
-               server->idleId = gtk_idle_add(
-                       ( GtkFunction ) addressbook_ldap_idle, server );
-               syldap_read_data_th( server );
-               addressbook_ldap_show_message( server );
+
+               /* Setup a query */
+               printf( "addressbook_ldap_lookup/Starting.../2\n" );
+
+               /* Sit back and wait for something to happen */
+               _idleID_ = gtk_idle_add(
+                       ( GtkFunction ) addressbook_ldap_idle, NULL );
+               addrindex_search_ldap_noid( server, sLookup, addressbook_ldap_idle_end  );
+               addressbook_status_show( _tempMessage_ );
        }
 }
 #endif
index d78f79a..38f4225 100644 (file)
 #include <gtk/gtkwidget.h>
 
 #include "compose.h"
-
-void addressbook_open                  (Compose        *target);
-void addressbook_set_target_compose    (Compose        *target);
-Compose *addressbook_get_target_compose        (void);
-void addressbook_read_file             (void);
-void addressbook_export_to_file                (void);
-gint addressbook_obj_name_compare      (gconstpointer   a,
-                                        gconstpointer   b);
+#include "addritem.h"
+
+void addressbook_open                  ( Compose *target );
+void addressbook_set_target_compose    ( Compose *target );
+Compose *addressbook_get_target_compose        ( void );
+void addressbook_read_file             ( void );
+void addressbook_export_to_file                ( void );
+gint addressbook_obj_name_compare      ( gconstpointer a,
+                                         gconstpointer b );
 void addressbook_destroy               ( void );
 
-gboolean addressbook_add_contact       ( const gchar   *name,
-                                         const gchar   *address,
-                                         const gchar   *remarks );
-
-gboolean addressbook_load_completion   ( gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) );
+gboolean addressbook_add_contact       ( const gchar *name,
+                                         const gchar *address,
+                                         const gchar *remarks );
+                                         
+gboolean addressbook_load_completion   (gint (*callBackFunc) 
+                                              (const gchar *, 
+                                               const gchar *, 
+                                               const gchar *));
 
 void addressbook_gather                        ( FolderItem *folderItem,
                                          gboolean sourceInd,
                                          GList *msgList );
-void addressbook_harvest               (FolderItem     *folderItem,
-                                        gboolean sourceInd,
-                                        GList *msgList);
+void addressbook_harvest               ( FolderItem *folderItem,
+                                         gboolean sourceInd,
+                                         GList *msgList);
+
+void addressbook_read_all              ( void );
 
 #endif /* __ADDRESSBOOK_H__ */
 
index f2dd845..febbf69 100644 (file)
@@ -36,6 +36,7 @@
 #include "addrbook.h"
 #include "addrindex.h"
 #include "xml.h"
+#include "addrquery.h"
 
 #ifndef DEV_STANDALONE
 #include "prefs_gtk.h"
@@ -49,7 +50,9 @@
 #endif
 
 #ifdef USE_LDAP
-#include "syldap.h"
+#include "ldapserver.h"
+#include "ldapctrl.h"
+#include "ldapquery.h"
 #endif
 
 #define TAG_ADDRESS_INDEX    "addressbook"
 #define ATTAG_LDAP_CRITERIA   "criteria"
 #define ATTAG_LDAP_MAX_ENTRY  "max-entry"
 #define ATTAG_LDAP_TIMEOUT    "timeout"
+#define ATTAG_LDAP_MAX_AGE    "max-age"
+#define ATTAG_LDAP_DYN_SEARCH "dyn-search"
+
+#define ELTAG_LDAP_ATTR_SRCH  "attribute"
+#define ATTAG_LDAP_ATTR_NAME  "name"
+
+/* New attributes */
+#define ATTAG_LDAP_DEFAULT    "default"
 
 #if 0
 N_("Common address")
@@ -104,6 +115,9 @@ N_("Personal address")
 #define DISP_OLD_COMMON       _("Common address")
 #define DISP_OLD_PERSONAL     _("Personal address")
 
+/*
+ * Define attribute name-value pair.
+ */
 typedef struct _AddressIfAttr AddressIfAttrib;
 struct _AddressIfAttr {
        gchar *name;
@@ -111,9 +125,27 @@ struct _AddressIfAttr {
 };
 
 /*
-* Build interface with default values.
+ * Define DOM fragment.
+ */
+typedef struct _AddressIfFrag AddressIfFragment;
+struct _AddressIfFrag {
+       gchar *name;
+       GList *children;
+       GList *attributes;
+};
+
+/**
+ * Build interface with default values.
+ *
+ * \param type Interface type.
+ * \param name Interface name.
+ * \param tagIf XML tag name for interface in address index file.
+ * \param tagDS XML tag name for datasource in address index file.
+ * \return Address interface object.
 */
-static AddressInterface *addrindex_create_interface( gint type, gchar *name, gchar *tagIf, gchar *tagDS ) {
+static AddressInterface *addrindex_create_interface(
+               gint type, gchar *name, gchar *tagIf, gchar *tagDS )
+{
        AddressInterface *iface = g_new0( AddressInterface, 1 );
 
        ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
@@ -129,6 +161,8 @@ static AddressInterface *addrindex_create_interface( gint type, gchar *name, gch
        iface->haveLibrary = TRUE;
        iface->useInterface = TRUE;
        iface->readOnly      = TRUE;
+
+       /* Set callbacks to NULL values - override for each interface */
        iface->getAccessFlag = NULL;
        iface->getModifyFlag = NULL;
        iface->getReadFlag   = NULL;
@@ -141,16 +175,27 @@ static AddressInterface *addrindex_create_interface( gint type, gchar *name, gch
        iface->getAllGroups  = NULL;
        iface->getName       = NULL;
        iface->listSource = NULL;
+
+       /* Search stuff */
+       iface->externalQuery = FALSE;
+       iface->searchOrder = 0;         /* Ignored */
+       iface->startSearch = NULL;
+       iface->stopSearch = NULL;
+
        return iface;
 }
 
-/*
-* Build table of interfaces.
-*/
+/**
+ * Build table of of all address book interfaces.
+ * \param addrIndex Address index object.
+ */
 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        AddressInterface *iface;
 
-       iface = addrindex_create_interface( ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK, TAG_DS_ADDRESS_BOOK );
+       /* Create intrinsic XML address book interface */
+       iface = addrindex_create_interface(
+                       ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK,
+                       TAG_DS_ADDRESS_BOOK );
        iface->readOnly      = FALSE;
        iface->getModifyFlag = ( void * ) addrbook_get_modified;
        iface->getAccessFlag = ( void * ) addrbook_get_accessed;
@@ -163,10 +208,16 @@ 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;
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       iface->searchOrder   = 0;
+
+       /* Add to list of interfaces in address book */ 
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       iface = addrindex_create_interface( ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
+       /* Create vCard interface */
+       iface = addrindex_create_interface(
+                       ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
        iface->getModifyFlag = ( void * ) vcard_get_modified;
        iface->getAccessFlag = ( void * ) vcard_get_accessed;
        iface->getReadFlag   = ( void * ) vcard_get_read_flag;
@@ -178,10 +229,15 @@ 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;
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       iface->searchOrder   = 0;
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       iface = addrindex_create_interface( ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT, TAG_DS_JPILOT );
+       /* Create JPilot interface */
+       iface = addrindex_create_interface(
+                       ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT,
+                       TAG_DS_JPILOT );
 #ifdef USE_JPILOT
        iface->haveLibrary = jpilot_test_pilot_lib();
        iface->useInterface = iface->haveLibrary;
@@ -196,72 +252,103 @@ 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   = 0;
 #else
        iface->useInterface = FALSE;
        iface->haveLibrary = FALSE;
 #endif
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       iface = addrindex_create_interface( ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
+       /* Create LDAP interface */
+       iface = addrindex_create_interface(
+                       ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
 #ifdef USE_LDAP
-       iface->haveLibrary = syldap_test_ldap_lib();
+       /* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
+       iface->haveLibrary = ldaputil_test_ldap_lib();
        iface->useInterface = iface->haveLibrary;
-       iface->getAccessFlag = ( void * ) syldap_get_accessed;
-       /* iface->getModifyFlag = ( void * ) syldap_get_modified; */
-       /* iface->getReadFlag   = ( void * ) syldap_get_read_flag; */
-       iface->getStatusCode = ( void * ) syldap_get_status;
-       iface->getReadData   = ( void * ) syldap_read_data;
-       iface->getRootFolder = ( void * ) syldap_get_root_folder;
-       iface->getListFolder = ( void * ) syldap_get_list_folder;
-       iface->getListPerson = ( void * ) syldap_get_list_person;
-       iface->getName       = ( void * ) syldap_get_name;
-       iface->setAccessFlag = ( void * ) syldap_set_accessed;
+       /* iface->getModifyFlag = ( void * ) ldapsvr_get_modified; */
+       iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
+       /* iface->getReadFlag   = ( void * ) ldapsvr_get_read_flag; */
+       iface->getStatusCode = ( void * ) ldapsvr_get_status;
+       /* iface->getReadData   = ( void * ) ldapsvr_read_data; */
+       iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
+       iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
+       iface->getListPerson = ( void * ) ldapsvr_get_list_person;
+       iface->getName       = ( void * ) ldapsvr_get_name;
+       iface->setAccessFlag = ( void * ) ldapsvr_set_accessed;
+       iface->externalQuery = TRUE;
+       iface->searchOrder   = 1;
 #else
        iface->useInterface = FALSE;
        iface->haveLibrary = FALSE;
 #endif
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       /* Two old legacy data sources */
+       /* Two old legacy data sources (pre 0.7.0) */
        iface = addrindex_create_interface(
                        ADDR_IF_COMMON, "Old Address - common",
                        TAG_IF_OLD_COMMON, NULL );
        iface->legacyFlag = TRUE;
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
        iface = addrindex_create_interface(
                        ADDR_IF_COMMON, "Old Address - personal",
                        TAG_IF_OLD_PERSONAL, NULL );
        iface->legacyFlag = TRUE;
-       addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
+       addrIndex->interfaceList =
+               g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
 }
 
-/*
-* Free name-value pairs.
-*/
-static void addrindex_free_attributes( GList *list ) {
-       GList *node = list;
+/**
+ * Free DOM fragment.
+ * \param fragment Fragment to free.
+ */
+static addrindex_free_fragment( AddressIfFragment *fragment ) {
+       GList *node;
+
+       /* Free children */
+       node = fragment->children;
+       while( node ) {
+               AddressIfFragment *child = node->data;
+               addrindex_free_fragment( child );
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( fragment->children );
+
+       /* Free attributes */
+       node = fragment->attributes;
        while( node ) {
                AddressIfAttrib *nv = node->data;
-               g_free( nv->name ); nv->name = NULL;
-               g_free( nv->value ); nv->value = NULL;
+               g_free( nv->name );
+               g_free( nv->value );
                g_free( nv );
                node->data = NULL;
                node = g_list_next( node );
        }
-       g_list_free( list );
+       g_list_free( fragment->attributes );
+
+       g_free( fragment->name );
+       fragment->name = NULL;
+       fragment->attributes = NULL;
+       fragment->children = NULL;
+
+       g_free( fragment );
 }
 
-/*
-* Create new data source.
-* Enter: ifType Interface type to create.
-* Return: Initialized data source.
-*/
+/**
+ * Create a new data source.
+ * \param ifType Interface type to create.
+ * \return Initialized data source.
+ */
 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
        AddressDataSource *ds = g_new0( AddressDataSource, 1 );
 
@@ -276,9 +363,10 @@ AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
        return ds;
 }
 
-/*
-* Free up data source.
-*/
+/**
+ * Free up data source.
+ * \param ds Data source to free.
+ */
 void addrindex_free_datasource( AddressDataSource *ds ) {
        AddressInterface *iface;
 
@@ -304,16 +392,16 @@ void addrindex_free_datasource( AddressDataSource *ds ) {
 #endif
 #ifdef USE_LDAP
                                else if( iface->type == ADDR_IF_LDAP ) {
-                                       SyldapServer *server = ds->rawDataSource;
-                                       syldap_free( server );
+                                       LdapServer *server = ds->rawDataSource;
+                                       ldapsvr_free( server );
                                }
 #endif
                                else {
                                }
                        }
                        else {
-                               GList *list = ds->rawDataSource;
-                               addrindex_free_attributes( list );
+                               AddressIfFragment *fragment = ds->rawDataSource;
+                               addrindex_free_fragment( fragment );
                        }
                }
        }
@@ -326,9 +414,14 @@ void addrindex_free_datasource( AddressDataSource *ds ) {
        ds->type = ADDR_IF_NONE;
        ds->interface = NULL;
        ds->rawDataSource = NULL;
+
        g_free( ds );
 }
 
+/**
+ * Free up all data sources for specified interface.
+ * \param iface Address interface to process.
+ */
 static void addrindex_free_all_datasources( AddressInterface *iface ) {
        GList *node = iface->listSource;
        while( node ) {
@@ -339,6 +432,10 @@ static void addrindex_free_all_datasources( AddressInterface *iface ) {
        }
 }
 
+/**
+ * Free up specified interface.
+ * \param iface Interface to process.
+ */
 static void addrindex_free_interface( AddressInterface *iface ) {
        /* Free up data sources */
        addrindex_free_all_datasources( iface );
@@ -366,14 +463,21 @@ static void addrindex_free_interface( AddressInterface *iface ) {
        iface->haveLibrary = FALSE;
        iface->listSource = NULL;
 
+       /* Search stuff */
+       iface->searchOrder = 0;
+       iface->startSearch = NULL;
+       iface->stopSearch = NULL;
+
        g_free( iface );
 }
 
-/*
+/**
  * Return cache ID for specified data source.
- * Enter: addrIndex Address index.
- *        ds        Data source.
- * Return: ID or NULL if not found. This can be g_free() when done.
+ *
+ * \param  addrIndex Address index.
+ * \param  ds        Data source.
+ * \return ID or NULL if not found. This should be <code>g_free()</code>
+ *         when done.
  */
 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
        gchar *cacheID = NULL;
@@ -394,23 +498,25 @@ gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds )
        return cacheID;
 }
 
-/*
- * Return data source for specified cacheID.
- * Enter: addrIndex Address index.
- *        cacheID   ID.
- * Return: Data source, or NULL if not found.
+/**
+ * Return reference to data source for specified cacheID.
+ * \param addrIndex Address index.
+ * \param cacheID   ID.
+ * \return Data source, or NULL if not found.
  */
-AddressDataSource *addrindex_get_datasource( AddressIndex *addrIndex, const gchar *cacheID ) {
+AddressDataSource *addrindex_get_datasource(
+               AddressIndex *addrIndex, const gchar *cacheID )
+{
        g_return_val_if_fail( addrIndex != NULL, NULL );
        g_return_val_if_fail( cacheID != NULL, NULL );
        return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
 }
 
-/*
- * Return cache for specified cacheID.
- * Enter: addrIndex Address index.
- *        cacheID   ID.
- * Return: Address cache, or NULL if not found.
+/**
+ * Return reference to address cache for specified cacheID.
+ * \param addrIndex Address index.
+ * \param cacheID   ID.
+ * \return Address cache, or NULL if not found.
  */
 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
        AddressDataSource *ds;
@@ -429,12 +535,14 @@ AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID
        return cache;
 }
 
-/*
- * Add data source into hash.
- * Enter: addrIndex Address index.
- *        ds        Data source.
+/**
+ * Add data source into hash table.
+ * \param addrIndex Address index.
+ * \param ds        Data source.
  */
-static void addrindex_hash_add_cache( AddressIndex *addrIndex, AddressDataSource *ds ) {
+static void addrindex_hash_add_cache(
+               AddressIndex *addrIndex, AddressDataSource *ds )
+{
        gchar *cacheID;
 
        cacheID = addrindex_get_cache_id( addrIndex, ds );
@@ -444,8 +552,8 @@ static void addrindex_hash_add_cache( AddressIndex *addrIndex, AddressDataSource
 }
 
 /*
-* Free hash table callback function.
-*/
+ * Free hash table callback function.
+ */
 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
        g_free( key );
        key = NULL;
@@ -454,8 +562,8 @@ static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer
 }
 
 /*
-* Free hash table of address cache items.
-*/
+ * 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 );
@@ -464,9 +572,13 @@ static void addrindex_free_cache_hash( GHashTable *table ) {
 }
 
 /*
-* Remove address cache for specified data source from internal hashtable.
-*/
-static void addrindex_hash_remove_cache( AddressIndex *addrIndex, AddressDataSource *ds ) {
+ * Remove data source from internal hashtable.
+ * \param addrIndex Address index.
+ * \param ds        Data source to remove.
+ */
+static void addrindex_hash_remove_cache(
+               AddressIndex *addrIndex, AddressDataSource *ds )
+{
        gchar *cacheID;
 
        cacheID = addrindex_get_cache_id( addrIndex, ds );
@@ -478,8 +590,9 @@ static void addrindex_hash_remove_cache( AddressIndex *addrIndex, AddressDataSou
 }
 
 /*
-* Create new object.
-*/
+ * Create a new address index.
+ * \return Initialized address index object.
+ */
 AddressIndex *addrindex_create_index( void ) {
        AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
 
@@ -498,46 +611,99 @@ AddressIndex *addrindex_create_index( void ) {
        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;
 }
 
-/*
-* Specify file to be used.
-*/
+/**
+ * Property - Specify file path to address index file.
+ * \param addrIndex Address index.
+ * \param value Path to index file.
+ */
 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
        g_return_if_fail( addrIndex != NULL );
        addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
 }
+
+/**
+ * Property - Specify file name to address index file.
+ * \param addrIndex Address index.
+ * \param value File name.
+ */
 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
        g_return_if_fail( addrIndex != NULL );
        addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
 }
+
+/**
+ * Property - Specify file path to be used.
+ * \param addrIndex Address index.
+ * \param value Path to JPilot file.
+ */
 void addrindex_set_dirty( AddressIndex *addrIndex, const gboolean value ) {
        g_return_if_fail( addrIndex != NULL );
        addrIndex->dirtyFlag = value;
 }
 
-/*
-* Return list of interfaces.
-*/
+/**
+ * Property - get loaded flag. Note that this flag is set after reading data
+ * from the address books.
+ * \param addrIndex Address index.
+ * \return <i>TRUE</i> if address index data was loaded.
+ */
+gboolean addrindex_get_loaded( AddressIndex *addrIndex ) {
+       g_return_val_if_fail( addrIndex != NULL, FALSE );
+       return addrIndex->loadedFlag;
+}
+
+/**
+ * Return list of address interfaces.
+ * \param addrIndex Address index.
+ * \return List of address interfaces.
+ */
 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
        g_return_val_if_fail( addrIndex != NULL, NULL );
        return addrIndex->interfaceList;
 }
 
-/*
-* Free up object.
-*/
+/**
+ * Perform any other initialization of address index.
+ * \param addrIndex Address index.
+ */
+void addrindex_initialize( AddressIndex *addrIndex ) {
+       addrcompl_initialize( addrIndex );
+}
+
+/**
+ * Perform any other teardown of address index.
+ * \param addrIndex Address index.
+ */
+void addrindex_teardown( AddressIndex *addrIndex ) {
+       addrcompl_teardown();
+}
+
+/**
+ * Free up address index.
+ * \param addrIndex Address index.
+ */
 void addrindex_free_index( AddressIndex *addrIndex ) {
        GList *node;
 
        g_return_if_fail( addrIndex != NULL );
 
+       /* Search stuff */
+       g_list_free( addrIndex->searchOrder );
+       addrIndex->searchOrder = NULL;
+
+       /* Free internal storage */
        g_free( ADDRITEM_ID(addrIndex) );
        g_free( ADDRITEM_NAME(addrIndex) );
        g_free( addrIndex->filePath );
        g_free( addrIndex->fileName );
+
+       /* Clear pointers */    
        ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
        ADDRITEM_ID(addrIndex) = NULL;
        ADDRITEM_NAME(addrIndex) = NULL;
@@ -551,6 +717,8 @@ void addrindex_free_index( AddressIndex *addrIndex ) {
        addrIndex->conversionError = FALSE;
        addrIndex->lastType = ADDR_IF_NONE;
        addrIndex->dirtyFlag = FALSE;
+
+       /* Free up interfaces */        
        node = addrIndex->interfaceList;
        while( node ) {
                AddressInterface *iface = node->data;
@@ -559,28 +727,40 @@ void addrindex_free_index( AddressIndex *addrIndex ) {
        }
        g_list_free( addrIndex->interfaceList );
        addrIndex->interfaceList = NULL;
+
+       /* Free up hash cache */
        addrindex_free_cache_hash( addrIndex->hashCache );
        addrIndex->hashCache = NULL;
+
+       addrIndex->loadedFlag = FALSE;
+
        g_free( addrIndex );
 }
 
-/*
-* Print address index.
+/**
+ * Print address index.
+ * \param addrIndex Address index.
+ * \parem stream    Stream to print.
 */
 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
        g_return_if_fail( addrIndex != NULL );
        fprintf( stream, "AddressIndex:\n" );
        fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
        fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
-       fprintf( stream, "\t   status: %d\n",   addrIndex->retVal );
-       fprintf( stream, "\tconverted: '%s'\n", addrIndex->wasConverted ? "yes" : "no" );
-       fprintf( stream, "\tcvt error: '%s'\n", addrIndex->conversionError ? "yes" : "no" );
+       fprintf( stream, "\t   status: %d\n", addrIndex->retVal );
+       fprintf( stream, "\tconverted: '%s'\n",
+                       addrIndex->wasConverted ? "yes" : "no" );
+       fprintf( stream, "\tcvt error: '%s'\n",
+                       addrIndex->conversionError ? "yes" : "no" );
        fprintf( stream, "\t---\n" );
 }
 
-/*
-* Retrieve specified interface from index.
-*/
+/**
+ * Retrieve reference to address interface for specified interface type.
+ * \param  addrIndex Address index.
+ * \param  ifType Interface type.
+ * \return Address interface, or NULL if not found.
+ */
 AddressInterface *addrindex_get_interface(
        AddressIndex *addrIndex, AddressIfType ifType )
 {
@@ -601,15 +781,16 @@ AddressInterface *addrindex_get_interface(
        return retVal;
 }
 
-/*
-* Add data source to index.
-* Enter: addrIndex  Address index object.
-*        ifType     Interface type to add.
-*        dataSource Actual data source to add.
-* Return: TRUE if data source was added.
-* Note: The raw data object (for example, AddressBookFile or VCardFile object) should be
-* supplied as the dataSource argument.
-*/
+/**
+ * Add raw data source to index. The raw data object (an AddressBookFile or
+ * VCardFile object, for example) should be supplied as the raw dataSource
+ * argument.
+ *
+ * \param  addrIndex Address index.
+ * \param ifType     Interface type to add.
+ * \param dataSource Actual raw data source to add. 
+ * \return Data source added, or NULL if invalid interface type.
+ */
 AddressDataSource *addrindex_index_add_datasource(
        AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
 {
@@ -634,13 +815,13 @@ AddressDataSource *addrindex_index_add_datasource(
        return ds;
 }
 
-/*
-* Remove data source from index.
-* Enter: addrIndex  Address index object.
-*        dataSource Data source to remove.
-* Return: Data source if removed, or NULL if data source was not found in
-* index. Note the this object must still be freed.
-*/
+/**
+ * Remove specified data source from index.
+ * \param  addrIndex Address index.
+ * \param  dataSource Data source to add. 
+ * \return Reference to data source if removed, or NULL if data source was not
+ *         found in index. Note the this object must still be freed.
+ */
 AddressDataSource *addrindex_index_remove_datasource(
        AddressIndex *addrIndex, AddressDataSource *dataSource )
 {
@@ -664,6 +845,14 @@ AddressDataSource *addrindex_index_remove_datasource(
        return retVal;
 }
 
+/**
+ * Retrieve a reference to address interface for specified interface type and
+ * XML interface tag name.
+ * \param  addrIndex Address index.
+ * \param  tag       XML interface tag name to match.
+ * \param  ifType    Interface type to match.
+ * \return Reference to address index, or NULL if not found in index.
+ */
 static AddressInterface *addrindex_tag_get_interface(
        AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
 {
@@ -689,6 +878,14 @@ static AddressInterface *addrindex_tag_get_interface(
        return retVal;
 }
 
+/**
+ * Retrieve a reference to address interface for specified interface type and
+ * XML datasource tag name.
+ * \param  addrIndex Address index.
+ * \param  ifType    Interface type to match.
+ * \param  tag       XML datasource tag name to match.
+ * \return Reference to address index, or NULL if not found in index.
+ */
 static AddressInterface *addrindex_tag_get_datasource(
        AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
 {
@@ -712,26 +909,27 @@ static AddressInterface *addrindex_tag_get_datasource(
 * Interface XML parsing functions.
 * ***********************************************************************
 */
-/*
-static void show_attribs( GList *attr ) {
-       while( attr ) {
-               gchar *name = ((XMLAttr *)attr->data)->name;
-               gchar *value = ((XMLAttr *)attr->data)->value;
-               printf( "\tattr value : %s :%s:\n", name, value );
-               attr = g_list_next( attr );
-       }
-       printf( "\t---\n" );
-}
-*/
 
-static void addrindex_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
+/**
+ * Write start of XML element to file.
+ * \param fp   File.
+ * \param lvl  Indentation level.
+ * \param name Element name.
+ */
+static void addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
        gint i;
        for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
        fputs( "<", fp );
        fputs( name, fp );
 }
 
-static void addrindex_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
+/**
+ * Write end of XML element to file.
+ * \param fp   File.
+ * \param lvl  Indentation level.
+ * \param name Element name.
+ */
+static void addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
        gint i;
        for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
        fputs( "</", fp );
@@ -739,7 +937,13 @@ static void addrindex_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
        fputs( ">\n", fp );
 }
 
-static void addrindex_write_attr( FILE *fp, gchar *name, gchar *value ) {
+/**
+ * Write XML attribute to file.
+ * \param fp    File.
+ * \param name  Attribute name.
+ * \param value Attribute value.
+ */
+static void addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
        fputs( " ", fp );
        fputs( name, fp );
        fputs( "=\"", fp );
@@ -747,16 +951,38 @@ static void addrindex_write_attr( FILE *fp, gchar *name, gchar *value ) {
        fputs( "\"", fp );
 }
 
-/*
-* Return list of name-value pairs.
-*/
-static GList *addrindex_read_attributes( XMLFile *file ) {
-       GList *list = NULL;
+/**
+ * Return DOM fragment for current XML tag from file.
+ * \param  file XML file being processed.
+ * \return Fragment representing DOM fragment for configuration element.
+ */
+static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
+       AddressIfFragment *fragment;
+       AddressIfFragment *child;
        AddressIfAttrib *nv;
+       XMLTag *xtag;
+       GList *list;
        GList *attr;
        gchar *name;
        gchar *value;
+       guint prevLevel;
+       gint rc;
+
+       /* printf( "addrindex_read_fragment\n" ); */
+
+       prevLevel = file->level;
+
+       /* Get current tag name */
+       xtag = xml_get_current_tag( file );
 
+       /* Create new fragment */
+       fragment = g_new0( AddressIfFragment, 1 );
+       fragment->name = g_strdup( xtag->tag );
+       fragment->children = NULL;
+       fragment->attributes = NULL;
+
+       /* Read attributes */
+       list = NULL;
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
                name = ((XMLAttr *)attr->data)->name;
@@ -767,38 +993,102 @@ static GList *addrindex_read_attributes( XMLFile *file ) {
                list = g_list_append( list, nv );
                attr = g_list_next( attr );
        }
-       return list;
+       fragment->attributes = list;
+
+       /* Now read the children */
+       while( TRUE ) {
+               rc = xml_parse_next_tag( file );
+               if( rc != 0 ) {
+                       /* End of file? */
+                       break;
+               }
+               if( file->level < prevLevel ) {
+                       /* We must be above level we start at */
+                       break;
+               }
+               child = addrindex_read_fragment( file );
+               fragment->children = g_list_append( fragment->children, child );
+       }
+
+       return fragment;
 }
 
-/*
-* Output name-value pairs.
-*/
-static void addrindex_write_attributes( FILE *fp, gchar *tag, GList *list, gint lvl ) {
+/**
+ * Write DOM fragment to file.
+ * \param fp       File to write.
+ * \param fragment DOM fragment for configuration element.
+ * \param lvl      Indent level.
+ */
+static void addrindex_write_fragment(
+               FILE *fp, const AddressIfFragment *fragment, const gint lvl )
+{
        GList *node;
-       AddressIfAttrib *nv;
-       if( list ) {
-               addrindex_write_elem_s( fp, lvl, tag );
-               node = list;
+
+       if( fragment ) {
+               addrindex_write_elem_s( fp, lvl, fragment->name );
+               node = fragment->attributes;
                while( node ) {
-                       nv = node->data;
+                       AddressIfAttrib *nv = node->data;
                        addrindex_write_attr( fp, nv->name, nv->value );
                        node = g_list_next( node );
                }
-               fputs(" />\n", fp);
+               if( fragment->children ) {
+                       fputs(" >\n", fp);
+
+                       /* Output children */
+                       node = fragment->children;
+                       while( node ) {
+                               AddressIfFragment *child = node->data;
+                               addrindex_write_fragment( fp, child, 1+lvl );
+                               node = g_list_next( node );
+                       }
+
+                       /* Output closing tag */
+                       addrindex_write_elem_e( fp, lvl, fragment->name );
+               }
+               else {
+                       fputs(" />\n", fp);
+               }
        }
 }
 
 /*
-static void addrindex_print_attributes( GList *list, FILE *stream ) {
-       GList *node = list;
+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;
-               fprintf( stream, "%s : %s\n", nv->name, nv->value );
+               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.
+ * \param  file Address index file.
+ * \return Data source.
+ */
 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
        AddressDataSource *ds;
        AddressBookFile *abf;
@@ -923,110 +1213,260 @@ static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
                fputs( " />\n", fp );
        }
 }
+
 #else
-/* Just read/write name-value pairs (preserve data found in file)  */
+/*
+ * 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_attributes( file );
+       ds->rawDataSource = addrindex_read_fragment( file );
        return ds;
 }
 
 static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
-       GList *list = ds->rawDataSource;
-       if( list ) {
-               addrindex_write_attributes( fp, TAG_DS_JPILOT, list, lvl );
+       AddressIfFragment *fragment = ds->rawDataSource;
+       if( fragment ) {
+               addrindex_write_fragment( fp, fragment, lvl );
        }
 }
 #endif
 
 #ifdef USE_LDAP
+/**
+ * Parse LDAP criteria attribute data from XML file.
+ * \param file Index file.
+ * \param ctl  LDAP control object to populate.
+ */
+static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
+       guint prevLevel;
+       XMLTag *xtag;
+       XMLTag *xtagPrev;
+       gint rc;
+       GList *attr;
+       GList *list;
+       GList *node;
+
+       if( file == NULL ) {
+               return;
+       }
+
+       list = NULL;
+       prevLevel = file->level;
+       xtagPrev = xml_get_current_tag( file );
+       while( TRUE ) {
+               rc = xml_parse_next_tag( file );
+               if( rc != 0 ) {
+                       /* Terminate prematurely */
+                       mgu_free_dlist( list );
+                       list = NULL;
+                       return;
+               }
+               if( file->level < prevLevel ) {
+                       /* We must be above level we start at */
+                       break;
+               }
+
+               /* Get a tag (element) */
+               xtag = xml_get_current_tag( file );
+               if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
+                       /* LDAP criteria attribute */
+                       attr = xml_get_current_tag_attr( file );
+                       while( attr ) {
+                               gchar *name = ((XMLAttr *)attr->data)->name;
+                               gchar *value = ((XMLAttr *)attr->data)->value;
+                               if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
+                                       if( value && strlen( value ) > 0 ) {
+                                               list = g_list_append(
+                                                       list, g_strdup( value ) );
+                                       }
+                               }
+                               attr = g_list_next( attr );
+                       }
+               }
+               else {
+                       if( xtag != xtagPrev ) {
+                               /* Found a new tag */
+                               break;
+                       }
+               }
+               xtag = xtagPrev;
+       }
+
+       /* Build list of search attributes */
+       ldapctl_criteria_list_clear( ctl );
+       node = list;
+       while( node ) {
+               ldapctl_criteria_list_add( ctl, node->data );
+               g_free( node->data );
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( list );
+       list = NULL;
+
+}
+
 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
        AddressDataSource *ds;
-       SyldapServer *server;
+       LdapServer *server;
+       LdapControl *ctl;
        GList *attr;
+       gchar *serverName = NULL;
+       gchar *criteria = NULL;
+       gboolean bSearch = FALSE;
+       gboolean cvtFlag = TRUE;
+
+       /* printf( "addrindex_parse_ldap\n" ); */
 
        ds = addrindex_create_datasource( ADDR_IF_LDAP );
-       server = syldap_create();
+       ctl = ldapctl_create();
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
                gchar *name = ((XMLAttr *)attr->data)->name;
                gchar *value = ((XMLAttr *)attr->data)->value;
                gint ivalue = atoi( value );
+
                if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
-                       syldap_set_name( server, value );
+                       if( serverName ) g_free( serverName );
+                       serverName = g_strdup( value );
                }
                else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
-                       syldap_set_host( server, value );
+                       ldapctl_set_host( ctl, value );
                }
                else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
-                       syldap_set_port( server, ivalue );
+                       ldapctl_set_port( ctl, ivalue );
                }
                else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
-                       syldap_set_base_dn( server, value );
+                       ldapctl_set_base_dn( ctl, value );
                }
                else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
-                       syldap_set_bind_dn( server, value );
+                       ldapctl_set_bind_dn( ctl, value );
                }
                else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
-                       syldap_set_bind_password( server, value );
+                       ldapctl_set_bind_password( ctl, value );
                }
                else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
-                       syldap_set_search_criteria( server, value );
+                       if( criteria ) g_free( criteria );
+                       criteria = g_strdup( value );
                }
                else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
-                       syldap_set_max_entries( server, ivalue );
+                       ldapctl_set_max_entries( ctl, ivalue );
                }
                else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
-                       syldap_set_timeout( server, ivalue );
+                       ldapctl_set_timeout( ctl, ivalue );
+               }
+               else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
+                       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;
+                       }
                }
                attr = g_list_next( attr );
        }
 
+       server = ldapsvr_create_noctl();
+       ldapsvr_set_name( server, serverName );
+       ldapsvr_set_search_flag( server, bSearch );
+       g_free( serverName );
+       ldapsvr_set_control( server, ctl );
        ds->rawDataSource = server;
+
+       addrindex_parse_ldap_attrlist( file, ctl );
+       /*
+        * If criteria have been specified and no attributes were listed, then
+        * convert old style criteria into an attribute list. Any criteria will
+        * be dropped when saving data.
+        */
+       if( criteria ) {
+               if( ! ldapctl_get_criteria_list( ctl ) ) {
+                       ldapctl_parse_ldap_search( ctl, criteria );
+               }
+               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;
 }
 
 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
-       SyldapServer *server = ds->rawDataSource;
+       LdapServer *server = ds->rawDataSource;
+       LdapControl *ctl = NULL;
+       GList *node;
+       gchar value[256];
+
        if( server ) {
-               gchar value[256];
+               ctl = server->control;
+       }
+       if( ctl == NULL ) return;
+
+       /* Output start element with attributes */
+       addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
+       addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) );
+       addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName );
 
-               addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
-               addrindex_write_attr( fp, ATTAG_LDAP_NAME, syldap_get_name( server ) );
-               addrindex_write_attr( fp, ATTAG_LDAP_HOST, server->hostName );
+       sprintf( value, "%d", ctl->port );      
+       addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
 
-               sprintf( value, "%d", server->port );   
-               addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
+       addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN );
+       addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN );
+       addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, ctl->bindPass );
 
-               addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, server->baseDN );
-               addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, server->bindDN );
-               addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, server->bindPass );
-               addrindex_write_attr( fp, ATTAG_LDAP_CRITERIA, server->searchCriteria );
+       sprintf( value, "%d", ctl->maxEntries );
+       addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
+       sprintf( value, "%d", ctl->timeOut );
+       addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
+       sprintf( value, "%d", ctl->maxQueryAge );
+       addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value );
 
-               sprintf( value, "%d", server->maxEntries );
-               addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
-               sprintf( value, "%d", server->timeOut );
-               addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
+       addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
+                       server->searchFlag ? "yes" : "no" );
 
+       fputs(" >\n", fp);
+
+       /* Output attributes */
+       node = ldapctl_get_criteria_list( ctl );
+       while( node ) {
+               addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH );
+               addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data );
                fputs(" />\n", fp);
+               node = g_list_next( node );
        }
+
+       /* End of element */    
+       addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP );
+
 }
+
 #else
-/* Just read/write name-value pairs (preserve data found in file)  */
+/*
+ * 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_attributes( file );
+       ds->rawDataSource = addrindex_read_fragment( file );
        return ds;
 }
 
 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
-       GList *list = ds->rawDataSource;
-       if( list ) {
-               addrindex_write_attributes( fp, TAG_DS_LDAP, list, lvl );
+       AddressIfFragment *fragment = ds->rawDataSource;
+       if( fragment ) {
+               addrindex_write_fragment( fp, fragment, lvl );
        }
 }
 #endif
@@ -1035,16 +1475,25 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
 * Address index I/O functions.
 * ***********************************************************************
 */
+/**
+ * Read address index file, creating appropriate data sources for each address
+ * index file entry.
+ *
+ * \param  addrIndex Address index.
+ * \param  file Address index file.
+ */
 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
        guint prev_level;
        XMLTag *xtag;
        AddressInterface *iface = NULL, *dsIFace = NULL;
        AddressDataSource *ds;
+       gint rc;
 
+       addrIndex->loadedFlag = FALSE;
        for (;;) {
                prev_level = file->level;
-               xml_parse_next_tag( file );
-               if( file->level < prev_level ) return;
+               rc = xml_parse_next_tag( file );
+               if( file->level == 0 ) return;
 
                xtag = xml_get_current_tag( file );
 
@@ -1083,7 +1532,44 @@ static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
                                }
                        }
                }
-               addrindex_read_index( addrIndex, file );
+       }
+}
+
+/*
+ * Search order sorting comparison function for building search order list.
+ */
+static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
+       AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
+       AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
+
+       return ifaceA->searchOrder - ifaceB->searchOrder;
+}
+
+/**
+ * Build list of data sources to process.
+ * \param addrIndex Address index object.
+ */
+static void addrindex_build_search_order( AddressIndex *addrIndex ) {
+       AddressInterface *iface;
+       GList *nodeIf;
+
+       /* Clear existing list */
+       g_list_free( addrIndex->searchOrder );
+       addrIndex->searchOrder = NULL;
+
+       /* Build new list */
+       nodeIf = addrIndex->interfaceList;
+       while( nodeIf ) {
+               AddressInterface *iface = nodeIf->data;
+               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 );
        }
 }
 
@@ -1099,7 +1585,9 @@ static gint addrindex_read_file( AddressIndex *addrIndex ) {
        g_free( fileSpec );
 
        if( file == NULL ) {
-               /* fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); */
+               /*
+               fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
+               */
                return addrIndex->retVal;
        }
 
@@ -1114,6 +1602,8 @@ static gint addrindex_read_file( AddressIndex *addrIndex ) {
        }
        xml_close_file( file );
 
+       addrindex_build_search_order( addrIndex );
+
        return addrIndex->retVal;
 }
 
@@ -1828,6 +2318,8 @@ 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;
@@ -1954,6 +2446,402 @@ GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
        return retVal;
 }
 
-/*
-* End of Source.
+/* **********************************************************************
+* Address search stuff.
+* ***********************************************************************
 */
+
+/**
+ * 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.
+ * \return ID allocated to query that will be executed.
+ */
+gint addrindex_setup_search(
+       AddressIndex *addrIndex, const gchar *searchTerm,
+       const gpointer target, AddrSearchCallbackFunc callBack )
+{
+       gint queryID;
+
+       /* printf( "search term ::%s::\n", searchTerm ); */
+       g_free( _searchTerm_ );
+       _searchTerm_ = g_strdup( searchTerm );
+
+       queryID = ++_currentQueryID_;
+       _searchTarget_ = target;
+       _searchCallback_ = callBack;
+       /* printf( "query ID ::%d::\n", queryID ); */
+       return queryID;
+}
+
+#ifdef USE_LDAP
+/**
+ * LDAP callback entry point for each address entry found.
+ * \param qry       LDAP query.
+ * \param listEMail List of Item EMail objects found.
+ */
+static void addrindex_ldap_entry_cb( LdapQuery *qry, GList *listEMail ) {
+       /*
+       GList *node;
+
+       printf( "\naddrindex::addrindex_ldap_entry_cb ::%s::\n", qry->queryName );
+       node = listEMail;
+       while( node ) {
+               ItemEMail *email = node->data;
+               printf( "\temail ::%s::\n", email->address );
+               node = g_list_next( node );
+       }
+       */
+       if( _searchCallback_ ) {
+               ( _searchCallback_ ) ( qry->queryID, listEMail, _searchTarget_ );
+       }
+       g_list_free( listEMail );
+}
+
+/**
+ * LDAP callback entry point for completion of search.
+ * \param qry LDAP query.
+ */
+static void addrindex_ldap_end_cb( LdapQuery *qry ) {
+       /* printf( "\naddrindex::addrindex_ldap_end_cb ::%s::\n", qry->queryName ); */
+}
+
+/**
+ * Return results of previous query.
+ * \param folder.
+ * \return List of ItemEMail objects.
+ */
+static void addrindex_ldap_use_previous( const ItemFolder *folder, const gint queryID )
+{
+       GList *listEMail;
+       GList *node;
+       GList *nodeEM;
+
+       listEMail = NULL;
+       if( _searchCallback_ ) {
+               node = folder->listPerson;
+               while( node ) {
+                       AddrItemObject *aio = node->data;
+                       if( aio &&  aio->type == ITEMTYPE_PERSON ) {
+                               ItemPerson *person = node->data;
+                               nodeEM = person->listEMail;
+                               while( nodeEM ) {
+                                       ItemEMail *email = nodeEM->data;
+                                       nodeEM = g_list_next( nodeEM );
+                                       listEMail = g_list_append( listEMail, email );
+                               }
+                       }
+                       node = g_list_next( node );
+               }
+               ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
+               g_list_free( listEMail );
+       }
+}
+
+LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
+
+/**
+ * Construct an LDAP query and initiate an LDAP search.
+ * \param server  LDAP server object.
+ * \param queryID ID of search query to be executed.
+ */
+static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
+       LdapQuery *qry;
+       gchar *name;
+
+       if( ! server->searchFlag ) return;
+
+       /* Retire any aged queries */
+       ldapsvr_retire_query( server );
+
+       /* Test whether any queries for the same term exist */
+       qry = ldapsvr_locate_query( server, _searchTerm_ );
+       if( qry ) {
+               ItemFolder *folder = qry->folder;
+
+               /* Touch query to ensure it hangs around for a bit longer */
+               ldapqry_touch( qry );
+               if( folder ) {
+                       addrindex_ldap_use_previous( folder, queryID );
+                       return;
+               }
+       }
+
+       /* Construct a query */
+       qry = ldapqry_create();
+       ldapqry_set_query_id( qry, queryID );
+       ldapqry_set_search_value( qry, _searchTerm_ );
+       ldapqry_set_query_type( qry, LDAPQUERY_DYNAMIC );
+       ldapqry_set_callback_entry( qry, addrindex_ldap_entry_cb );
+       ldapqry_set_callback_end( qry, addrindex_ldap_end_cb );
+
+       /* Name the query */
+       name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
+       ldapqry_set_name( qry, name );
+       g_free( name );
+
+       ldapsvr_add_query( server, qry );
+       ldapsvr_execute_query( server, qry );
+}
+
+/**
+ * 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.
+ *
+ */
+void addrindex_search_ldap_noid(
+       LdapServer *server, const gchar *searchTerm, void * callbackEnd )
+{
+       LdapQuery *qry;
+       gchar *name;
+
+       /* 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 );
+
+       /* Name the query */
+       name = g_strdup_printf( "Static Search for '%s'", searchTerm );
+       ldapqry_set_name( qry, name );
+       g_free( name );
+
+       ldapsvr_add_query( server, qry );
+       /* printf( "addrindex_search_ldap_noid::executing static search...\n" ); */
+       ldapsvr_execute_query( server, qry );
+}
+#endif
+
+/**
+ * Perform the previously registered search.
+ * \param  addrIndex  Address index object.
+ * \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;
+       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;
+               }
+
+               if( ! iface->externalQuery ) {
+                       continue;
+               }
+
+               type = iface->type;
+               nodeDS = iface->listSource;
+               while( nodeDS ) {
+                       ds = nodeDS->data;
+                       nodeDS = g_list_next( nodeDS );
+#ifdef USE_LDAP
+                       if( type == ADDR_IF_LDAP ) {
+                               LdapServer *server = ds->rawDataSource;
+                               addrindex_search_ldap( server, queryID );
+                       }
+#endif
+               }
+       }
+       return TRUE;
+}
+
+/**
+ * Stop the previously registered search.
+ * \param addrIndex Address index object.
+ * \param queryID ID of search query to stop.
+ */
+void addrindex_stop_search( AddressIndex *addrIndex, const gint queryID ){
+#ifdef USE_LDAP
+       AddressInterface *iface;
+       AddressDataSource *ds;
+       GList *nodeIf;
+       GList *nodeDS;
+       gint type;
+
+       /* If query ID does not match, search has not been setup */
+       /* if( queryID != _queryID_ ) return; */
+
+       /* printf( "addrindex_stop_search::%d::\n", queryID ); */
+       nodeIf = addrIndex->searchOrder;
+       while( nodeIf ) {
+               iface = nodeIf->data;
+               nodeIf = g_list_next( nodeIf );
+
+               if( ! iface->useInterface ) {
+                       continue;
+               }
+
+               type = iface->type;
+               nodeDS = iface->listSource;
+               while( nodeDS ) {
+                       ds = nodeDS->data;
+                       nodeDS = g_list_next( nodeDS );
+                       if( type == ADDR_IF_LDAP ) {
+                               LdapServer *server = ds->rawDataSource;
+                               ldapsvr_stop_all_query( server );
+                       }
+               }
+       }
+#endif
+}
+
+/**
+ * Read all address books that do not support dynamic queries.
+ * \param addrIndex Address index object.
+ */
+void addrindex_read_all( AddressIndex *addrIndex ) {
+       AddressInterface *iface;
+       AddressDataSource *ds;
+       GList *nodeIf;
+       GList *nodeDS;
+
+       nodeIf = addrIndex->searchOrder;
+       while( nodeIf ) {
+               iface = nodeIf->data;
+               nodeIf = g_list_next( nodeIf );
+
+               if( ! iface->useInterface ) {
+                       continue;
+               }
+               if( iface->externalQuery ) {
+                       continue;
+               }
+               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;
+}
+
+/**
+ * This function is used by the address completion function to load
+ * addresses for all non-external address book interfaces.
+ *
+ * \param addrIndex Address index object.
+ * \param callBackFunc Function to be called when an address is
+ *                     to be loaded.
+ * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded.
+ */
+gboolean addrindex_load_completion(
+               AddressIndex *addrIndex,
+               gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) )
+{
+       AddressDataSource *ds;
+       AddressInterface *iface;
+       GList *nodeIf, *nodeDS;
+       GList *listP, *nodeP;
+       GList *nodeM;
+       gchar *sName, *sAddress, *sAlias, *sFriendly;
+
+       if( addrIndex == NULL ) return FALSE;
+
+       nodeIf = addrindex_get_interface_list( addrIndex );
+       while( nodeIf ) {
+               AddressInterface *iface = nodeIf->data;
+
+               nodeIf = g_list_next( nodeIf );
+               if( ! iface->useInterface ) {
+                       continue;
+               }
+               if( iface->externalQuery ) {
+                       continue;
+               }
+               nodeDS = iface->listSource;
+               while( nodeDS ) {
+                       ds = nodeDS->data;
+
+                       /* Read address book */
+                       if( addrindex_ds_get_modify_flag( ds ) ) {
+                               addrindex_ds_read_data( ds );
+                       }
+
+                       if( ! addrindex_ds_get_read_flag( ds ) ) {
+                               addrindex_ds_read_data( ds );
+                       }
+
+                       /* 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 = person->nickName;
+                               if( sName == NULL || *sName == '\0' ) {
+                                       sName = ADDRITEM_NAME(person);
+                               }
+
+                               /* Process each E-Mail address */
+                               while( nodeM ) {
+                                       ItemEMail *email = nodeM->data;
+                                       /* Have mail */
+                                       sFriendly = sName;
+                                       sAddress = email->address;
+                                       if( sAddress || *sAddress != '\0' ) {
+                                               sAlias = ADDRITEM_NAME(email);
+                                               if( sAlias && *sAlias != '\0' ) {
+                                                       sFriendly = sAlias;
+                                               }
+                                               ( callBackFunc ) ( sFriendly, sAddress, sName );
+                                       }
+
+                                       nodeM = g_list_next( nodeM );
+                               }
+                               nodeP = g_list_next( nodeP );
+                       }
+                       /* Free up the list */
+                       g_list_free( listP );
+
+                       nodeDS = g_list_next( nodeDS );
+               }
+       }
+
+       return TRUE;
+}
+
+/*
+ * End of Source.
+ */
+
+
index 2c602c1..ab08261 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001-2002 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
@@ -28,6 +28,7 @@
 #include <glib.h>
 #include "addritem.h"
 #include "addrcache.h"
+#include "addrquery.h"
 
 #define ADDRESSBOOK_MAX_IFACE  4
 #define ADDRESSBOOK_INDEX_FILE "addrbook--index.xml"
@@ -56,6 +57,8 @@ struct _AddressIndex {
        gboolean dirtyFlag;
        GList *interfaceList;
        GHashTable *hashCache;
+       gboolean loadedFlag;
+       GList *searchOrder;
 };
 
 typedef struct _AddressInterface AddressInterface;
@@ -82,6 +85,10 @@ struct _AddressInterface {
        GList *(*getAllGroups)( void * );
        gchar *(*getName)( void * );
        void (*setAccessFlag)( void *, void * );
+       gboolean externalQuery;
+       gint searchOrder;
+       void (*startSearch)( void * );
+       void (*stopSearch)( void * );
 };
 
 typedef struct _AddressDataSource AddressDataSource;
@@ -99,6 +106,8 @@ void addrindex_set_file_name         ( AddressIndex *addrIndex,
                                          const gchar *value );
 void addrindex_set_dirty               ( AddressIndex *addrIndex,
                                          const gboolean value );
+gboolean addrindex_get_loaded          ( AddressIndex *addrIndex );
+
 GList *addrindex_get_interface_list    ( AddressIndex *addrIndex );
 void addrindex_free_index              ( AddressIndex *addrIndex );
 void addrindex_print_index             ( AddressIndex *addrIndex, FILE *stream );
@@ -144,6 +153,22 @@ gboolean addrindex_ds_get_readonly ( AddressDataSource *ds );
 GList *addrindex_ds_get_all_persons    ( AddressDataSource *ds );
 GList *addrindex_ds_get_all_groups     ( AddressDataSource *ds );
 
+/* Search support */
+gint addrindex_setup_search    ( AddressIndex *addrIndex,
+                                 const gchar *searchTerm,
+                                 const gpointer target,
+                                 AddrSearchCallbackFunc callBack );
+gboolean addrindex_start_search        ( AddressIndex *addrIndex,
+                                 const gint queryID );
+void addrindex_stop_search     ( AddressIndex *addrIndex,
+                                 const gint queryID );
+
+void addrindex_read_all                ( AddressIndex *addrIndex );
+gboolean addrindex_load_completion(
+               AddressIndex *addrIndex,
+               gint (*callBackFunc)
+                       ( const gchar *, const gchar *, const gchar * ) );
+
 #endif /* __ADDRINDEX_H__ */
 
 /*
index 8da644e..0c78ea5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001-2002 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
@@ -903,9 +903,10 @@ void addritem_print_item_group( ItemGroup *group, FILE *stream ) {
        fprintf( stream, "\t***\n" );
 }
 
-/*
-* Create new address folder.
-*/
+/**
+ * Create new address folder.
+ * \return Initialized address folder object.
+ */
 ItemFolder *addritem_create_item_folder( void ) {
        ItemFolder *folder;
        folder = g_new0( ItemFolder, 1 );
@@ -920,14 +921,17 @@ ItemFolder *addritem_create_item_folder( void ) {
        folder->listFolder = NULL;
        folder->listPerson = NULL;
        folder->listGroup = NULL;
+       folder->folderType = ADDRFOLDER_NONE;
+       folder->folderData = NULL;
        return folder;
 }
 
-/*
-* Copy address book folder.
-* Enter:  item Folder to copy.
-* Return: A copy of the folder. 
-*/
+/**
+ * Copy address book folder. Note that only the folder and not its contents are
+ * copied.
+ * \param  item Folder to copy.
+ * \return A copy of the folder, or <i>NULL</i> if null argument supplied.
+ */
 ItemFolder *addritem_copy_item_folder( ItemFolder *item ) {
        ItemFolder *itemNew;
 
@@ -935,6 +939,7 @@ ItemFolder *addritem_copy_item_folder( ItemFolder *item ) {
        if( item ) {
                itemNew = addritem_create_item_folder();
                ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+               itemNew->folderType = item->folderType;
        }
        return itemNew;
 }
@@ -966,11 +971,12 @@ void addritem_folder_set_remarks( ItemFolder *folder, const gchar *value ) {
        folder->remarks = mgu_replace_string( folder->remarks, value );
 }
 
-/*
-* Free address folder. Note: this does not free up the lists of children
-* (folders, groups and person). This should be done prior to calling this
-* function.
-*/
+/**
+ * Free address folder. Note: this does not free up the lists of children
+ * (folders, groups and person). This should be done prior to calling this
+ * function.
+ * \param folder Folder to free.
+ */
 void addritem_free_item_folder( ItemFolder *folder ) {
        g_return_if_fail( folder != NULL );
 
@@ -992,6 +998,8 @@ void addritem_free_item_folder( ItemFolder *folder ) {
        folder->listFolder = NULL;
        folder->listGroup = NULL;
        folder->listPerson = NULL;
+       folder->folderType = ADDRFOLDER_NONE;
+       folder->folderData = NULL;
 
        g_free( folder );
 }
@@ -1099,6 +1107,7 @@ void addritem_print_item_folder( ItemFolder *folder, FILE *stream ) {
        fprintf( stream, "\tsub: %d\n", ADDRITEM_SUBTYPE(folder) );
        fprintf( stream, "\tnam: '%s'\n", ADDRITEM_NAME(folder) );
        fprintf( stream, "\trem: '%s'\n", folder->remarks );
+       fprintf( stream, "\ttyp: %d\n", folder->folderType );
        fprintf( stream, "\t---\n" );
        parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
        if( parent ) {
@@ -1366,6 +1375,42 @@ GList *addritem_folder_path( const ItemFolder *folder, const gboolean seq ) {
        return list;
 }
 
+/**
+ * Format E-Mail address.
+ * \param email EMail item to format.
+ * \return Formatted string. Should be freed after use.
+ */
+gchar *addritem_format_email( ItemEMail *email ) {
+       gchar *address;
+       gchar *name;
+       ItemPerson *person;
+
+       address = NULL;
+       name = NULL;
+       if( ADDRITEM_NAME( email ) ) {
+               if( strlen( ADDRITEM_NAME( email ) ) ) {
+                       name = ADDRITEM_NAME( email );
+               }
+       }
+       if( ! name ) {
+               person = ( ItemPerson * ) ADDRITEM_PARENT( email );
+               name = ADDRITEM_NAME( person );
+       }
+
+       if( name ) {
+               if( strchr_with_skip_quote( name, '"', ',' ) ) {
+                       address = g_strdup_printf( "\"%s\" <%s>", name, email->address );
+               }
+               else {
+                       address = g_strdup_printf( "%s <%s>", name, email->address );
+               }
+       }
+       else {
+               address = g_strdup_printf( "%s", email->address );
+       }
+       return address;
+}
+
 /*
 * End of Source.
 */
index df4ca39..d1a76b7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
@@ -45,6 +45,14 @@ typedef enum {
        ITEMTYPE_DATASOURCE
 } ItemObjectType;
 
+typedef enum {
+       ADDRFOLDER_NONE,
+       ADDRFOLDER_ROOT,
+       ADDRFOLDER_REGULAR,
+       ADDRFOLDER_CATEGORY,
+       ADDRFOLDER_LDAP_QUERY
+} AddressFolderType;
+
 typedef struct _AddrItemObject AddrItemObject;
 struct _AddrItemObject {
        ItemObjectType type;
@@ -89,6 +97,8 @@ struct _ItemFolder {
        GList    *listFolder;   /* List of contained (child) folders */
        GList    *listPerson;   /* List of contained persons */
        GList    *listGroup;    /* List of contained (child) groups */
+       AddressFolderType folderType;   /* Folder type */
+       gpointer *folderData;           /* Pointer to folder's data */
 };
 
 typedef struct _ItemGroup ItemGroup;
@@ -182,5 +192,6 @@ ItemEMail *addritem_move_email_after        ( ItemPerson *person,
 void addritem_parse_first_last         ( ItemPerson *person );
 GList *addritem_folder_path            ( const ItemFolder *folder,
                                          const gboolean seq );
+gchar *addritem_format_email           ( ItemEMail *email );
 
 #endif /* __ADDRITEM_H__ */
index 584b9bf..10e1be6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * 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
index 0d8d38d..05c1122 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999,2000 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * 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
index 9a21375..a86bbf9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * 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
index 6a3571d..6fb2599 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
index 2e5e552..3fda5c0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001-2002 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
 #include "prefs_common.h"
 #include "addressitem.h"
 #include "mgutils.h"
-#include "syldap.h"
+#include "ldapserver.h"
+#include "ldapctrl.h"
+#include "ldaputil.h"
 #include "editldap_basedn.h"
 #include "manage_window.h"
 #include "gtkutils.h"
 
+#define PAGE_BASIC      0
+#define PAGE_SEARCH     1
+#define PAGE_EXTENDED   2
+
 #define ADDRESSBOOK_GUESS_LDAP_NAME    "MyServer"
 #define ADDRESSBOOK_GUESS_LDAP_SERVER  "localhost"
 
@@ -68,10 +74,52 @@ static struct _LDAPEdit {
        GtkWidget *spinbtn_timeout;
        GtkWidget *entry_bindDN;
        GtkWidget *entry_bindPW;
-       GtkWidget *entry_criteria;
        GtkWidget *spinbtn_maxentry;
+       GtkWidget *entry_criteria;
+       GtkWidget *spinbtn_queryage;
+       GtkWidget *check_dynsearch;
 } ldapedit;
 
+/**
+ * Parse out individual attribute names from criteria string.
+ * \param criteria Criteria string.
+ * \ctl   Control object.
+ */
+static gboolean editldap_validate_criteria( gchar *criteria ) {
+       gchar *ptr;
+       gchar **splitStr;
+       gint i;
+       gboolean errorFlag;
+
+       errorFlag = TRUE;
+
+       /* Replace delimiters with spaces */
+       ptr = criteria;
+       while( *ptr ) {
+               if( *ptr == ',' || *ptr == ';' || *ptr == '|' )
+                       *ptr = ' ';
+               ptr++;
+       }
+
+       /* Parse string */
+       splitStr = g_strsplit( criteria, " ", 0 );
+       i = 0;
+       while( TRUE ) {
+               if( splitStr[i] ) {
+                       if( *splitStr[i] ) {
+                               errorFlag = FALSE;
+                               break;
+                       }
+               }
+               else {
+                       break;
+               }
+               i++;
+       }
+       g_strfreev( splitStr );
+       return errorFlag;
+}
+
 /*
 * Edit functions.
 */
@@ -79,14 +127,67 @@ static void edit_ldap_status_show( gchar *msg ) {
        if( ldapedit.statusbar != NULL ) {
                gtk_statusbar_pop( GTK_STATUSBAR(ldapedit.statusbar), ldapedit.status_cid );
                if( msg ) {
-                       gtk_statusbar_push( GTK_STATUSBAR(ldapedit.statusbar), ldapedit.status_cid, msg );
+                       gtk_statusbar_push( GTK_STATUSBAR(ldapedit.statusbar),
+                               ldapedit.status_cid, msg );
+               }
+       }
+}
+
+static gboolean edit_ldap_validate( void ) {
+       gchar *str;
+       gboolean errorFlag;
+       gint page;
+
+       errorFlag = FALSE;
+       str = gtk_editable_get_chars(
+                       GTK_EDITABLE(ldapedit.entry_name), 0, -1 );
+       if( *str == '\0' ) {
+               page = PAGE_BASIC;
+               gtk_widget_grab_focus( ldapedit.entry_name );
+               edit_ldap_status_show( _( "A Name must be supplied." ) );
+               errorFlag = TRUE;
+       }
+       g_free( str );
+
+       if( ! errorFlag ) {
+               str = gtk_editable_get_chars(
+                               GTK_EDITABLE(ldapedit.entry_server), 0, -1 );
+               if( *str == '\0' ) {
+                       page = PAGE_BASIC;
+                       gtk_widget_grab_focus( ldapedit.entry_server );
+                       edit_ldap_status_show(
+                               _( "A Hostname must be supplied for the server." ) );
+                       errorFlag = TRUE;
+               }
+               g_free( str );
+       }
+
+       if( ! errorFlag ) {
+               str = gtk_editable_get_chars(
+                               GTK_EDITABLE(ldapedit.entry_criteria), 0, -1 );
+               if( editldap_validate_criteria( str ) ) {
+                       page = PAGE_SEARCH;
+                       gtk_widget_grab_focus( ldapedit.entry_criteria );
+                       edit_ldap_status_show(
+                               _( "At least one LDAP search attribute should be supplied." ) );
+                       errorFlag = TRUE;
                }
+               g_free( str );
+       }
+
+       /* Switch to page with error */
+       if( errorFlag ) {
+               gtk_notebook_set_page( GTK_NOTEBOOK(ldapedit.notebook), page );
        }
+
+       return errorFlag;
 }
 
 static void edit_ldap_ok( GtkWidget *widget, gboolean *cancelled ) {
-       *cancelled = FALSE;
-       gtk_main_quit();
+       if( ! edit_ldap_validate() ) {
+               *cancelled = FALSE;
+               gtk_main_quit();
+       }
 }
 
 static void edit_ldap_cancel( GtkWidget *widget, gboolean *cancelled ) {
@@ -107,10 +208,6 @@ static void edit_ldap_key_pressed( GtkWidget *widget, GdkEventKey *event, gboole
        }
 }
 
-static void edit_ldap_switch_page( GtkWidget *widget ) {
-       edit_ldap_status_show( "" );
-}
-
 static void edit_ldap_server_check( void ) {
        gchar *sHost, *sBind, *sPass;
        gint iPort, iTime;
@@ -118,6 +215,7 @@ static void edit_ldap_server_check( void ) {
        gchar *sBaseDN = NULL;
        gint iBaseDN = 0;
        gboolean flg;
+       GList *baseDN = NULL;
 
        edit_ldap_status_show( "" );
        flg = FALSE;
@@ -131,9 +229,9 @@ static void edit_ldap_server_check( void ) {
        g_strchomp( sPass ); g_strchug( sPass );
        if( *sHost != '\0' ) {
                /* Test connection to server */
-               if( syldap_test_connect_s( sHost, iPort ) ) {
+               if( ldaputil_test_connect( sHost, iPort ) ) {
                        /* Attempt to read base DN */
-                       GList *baseDN = syldap_read_basedn_s( sHost, iPort, sBind, sPass, iTime );
+                       baseDN = ldaputil_read_basedn( sHost, iPort, sBind, sPass, iTime );
                        if( baseDN ) {
                                GList *node = baseDN;
                                while( node ) {
@@ -196,7 +294,7 @@ static void edit_ldap_basedn_select( void ) {
 }
 
 static void edit_ldap_search_reset( void ) {
-       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), SYLDAP_DFL_CRITERIA );
+       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), LDAPCTL_DFL_ATTR_LIST );
 }
 
 static void addressbook_edit_ldap_dialog_create( gboolean *cancelled ) {
@@ -223,7 +321,6 @@ static void addressbook_edit_ldap_dialog_create( gboolean *cancelled ) {
                           cancelled);
 
        vbox = gtk_vbox_new( FALSE, 6 );
-       /* gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); */
        gtk_widget_show( vbox );
        gtk_container_add( GTK_CONTAINER( window ), vbox );
 
@@ -249,8 +346,6 @@ static void addressbook_edit_ldap_dialog_create( gboolean *cancelled ) {
                           GTK_SIGNAL_FUNC(edit_ldap_ok), cancelled);
        gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
                           GTK_SIGNAL_FUNC(edit_ldap_cancel), cancelled);
-       gtk_signal_connect(GTK_OBJECT(notebook), "switch_page",
-                          GTK_SIGNAL_FUNC(edit_ldap_switch_page), NULL );
 
        gtk_widget_show_all(vbox);
 
@@ -259,10 +354,12 @@ static void addressbook_edit_ldap_dialog_create( gboolean *cancelled ) {
        ldapedit.ok_btn     = ok_btn;
        ldapedit.cancel_btn = cancel_btn;
        ldapedit.statusbar  = statusbar;
-       ldapedit.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit LDAP Server Dialog" );
+       ldapedit.status_cid =
+               gtk_statusbar_get_context_id(
+                       GTK_STATUSBAR(statusbar), "Edit LDAP Server Dialog" );
 }
 
-void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
+static void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *table;
        GtkWidget *label;
@@ -279,7 +376,6 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        vbox = gtk_vbox_new( FALSE, 8 );
        gtk_widget_show( vbox );
        gtk_container_add( GTK_CONTAINER( ldapedit.notebook ), vbox );
-       /* gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH ); */
 
        label = gtk_label_new( pageLbl );
        gtk_widget_show( label );
@@ -300,7 +396,8 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_name = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        /* Next row */
        ++top;
@@ -309,7 +406,8 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_server = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_server, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_server, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        /* Next row */
        ++top;
@@ -323,7 +421,8 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_port, FALSE, FALSE, 0);
        gtk_widget_set_usize (spinbtn_port, 64, -1);
        gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_port), TRUE);
-       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        check_btn = gtk_button_new_with_label( _(" Check Server "));
        gtk_table_attach(GTK_TABLE(table), check_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
@@ -335,16 +434,19 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_baseDN = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_baseDN, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_baseDN, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        lookdn_btn = gtk_button_new_with_label( _(" ... "));
        gtk_table_attach(GTK_TABLE(table), lookdn_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
 
+       /* Signal handlers */
        gtk_signal_connect(GTK_OBJECT(check_btn), "clicked",
                           GTK_SIGNAL_FUNC(edit_ldap_server_check), NULL);
        gtk_signal_connect(GTK_OBJECT(lookdn_btn), "clicked",
                           GTK_SIGNAL_FUNC(edit_ldap_basedn_select), NULL);
 
+       /* Done */
        gtk_widget_show_all(vbox);
 
        ldapedit.entry_name   = entry_name;
@@ -353,25 +455,21 @@ void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
        ldapedit.entry_baseDN = entry_baseDN;
 }
 
-void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
+static void addressbook_edit_ldap_page_search( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *table;
        GtkWidget *label;
-       GtkWidget *entry_bindDN;
-       GtkWidget *entry_bindPW;
        GtkWidget *entry_criteria;
        GtkWidget *hbox_spin;
-       GtkObject *spinbtn_timeout_adj;
-       GtkWidget *spinbtn_timeout;
-       GtkObject *spinbtn_maxentry_adj;
-       GtkWidget *spinbtn_maxentry;
+       GtkObject *spinbtn_queryage_adj;
+       GtkWidget *spinbtn_queryage;
+       GtkWidget *check_dynsearch;
        GtkWidget *reset_btn;
        gint top;
 
        vbox = gtk_vbox_new( FALSE, 8 );
        gtk_widget_show( vbox );
        gtk_container_add( GTK_CONTAINER( ldapedit.notebook ), vbox );
-       /* gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH ); */
 
        label = gtk_label_new( pageLbl );
        gtk_widget_show( label );
@@ -387,24 +485,90 @@ void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
 
        /* First row */
        top = 0;
-       label = gtk_label_new(_("Search Criteria"));
+       label = gtk_label_new(_("Search Attributes"));
        gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_criteria = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_criteria, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_criteria, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
-       reset_btn = gtk_button_new_with_label( _(" Reset "));
+       reset_btn = gtk_button_new_with_label( _(" Defaults "));
        gtk_table_attach(GTK_TABLE(table), reset_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
 
        /* Next row */
        ++top;
+       label = gtk_label_new(_("Max Query Age (secs)"));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+       hbox_spin = gtk_hbox_new (FALSE, 8);
+       spinbtn_queryage_adj = gtk_adjustment_new(
+               LDAPCTL_DFL_QUERY_AGE, 1, LDAPCTL_MAX_QUERY_AGE, 10, 1000, 1000 );
+       spinbtn_queryage = gtk_spin_button_new(GTK_ADJUSTMENT (spinbtn_queryage_adj), 1, 0);
+       gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_queryage, FALSE, FALSE, 0);
+       gtk_widget_set_usize (spinbtn_queryage, 64, -1);
+       gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_queryage), TRUE);
+       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+       /* Next row */
+       ++top;
+       check_dynsearch = gtk_check_button_new_with_label(
+                               _("Include server in dynamic search") );
+       gtk_table_attach(GTK_TABLE(table), check_dynsearch, 1, 3, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+       /* Signal handlers */
+       gtk_signal_connect(GTK_OBJECT(reset_btn), "clicked",
+                          GTK_SIGNAL_FUNC(edit_ldap_search_reset), NULL);
+
+       /* Done */
+       gtk_widget_show_all(vbox);
+
+       ldapedit.entry_criteria   = entry_criteria;
+       ldapedit.spinbtn_queryage = spinbtn_queryage;
+       ldapedit.check_dynsearch  = check_dynsearch;
+}
+
+static void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *vbox;
+       GtkWidget *table;
+       GtkWidget *label;
+       GtkWidget *entry_bindDN;
+       GtkWidget *entry_bindPW;
+       GtkWidget *hbox_spin;
+       GtkObject *spinbtn_timeout_adj;
+       GtkWidget *spinbtn_timeout;
+       GtkObject *spinbtn_maxentry_adj;
+       GtkWidget *spinbtn_maxentry;
+       gint top;
+
+       vbox = gtk_vbox_new( FALSE, 8 );
+       gtk_widget_show( vbox );
+       gtk_container_add( GTK_CONTAINER( ldapedit.notebook ), vbox );
+
+       label = gtk_label_new( pageLbl );
+       gtk_widget_show( label );
+       gtk_notebook_set_tab_label(
+               GTK_NOTEBOOK( ldapedit.notebook ),
+               gtk_notebook_get_nth_page( GTK_NOTEBOOK( ldapedit.notebook ), pageNum ), label );
+
+       table = gtk_table_new( LDAPEDIT_TABLE_ROWS, LDAPEDIT_TABLE_COLS, FALSE);
+       gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+       gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+       gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+       gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+       /* Next row */
+       top = 0;
        label = gtk_label_new(_("Bind DN"));
        gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_bindDN = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_bindDN, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_bindDN, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        /* Next row */
        ++top;
@@ -413,7 +577,8 @@ void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
        entry_bindPW = gtk_entry_new();
-       gtk_table_attach(GTK_TABLE(table), entry_bindPW, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), entry_bindPW, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        /* Next row */
        ++top;
@@ -427,7 +592,8 @@ void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
        gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_timeout, FALSE, FALSE, 0);
        gtk_widget_set_usize (spinbtn_timeout, 64, -1);
        gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_timeout), TRUE);
-       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        /* Next row */
        ++top;
@@ -441,14 +607,12 @@ void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
        gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_maxentry, FALSE, FALSE, 0);
        gtk_widget_set_usize (spinbtn_maxentry, 64, -1);
        gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_maxentry), TRUE);
-       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
-
-       gtk_signal_connect(GTK_OBJECT(reset_btn), "clicked",
-                          GTK_SIGNAL_FUNC(edit_ldap_search_reset), NULL);
+       gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
+       /* Done */
        gtk_widget_show_all(vbox);
 
-       ldapedit.entry_criteria   = entry_criteria;
        ldapedit.entry_bindDN     = entry_bindDN;
        ldapedit.entry_bindPW     = entry_bindPW;
        ldapedit.spinbtn_timeout  = spinbtn_timeout;
@@ -459,6 +623,7 @@ static void addressbook_edit_ldap_create( gboolean *cancelled ) {
        gint page = 0;
        addressbook_edit_ldap_dialog_create( cancelled );
        addressbook_edit_ldap_page_basic( page++, _( "Basic" ) );
+       addressbook_edit_ldap_page_search( page++, _( "Search" ) );
        addressbook_edit_ldap_page_extended( page++, _( "Extended" ) );
        gtk_widget_show_all( ldapedit.window );
 }
@@ -496,17 +661,155 @@ gint edit_ldap_get_optmenu( GtkOptionMenu *optmenu ) {
        return GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)));
 }
 
+/**
+ * Format criteria list for display.
+ * \param ctl Control object.
+ * \return Formatted string, or <i>NULL</i> if no attributes found.
+ */
+static gchar *editldap_build_criteria_list( const LdapControl *ctl ) {
+       gchar *str = NULL;
+       gchar *tmp = NULL;
+       GList *node;
+
+       node = ldapctl_get_criteria_list( ctl );
+       while( node ) {
+               gchar *attr = node->data;
+               if( str ) {
+                       tmp = g_strdup_printf( "%s, %s", str, attr );
+                       g_free( str );
+                       str = tmp;
+                       tmp = NULL;
+               }
+               else {
+                       str = g_strdup( attr );
+               }
+               node = g_list_next( node );
+       }
+
+       return str;
+}
+
+/**
+ * Parse out individual attribute names from criteria string.
+ * \param criteria Criteria string.
+ * \ctl   Control object.
+ */
+static void editldap_parse_criteria( gchar *criteria, LdapControl *ctl ) {
+       gchar *ptr;
+       gchar **splitStr;
+       gint i;
+
+       /* Replace delimiters with spaces */
+       ptr = criteria;
+       while( *ptr ) {
+               if( *ptr == ',' || *ptr == ';' || *ptr == '|' )
+                       *ptr = ' ';
+               ptr++;
+       }
+
+       /* Parse string */
+       ldapctl_criteria_list_clear( ctl );
+       splitStr = g_strsplit( criteria, " ", 0 );
+       i = 0;
+       while( TRUE ) {
+               if( splitStr[i] ) {
+                       if( *splitStr[i] ) {
+                               ldapctl_criteria_list_add( ctl, splitStr[i] );
+                       }
+               }
+               else {
+                       break;
+               }
+               i++;
+       }
+       g_strfreev( splitStr );
+}
+
+/**
+ * Clear entry fields to reasonable defaults (for a new server entry).
+ */
+static void edit_ldap_clear_fields( void ) {
+       gtk_entry_set_text(
+               GTK_ENTRY(ldapedit.entry_name), ADDRESSBOOK_GUESS_LDAP_NAME );
+       gtk_entry_set_text(
+               GTK_ENTRY(ldapedit.entry_server), ADDRESSBOOK_GUESS_LDAP_SERVER );
+       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), "");
+       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindDN), "");
+       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindPW), "");
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), LDAPCTL_DFL_PORT );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ), LDAPCTL_DFL_TIMEOUT );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ), LDAPCTL_DFL_TIMEOUT );
+       gtk_entry_set_text(
+               GTK_ENTRY(ldapedit.entry_criteria), LDAPCTL_DFL_ATTR_LIST );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON(ldapedit.spinbtn_queryage), LDAPCTL_DFL_QUERY_AGE );
+       gtk_toggle_button_set_active(
+               GTK_TOGGLE_BUTTON( ldapedit.check_dynsearch), TRUE );
+}
+
+/**
+ * Load entry fields from server control data.
+ * \param server Server object.
+ */
+static void edit_ldap_set_fields( LdapServer *server ) {
+       LdapControl *ctl;
+       gchar *crit;
+
+       if( ldapsvr_get_name( server ) )
+               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name),
+               ldapsvr_get_name( server ) );
+
+       ctl = server->control;
+       if( ctl->hostName )
+               gtk_entry_set_text(
+                       GTK_ENTRY(ldapedit.entry_server), ctl->hostName);
+       if( ctl->baseDN )
+               gtk_entry_set_text(
+                       GTK_ENTRY(ldapedit.entry_baseDN), ctl->baseDN );
+       if( ctl->bindDN )
+               gtk_entry_set_text(
+                       GTK_ENTRY(ldapedit.entry_bindDN), ctl->bindDN );
+       if( ctl->bindPass )
+               gtk_entry_set_text(
+                       GTK_ENTRY(ldapedit.entry_bindPW), ctl->bindPass );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON(ldapedit.spinbtn_port), ctl->port );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON(ldapedit.spinbtn_timeout), ctl->timeOut );
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON(ldapedit.spinbtn_maxentry), ctl->maxEntries );
+
+       /* Format criteria */
+       crit = editldap_build_criteria_list( ctl );
+       if( crit ) {
+               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), crit );
+               g_free( crit );
+       }
+       else {
+               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), "" );
+       }
+       gtk_spin_button_set_value(
+               GTK_SPIN_BUTTON(ldapedit.spinbtn_queryage), ctl->maxQueryAge );
+       gtk_toggle_button_set_active(
+               GTK_TOGGLE_BUTTON( ldapedit.check_dynsearch), server->searchFlag );
+}
+
 AdapterDSource *addressbook_edit_ldap( AddressIndex *addrIndex, AdapterDSource *ads ) {
        static gboolean cancelled;
        gchar *sName, *sHost, *sBase, *sBind, *sPass, *sCrit;
-       gint iPort, iMaxE, iTime;
+       gint iPort, iMaxE, iTime, iAge;
+       gboolean bSrch;
        AddressDataSource *ds = NULL;
-       SyldapServer *server = NULL;
+       LdapServer *server = NULL;
+       LdapControl *ctl = NULL;
        gboolean fin;
 
        if (!ldapedit.window)
                addressbook_edit_ldap_create(&cancelled);
-       gtk_notebook_set_page( GTK_NOTEBOOK(ldapedit.notebook), 0 );
+       gtk_notebook_set_page( GTK_NOTEBOOK(ldapedit.notebook), PAGE_BASIC );
        gtk_widget_grab_focus(ldapedit.ok_btn);
        gtk_widget_grab_focus(ldapedit.entry_name);
        gtk_widget_show(ldapedit.window);
@@ -516,72 +819,60 @@ AdapterDSource *addressbook_edit_ldap( AddressIndex *addrIndex, AdapterDSource *
        if( ads ) {
                ds = ads->dataSource;
                server = ds->rawDataSource;
-               if ( syldap_get_name( server ) )
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name),
-                               syldap_get_name( server ) );
-               if (server->hostName)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_server), server->hostName);
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), server->port );
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ), server->timeOut );
-               if (server->baseDN)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), server->baseDN);
-               if (server->searchCriteria)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), server->searchCriteria);
-               if (server->bindDN)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindDN), server->bindDN);
-               if (server->bindPass)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindPW), server->bindPass);
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ), server->maxEntries );
-               gtk_window_set_title( GTK_WINDOW(ldapedit.window), _("Edit LDAP Server"));
+               edit_ldap_set_fields( server );
+               gtk_window_set_title(
+                       GTK_WINDOW(ldapedit.window), _("Edit LDAP Server"));
        }
        else {
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name), ADDRESSBOOK_GUESS_LDAP_NAME );
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_server), ADDRESSBOOK_GUESS_LDAP_SERVER );
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), SYLDAP_DFL_PORT );
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ), SYLDAP_DFL_TIMEOUT );
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), "");
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), SYLDAP_DFL_CRITERIA );
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindDN), "");
-               gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindPW), "");
-               gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ), SYLDAP_MAX_ENTRIES );
-               gtk_window_set_title( GTK_WINDOW(ldapedit.window), _("Add New LDAP Server"));
+               edit_ldap_clear_fields();
+               gtk_window_set_title(
+                       GTK_WINDOW(ldapedit.window), _("Add New LDAP Server"));
        }
 
        gtk_main();
        gtk_widget_hide(ldapedit.window);
        if (cancelled == TRUE) return NULL;
 
-       fin = FALSE;
        sName = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_name), 0, -1 );
        sHost = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_server), 0, -1 );
-       iPort = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ) );
-       iTime = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ) );
        sBase = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_baseDN), 0, -1 );
        sCrit = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_criteria), 0, -1 );
        sBind = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindDN), 0, -1 );
        sPass = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindPW), 0, -1 );
+       iPort = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ) );
+       iTime = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ) );
        iMaxE = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ) );
+       iAge  = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_queryage ) );
+       bSrch = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( ldapedit.check_dynsearch ) );
 
+       fin = FALSE;
        if( *sName == '\0' ) fin = TRUE;
        if( *sHost == '\0' ) fin = TRUE;
-       if( *sBase == '\0' ) fin = TRUE;
 
        if( ! fin ) {
+               /* Save changes */
                if( ! ads ) {
-                       server = syldap_create();
+                       /* New server */
+                       server = ldapsvr_create();
                        ds = addrindex_index_add_datasource( addrIndex, ADDR_IF_LDAP, server );
                        ads = addressbook_create_ds_adapter( ds, ADDR_LDAP, NULL );
                }
+               ctl = server->control;
                addressbook_ads_set_name( ads, sName );
-               syldap_set_name( server, sName );
-               syldap_set_host( server, sHost );
-               syldap_set_port( server, iPort );
-               syldap_set_base_dn( server, sBase );
-               syldap_set_bind_dn( server, sBind );
-               syldap_set_bind_password( server, sPass );
-               syldap_set_search_criteria( server, sCrit );
-               syldap_set_max_entries( server, iMaxE );
-               syldap_set_timeout( server, iTime );
+               ldapsvr_set_name( server, sName );
+               ldapsvr_set_search_flag( server, bSrch );
+               ldapctl_set_host( ctl, sHost );
+               ldapctl_set_base_dn( ctl, sBase );
+               ldapctl_set_bind_dn( ctl, sBind );
+               ldapctl_set_bind_password( ctl, sPass );
+               ldapctl_set_port( ctl, iPort );
+               ldapctl_set_max_entries( ctl, iMaxE );
+               ldapctl_set_timeout( ctl, iTime );
+               ldapctl_set_max_query_age( ctl, iAge );
+
+               /* Save attributes */
+               editldap_parse_criteria( sCrit, ctl );
+
        }
        g_free( sName );
        g_free( sHost );
index d1bab62..bc80906 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
index 6cb32e9..7b144c4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
@@ -41,7 +41,7 @@
 
 #include "intl.h"
 #include "prefs_common.h"
-#include "syldap.h"
+#include "ldaputil.h"
 #include "mgutils.h"
 #include "gtkutils.h"
 #include "manage_window.h"
@@ -237,16 +237,21 @@ static void edit_ldap_bdn_create(void) {
        ldapedit_basedn.ok_btn     = ok_btn;
        ldapedit_basedn.cancel_btn = cancel_btn;
        ldapedit_basedn.statusbar  = statusbar;
-       ldapedit_basedn.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit LDAP Select Base DN" );
+       ldapedit_basedn.status_cid =
+               gtk_statusbar_get_context_id(
+                       GTK_STATUSBAR(statusbar), "Edit LDAP Select Base DN" );
 }
 
-void edit_ldap_bdn_load_data( const gchar *hostName, const gint iPort, const gint tov, const gchar* bindDN,
-              const gchar *bindPW ) {
+void edit_ldap_bdn_load_data(
+       const gchar *hostName, const gint iPort, const gint tov,
+       const gchar* bindDN, const gchar *bindPW )
+{
        gchar *sHost;
        gchar *sMsg = NULL;
        gchar sPort[20];
        gboolean flgConn;
        gboolean flgDN;
+       GList *baseDN = NULL;
 
        edit_ldap_bdn_status_show( "" );
        gtk_clist_clear(GTK_CLIST(ldapedit_basedn.basedn_list));
@@ -258,9 +263,9 @@ void edit_ldap_bdn_load_data( const gchar *hostName, const gint iPort, const gin
        gtk_label_set_text(GTK_LABEL(ldapedit_basedn.port_label), sPort);
        if( *sHost != '\0' ) {
                /* Test connection to server */
-               if( syldap_test_connect_s( sHost, iPort ) ) {
+               if( ldaputil_test_connect( sHost, iPort ) ) {
                        /* Attempt to read base DN */
-                       GList *baseDN = syldap_read_basedn_s( sHost, iPort, bindDN, bindPW, tov );
+                       baseDN = ldaputil_read_basedn( sHost, iPort, bindDN, bindPW, tov );
                        if( baseDN ) {
                                GList *node = baseDN;
                                gchar *text[2] = { NULL, NULL };
index a4affd0..8e644b9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2003 Match Grun
  *
  * 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
index 90da502..9a9d2a3 100644 (file)
@@ -77,7 +77,6 @@ struct _LdapQuery {
        void        (*callBackEnd)( void * );
        ItemFolder  *folder;            /* Reference to folder in cache */
        LdapServer  *server;            /* Reference to (parent) LDAP server */
-       /* SyldapServer *server; */             /* Reference to (parent) LDAP server */
 };
 
 /* Function prototypes */