+2003-03-16 [match] 0.8.11claws20
+ * src/ldapserver.[ch] ** NEW **
+ * src/ldapctrl.[ch] ** NEW **
+ * src/ldapquery.[ch] ** NEW **
+ * src/ldaputil.[ch] ** NEW **
+ * src/addrcindex.[ch] ** NEW **
+ * src/addrquery.h ** NEW **
+ * src/addritem.[ch]
+ * src/addrcache.[ch]
+ * src/addrindex.[ch]
+ * src/addr_compl.[ch]
+ * src/addressbook.[ch]
+ * src/addrbook.[ch]
+ * src/editgroup.c
+ * src/editaddress.c
+ * src/editldap.c
+ * src/editldap_basedn.c
+ * src/vcard.c
+ * src/jpilot.c
+ * src/Makefile.am
+ included dynamic LDAP queries. improved address
+ completion.
+
2003-03-16 [paul] 0.8.11claws19
* tools/multiwebsearch.pl
MICRO_VERSION=11
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=claws19
+EXTRA_VERSION=claws20
VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
dnl set $target
addr_compl.c addr_compl.h \
addressitem.h \
adbookbase.h \
+ addrquery.h \
addritem.c addritem.h \
addrcache.c addrcache.h \
+ addrcindex.c addrcindex.h \
addrclip.c addrclip.h \
addrselect.c addrselect.h \
addrbook.c addrbook.h \
importpine.c importpine.h \
jpilot.c jpilot.h \
syldap.c syldap.h \
+ ldapserver.c ldapserver.h \
+ ldapctrl.c ldapctrl.h \
+ ldapquery.c ldapquery.h \
+ ldaputil.c ldaputil.h \
editbook.c editbook.h \
editgroup.c editgroup.h \
editaddress.c editaddress.h \
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
*
- * Copyright (c) 2000-2001 by Alfons Hoogervorst <alfons@proteus.demon.nl>
+ * Copyright (c) 2000-2003 by Alfons Hoogervorst <alfons@proteus.demon.nl>
*
* 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 "addressbook.h"
#include "addr_compl.h"
#include "utils.h"
+#include "addritem.h"
+#include "addrquery.h"
+#include <pthread.h>
/* How it works:
*
* After calling the g_completion_complete(), we get a reference
* to a valid email address.
*
- * Completion is very simplified. We never complete on another prefix,
- * i.e. we neglect the next smallest possible prefix for the current
+ * Completion is very simplified. We never complete on another searchTerm,
+ * i.e. we neglect the next smallest possible searchTerm for the current
* completion cache. This is simply done so we might break up the
* addresses a little more (e.g. break up alfons@proteus.demon.nl into
* something like alfons, proteus, demon, nl; and then completing on
* any of those words).
- */
-
-/* address_entry - structure which refers to the original address entry in the
- * address book
*/
-typedef struct
-{
- gchar *name;
- gchar *address;
-} address_entry;
-/* completion_entry - structure used to complete addresses, with a reference
- * the the real address information.
- */
-typedef struct
-{
- gchar *string; /* string to complete */
- address_entry *ref; /* address the string belongs to */
-} completion_entry;
+typedef struct _CompletionWindow CompletionWindow;
+struct _CompletionWindow {
+ gint listCount;
+ gchar *searchTerm;
+ GtkWidget *window;
+ GtkWidget *entry;
+ GtkWidget *clist;
+};
-/*******************************************************************************/
+/**
+ * Current query ID.
+ */
+static gint _queryID_ = 0;
-static gint g_ref_count; /* list ref count */
-static GList *g_completion_list; /* list of strings to be checked */
-static GList *g_address_list; /* address storage */
-static GCompletion *g_completion; /* completion object */
+/**
+ * Completion idle ID.
+ */
+static gint _completionIdleID_ = 0;
-/* To allow for continuing completion we have to keep track of the state
- * using the following variables. No need to create a context object. */
+/**
+ * Completion window.
+ */
+static CompletionWindow *_compWindow_ = NULL;
-static gint g_completion_count; /* nr of addresses incl. the prefix */
-static gint g_completion_next; /* next prev address */
-static GSList *g_completion_addresses; /* unique addresses found in the
- completion cache. */
-static gchar *g_completion_prefix; /* last prefix. (this is cached here
- * because the prefix passed to g_completion
- * is g_strdown()'ed */
+/**
+ * Mutex to protect callback from multiple threads.
+ */
+static pthread_mutex_t _completionMutex_ = PTHREAD_MUTEX_INITIALIZER;
-/*******************************************************************************/
+/**
+ * Completion queue list.
+ */
+static GList *_displayQueue_ = NULL;
-/* completion_func() - used by GTK to find the string data to be used for
- * completion
+/**
+ * Create a completion window object.
+ * \return Initialized completion window.
*/
-static gchar *completion_func(gpointer data)
-{
- g_return_val_if_fail(data != NULL, NULL);
+static CompletionWindow *addrcompl_create_window( void ) {
+ CompletionWindow *cw;
- return ((completion_entry *)data)->string;
-}
+ cw = g_new0( CompletionWindow, 1 );
+ cw->listCount = 0;
+ cw->searchTerm = NULL;
+ cw->window = NULL;
+ cw->entry = NULL;
+ cw->clist = NULL;
-static void init_all(void)
-{
- g_completion = g_completion_new(completion_func);
- g_return_if_fail(g_completion != NULL);
+ return cw;
}
-static void free_all(void)
-{
- GList *walk;
-
- walk = g_list_first(g_completion_list);
- for (; walk != NULL; walk = g_list_next(walk)) {
- completion_entry *ce = (completion_entry *) walk->data;
- g_free(ce->string);
- g_free(walk->data);
- }
- g_list_free(g_completion_list);
- g_completion_list = NULL;
-
- walk = g_address_list;
- for (; walk != NULL; walk = g_list_next(walk)) {
- address_entry *ae = (address_entry *) walk->data;
- g_free(ae->name);
- g_free(ae->address);
- g_free(walk->data);
+/**
+ * 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;
}
- g_list_free(g_address_list);
- g_address_list = NULL;
-
- g_completion_free(g_completion);
- g_completion = NULL;
-}
-static void add_address1(const char *str, address_entry *ae)
-{
- completion_entry *ce1;
- ce1 = g_new0(completion_entry, 1),
- ce1->string = g_strdup(str);
- /* GCompletion list is case sensitive */
- g_strdown(ce1->string);
- ce1->ref = ae;
-
- g_completion_list = g_list_prepend(g_completion_list, ce1);
+ /* 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;
+ }
}
-/* add_address() - adds address to the completion list. this function looks
- * complicated, but it's only allocation checks.
+/**
+ * Free up completion window.
+ * \param cw Window to free.
*/
-static gint add_address(const gchar *name, const gchar *address, const gchar *alias)
-{
- address_entry *ae;
-
- if (!name || !address) return -1;
-
- ae = g_new0(address_entry, 1);
+static void addrcompl_free_window( CompletionWindow *cw ) {
+ /* printf( "addrcompl_free_window...\n" ); */
+ if( cw ) {
+ addrcompl_destroy_window( cw );
- g_return_val_if_fail(ae != NULL, -1);
-
- ae->name = g_strdup(name);
- ae->address = g_strdup(address);
-
- g_address_list = g_list_prepend(g_address_list, ae);
-
- add_address1(name, ae);
- add_address1(address, ae);
- add_address1(alias, ae);
-
- return 0;
-}
+ g_free( cw->searchTerm );
+ cw->searchTerm = NULL;
-/* read_address_book()
- */
-static void read_address_book(void) {
- addressbook_load_completion( add_address );
- g_address_list = g_list_reverse(g_address_list);
- g_completion_list = g_list_reverse(g_completion_list);
-}
+ /* Clear references */
+ cw->listCount = 0;
-/* start_address_completion() - returns the number of addresses
- * that should be matched for completion.
- */
-gint start_address_completion(void)
-{
- clear_completion_cache();
- if (!g_ref_count) {
- init_all();
- /* open the address book */
- read_address_book();
- /* merge the completion entry list into g_completion */
- if (g_completion_list)
- g_completion_add_items(g_completion, g_completion_list);
+ /* Free object */
+ g_free( cw );
}
- g_ref_count++;
- debug_print("start_address_completion ref count %d\n", g_ref_count);
-
- return g_list_length(g_completion_list);
+ /* printf( "addrcompl_free_window...done\n" ); */
}
-/* 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.
+/**
+ * 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.
*/
-gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
+static gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
{
const gchar *edit_text;
gint cur_pos;
g_free(wtext);
return str;
-}
+}
-/* replace_address_in_edit() - replaces an incompleted address with a completed one.
+/**
+ * Replace text in entry field with specified address.
+ * \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_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.
+/**
+ * Format E-Mail address.
+ * \param email EMail item to format.
+ * \return Formatted string. Should be freed after use.
*/
-guint complete_address(const gchar *str)
-{
- GList *result;
- gchar *d;
- guint count, cpl;
- completion_entry *ce;
-
- g_return_val_if_fail(str != NULL, 0);
+static gchar *addrcompl_format_email( ItemEMail *email ) {
+ gchar *address;
+ gchar *name;
+ ItemPerson *person;
- Xstrdup_a(d, str, return 0);
-
- clear_completion_cache();
- g_completion_prefix = g_strdup(str);
-
- /* g_completion is case sensitive */
- g_strdown(d);
- result = g_completion_complete(g_completion, d, NULL);
-
- count = g_list_length(result);
- if (count) {
- /* create list with unique addresses */
- for (cpl = 0, result = g_list_first(result);
- result != NULL;
- result = g_list_next(result)) {
- ce = (completion_entry *)(result->data);
- if (NULL == g_slist_find(g_completion_addresses,
- ce->ref)) {
- cpl++;
- g_completion_addresses =
- g_slist_append(g_completion_addresses,
- ce->ref);
- }
+ address = NULL;
+ name = NULL;
+ if( ADDRITEM_NAME( email ) ) {
+ if( strlen( ADDRITEM_NAME( email ) ) ) {
+ name = ADDRITEM_NAME( email );
}
- count = cpl + 1; /* index 0 is the original prefix */
- g_completion_next = 1; /* we start at the first completed one */
- } else {
- g_free(g_completion_prefix);
- g_completion_prefix = NULL;
+ }
+ if( ! name ) {
+ person = ( ItemPerson * ) ADDRITEM_PARENT( email );
+ name = ADDRITEM_NAME( person );
}
- g_completion_count = count;
- return count;
-}
-
-/* get_complete_address() - returns a complete address. the returned
- * string should be freed
- */
-gchar *get_complete_address(gint index)
-{
- const address_entry *p;
- gchar *address = NULL;
-
- if (index < g_completion_count) {
- if (index == 0)
- address = g_strdup(g_completion_prefix);
+ if( name ) {
+ if( strchr_with_skip_quote( name, '"', ',' ) ) {
+ address = g_strdup_printf( "\"%s\" <%s>", name, email->address );
+ }
else {
- /* get something from the unique addresses */
- p = (address_entry *)g_slist_nth_data
- (g_completion_addresses, index - 1);
- if (p != NULL) {
- if (!p->name || p->name[0] == '\0')
- address = g_strdup_printf(p->address);
- else if (strchr_with_skip_quote(p->name, '"', ','))
- address = g_strdup_printf
- ("\"%s\" <%s>", p->name, p->address);
- else
- address = g_strdup_printf
- ("%s <%s>", p->name, p->address);
- }
+ address = g_strdup_printf( "%s <%s>", name, email->address );
}
}
-
+ else {
+ address = g_strdup_printf( "%s", email->address );
+ }
return address;
}
-gchar *get_next_complete_address(void)
-{
- if (is_completion_pending()) {
- gchar *res;
+/**
+ * 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;
- res = get_complete_address(g_completion_next);
- g_completion_next += 1;
- if (g_completion_next >= g_completion_count)
- g_completion_next = 0;
+ /* Get current geometry of window */
+ gdk_window_get_geometry( cw->window->window, &x, &y, &width, &height, &depth );
- return res;
- } else
- return NULL;
-}
+ 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 );
-gchar *get_prev_complete_address(void)
-{
- if (is_completion_pending()) {
- int n = g_completion_next - 2;
-
- /* real previous */
- n = (n + (g_completion_count * 5)) % g_completion_count;
-
- /* real next */
- g_completion_next = n + 1;
- if (g_completion_next >= g_completion_count)
- g_completion_next = 0;
- return get_complete_address(n);
- } else
- return NULL;
+ /* 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 );
+ }
}
-guint get_completion_count(void)
-{
- if (is_completion_pending())
- return g_completion_count;
- else
- return 0;
-}
+/**
+ * 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 };
-/* 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);
+ /* printf( "\t\tAdding :%s\n", address ); */
+ text[0] = address;
+ gtk_clist_append( GTK_CLIST(cw->clist), text );
+ cw->listCount++;
- if (g_completion_addresses) {
- g_slist_free(g_completion_addresses);
- g_completion_addresses = NULL;
- }
+ /* Resize window */
+ addrcompl_resize_window( cw );
+ gtk_grab_add( cw->window );
- g_completion_count = g_completion_next = 0;
+ if( cw->listCount == 2 ) {
+ /* Move off first row */
+ gtk_clist_select_row( GTK_CLIST(cw->clist), 1, 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;
+/**
+ * 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 ) {
+ ItemEMail *email = node->data;
+ /* printf( "email/address ::%s::\n", email->address ); */
+ address = addrcompl_format_email( email );
+ /* 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;
}
-/* invalidate_address_completion() - should be called if address book
- * changed;
+/**
+ * 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.
*/
-gint invalidate_address_completion(void)
+static gint addrcompl_callback(
+ gint queryID, GList *listEMail, gpointer target )
{
- if (g_ref_count) {
- /* simply the same as start_address_completion() */
- debug_print("Invalidation request for address completion\n");
- free_all();
- init_all();
- read_address_book();
- g_completion_add_items(g_completion, g_completion_list);
- clear_completion_cache();
- }
+ GList *node;
+ gchar *address;
- return g_list_length(g_completion_list);
+ pthread_mutex_lock( & _completionMutex_ );
+ if( queryID == _queryID_ ) {
+ /* Append contents to end of display queue */
+ node = listEMail;
+ while( node ) {
+ ItemEMail *email = node->data;
+ if( target ) {
+ /*
+ printf( "\temail/address ::%s::\n", email->address );
+ */
+ _displayQueue_ = g_list_append( _displayQueue_, email );
+ }
+ node = g_list_next( node );
+ }
+ }
+ pthread_mutex_unlock( & _completionMutex_ );
}
-gint end_address_completion(void)
-{
- clear_completion_cache();
+/**
+ * Start the search.
+ */
+static void addrcompl_start_search( void ) {
+ gchar *searchTerm;
- if (0 == --g_ref_count)
- free_all();
+ searchTerm = g_strdup( _compWindow_->searchTerm );
- debug_print("end_address_completion ref count %d\n", g_ref_count);
+ /* Clear out display queue */
+ pthread_mutex_lock( & _completionMutex_ );
- return g_ref_count;
-}
+ g_list_free( _displayQueue_ );
+ _displayQueue_ = NULL;
+ pthread_mutex_unlock( & _completionMutex_ );
-/* address completion entry ui. the ui (completion list was inspired by galeon's
+ /* Setup the search */
+ _queryID_ = addressbook_setup_search(
+ searchTerm, _compWindow_, addrcompl_callback );
+ g_free( searchTerm );
+
+ /* Sit back and wait until something happens */
+ _completionIdleID_ =
+ gtk_idle_add( ( GtkFunction ) addrcompl_idle, _compWindow_ );
+ addressbook_start_search( _queryID_ );
+}
+
+/*
+ * 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,
- gpointer data);
static gboolean address_completion_entry_key_pressed (GtkEntry *entry,
GdkEventKey *ev,
gpointer data);
static gboolean address_completion_complete_address_in_entry
- (GtkEntry *entry,
- gboolean next);
+ (GtkEntry *entry);
+
static void address_completion_create_completion_window (GtkEntry *entry);
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 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 0
-/* completion_window_accept_selection() - accepts the current selection in the
- * clist, and destroys the window */
-static void completion_window_accept_selection(GtkWidget **window,
- GtkCList *clist,
- GtkEntry *entry)
-{
- gchar *address = NULL, *text = NULL;
- gint cursor_pos, row;
-
- g_return_if_fail(window != NULL);
- g_return_if_fail(*window != NULL);
- g_return_if_fail(clist != NULL);
- g_return_if_fail(entry != NULL);
- g_return_if_fail(clist->selection != NULL);
-
- /* FIXME: I believe it's acceptable to access the selection member directly */
- row = GPOINTER_TO_INT(clist->selection->data);
-
- /* we just need the cursor position */
- 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);
- clear_completion_cache();
- gtk_widget_destroy(*window);
- *window = NULL;
+ 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);
+ }
}
-#endif
-/* completion_window_apply_selection() - apply the current selection in the
- * clist */
+/**
+ * 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);
-}
-
-/* should be called when creating the main window containing address
- * completion entries */
-void address_completion_start(GtkWidget *mainwindow)
-{
- start_address_completion();
-
- /* register focus change hook */
- gtk_signal_connect(GTK_OBJECT(mainwindow), "set_focus",
- GTK_SIGNAL_FUNC(address_completion_mainwindow_set_focus),
- mainwindow);
-}
-
-/* Need unique data to make unregistering signal handler possible for the auto
- * completed entry */
-#define COMPLETION_UNIQUE_DATA (GINT_TO_POINTER(0xfeefaa))
-
-void address_completion_register_entry(GtkEntry *entry)
-{
- g_return_if_fail(entry != NULL);
- g_return_if_fail(GTK_IS_ENTRY(entry));
-
- /* add hooked property */
- gtk_object_set_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK, entry);
-
- /* add keypress event */
- gtk_signal_connect_full(GTK_OBJECT(entry), "key_press_event",
- GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
- NULL,
- COMPLETION_UNIQUE_DATA,
- NULL,
- 0,
- 0); /* magic */
-}
-
-void address_completion_unregister_entry(GtkEntry *entry)
-{
- GtkObject *entry_obj;
-
- g_return_if_fail(entry != NULL);
- g_return_if_fail(GTK_IS_ENTRY(entry));
-
- entry_obj = gtk_object_get_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK);
- g_return_if_fail(entry_obj);
- g_return_if_fail(entry_obj == GTK_OBJECT(entry));
-
- /* has the hooked property? */
- gtk_object_set_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK, NULL);
- /* remove the hook */
- gtk_signal_disconnect_by_func(GTK_OBJECT(entry),
- GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
- 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 */
-void address_completion_end(GtkWidget *mainwindow)
-{
- /* if address_completion_end() is really called on closing the window,
- * we don't need to unregister the set_focus_cb */
- end_address_completion();
-}
+ /* Move focus to next widget */
+ parent = GTK_WIDGET(entry)->parent;
+ if( parent ) {
+ gtk_container_focus( GTK_CONTAINER(parent), GTK_DIR_TAB_FORWARD );
+ }
-/* if focus changes to another entry, then clear completion cache */
-static void address_completion_mainwindow_set_focus(GtkWindow *window,
- GtkWidget *widget,
- gpointer data)
-{
- if (widget)
- 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);
+ if (address_completion_complete_address_in_entry(entry)) {
/* route a void character to the default handler */
/* this is a dirty hack; we're actually changing a key
* reported by the system. */
ev->state &= ~GDK_SHIFT_MASK;
gtk_signal_emit_stop_by_name(GTK_OBJECT(entry),
"key_press_event");
- } else {
- /* old behaviour */
- }
- } else if (ev->keyval == GDK_Shift_L
- || ev->keyval == GDK_Shift_R
- || ev->keyval == GDK_Control_L
- || ev->keyval == GDK_Control_R
- || ev->keyval == GDK_Caps_Lock
- || ev->keyval == GDK_Shift_Lock
- || ev->keyval == GDK_Meta_L
- || ev->keyval == GDK_Meta_R
- || ev->keyval == GDK_Alt_L
- || ev->keyval == GDK_Alt_R) {
- /* these buttons should not clear the cache... */
- } else
- clear_completion_cache();
+ /* printf( "entry_key_pressed::create window\n" ); */
+ address_completion_create_completion_window( entry );
+ /* printf( "entry_key_pressed::create window...done\n" ); */
+ addrcompl_start_search();
+ }
+ }
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. :) */
-static gboolean address_completion_complete_address_in_entry(GtkEntry *entry,
- gboolean next)
+/**
+ * Initialize search term for address completion.
+ * \param entry Address entry field.
+ */
+static gboolean address_completion_complete_address_in_entry( GtkEntry *entry )
{
- gint ncount, cursor_pos;
- gchar *address, *new = NULL;
- gboolean completed = FALSE;
+ gint cursor_pos;
+ gchar *searchTerm;
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;
-
- /* 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();
- }
+ searchTerm = get_address_from_edit( entry, &cursor_pos );
+ if (! searchTerm ) return FALSE;
- if (new) {
- /* prevent "change" signal */
- /* replace_address_in_edit(entry, new, cursor_pos); */
- g_free(new);
- completed = TRUE;
+ /* Clear any existing search */
+ if( _compWindow_->searchTerm ) {
+ g_free( _compWindow_->searchTerm );
}
- g_free(address);
+ /* Replace with new search term */
+ _compWindow_->searchTerm = 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_);
+ gchar *searchTerm;
- 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);
-
- 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);
- }
+ gtk_widget_set_uposition(window, x, y);
- gtk_signal_connect(GTK_OBJECT(completion_window),
+ /* 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 );
+
+ /* 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);
-}
+ /* Add first entry into address list */
+ searchTerm = g_strdup( _compWindow_->searchTerm );
+ addrcompl_add_entry( _compWindow_, searchTerm );
+ gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
-/* row selection sends completed address to entry.
- * note: event is NULL if selected by anything else than a mouse button. */
+ g_free( searchTerm );
+}
+
+/**
+ * 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;
- clear_completion_cache();
- gtk_widget_destroy(*completion_window);
- *completion_window = NULL;
+ /* User selected address by releasing the mouse in drop-down list*/
+ completion_window_apply_selection( clist, entry );
+
+ 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) {
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 */
/* look for presses that accept the selection */
if (event->keyval == GDK_Return || event->keyval == GDK_space) {
- clear_completion_cache();
- gtk_widget_destroy(*completion_window);
- *completion_window = NULL;
+ /* 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 */
+ addrcompl_destroy_window( _compWindow_ );
return FALSE;
}
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;
gtk_widget_event(entry, (GdkEvent *)&tmp_event);
/* and close the completion window */
- gtk_widget_destroy(*completion_window);
- *completion_window = NULL;
+ addrcompl_destroy_window( _compWindow_ );
return TRUE;
}
+
+/*
+ * ============================================================================
+ * Publically accessible functions.
+ * ============================================================================
+ */
+/**
+ * Start address completion operation.
+ */
+gint start_address_completion(void)
+{
+ if( ! _compWindow_ ) {
+ _compWindow_ = addrcompl_create_window();
+ _queryID_ = 0;
+ }
+ addressbook_read_all();
+ return 0;
+}
+
+/**
+ * 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 searchTerm at index 0.
+ * TODO: move out of here. This should be used for retrieving an address
+ * without completion.
+ */
+guint complete_address(const gchar *str)
+{
+ g_return_val_if_fail(str != NULL, 0);
+
+ /* Xstrdup_a(d, str, return 0); */
+
+ /* Attempt completion */
+ /* printf( "addrcompl: Start search...\n" ); */
+ /* addressbook_start_search( 0, str, NULL, address_completion_callback ); */
+ /* printf( "addrcompl: Start search...done\n" ); */
+ /* Existing code is below */
+
+ return 0;
+}
+
+/**
+ * Returns a complete address. TODO: remove
+ * get_complete_address() - returns a complete address. the returned
+ * string should be freed
+ */
+gchar *get_complete_address(gint index)
+{
+ return NULL;
+}
+
+/**
+ * Terminate addess completion.
+ */
+gint end_address_completion(void)
+{
+ return 0;
+}
+
+/**
+ * Start address completion. Should be called when creating the main window
+ * containing address completion entries. This originally cleared the cache.
+ * Function no longer required?
+ */
+void address_completion_start(GtkWidget *mainwindow)
+{
+ start_address_completion();
+}
+
+/**
+ * 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);
+ g_return_if_fail(GTK_IS_ENTRY(entry));
+
+ /* add hooked property */
+ gtk_object_set_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK, entry);
+
+ /* add keypress event */
+ gtk_signal_connect_full(GTK_OBJECT(entry), "key_press_event",
+ GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
+ NULL,
+ COMPLETION_UNIQUE_DATA,
+ NULL,
+ 0,
+ 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;
+
+ g_return_if_fail(entry != NULL);
+ g_return_if_fail(GTK_IS_ENTRY(entry));
+
+ entry_obj = gtk_object_get_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK);
+ g_return_if_fail(entry_obj);
+ g_return_if_fail(entry_obj == GTK_OBJECT(entry));
+
+ /* has the hooked property? */
+ gtk_object_set_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK, NULL);
+
+ /* remove the hook */
+ gtk_signal_disconnect_by_func(GTK_OBJECT(entry),
+ GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
+ COMPLETION_UNIQUE_DATA);
+}
+
+/**
+ * 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.
+ */
+void address_completion_end(GtkWidget *mainwindow)
+{
+ /* if address_completion_end() is really called on closing the window,
+ * we don't need to unregister the set_focus_cb */
+ end_address_completion();
+}
+
+/**
+ * Setup completion object.
+ */
+void addrcompl_initialize( void ) {
+ 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;
+ printf( "addrcompl_teardown...done\n" );
+}
+
+/*
+ * End of Source.
+ */
+
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
*
- * Copyright (c) 2000 by Alfons Hoogervorst <alfons@proteus.demon.nl>
+ * Copyright (c) 2000-2003 by Alfons Hoogervorst <alfons@proteus.demon.nl>
*
* 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
#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);
-
+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 ( void );
+void addrcompl_teardown ( void );
#endif /* __ADDR_COMPL_H__ */
book->tempList = NULL;
book->tempHash = NULL;
book->addressCache->modified = TRUE;
+
+ /* We want to use an address completion index */
+ addrcache_use_index( book->addressCache, TRUE );
+
return book;
}
g_return_if_fail(book != NULL);
/* Clear cache */
- addrcache_clear(book->addressCache);
addrcache_free(book->addressCache);
/* Free up internal objects */
g_return_if_fail(book != NULL);
fprintf(stream, "AddressBook:\n");
- fprintf(stream, "\t path : '%s'\n", book->path);
- fprintf(stream, "\t file : '%s'\n", book->fileName);
- fprintf(stream, "\tstatus : %d\n", book->retVal );
+ fprintf(stream, "\tpath : '%s'\n", book->path);
+ fprintf(stream, "\tfile : '%s'\n", book->fileName);
+ fprintf(stream, "\tstatus : %d\n", book->retVal );
addrcache_print(book->addressCache, stream);
}
book->addressCache->modified = FALSE;
book->addressCache->dataRead = TRUE;
addrcache_set_dirty(book->addressCache, FALSE);
+
+ /* Build address completion index */
+ addrcache_build_index( book->addressCache );
}
return book->retVal;
}
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 );
+ addrcache_invalidate( book->addressCache );
+ 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;
fileList = NULL;
return newFile;
}
+
+/**
+ * Invalidate the address book data. This will cause index to be rebuilt.
+ * \param book Address book.
+ */
+void addrbook_invalidate( AddressBookFile *book ) {
+ g_return_if_fail( book != NULL );
+ addrcache_invalidate( book->addressCache );
+}
+
+/*
+* End of Source.
+*/
+
+
const gchar *remarks );
gchar *addrbook_guess_next_file ( AddressBookFile *book );
+void addrbook_invalidate ( AddressBookFile *book );
#endif /* __ADDRBOOK_H__ */
cache->rootFolder = addritem_create_item_folder();
cache->rootFolder->isRoot = TRUE;
ADDRITEM_PARENT(cache->rootFolder) = NULL;
+
+ cache->searchIndex = NULL;
+
return cache;
}
void addrcache_clear( AddressCache *cache ) {
g_return_if_fail( cache != NULL );
- /* printf( "...addrcache_clear :%s:\n", cache->name ); */
+ /* Clear completion index */
+ addrcindex_clear( cache->searchIndex );
+
/* Free up folders and hash table */
addrcache_free_all_folders( cache->rootFolder );
addrcache_free_item_hash( cache->itemHash );
void addrcache_free( AddressCache *cache ) {
g_return_if_fail( cache != NULL );
+ /* Free completion index */
+ addrcindex_free( cache->searchIndex );
+ cache->searchIndex = NULL;
+
cache->dirtyFlag = FALSE;
addrcache_free_all_folders( cache->rootFolder );
addrcache_free_item_hash( cache->itemHash );
cache->cacheID = NULL;
g_free( cache->name );
cache->name = NULL;
+
g_free( cache );
}
return person;
}
+/**
+ * Clear address completion index.
+ * \param cache Cache.
+ */
+void addrcache_clear_index( AddressCache *cache ) {
+ g_return_if_fail( cache != NULL );
+ addrcindex_clear( cache->searchIndex );
+}
+
+/**
+ * Control creation of an address completion index.
+ * \param cache Cache.
+ * \param value Set to <i>TRUE</i> to create an index, or <i>FALSE</i> to
+ * destroy index.
+ */
+void addrcache_use_index( AddressCache *cache, gboolean value ) {
+ g_return_if_fail( cache != NULL );
+
+ if( value ) {
+ if( cache->searchIndex ) {
+ addrcindex_clear( cache->searchIndex );
+ }
+ else {
+ cache->searchIndex = addrcindex_create();
+ }
+ }
+ else {
+ addrcindex_free( cache->searchIndex );
+ cache->searchIndex = NULL;
+ }
+}
+
+/*
+ * Load completion callback function.
+ */
+static void addrcache_load_index_cb( gpointer key, gpointer value, gpointer data ) {
+ AddrItemObject *obj = ( AddrItemObject * ) value;
+
+ if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
+ ItemPerson *person = ( ItemPerson * ) obj;
+ AddrCacheIndex *index = data;
+ addrcindex_add_person( index, person );
+ }
+}
+
+/**
+ * Rebuild address completion index with all persons in cache.
+ * \param cache Cache.
+ */
+void addrcache_build_index( AddressCache *cache ) {
+ g_return_if_fail( cache != NULL );
+
+ if( cache->searchIndex == NULL ) return;
+
+ /* Clear index */
+ addrcindex_clear( cache->searchIndex );
+
+ /* Now load up */
+ g_hash_table_foreach(
+ cache->itemHash, addrcache_load_index_cb, cache->searchIndex );
+ addrcindex_validate( cache->searchIndex );
+
+ /* addrcindex_print( cache->searchIndex, stdout ); */
+}
+
+/**
+ * Invalidate the address cache. This will cause index to be rebuilt.
+ * \param cache Cache.
+ */
+void addrcache_invalidate( AddressCache *cache ) {
+ g_return_if_fail( cache != NULL );
+
+ if( cache->searchIndex == NULL ) return;
+ addrcindex_invalidate( cache->searchIndex );
+}
+
/*
* End of Source.
*/
+
+
#include <stdio.h>
#include <glib.h>
#include "addritem.h"
+#include "addrcindex.h"
/* Address cache */
typedef struct _AddressCache AddressCache;
gboolean dirtyFlag;
gboolean accessFlag;
gchar *name;
+ AddrCacheIndex *searchIndex;
};
/* Function prototypes */
const gchar *address,
const gchar *remarks );
+void addrcache_clear_index ( AddressCache *cache );
+void addrcache_create_index ( AddressCache *cache,
+ gboolean value );
+void addrcache_build_index ( AddressCache *cache );
+void addrcache_invalidate ( AddressCache *cache );
+
#endif /* __ADDRCACHE_H__ */
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002-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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions to maintain address completion index.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mgutils.h"
+#include "addritem.h"
+#include "addrcindex.h"
+
+/*
+static gint _n_created = 0;
+static gint _n_freed = 0;
+*/
+
+typedef struct {
+ gchar *name;
+ ItemEMail *address;
+}
+AddrIndexEntry;
+
+static gchar *addrcindex_function( gpointer data ) {
+ return ( ( AddrIndexEntry * ) data )->name;
+}
+
+/*
+* Create new completion index.
+*/
+AddrCacheIndex *addrcindex_create( void ) {
+ AddrCacheIndex *index;
+
+ /*
+ ++_n_created;
+ printf( "addrcindex_create/1/%d\n", _n_created );
+ */
+ index = g_new0( AddrCacheIndex, 1 );
+ index->completion = g_completion_new( addrcindex_function );
+ index->addressList = NULL;
+ index->invalid = TRUE;
+
+ return index;
+}
+
+/*
+* Clear the completion index.
+*/
+void addrcindex_clear( AddrCacheIndex *index ) {
+ if( index ) {
+ /* Clear completion index */
+ g_completion_clear_items( index->completion );
+
+ /* Clear address list */
+ g_list_free( index->addressList );
+ index->addressList = NULL;
+ index->invalid = TRUE;
+ }
+}
+
+/*
+* Free completion index.
+*/
+void addrcindex_free( AddrCacheIndex *index ) {
+ if( index ) {
+ /*
+ ++_n_freed;
+ printf( "addrcindex_free/2/%d\n", _n_freed );
+ */
+ /* Clear out */
+ addrcindex_clear( index );
+
+ /* Free up */
+ g_completion_free( index->completion );
+ index->completion = NULL;
+ index->invalid = FALSE;
+
+ g_free( index );
+ }
+}
+
+/**
+ * Mark index as invalid. Will need to be rebuilt.
+ * \param index Address completion index.
+ */
+void addrcindex_invalidate( AddrCacheIndex *index ) {
+ g_return_if_fail( index != NULL );
+ index->invalid = TRUE;
+}
+
+/**
+ * Mark index as valid.
+ * \param index Address completion index.
+ */
+void addrcindex_validate( AddrCacheIndex *index ) {
+ g_return_if_fail( index != NULL );
+ index->invalid = FALSE;
+}
+
+/*
+ * Add completion entry to index.
+ * Enter: index Index.
+ * name Name.
+ * email EMail entry to add.
+ */
+void addrcindex_add_entry(
+ AddrCacheIndex *index, gchar *name, ItemEMail *email )
+{
+ AddrIndexEntry *entry;
+
+ entry = g_new0( AddrIndexEntry, 1 );
+ entry->name = g_strdup( name );
+ entry->address = email;
+ g_strdown( entry->name );
+ index->addressList = g_list_append( index->addressList, entry );
+}
+
+/*
+* Add an email entry into index. The index will also include all name fields
+* for the person.
+*
+* Add address into index.
+* Enter: index Index.
+* email E-Mail to add.
+*/
+void addrcindex_add_email( AddrCacheIndex *index, ItemEMail *email ) {
+ ItemPerson *person;
+ gchar *name;
+ GSList *uniqName;
+ GSList *node;
+ gboolean flag;
+
+ g_return_if_fail( index != NULL );
+ g_return_if_fail( email != NULL );
+
+ flag = FALSE;
+ uniqName = NULL;
+ name = ADDRITEM_NAME( email );
+ if( name != NULL ) {
+ if( strlen( name ) > 0 ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+ }
+ name = email->address;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+ if( name ) {
+ if( strlen( name ) > 0 ) flag = TRUE;
+ }
+
+ /* Bail if no email address */
+ if( ! flag ) {
+ g_slist_free( uniqName );
+ return;
+ }
+
+ person = ( ItemPerson * ) ADDRITEM_PARENT( email );
+ if( person != NULL ) {
+ name = ADDRITEM_NAME( person );
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->nickName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->firstName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->lastName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+ }
+
+ /* Create a completion entry for each unique name */
+ node = uniqName;
+ while( node ) {
+ addrcindex_add_entry( index, node->data, email );
+ node = g_slist_next( node );
+ }
+ g_slist_free( uniqName );
+
+}
+
+/*
+ * Process email address entry, checking for unique alias and address. If the
+ * address field is empty, no entries will be generated.
+ * Enter: index Index.
+ * uniqName List of unique names to examine.
+ * email EMail address item to process.
+ * Return: List of entries from email object to add to index.
+ */
+static GSList *addrcindex_proc_mail(
+ AddrCacheIndex *index, GSList *uniqName, ItemEMail *email )
+{
+ GSList *list;
+ gchar *name;
+
+ /* Test for address */
+ list = NULL;
+ name = email->address;
+ if( name ) {
+ if( strlen( name ) > 0 ) {
+ /* Address was supplied */
+ /* Append alias if unique */
+ name = ADDRITEM_NAME( email );
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ list = g_slist_append( list, name );
+ }
+ /* Then append the address if unique */
+ /* Note is possible that the address has already */
+ /* been entered into one of the name fields. */
+ if( mgu_slist_test_unq_nc( uniqName, email->address ) ) {
+ list = g_slist_append( list, email->address );
+ }
+ }
+ }
+ return list;
+}
+
+/*
+* Add person's address entries into index. Each email address is processed.
+* If the address field has been supplied, entries will be made. The index
+* will include the address, alias and all name fields for the person.
+*
+* Enter: index Index.
+* person Person to add.
+*/
+void addrcindex_add_person( AddrCacheIndex *index, ItemPerson *person ) {
+ gchar *name;
+ GSList *uniqName;
+ GSList *node;
+ GSList *listMail;
+ GList *listEMail;
+ ItemEMail *email;
+
+ g_return_if_fail( index != NULL );
+ g_return_if_fail( person != NULL );
+
+ /* Build list of all unique names in person's name fields */
+ uniqName = NULL;
+ name = ADDRITEM_NAME( person );
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->nickName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->firstName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ name = person->lastName;
+ if( mgu_slist_test_unq_nc( uniqName, name ) ) {
+ uniqName = g_slist_append( uniqName, name );
+ }
+
+ /* Process each email address entry */
+ listEMail = person->listEMail;
+ while( listEMail ) {
+ email = listEMail->data;
+ listMail = addrcindex_proc_mail( index, uniqName, email );
+ if( listMail ) {
+ /* Create a completion entry for the address item */
+ node = listMail;
+ while( node ) {
+ /* printf( "\tname-m::%s::\n", node->data ); */
+ addrcindex_add_entry( index, node->data, email );
+ node = g_slist_next( node );
+ }
+ /* ... and all person's name entries */
+ node = uniqName;
+ while( node ) {
+ /* printf( "\tname-p::%s::\n", node->data ); */
+ addrcindex_add_entry( index, node->data, email );
+ node = g_slist_next( node );
+ }
+ g_slist_free( listMail );
+ }
+ listEMail = g_list_next( listEMail );
+ }
+
+ /* Free up the list */
+ g_slist_free( uniqName );
+}
+
+/*
+* Print index to stream.
+* Enter: index Index.
+* stream Output stream.
+*/
+void addrcindex_print( AddrCacheIndex *index, FILE *stream ) {
+ GList *node;
+ AddrIndexEntry *entry;
+ ItemEMail *email;
+
+ g_return_if_fail( index != NULL );
+ fprintf( stream, "AddressSearchIndex:\n" );
+ node = index->addressList;
+ while( node ) {
+ entry = node->data;
+ email = entry->address;
+ fprintf( stream, "\tname: '%s'\t'%s'\n", entry->name, email->address );
+ node = g_list_next( node );
+ }
+}
+
+/*
+* Perform search for specified search term.
+* Enter: index Completion index.
+* search Search string.
+* Return: List of references to ItemEMail objects meeting search criteria. The
+* list should be g_list_free() when no longer required.
+*/
+GList *addrcindex_search( AddrCacheIndex *index, const gchar *search ) {
+ AddrIndexEntry *entry;
+ gchar *prefix;
+ GList *list;
+ GList *node;
+ GList *listEMail;
+
+ g_return_if_fail( index != NULL );
+ g_return_if_fail( search != NULL );
+
+ listEMail = NULL;
+ if( index->addressList != NULL ) {
+ /* Add items to list */
+ g_completion_add_items( index->completion, index->addressList );
+
+ /* Perform the search */
+ prefix = g_strdup( search );
+ g_strdown( prefix );
+ list = g_completion_complete( index->completion, prefix, NULL );
+ g_free( prefix );
+
+ /* Build list of unique EMail objects */
+ node = list;
+ while( node ) {
+ entry = node->data;
+ /* printf( "\tname ::%s::\n", entry->name ); */
+ if( NULL == g_list_find( listEMail, entry->address ) ) {
+ listEMail = g_list_append(
+ listEMail, entry->address );
+ }
+ node = g_list_next( node );
+ }
+ }
+
+ return listEMail;
+}
+
+/*
+* End of Source.
+*/
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002-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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions to maintain address completion index.
+ */
+
+#ifndef __ADDRCINDEX_H__
+#define __ADDRCINDEX_H__
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "addritem.h"
+
+/*
+ * Constants.
+ */
+
+/* Data structures */
+typedef struct {
+ GCompletion *completion;
+ GList *addressList;
+ gboolean invalid;
+}
+AddrCacheIndex;
+
+/* Function prototypes */
+AddrCacheIndex *addrcindex_create ( void );
+void addrcindex_clear ( AddrCacheIndex *index );
+void addrcindex_free ( AddrCacheIndex *index );
+void addrcindex_invalidate ( AddrCacheIndex *index );
+void addrcindex_validate ( AddrCacheIndex *index );
+void addrcindex_add_entry ( AddrCacheIndex *index,
+ gchar *name,
+ ItemEMail *email );
+void addrcindex_add_email ( AddrCacheIndex *index, ItemEMail *email );
+void addrcindex_add_person ( AddrCacheIndex *index, ItemPerson *person );
+void addrcindex_print ( AddrCacheIndex *index, FILE *stream );
+GList *addrcindex_search ( AddrCacheIndex *index, const gchar *search );
+
+#endif /* __ADDRCINDEX_H__ */
+
+/*
+* End of Source.
+*/
#ifdef USE_LDAP
#include <pthread.h>
-#include "syldap.h"
+#include "ldapserver.h"
#include "editldap.h"
#define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
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 */
if( _clipBoard_ != NULL ) {
addrclip_free( _clipBoard_ );
}
+ addrcompl_teardown();
if( _addressIndex_ != NULL ) {
addrindex_free_index( _addressIndex_ );
}
person = ( ItemPerson * ) ADDRITEM_PARENT(email);
if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return;
addressbook_folder_refresh_one_person( clist, person );
- invalidate_address_completion();
return;
}
}
/* Edit person - basic page */
ItemPerson *person = ( ItemPerson * ) obj;
if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
- invalidate_address_completion();
addressbook_folder_refresh_one_person( clist, person );
return;
}
}
addrIndex = addrindex_create_index();
+ addrcompl_initialize();
/* Use new address book index. */
addrindex_set_file_path( addrIndex, get_rc_dir() );
* 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;
newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
atci->treeLeaf, atci->treeExpand );
- gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
- addressbook_free_treenode );
+ if( newNode )
+ gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
+ addressbook_free_treenode );
}
listItems = itemFolder->listFolder;
if( _addressIndex_->retVal != MGU_SUCCESS ) {
addrindex_print_index( _addressIndex_, stdout );
}
-
- /* Notify address completion of new data */
- invalidate_address_completion();
}
}
}
}
-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;
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), "" );
}
}
}
+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;
}
/*
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
*/
static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
+ AddressObject *pobj;
AddressObject *obj;
AdapterDSource *ads = NULL;
gchar *sLookup;
+ GtkCTreeNode *node = NULL, *parentNode = NULL;
if( ! addrbook.treeSelected ) return;
if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
sLookup = gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
g_strchomp( sLookup );
+ /* printf( "addressbook_lup_clicked/Lookup: '%s'\n", sLookup ); */
if( obj->type == ADDR_DATASOURCE ) {
+ /* printf( "I am a datasource\n" ); */
ads = ADAPTER_DSOURCE(obj);
-#ifdef USE_LDAP
- if( ads->subType == ADDR_LDAP ) {
- addressbook_ldap_lookup( ads, sLookup );
+ }
+ else {
+ /* printf( "Test my parent\n" ); */
+ parentNode = GTK_CTREE_ROW(addrbook.treeSelected)->parent;
+ obj = gtk_ctree_node_get_row_data( ctree, parentNode );
+ if( obj->type == ADDR_DATASOURCE ) {
+ ads = ADAPTER_DSOURCE(obj);
}
-#endif /* USE_LDAP */
}
-
+#ifdef USE_LDAP
+ if( ads && ads->subType == ADDR_LDAP ) {
+ addressbook_ldap_lookup( ads, sLookup );
+ }
+#endif
g_free( sLookup );
}
return TRUE;
}
-/* **********************************************************************
-* Address completion support.
-* ***********************************************************************
-*/
-
-/*
-* This function is used by the address completion function to load
-* addresses.
-* Enter: callBackFunc Function to be called when an address is
-* to be loaded.
-* Return: TRUE if data loaded, FALSE if address index not loaded.
-*/
-gboolean addressbook_load_completion( gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) ) {
- AddressDataSource *ds;
- GList *nodeIf, *nodeDS;
- GList *listP, *nodeP;
- GList *nodeM;
- gchar *sName, *sAddress, *sAlias, *sFriendly;
-
- debug_print( "addressbook_load_completion\n" );
-
- if( _addressIndex_ == NULL ) return FALSE;
-
- nodeIf = addrindex_get_interface_list( _addressIndex_ );
- while( nodeIf ) {
- AddressInterface *interface = nodeIf->data;
- nodeDS = interface->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 );
- }
- nodeIf = g_list_next( nodeIf );
- }
- debug_print( "addressbook_load_completion... done\n" );
-
- return TRUE;
-}
-
/* **********************************************************************
* Address Import.
* ***********************************************************************
newNode );
addrbook.treeSelected = newNode;
}
-
- /* Notify address completion */
- invalidate_address_completion();
}
}
}
newNode );
addrbook.treeSelected = newNode;
}
-
- /* Notify address completion */
- invalidate_address_completion();
}
}
}
newNode );
addrbook.treeSelected = newNode;
}
-
- /* Notify address completion */
- invalidate_address_completion();
}
}
}
ADDRESS_OBJECT(ads) );
}
}
-
- /* Notify address completion */
- invalidate_address_completion();
}
}
/*
* End of Source.
*/
+/* **********************************************************************
+* Address completion and search support.
+* ***********************************************************************
+*/
+
+/**
+ * Setup search for specified search string.
+ * \param searchTerm Search string.
+ * \param target Target data.
+ * \param callBack Call back function.
+ * \return ID allotcated to this query, or 0 if none.
+ */
+gint addressbook_setup_search(
+ const gchar *searchTerm, const gpointer target,
+ AddrSearchCallbackFunc callback )
+{
+ if( _addressIndex_ == NULL ) {
+ printf( "address index not loaded\n" );
+ return 0;
+ }
+ return addrindex_setup_search( _addressIndex_, searchTerm, target, callback );
+}
+
+/**
+ * Perform the previously registered search.
+ * \param queryID ID of search query to be executed.
+ * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
+ * failed.
+ */
+gboolean addressbook_start_search( const gint queryID ) {
+ if( _addressIndex_ == NULL ) {
+ printf( "address index not loaded\n" );
+ return FALSE;
+ }
+ return addrindex_start_search( _addressIndex_, queryID );
+}
+
+/**
+ * Stop the previously registered search.
+ * \param queryID ID of search query to stop.
+ */
+void addressbook_stop_search( const gint queryID ){
+ if( _addressIndex_ == NULL ) {
+ /* printf( "address index not loaded\n" ); */
+ return;
+ }
+ addrindex_stop_search( _addressIndex_, queryID );
+}
+
+/**
+ * Read all address interfaces and data sources.
+ */
+void addressbook_read_all( void ) {
+ if( _addressIndex_ == NULL ) {
+ /* Load index file */
+ /* printf( "address index not loaded\n" ); */
+ /* addressbook_read_file(); */
+ }
+
+ if( ! addrindex_get_loaded( _addressIndex_ ) ) {
+ /* Read all address books */
+ addrindex_read_all( _addressIndex_ );
+ }
+ /*
+ else {
+ printf( "Address data already loaded!!!!!!!!!!!!!!!\n" );
+ }
+ */
+}
+
+/**
+ * Perform a simple search of all non-query type data sources for specified
+ * search term. If several entries are found, only the first item is
+ * returned. Interfaces that require a time-consuming "query" are ignored for
+ * this search.
+ *
+ * \param searchTerm Search term to find. Typically an email address.
+ * \return Reference to a single E-Mail object that was found in the address
+ * book, or <i>NULL</i> if nothing found. This should *NOT* be freed
+ * when done.
+ */
+ItemEMail *addressbook_quick_search_single( const gchar *searchTerm ) {
+ if( _addressIndex_ == NULL ) {
+ /* printf( "address index not loaded\n" ); */
+ return NULL;
+ }
+ return addrindex_quick_search_single( _addressIndex_, searchTerm );
+}
+
+/**
+ * Perform a simple search of all non-query type data sources for specified
+ * search term. If several entries are found, only the first item is
+ * returned. Interfaces that require a time-consuming "query" are ignored for
+ * this search.
+ *
+ * \param addrIndex Address index object.
+ * \param searchTerm Search term to find. Typically an email address.
+ * \return List of references to zero or mail E-Mail object that was found in
+ * the address books, or <i>NULL</i> if nothing found. This list
+ * *SHOULD* be freed when done.
+ */
+GList *addressbook_quick_search_list( const gchar *searchTerm )
+{
+ if( _addressIndex_ == NULL ) {
+ printf( "address index not loaded\n" );
+ return NULL;
+ }
+ return addrindex_quick_search_list( _addressIndex_, searchTerm );
+}
+/*
+* End of Source.
+*/
/*
* 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
#include <gtk/gtkwidget.h>
#include "compose.h"
+#include "addrquery.h"
+#include "addritem.h"
void addressbook_open (Compose *target);
void addressbook_set_target_compose (Compose *target);
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 );
gboolean sourceInd,
GList *msgList);
+gint addressbook_setup_search ( const gchar *searchTerm,
+ const gpointer target,
+ AddrSearchCallbackFunc callback );
+gboolean addressbook_start_search ( const gint queryID );
+void addressbook_stop_search ( const gint queryID );
+
+void addressbook_read_all ( void );
+GList *addressbook_quick_search_list ( const gchar *searchTerm );
+ItemEMail *addressbook_quick_search_single( const gchar *searchTerm );
+
#endif /* __ADDRESSBOOK_H__ */
#include "addrbook.h"
#include "addrindex.h"
#include "xml.h"
+#include "addrquery.h"
#ifndef DEV_STANDALONE
#include "prefs_gtk.h"
#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")
#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;
};
/*
-* 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;
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;
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;
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 = 2;
+
+ /* 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;
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 = 3;
+ 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;
iface->getAllPersons = ( void * ) jpilot_get_all_persons;
iface->getName = ( void * ) jpilot_get_name;
iface->setAccessFlag = ( void * ) jpilot_set_accessed;
+ iface->searchOrder = 3;
#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 );
return ds;
}
-/*
-* Free up data source.
-*/
+/**
+ * Free up data source.
+ * \param ds Data source to free.
+ */
void addrindex_free_datasource( AddressDataSource *ds ) {
AddressInterface *iface;
+ AddressCache *cache;
g_return_if_fail( ds != NULL );
#endif
#ifdef USE_LDAP
else if( iface->type == ADDR_IF_LDAP ) {
- SyldapServer *server = ds->rawDataSource;
- syldap_free( server );
+ LdapServer *server = ds->rawDataSource;
+ cache = server->addressCache;
+ addrcache_use_index( cache, FALSE );
+ ldapsvr_free( server );
}
#endif
else {
}
}
else {
- GList *list = ds->rawDataSource;
- addrindex_free_attributes( list );
+ AddressIfFragment *fragment = ds->rawDataSource;
+ addrindex_free_fragment( fragment );
}
}
}
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 ) {
}
}
+/**
+ * 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 );
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;
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;
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 );
}
/*
-* 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;
}
/*
-* 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 );
}
/*
-* 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 );
}
/*
-* Create new object.
-*/
+ * Create a new address index.
+ * \return Initialized address index object.
+ */
AddressIndex *addrindex_create_index( void ) {
AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
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.
-*/
+/**
+ * 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;
addrIndex->conversionError = FALSE;
addrIndex->lastType = ADDR_IF_NONE;
addrIndex->dirtyFlag = FALSE;
+
+ /* Free up interfaces */
node = addrIndex->interfaceList;
while( node ) {
AddressInterface *iface = node->data;
}
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 )
{
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 )
{
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 )
{
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 )
{
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 )
{
* 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 );
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 );
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;
+
+ 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;
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;
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;
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();
+ 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 );
+
+ sprintf( value, "%d", ctl->port );
+ addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
- 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 );
+ 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 );
- sprintf( value, "%d", server->port );
- addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
+ 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 );
- 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 );
+ addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
+ server->searchFlag ? "yes" : "no" );
- 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 );
+ 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
* 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 );
}
}
}
- 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->searchOrder > 0 ) {
+ /* Add to search order list */
+ addrIndex->searchOrder = g_list_insert_sorted(
+ addrIndex->searchOrder, iface,
+ addrindex_search_order_compare );
+ }
+ nodeIf = g_list_next( nodeIf );
+ }
+
+ nodeIf = addrIndex->searchOrder;
+ while( nodeIf ) {
+ AddressInterface *iface = nodeIf->data;
+ nodeIf = g_list_next( nodeIf );
+ }
+
+}
+
static gint addrindex_read_file( AddressIndex *addrIndex ) {
XMLFile *file = NULL;
gchar *fileSpec = NULL;
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;
}
}
xml_close_file( file );
+ addrindex_build_search_order( addrIndex );
+
return addrIndex->retVal;
}
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;
+}
+
+/**
+ * Perform the search for specified address cache.
+ * \param cache Cache to be searched.
+ * \param queryID ID of search query to be executed.
+ */
+static void addrindex_search_cache( AddressCache *cache, const gint queryID ) {
+ AddrCacheIndex *index;
+ GList *listEMail;
+
+ index = cache->searchIndex;
+ if( index == NULL ) return;
+ if( index->invalid ) {
+ addrcache_build_index( cache );
+ }
+
+ /*
+ printf( "query ::%d:: searching index for ::%s::\n", queryID, _searchTerm_ );
+ */
+ listEMail = addrcindex_search( index, _searchTerm_ );
+ ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
+ g_list_free( listEMail );
+ listEMail = NULL;
+ /* printf( "searching index done\n" ); */
+}
+
+#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;
+ printf( "Searching ::%s::\n", ldapsvr_get_name( server ) );
+
+ /* 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 );
+ /* printf( "addrindex_search_ldap::executing dynamic search...\n" ); */
+ 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;
+ AddressCache *cache;
+ GList *nodeIf;
+ GList *nodeDS;
+ gint type;
+
+ /* printf( "addrindex_start_search::%d::\n", queryID ); */
+ nodeIf = addrIndex->searchOrder;
+ while( nodeIf ) {
+ iface = nodeIf->data;
+ nodeIf = g_list_next( nodeIf );
+
+ if( ! iface->useInterface ) {
+ continue;
+ }
+
+ type = iface->type;
+ nodeDS = iface->listSource;
+ while( nodeDS ) {
+ ds = nodeDS->data;
+ nodeDS = g_list_next( nodeDS );
+ cache = NULL;
+
+ if( type == ADDR_IF_BOOK ) {
+ AddressBookFile *abf = ds->rawDataSource;
+ cache = abf->addressCache;
+ }
+ else if( type == ADDR_IF_VCARD ) {
+ VCardFile *vcf = ds->rawDataSource;
+ cache = vcf->addressCache;
+ }
+#ifdef USE_JPILOT
+ else if( type == ADDR_IF_JPILOT ) {
+ JPilotFile *jpf = ds->rawDataSource;
+ cache = jpf->addressCache;
+ }
+#endif
+#ifdef USE_LDAP
+ else if( type == ADDR_IF_LDAP ) {
+ LdapServer *server = ds->rawDataSource;
+ addrindex_search_ldap( server, queryID );
+ }
+#endif
+ if( cache ) {
+ addrindex_search_cache( cache, queryID );
+ }
+ }
+ }
+ 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;
+}
+
+/**
+ * Perform a simple search of all non-query type data sources for specified
+ * search term. If several entries are found, only the first item is
+ * returned. Interfaces that require a time-consuming "external query" are
+ * ignored for this search.
+ *
+ * \param addrIndex Address index object.
+ * \param searchTerm Search term to find. Typically an email address.
+ * \return List of references to zero or mail E-Mail object that was found in
+ * the address books, or <i>NULL</i> if nothing found. This list
+ * *SHOULD* be freed when done.
+ */
+GList *addrindex_quick_search_list(
+ AddressIndex *addrIndex, const gchar *searchTerm )
+{
+ GList *listRet = NULL;
+ GList *listEMail;
+ AddressInterface *iface;
+ AddressDataSource *ds;
+ AddressCache *cache;
+ AddrCacheIndex *index;
+ ItemEMail *email;
+ GList *nodeIf;
+ GList *nodeDS;
+ GList *nodeEM;
+ gint type;
+
+ nodeIf = addrIndex->searchOrder;
+ while( nodeIf ) {
+ iface = nodeIf->data;
+ nodeIf = g_list_next( nodeIf );
+
+ if( ! iface->useInterface ) {
+ /* Ignore interfaces that don't have a library */
+ continue;
+ }
+ if( iface->externalQuery ) {
+ /* Ignore interfaces that require a "query" */
+ continue;
+ }
+
+ type = iface->type;
+ nodeDS = iface->listSource;
+ while( nodeDS ) {
+ ds = nodeDS->data;
+ nodeDS = g_list_next( nodeDS );
+ cache = NULL;
+
+ if( type == ADDR_IF_BOOK ) {
+ AddressBookFile *abf = ds->rawDataSource;
+ cache = abf->addressCache;
+ }
+ else if( type == ADDR_IF_VCARD ) {
+ VCardFile *vcf = ds->rawDataSource;
+ cache = vcf->addressCache;
+ }
+#ifdef USE_JPILOT
+ else if( type == ADDR_IF_JPILOT ) {
+ JPilotFile *jpf = ds->rawDataSource;
+ cache = jpf->addressCache;
+ }
+#endif
+ if( cache ) {
+ index = cache->searchIndex;
+ if( index == NULL ) {
+ continue;
+ }
+ if( index->invalid ) {
+ addrcache_build_index( cache );
+ }
+ listEMail = addrcindex_search( index, searchTerm );
+ nodeEM = listEMail;
+ while( nodeEM ) {
+ email = listEMail->data;
+ listRet = g_list_append( listRet, email );
+ nodeEM = g_list_next( nodeEM );
+ }
+ g_list_free( listEMail );
+ }
+ }
+ }
+ return listRet;
+}
+
+/**
+ * Perform a simple search of all non-query type data sources for specified
+ * search term. If several entries are found, only the first item is
+ * returned. Interfaces that require a time-consuming "external query" are
+ * ignored for this search.
+ *
+ * \param addrIndex Address index object.
+ * \param searchTerm Search term to find. Typically an email address.
+ * \return Reference to a single E-Mail object that was found in the address
+ * book, or <i>NULL</i> if nothing found. This should *NOT* be freed
+ * when done.
+ */
+ItemEMail *addrindex_quick_search_single(
+ AddressIndex *addrIndex, const gchar *searchTerm )
+{
+ ItemEMail *email = NULL;
+ AddressInterface *iface;
+ AddressDataSource *ds;
+ AddressCache *cache;
+ AddrCacheIndex *index;
+ GList *listEMail;
+ GList *nodeIf;
+ GList *nodeDS;
+ gint type;
+
+ /* printf( "addrindex_quick_search::%s::\n", searchTerm ); */
+ 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 );
+ cache = NULL;
+
+ if( type == ADDR_IF_BOOK ) {
+ AddressBookFile *abf = ds->rawDataSource;
+ cache = abf->addressCache;
+ }
+ else if( type == ADDR_IF_VCARD ) {
+ VCardFile *vcf = ds->rawDataSource;
+ cache = vcf->addressCache;
+ }
+#ifdef USE_JPILOT
+ else if( type == ADDR_IF_JPILOT ) {
+ JPilotFile *jpf = ds->rawDataSource;
+ cache = jpf->addressCache;
+ }
+#endif
+ if( cache ) {
+ index = cache->searchIndex;
+ if( index == NULL ) {
+ continue;
+ }
+ if( index->invalid ) {
+ addrcache_build_index( cache );
+ }
+
+ listEMail = addrcindex_search( index, searchTerm );
+ if( listEMail ) {
+ email = listEMail->data;
+ }
+ g_list_free( listEMail );
+ if( email ) break;
+ }
+ }
+ }
+ return email;
+}
+
+/*
+ * End of Source.
+ */
+
+
#include <glib.h>
#include "addritem.h"
#include "addrcache.h"
+#include "addrquery.h"
#define ADDRESSBOOK_MAX_IFACE 4
#define ADDRESSBOOK_INDEX_FILE "addrbook--index.xml"
gboolean dirtyFlag;
GList *interfaceList;
GHashTable *hashCache;
+ gboolean loadedFlag;
+ GList *searchOrder;
};
typedef struct _AddressInterface 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;
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 );
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 );
+GList *addrindex_quick_search_list ( AddressIndex *addrIndex,
+ const gchar *searchTerm );
+ItemEMail *addrindex_quick_search_single( AddressIndex *addrIndex,
+ const gchar *searchTerm );
+
#endif /* __ADDRINDEX_H__ */
/*
folder->listFolder = NULL;
folder->listPerson = NULL;
folder->listGroup = NULL;
+ folder->folderType = ADDRFOLDER_NONE;
+ folder->folderData = NULL;
return folder;
}
if( item ) {
itemNew = addritem_create_item_folder();
ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+ itemNew->folderType = item->folderType;
}
return itemNew;
}
folder->listFolder = NULL;
folder->listGroup = NULL;
folder->listPerson = NULL;
+ folder->folderType = ADDRFOLDER_NONE;
+ folder->folderData = NULL;
g_free( folder );
}
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 ) {
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;
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;
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions to define an address query (a request).
+ */
+
+#ifndef __ADDRQUERY_H__
+#define __ADDRQUERY_H__
+
+#include <glib.h>
+// #include <stdio.h>
+
+/* Address search call back function */
+typedef gint ( AddrSearchCallbackFunc ) ( gint cacheID,
+ GList *listEMail,
+ gpointer target );
+
+#endif /* __ADDRQUERY_H__ */
+
+/*
+ * End of Source.
+ */
g_free( name );
}
g_free( cn );
+ addrbook_invalidate( abf );
gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
name = gtk_editable_get_chars( GTK_EDITABLE(groupeditdlg.entry_name), 0, -1 );
addritem_group_set_name( group, name );
g_free( name );
+ addrbook_invalidate( abf );
listEMail = NULL;
return group;
}
addritem_folder_set_name( folder, name );
g_free( name );
+ addrbook_invalidate( abf );
return folder;
}
#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"
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.
*/
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 ) {
}
}
-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;
gchar *sBaseDN = NULL;
gint iBaseDN = 0;
gboolean flg;
+ GList *baseDN = NULL;
edit_ldap_status_show( "" );
flg = FALSE;
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 ) {
}
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 ) {
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 );
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);
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;
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 );
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;
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;
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);
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;
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 );
/* 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;
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;
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;
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;
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 );
}
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);
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 );
#include "intl.h"
#include "prefs_common.h"
-#include "syldap.h"
+#include "ldaputil.h"
#include "mgutils.h"
#include "gtkutils.h"
#include "manage_window.h"
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));
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 };
pilotFile->labelInd = NULL;
pilotFile->havePC3 = FALSE;
pilotFile->pc3ModifyTime = 0;
+
+ /* We want to use an address completion index */
+ addrcache_use_index( pilotFile->addressCache, TRUE );
+
return pilotFile;
}
jpilot_clear_custom_labels( pilotFile );
/* Clear cache */
- addrcache_clear( pilotFile->addressCache );
addrcache_free( pilotFile->addressCache );
/* Free internal stuff */
if( pilotFile->retVal == MGU_SUCCESS ) {
pilotFile->addressCache->modified = FALSE;
pilotFile->addressCache->dataRead = TRUE;
+
+ /* Build address completion index */
+ addrcache_build_index( pilotFile->addressCache );
}
}
}
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions for LDAP control data.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include "ldapctrl.h"
+#include "mgutils.h"
+
+/**
+ * Create new LDAP control block object.
+ * \return Initialized control object.
+ */
+LdapControl *ldapctl_create( void ) {
+ LdapControl *ctl;
+
+ ctl = g_new0( LdapControl, 1 );
+ ctl->hostName = NULL;
+ ctl->port = LDAPCTL_DFL_PORT;
+ ctl->baseDN = NULL;
+ ctl->bindDN = NULL;
+ ctl->bindPass = NULL;
+ ctl->listCriteria = NULL;
+ ctl->attribEMail = g_strdup( LDAPCTL_ATTR_EMAIL );
+ ctl->attribCName = g_strdup( LDAPCTL_ATTR_COMMONNAME );
+ ctl->attribFName = g_strdup( LDAPCTL_ATTR_GIVENNAME );
+ ctl->attribLName = g_strdup( LDAPCTL_ATTR_SURNAME );
+ ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
+ ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
+ ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
+
+ /* Mutex to protect control block */
+ ctl->mutexCtl = g_malloc0( sizeof( pthread_mutex_t ) );
+ pthread_mutex_init( ctl->mutexCtl, NULL );
+
+ return ctl;
+}
+
+/**
+ * Specify hostname to be used.
+ * \param ctl Control object to process.
+ * \param value Host name.
+ */
+void ldapctl_set_host( LdapControl* ctl, const gchar *value ) {
+ ctl->hostName = mgu_replace_string( ctl->hostName, value );
+ g_strstrip( ctl->hostName );
+}
+
+/**
+ * Specify port to be used.
+ * \param ctl Control object to process.
+ * \param value Port.
+ */
+void ldapctl_set_port( LdapControl* ctl, const gint value ) {
+ if( value > 0 ) {
+ ctl->port = value;
+ }
+ else {
+ ctl->port = LDAPCTL_DFL_PORT;
+ }
+}
+
+/**
+ * Specify base DN to be used.
+ * \param ctl Control object to process.
+ * \param value Base DN.
+ */
+void ldapctl_set_base_dn( LdapControl* ctl, const gchar *value ) {
+ ctl->baseDN = mgu_replace_string( ctl->baseDN, value );
+ g_strstrip( ctl->baseDN );
+}
+
+/**
+ * Specify bind DN to be used.
+ * \param ctl Control object to process.
+ * \param value Bind DN.
+ */
+void ldapctl_set_bind_dn( LdapControl* ctl, const gchar *value ) {
+ ctl->bindDN = mgu_replace_string( ctl->bindDN, value );
+ g_strstrip( ctl->bindDN );
+}
+
+/**
+ * Specify bind password to be used.
+ * \param ctl Control object to process.
+ * \param value Password.
+ */
+void ldapctl_set_bind_password( LdapControl* ctl, const gchar *value ) {
+ ctl->bindPass = mgu_replace_string( ctl->bindPass, value );
+ g_strstrip( ctl->bindPass );
+}
+
+/**
+ * Specify maximum number of entries to retrieve.
+ * \param ctl Control object to process.
+ * \param value Maximum entries.
+ */
+void ldapctl_set_max_entries( LdapControl* ctl, const gint value ) {
+ if( value > 0 ) {
+ ctl->maxEntries = value;
+ }
+ else {
+ ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
+ }
+}
+
+/**
+ * Specify timeout value for LDAP operation (in seconds).
+ * \param ctl Control object to process.
+ * \param value Timeout.
+ */
+void ldapctl_set_timeout( LdapControl* ctl, const gint value ) {
+ if( value > 0 ) {
+ ctl->timeOut = value;
+ }
+ else {
+ ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
+ }
+}
+
+/**
+ * Specify maximum age of query (in seconds) before query is retired.
+ * \param ctl Control object to process.
+ * \param value Maximum age.
+ */
+void ldapctl_set_max_query_age( LdapControl* ctl, const gint value ) {
+ if( value > LDAPCTL_MAX_QUERY_AGE ) {
+ ctl->maxQueryAge = LDAPCTL_MAX_QUERY_AGE;
+ }
+ else if( value < 1 ) {
+ ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
+ }
+ else {
+ ctl->maxQueryAge = value;
+ }
+}
+
+/**
+ * Specify search criteria list to be used.
+ * \param ctl Control data object.
+ * \param value Linked list of LDAP attribute names to use for search.
+ */
+void ldapctl_set_criteria_list( LdapControl* ctl, GList *value ) {
+ g_return_if_fail( ctl != NULL );
+ mgu_free_dlist( ctl->listCriteria );
+ ctl->listCriteria = value;
+}
+
+/**
+ * Return search criteria list.
+ * \param ctl Control data object.
+ * \return Linked list of character strings containing LDAP attribute names to
+ * use for a search. This should not be modified directly. Use the
+ * <code>ldapctl_set_criteria_list()</code>,
+ * <code>ldapctl_criteria_list_clear()</code> and
+ * <code>ldapctl_criteria_list_add()</code> functions for this purpose.
+ */
+GList *ldapctl_get_criteria_list( const LdapControl* ctl ) {
+ g_return_val_if_fail( ctl != NULL, NULL );
+ return ctl->listCriteria;
+}
+
+/**
+ * Clear list of LDAP search attributes.
+ * \param ctl Control data object.
+ */
+void ldapctl_criteria_list_clear( LdapControl *ctl ) {
+ g_return_if_fail( ctl != NULL );
+ mgu_free_dlist( ctl->listCriteria );
+ ctl->listCriteria = NULL;
+}
+
+/**
+ * Add LDAP attribute to criteria list.
+ * \param ctl Control object to process.
+ * \param attr Attribute name to append. If not NULL and unique, a copy will
+ * be appended to the list.
+ */
+void ldapctl_criteria_list_add( LdapControl *ctl, gchar *attr ) {
+ g_return_if_fail( ctl != NULL );
+ if( attr != NULL ) {
+ if( mgu_list_test_unq_nc( ctl->listCriteria, attr ) ) {
+ ctl->listCriteria = g_list_append(
+ ctl->listCriteria, g_strdup( attr ) );
+ }
+ }
+}
+
+/**
+ * Build criteria list using default attributes.
+ * \param ctl Control object to process.
+ */
+void ldapctl_default_attributes( LdapControl *ctl ) {
+ g_return_if_fail( ctl != NULL );
+
+ ldapctl_criteria_list_clear( ctl );
+ ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_COMMONNAME );
+ ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_GIVENNAME );
+ ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_SURNAME );
+ ldapctl_criteria_list_add( ctl, LDAPCTL_ATTR_EMAIL );
+}
+
+/**
+ * Clear LDAP server member variables.
+ * \param ctl Control object to clear.
+ */
+void ldapctl_clear( LdapControl *ctl ) {
+ g_return_if_fail( ctl != NULL );
+
+ /* Free internal stuff */
+ g_free( ctl->hostName );
+ g_free( ctl->baseDN );
+ g_free( ctl->bindDN );
+ g_free( ctl->bindPass );
+ g_free( ctl->attribEMail );
+ g_free( ctl->attribCName );
+ g_free( ctl->attribFName );
+ g_free( ctl->attribLName );
+
+ ldapctl_criteria_list_clear( ctl );
+
+ /* Clear pointers */
+ ctl->hostName = NULL;
+ ctl->port = 0;
+ ctl->baseDN = NULL;
+ ctl->bindDN = NULL;
+ ctl->bindPass = NULL;
+ ctl->attribEMail = NULL;
+ ctl->attribCName = NULL;
+ ctl->attribFName = NULL;
+ ctl->attribLName = NULL;
+ ctl->maxEntries = 0;
+ ctl->timeOut = 0;
+ ctl->maxQueryAge = 0;
+}
+
+/**
+ * Free up LDAP server interface object by releasing internal memory.
+ * \param ctl Control object to free.
+ */
+void ldapctl_free( LdapControl *ctl ) {
+ g_return_if_fail( ctl != NULL );
+
+ /* Free internal stuff */
+ ldapctl_clear( ctl );
+
+ /* Free the mutex */
+ pthread_mutex_destroy( ctl->mutexCtl );
+ g_free( ctl->mutexCtl );
+ ctl->mutexCtl = NULL;
+
+ /* Now release LDAP control object */
+ g_free( ctl );
+}
+
+/**
+ * Setup default (empty) values for specified object.
+ * \param ctl Control object to process.
+ */
+void ldapctl_default_values( LdapControl *ctl ) {
+ g_return_if_fail( ctl != NULL );
+
+ /* Clear our destination */
+ ldapctl_clear( ctl );
+
+ /* Copy strings */
+ ctl->hostName = g_strdup( "" );
+ ctl->baseDN = g_strdup( "" );
+ ctl->bindDN = g_strdup( "" );
+ ctl->bindPass = g_strdup( "" );
+ ctl->port = LDAPCTL_DFL_PORT;
+ ctl->maxEntries = LDAPCTL_MAX_ENTRIES;
+ ctl->timeOut = LDAPCTL_DFL_TIMEOUT;
+ ctl->maxQueryAge = LDAPCTL_DFL_QUERY_AGE;
+
+ ldapctl_default_attributes( ctl );
+}
+
+/**
+ * Display object to specified stream.
+ * \param ctl Control object to process.
+ * \param stream Output stream.
+ */
+void ldapctl_print( const LdapControl *ctl, FILE *stream ) {
+ g_return_if_fail( ctl != NULL );
+
+ pthread_mutex_lock( ctl->mutexCtl );
+ fprintf( stream, "LdapControl:\n" );
+ fprintf( stream, "host name: '%s'\n", ctl->hostName );
+ fprintf( stream, " port: %d\n", ctl->port );
+ fprintf( stream, " base dn: '%s'\n", ctl->baseDN );
+ fprintf( stream, " bind dn: '%s'\n", ctl->bindDN );
+ fprintf( stream, "bind pass: '%s'\n", ctl->bindPass );
+ fprintf( stream, "attr mail: '%s'\n", ctl->attribEMail );
+ fprintf( stream, "attr comn: '%s'\n", ctl->attribCName );
+ fprintf( stream, "attr frst: '%s'\n", ctl->attribFName );
+ fprintf( stream, "attr last: '%s'\n", ctl->attribLName );
+ fprintf( stream, "max entry: %d\n", ctl->maxEntries );
+ fprintf( stream, " timeout: %d\n", ctl->timeOut );
+ fprintf( stream, " max age: %d\n", ctl->maxQueryAge );
+ fprintf( stream, "crit list:\n" );
+ if( ctl->listCriteria ) {
+ mgu_print_dlist( ctl->listCriteria, stream );
+ }
+ else {
+ fprintf( stream, "\t!!!none!!!\n" );
+ }
+ pthread_mutex_unlock( ctl->mutexCtl );
+}
+
+/**
+ * Copy member variables to specified object. Mutex lock object is
+ * not copied.
+ * \param ctlFrom Object to copy from.
+ * \param ctlTo Destination object.
+ */
+void ldapctl_copy( const LdapControl *ctlFrom, LdapControl *ctlTo ) {
+ GList *node;
+
+ g_return_if_fail( ctlFrom != NULL );
+ g_return_if_fail( ctlTo != NULL );
+
+ /* Lock both objects */
+ pthread_mutex_lock( ctlFrom->mutexCtl );
+ pthread_mutex_lock( ctlTo->mutexCtl );
+
+ /* Clear our destination */
+ ldapctl_clear( ctlTo );
+
+ /* Copy strings */
+ ctlTo->hostName = g_strdup( ctlFrom->hostName );
+ ctlTo->baseDN = g_strdup( ctlFrom->baseDN );
+ ctlTo->bindDN = g_strdup( ctlFrom->bindDN );
+ ctlTo->bindPass = g_strdup( ctlFrom->bindPass );
+ ctlTo->attribEMail = g_strdup( ctlFrom->attribEMail );
+ ctlTo->attribCName = g_strdup( ctlFrom->attribCName );
+ ctlTo->attribFName = g_strdup( ctlFrom->attribFName );
+ ctlTo->attribLName = g_strdup( ctlFrom->attribLName );
+
+ /* Copy search criteria */
+ node = ctlFrom->listCriteria;
+ while( node ) {
+ ctlTo->listCriteria = g_list_append(
+ ctlTo->listCriteria, g_strdup( node->data ) );
+ node = g_list_next( node );
+ }
+
+ /* Copy other members */
+ ctlTo->port = ctlFrom->port;
+ ctlTo->maxEntries = ctlFrom->maxEntries;
+ ctlTo->timeOut = ctlFrom->timeOut;
+ ctlTo->maxQueryAge = ctlFrom->maxQueryAge;
+
+ /* Unlock */
+ pthread_mutex_unlock( ctlTo->mutexCtl );
+ pthread_mutex_unlock( ctlFrom->mutexCtl );
+}
+
+/**
+ * Build a formatted LDAP search criteria string from criteria list.
+ * \param ctl Control object to process.
+ * \param searchVal Value to search for.
+ * \return Formatted string. Should be g_free() when done.
+ */
+gchar *ldapctl_format_criteria( LdapControl *ctl, const gchar *searchVal ) {
+ GList *node;
+ gchar *p1, *p2, *retVal;
+
+ g_return_val_if_fail( ctl != NULL, NULL );
+
+ /* p1 contains previous formatted criteria */
+ /* p2 contains next formatted criteria */
+ retVal = p1 = p2 = NULL;
+ node = ctl->listCriteria;
+ while( node ) {
+ gchar *attr, *tmp;
+
+ attr = node->data;
+ node = g_list_next( node );
+
+ /* Switch pointers */
+ tmp = p1; p1 = p2; p2 = tmp;
+
+ if( p1 ) {
+ /* Subsequent time through */
+ gchar *crit;
+
+ /* Format query criteria */
+ crit = g_strdup_printf( "(%s=%s*)", attr, searchVal );
+
+ /* Append to existing criteria */
+ g_free( p2 );
+ p2 = g_strdup_printf( "(|%s%s)", p1, crit );
+
+ g_free( crit );
+ }
+ else {
+ /* First time through - Format query criteria */
+ p2 = g_strdup_printf( "(%s=%s*)", attr, searchVal );
+ }
+ }
+
+ if( p2 == NULL ) {
+ /* Nothing processed - format a default attribute */
+ retVal = g_strdup_printf( "(%s=*)", LDAPCTL_ATTR_EMAIL );
+ }
+ else {
+ /* We have something - free up previous result */
+ retVal = p2;
+ g_free( p1 );
+ }
+ return retVal;
+}
+
+/**
+ * Return array of pointers to attributes for LDAP query.
+ * \param ctl Control object to process.
+ * \return NULL terminated list.
+ */
+char **ldapctl_attribute_array( LdapControl *ctl ) {
+ char **ptrArray;
+ GList *node;
+ gint cnt, i;
+ g_return_val_if_fail( ctl != NULL, NULL );
+
+ cnt = g_list_length( ctl->listCriteria );
+ ptrArray = g_new0( char *, 1 + cnt );
+ i = 0;
+ node = ctl->listCriteria;
+ while( node ) {
+ ptrArray[ i++ ] = node->data;
+ node = g_list_next( node );
+ }
+ ptrArray[ i ] = NULL;
+ return ptrArray;
+}
+
+/**
+ * Free array of pointers allocated by ldapctl_criteria_array().
+ * param ptrArray Array to clear.
+ */
+void ldapctl_free_attribute_array( char **ptrArray ) {
+ gint i;
+
+ /* Clear array to NULL's */
+ for( i = 0; ptrArray[i] != NULL; i++ ) {
+ ptrArray[i] = NULL;
+ }
+ g_free( ptrArray );
+}
+
+/**
+ * Parse LDAP search string, building list of LDAP criteria attributes. This
+ * may be used to convert an old style Sylpheed LDAP search criteria to the
+ * new format. The old style uses a standard LDAP search string, for example:
+ * <pre>
+ * (&(mail=*)(cn=%s*))
+ * </pre>
+ * This function extracts the two LDAP attributes <code>mail</code> and
+ * <code>cn</code>, adding each to a list.
+ *
+ * \param ctl Control object to process.
+ * \param criteria LDAP search criteria string.
+ */
+void ldapctl_parse_ldap_search( LdapControl *ctl, gchar *criteria ) {
+ gchar *ptr;
+ gchar *pFrom;
+ gchar *attrib;
+ gint iLen;
+
+ g_return_if_fail( ctl != NULL );
+
+ ldapctl_criteria_list_clear( ctl );
+ if( criteria == NULL ) return;
+
+ pFrom = NULL;
+ ptr = criteria;
+ while( *ptr ) {
+ if( *ptr == '(' ) {
+ pFrom = 1 + ptr;
+ }
+ if( *ptr == '=' ) {
+ if( pFrom ) {
+ iLen = ptr - pFrom;
+ attrib = g_strndup( pFrom, iLen );
+ g_strstrip( attrib );
+ ldapctl_criteria_list_add( ctl, attrib );
+ g_free( attrib );
+ }
+ pFrom = NULL;
+ }
+ ptr++;
+ }
+}
+
+#endif /* USE_LDAP */
+
+/*
+ * End of Source.
+ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions for LDAP control data.
+ */
+
+#ifndef __LDAPCTRL_H__
+#define __LDAPCTRL_H__
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+/*
+ * Constants.
+ */
+#define LDAPCTL_DFL_PORT 389
+#define LDAPCTL_MAX_ENTRIES 30
+#define LDAPCTL_DFL_TIMEOUT 30
+#define LDAPCTL_DFL_QUERY_AGE 600
+#define LDAPCTL_MAX_QUERY_AGE 86400
+
+#define LDAPCTL_ATTR_EMAIL "mail"
+#define LDAPCTL_ATTR_COMMONNAME "cn"
+#define LDAPCTL_ATTR_GIVENNAME "givenName"
+#define LDAPCTL_ATTR_SURNAME "sn"
+
+#define LDAPCTL_DFL_ATTR_LIST "mail, cn, givenName, sn"
+
+/*
+ * Data structures.
+ */
+typedef struct _LdapControl LdapControl;
+struct _LdapControl {
+ gchar *hostName;
+ gint port;
+ gchar *baseDN;
+ gchar *bindDN;
+ gchar *bindPass;
+ gint maxEntries;
+ gint timeOut;
+ gint maxQueryAge;
+ gchar *attribEMail;
+ gchar *attribCName;
+ gchar *attribFName;
+ gchar *attribLName;
+ GList *listCriteria;
+ pthread_mutex_t *mutexCtl;
+};
+
+/* Function prototypes */
+LdapControl *ldapctl_create ( void );
+void ldapctl_set_host ( LdapControl* ctl, const gchar *value );
+void ldapctl_set_port ( LdapControl* ctl, const gint value );
+void ldapctl_set_base_dn ( LdapControl* ctl, const gchar *value );
+void ldapctl_set_bind_dn ( LdapControl* ctl, const gchar *value );
+void ldapctl_set_bind_password ( LdapControl* ctl, const gchar *value );
+void ldapctl_set_max_entries ( LdapControl* ctl, const gint value );
+void ldapctl_set_timeout ( LdapControl* ctl, const gint value );
+void ldapctl_set_max_query_age ( LdapControl* ctl, const gint value );
+void ldapctl_set_criteria_list ( LdapControl* ctl, GList *value );
+GList *ldapctl_get_criteria_list( const LdapControl* ctl );
+void ldapctl_criteria_list_clear( LdapControl *ctl );
+void ldapctl_criteria_list_add ( LdapControl *ctl, gchar *attr );
+void ldapctl_default_attributes ( LdapControl *ctl );
+void ldapctl_clear ( LdapControl *ctl );
+void ldapctl_free ( LdapControl *ctl );
+void ldapctl_default_values ( LdapControl *ctl );
+void ldapctl_print ( const LdapControl *ctl, FILE *stream );
+void ldapctl_copy ( const LdapControl *ctlFrom,
+ LdapControl *ctlTo );
+gchar *ldapctl_format_criteria ( LdapControl *ctl, const gchar *searchVal );
+char **ldapctl_attribute_array ( LdapControl *ctl );
+void ldapctl_free_attribute_array( char **ptrArray );
+void ldapctl_parse_ldap_search ( LdapControl *ctl, gchar *criteria );
+
+#endif /* USE_LDAP */
+
+#endif /* __LDAPCTRL_H__ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions necessary to define and perform LDAP queries.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <ldap.h>
+#include <lber.h>
+
+#include "ldapquery.h"
+#include "ldapctrl.h"
+#include "mgutils.h"
+
+#include "addritem.h"
+#include "addrcache.h"
+
+/*
+ * Key for thread specific data.
+ */
+static pthread_key_t _queryThreadKey_;
+static gboolean _queryThreadInit_ = FALSE;
+
+/**
+ * Create new LDAP query object.
+ * \return Initialized query object.
+ */
+LdapQuery *ldapqry_create( void ) {
+ LdapQuery *qry;
+
+ qry = g_new0( LdapQuery, 1 );
+ qry->control = NULL;
+ qry->retVal = LDAPRC_SUCCESS;
+ qry->queryType = LDAPQUERY_NONE;
+ qry->queryName = NULL;
+ qry->searchValue = NULL;
+ qry->queryID = 0;
+ qry->entriesRead = 0;
+ qry->elapsedTime = 0;
+ qry->stopFlag = FALSE;
+ qry->busyFlag = FALSE;
+ qry->agedFlag = FALSE;
+ qry->completed = FALSE;
+ qry->thread = NULL;
+ qry->callBackStart = NULL;
+ qry->callBackEntry = NULL;
+ qry->callBackEnd = NULL;
+ qry->folder = NULL;
+ qry->server = NULL;
+
+ /* Mutex to protect stop and busy flags */
+ qry->mutexStop = g_malloc0( sizeof( pthread_mutex_t ) );
+ pthread_mutex_init( qry->mutexStop, NULL );
+ qry->mutexBusy = g_malloc0( sizeof( pthread_mutex_t ) );
+ pthread_mutex_init( qry->mutexBusy, NULL );
+
+ /* Mutex to protect critical section */
+ qry->mutexEntry = g_malloc0( sizeof( pthread_mutex_t ) );
+ pthread_mutex_init( qry->mutexEntry, NULL );
+
+ return qry;
+}
+
+/**
+ * Specify the reference to control data that will be used for the query. The calling
+ * module should be responsible for creating and destroying this control object.
+ * \param qry Query object.
+ * \param ctl Control object.
+ */
+void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
+ g_return_if_fail( qry != NULL );
+ qry->control = ctl;
+}
+
+/**
+ * Specify query name to be used.
+ * \param qry Query object.
+ * \param value Name.
+ */
+void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
+ qry->queryName = mgu_replace_string( qry->queryName, value );
+ g_strstrip( qry->queryName );
+}
+
+/**
+ * Specify search value to be used.
+ * \param qry Query object.
+ * \param value
+ */
+void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
+ qry->searchValue = mgu_replace_string( qry->searchValue, value );
+ g_strstrip( qry->searchValue );
+}
+
+/**
+ * Specify error/status.
+ * \param qry Query object.
+ * \param value Status.
+ */
+void ldapqry_set_error_status( LdapQuery* qry, const gint value ) {
+ qry->retVal = value;
+}
+
+/**
+ * Specify query type.
+ * \param qry Query object.
+ * \param value Query type, either:
+ * <ul>
+ * <li><code>LDAPQUERY_NONE</code></li>
+ * <li><code>LDAPQUERY_STATIC</code></li>
+ * <li><code>LDAPQUERY_DYNAMIC</code></li>
+ * </ul>
+ */
+void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
+ qry->queryType = value;
+}
+
+/**
+ * Specify query ID.
+ * \param qry Query object.
+ * \param value ID for the query.
+ */
+void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
+ qry->queryID = value;
+}
+
+/**
+ * Specify maximum number of LDAP entries to retrieve.
+ * \param qry Query object.
+ * \param value Entries to read.
+ */
+void ldapqry_set_entries_read( LdapQuery* qry, const gint value ) {
+ if( value > 0 ) {
+ qry->entriesRead = value;
+ }
+ else {
+ qry->entriesRead = 0;
+ }
+}
+
+/**
+ * Register a callback function that will be executed when the search
+ * starts. When called, the function will be passed this query object
+ * as an argument.
+ * \param qry Query object.
+ * \param func Function.
+ */
+void ldapqry_set_callback_start( LdapQuery *qry, void *func ) {
+ qry->callBackStart = func;
+}
+
+/**
+ * Register a callback function that will be executed when each entry
+ * has been read and processed. When called, the function will be passed
+ * this query object and a GList of ItemEMail objects as arguments. An
+ * example of typical usage is shown below.
+ *
+ * <pre>
+ * ------------------------------------------------------------
+ * void myCallbackEntry( LdapQuery *qry, GList *listEMail ) {
+ * GList *node;
+ *
+ * node = listEMail;
+ * while( node ) {
+ * ItemEMail *email = node->data;
+ * ... process email object ...
+ * node = g_list_next( node );
+ * }
+ * g_list_free( listEMail );
+ * }
+ * ...
+ * ...
+ * ldapqry_set_callback_entry( qry, myCallbackEntry );
+ * ------------------------------------------------------------
+ * </pre>
+ *
+ * \param qry Query object.
+ * \param func Function.
+ */
+void ldapqry_set_callback_entry( LdapQuery *qry, void *func ) {
+ pthread_mutex_lock( qry->mutexEntry );
+ qry->callBackEntry = func;
+ pthread_mutex_unlock( qry->mutexEntry );
+}
+
+/**
+ * Register a callback function that will be executed when the search
+ * is complete. When called, the function will be passed this query
+ * object as an argument.
+ * \param qry Query object.
+ * \param func Function.
+ */
+void ldapqry_set_callback_end( LdapQuery *qry, void *func ) {
+ qry->callBackEnd = func;
+}
+
+/**
+ * Notify query to start/stop executing. This method should be called with a
+ * value if <i>TRUE</i> to terminate an existing running query.
+ *
+ * \param qry Query object.
+ * \param value Value of stop flag.
+ */
+void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
+ g_return_if_fail( qry != NULL );
+
+ pthread_mutex_lock( qry->mutexStop );
+ qry->stopFlag = value;
+ pthread_mutex_unlock( qry->mutexStop );
+}
+
+/**
+ * Test value of stop flag. This method should be used to determine whether a
+ * query has stopped running.
+ * \param qry Query object.
+ * \return Value of stop flag.
+ */
+gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
+ gboolean value;
+ g_return_if_fail( qry != NULL );
+
+ pthread_mutex_lock( qry->mutexStop );
+ value = qry->stopFlag;
+ pthread_mutex_unlock( qry->mutexStop );
+ return value;
+}
+
+/**
+ * Set busy flag.
+ * \param qry Query object.
+ * \param value Value of busy flag.
+ */
+void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
+ g_return_if_fail( qry != NULL );
+
+ pthread_mutex_lock( qry->mutexBusy );
+ qry->busyFlag = value;
+ pthread_mutex_unlock( qry->mutexBusy );
+}
+
+/**
+ * Test value of busy flag. This method will return a value of <i>FALSE</i>
+ * when a query has completed running.
+ * \param qry Query object.
+ * \return Value of busy flag.
+ */
+gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
+ gboolean value;
+ g_return_if_fail( qry != NULL );
+
+ pthread_mutex_lock( qry->mutexBusy );
+ value = qry->busyFlag;
+ pthread_mutex_unlock( qry->mutexBusy );
+ return value;
+}
+
+/**
+ * Set query aged flag.
+ * \param qry Query object.
+ * \param value Value of aged flag.
+ */
+void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
+ g_return_if_fail( qry != NULL );
+ qry->agedFlag = value;
+}
+
+/**
+ * Test value of aged flag.
+ * \param qry Query object.
+ * \return <i>TRUE</i> if query has been marked as aged (and can be retired).
+ */
+gboolean ldapqry_get_aged_flag( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+ return qry->agedFlag;
+}
+
+/**
+ * Release the thread associated with the query.
+ * \param qry Query object to process.
+ */
+void ldapqry_release_thread( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+ printf( "ldapqry_release_thread...\n" );
+ if( qry->thread != NULL ) {
+ g_free( qry->thread );
+ printf( "\t===========>done\n" );
+ }
+ qry->thread = NULL;
+}
+
+/**
+ * Release the LDAP control data associated with the query.
+ * \param qry Query object to process.
+ */
+void ldapqry_release_control( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+ if( qry->control != NULL ) {
+ ldapctl_free( qry->control );
+ }
+ qry->control = NULL;
+}
+
+/**
+ * Clear LDAP query member variables.
+ * \param qry Query object.
+ */
+void ldapqry_clear( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+
+ /* Free internal stuff */
+ g_free( qry->queryName );
+ g_free( qry->searchValue );
+
+ /* Clear pointers and value */
+ qry->queryName = NULL;
+ qry->searchValue = NULL;
+ qry->retVal = LDAPRC_SUCCESS;
+ qry->queryType = LDAPQUERY_NONE;
+ qry->queryID = 0;
+ qry->entriesRead = 0;
+ qry->elapsedTime = 0;
+ qry->stopFlag = FALSE;
+ qry->busyFlag = FALSE;
+ qry->agedFlag = FALSE;
+ qry->completed = FALSE;
+ qry->callBackStart = NULL;
+ qry->callBackEntry = NULL;
+ qry->callBackEnd = NULL;
+}
+
+/**
+ * Free up LDAP query object by releasing internal memory.
+ * \param qry Query object to process.
+ */
+void ldapqry_free( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+
+ /* Clear out internal members */
+ ldapqry_clear( qry );
+
+ /* Free the mutex */
+ pthread_mutex_destroy( qry->mutexStop );
+ pthread_mutex_destroy( qry->mutexBusy );
+ pthread_mutex_destroy( qry->mutexEntry );
+ g_free( qry->mutexStop );
+ g_free( qry->mutexBusy );
+ g_free( qry->mutexEntry );
+ qry->mutexEntry = NULL;
+ qry->mutexBusy = NULL;
+ qry->mutexStop = NULL;
+
+ /* Do not free folder - parent server object should free */
+ qry->folder = NULL;
+
+ /* Do not free thread - thread should be terminated before freeing */
+ qry->thread = NULL;
+
+ /* Do not free LDAP control - should be destroyed before freeing */
+ qry->control = NULL;
+
+ /* Now release object */
+ g_free( qry );
+}
+
+/**
+ * Display object to specified stream.
+ * \param qry Query object to process.
+ * \param stream Output stream.
+ */
+void ldapqry_print( const LdapQuery *qry, FILE *stream ) {
+ g_return_if_fail( qry != NULL );
+
+ fprintf( stream, "LdapQuery:\n" );
+ fprintf( stream, " control?: %s\n", qry->control ? "yes" : "no" );
+ fprintf( stream, "err/status: %d\n", qry->retVal );
+ fprintf( stream, "query type: %d\n", qry->queryType );
+ fprintf( stream, "query name: '%s'\n", qry->queryName );
+ fprintf( stream, "search val: '%s'\n", qry->searchValue );
+ fprintf( stream, " queryID: %d\n", qry->queryID );
+ fprintf( stream, " entries: %d\n", qry->entriesRead );
+ fprintf( stream, " elapsed: %d\n", qry->elapsedTime );
+ fprintf( stream, " stop flag: %s\n", qry->stopFlag ? "yes" : "no" );
+ fprintf( stream, " busy flag: %s\n", qry->busyFlag ? "yes" : "no" );
+ fprintf( stream, " aged flag: %s\n", qry->agedFlag ? "yes" : "no" );
+ fprintf( stream, " completed: %s\n", qry->completed ? "yes" : "no" );
+}
+
+/**
+ * Free linked lists of character strings.
+ * \param listName List of common names.
+ * \param listAddr List of addresses.
+ * \param listFirst List of first names.
+ * \param listLast List of last names.
+ */
+static void ldapqry_free_lists(
+ GSList *listName, GSList *listAddr, GSList *listFirst,
+ GSList *listLast )
+{
+ mgu_free_list( listName );
+ mgu_free_list( listAddr );
+ mgu_free_list( listFirst );
+ mgu_free_list( listLast );
+}
+
+/**
+ * Add all LDAP attribute values to a list.
+ * \param ld LDAP handle.
+ * \param entry LDAP entry to process.
+ * \param attr LDAP attribute.
+ * \return List of values.
+ */
+static GSList *ldapqry_add_list_values(
+ LDAP *ld, LDAPMessage *entry, char *attr )
+{
+ GSList *list = NULL;
+ gint i;
+ gchar **vals;
+
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ /* printf( "lv\t%s: %s\n", attr, vals[i] ); */
+ list = g_slist_append( list, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/**
+ * Add a single attribute value to a list.
+ * \param ld LDAP handle.
+ * \param entry LDAP entry to process.
+ * \param attr LDAP attribute name to process.
+ * \return List of values; only one value will be present.
+ */
+static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
+ GSList *list = NULL;
+ gchar **vals;
+
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ if( vals[0] != NULL ) {
+ /* printf( "sv\t%s: %s\n", attr, vals[0] ); */
+ list = g_slist_append( list, g_strdup( vals[0] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/**
+ * Build an address list entry and append to list of address items. Name is formatted
+ * as "<first-name> <last-name>".
+ *
+ * \param cache Address cache to load.
+ * \param qry Query object to process.
+ * \param dn DN for entry found on server.
+ * \param listName List of common names for entry; see notes below.
+ * \param listAddr List of EMail addresses for entry.
+ * \param listFirst List of first names for entry.
+ * \param listLast List of last names for entry.
+ *
+ * \return List of ItemEMail objects.
+ *
+ * Notes:
+ * 1) Each LDAP server entry may have multiple LDAP attributes with the same
+ * name. For example, a single entry for a person may have more than one
+ * common name, email address, etc.
+*
+ * 2) The DN for the entry is unique for the server.
+ */
+static GList *ldapqry_build_items_fl(
+ AddressCache *cache, LdapQuery *qry, gchar *dn,
+ GSList *listName, GSList *listAddr, GSList *listFirst,
+ GSList *listLast )
+{
+ GSList *nodeAddress;
+ gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
+ gboolean allocated;
+ ItemPerson *person;
+ ItemEMail *email;
+ ItemFolder *folder;
+ GList *listReturn;
+
+ listReturn = NULL;
+
+ /* Find longest first name in list */
+ firstName = mgu_slist_longest_entry( listFirst );
+
+ /* Format last name */
+ if( listLast ) {
+ lastName = listLast->data;
+ }
+
+ /* Find longest common name */
+ allocated = FALSE;
+ fullName = mgu_slist_longest_entry( listName );
+ if( fullName == NULL ) {
+ /* Format a full name from first and last names */
+ if( firstName ) {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s %s", firstName, lastName );
+ }
+ else {
+ fullName = g_strdup_printf( "%s", firstName );
+ }
+ }
+ else {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s", lastName );
+ }
+ }
+ if( fullName ) {
+ g_strchug( fullName ); g_strchomp( fullName );
+ allocated = TRUE;
+ }
+ }
+
+ if( listAddr ) {
+ /* Create new folder for results */
+ if( qry->folder == NULL ) {
+ folder = addritem_create_item_folder();
+ addritem_folder_set_name( folder, qry->queryName );
+ addritem_folder_set_remarks( folder, "" );
+ addrcache_id_folder( cache, folder );
+ addrcache_add_folder( cache, folder );
+ qry->folder = folder;
+
+ /* Specify folder type and back reference */
+ folder->folderType = ADDRFOLDER_LDAP_QUERY;
+ folder->folderData = ( gpointer ) qry;
+ }
+
+ /* Add person into folder */
+ person = addritem_create_item_person();
+ addritem_person_set_common_name( person, fullName );
+ addritem_person_set_first_name( person, firstName );
+ addritem_person_set_last_name( person, lastName );
+ addrcache_id_person( cache, person );
+ addritem_person_set_external_id( person, dn );
+ addrcache_folder_add_person( cache, qry->folder, person );
+
+ qry->entriesRead++;
+ }
+
+ /* Add each address item */
+ nodeAddress = listAddr;
+ while( nodeAddress ) {
+ email = addritem_create_item_email();
+ addritem_email_set_address( email, nodeAddress->data );
+ addrcache_id_email( cache, email );
+ addrcache_person_add_email( cache, person, email );
+ addritem_person_add_email( person, email );
+ listReturn = g_list_append( listReturn, email );
+ nodeAddress = g_slist_next( nodeAddress );
+ }
+
+ /* Free any allocated memory */
+ if( allocated ) {
+ g_free( fullName );
+ }
+ fullName = firstName = lastName = NULL;
+
+ return listReturn;
+}
+
+/**
+ * Process a single search entry.
+ * \param cache Address cache to load.
+ * \param qry Query object to process.
+ * \param ld LDAP handle.
+ * \param e LDAP message.
+ * \return List of EMail objects found.
+ */
+static GList *ldapqry_process_single_entry(
+ AddressCache *cache, LdapQuery *qry, LDAP *ld, LDAPMessage *e )
+{
+ char *dnEntry;
+ char *attribute;
+ LdapControl *ctl;
+ BerElement *ber;
+ GSList *listName = NULL, *listAddress = NULL;
+ GSList *listFirst = NULL, *listLast = NULL;
+ GList *listReturn;
+
+ listReturn = NULL;
+ ctl = qry->control;
+ dnEntry = ldap_get_dn( ld, e );
+ /* printf( "DN: %s\n", dnEntry ); */
+
+ /* Process all attributes */
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+
+ if( strcasecmp( attribute, ctl->attribEMail ) == 0 ) {
+ listAddress = ldapqry_add_list_values( ld, e, attribute );
+ }
+ else if( strcasecmp( attribute, ctl->attribCName ) == 0 ) {
+ listName = ldapqry_add_list_values( ld, e, attribute );
+ }
+ else if( strcasecmp( attribute, ctl->attribFName ) == 0 ) {
+ listFirst = ldapqry_add_list_values( ld, e, attribute );
+ }
+ else if( strcasecmp( attribute, ctl->attribLName ) == 0 ) {
+ listLast = ldapqry_add_single_value( ld, e, attribute );
+ }
+
+ /* Free memory used to store attribute */
+ ldap_memfree( attribute );
+ }
+
+ /* Format and add items to cache */
+ listReturn = ldapqry_build_items_fl(
+ cache, qry, dnEntry, listName, listAddress, listFirst, listLast );
+
+ /* Free up */
+ ldapqry_free_lists( listName, listAddress, listFirst, listLast );
+ listName = listAddress = listFirst = listLast = NULL;
+
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ g_free( dnEntry );
+
+ return listReturn;
+}
+
+/**
+ * Check parameters that are required for a search. This should
+ * be called before performing a search.
+ * \param qry Query object to process.
+ * \return <i>TRUE</i> if search criteria appear OK.
+ */
+gboolean ldapqry_check_search( LdapQuery *qry ) {
+ LdapControl *ctl;
+ qry->retVal = LDAPRC_CRITERIA;
+
+ /* Test for control data */
+ ctl = qry->control;
+ if( ctl == NULL ) {
+ return FALSE;
+ }
+
+ /* Test for search value */
+ if( qry->searchValue == NULL ) {
+ return FALSE;
+ }
+ if( strlen( qry->searchValue ) < 1 ) {
+ return FALSE;
+ }
+
+ qry->retVal = LDAPRC_SUCCESS;
+ return TRUE;
+}
+
+/**
+ * Touch the query. This nudges the touch time with the current time.
+ * \param qry Query object to process.
+ */
+void ldapqry_touch( LdapQuery *qry ) {
+ qry->touchTime = time( NULL );
+ qry->agedFlag = FALSE;
+}
+
+/**
+ * Perform the LDAP search, reading LDAP entries into cache.
+ * Note that one LDAP entry can have multiple values for many of its
+ * attributes. If these attributes are E-Mail addresses; these are
+ * broken out into separate address items. For any other attribute,
+ * only the first occurrence is read.
+ *
+ * \param qry Query object to process.
+ * \return Error/status code.
+ */
+static gint ldapqry_perform_search( LdapQuery *qry ) {
+ LdapControl *ctl;
+ LDAP *ld;
+ LDAPMessage *result, *e;
+ char **attribs;
+ gchar *criteria;
+ gboolean entriesFound;
+ gboolean first;
+ struct timeval timeout;
+ gint rc;
+ time_t tstart, tend;
+ AddressCache *cache;
+ GList *listEMail;
+
+ /* Initialize some variables */
+ ctl = qry->control;
+ cache = qry->server->addressCache;
+ timeout.tv_sec = ctl->timeOut;
+ timeout.tv_usec = 0L;
+ entriesFound = FALSE;
+ qry->elapsedTime = -1;
+ qry->retVal = LDAPRC_SUCCESS;
+
+ /* Check search criteria */
+ if( ! ldapqry_check_search( qry ) ) {
+ return qry->retVal;
+ }
+
+ /* Initialize connection */
+ ldapqry_touch( qry );
+ tstart = qry->touchTime;
+ tend = tstart - 1;
+ if( ( ld = ldap_init( ctl->hostName, ctl->port ) ) == NULL ) {
+ qry->retVal = LDAPRC_INIT;
+ return qry->retVal;
+ }
+ if( ldapqry_get_stop_flag( qry ) ) {
+ qry->retVal = LDAPRC_SUCCESS;
+ return qry->retVal;
+ }
+ ldapqry_touch( qry );
+
+ /*
+ printf( "connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port );
+ */
+
+ /* Bind to the server, if required */
+ if( ctl->bindDN ) {
+ if( * ctl->bindDN != '\0' ) {
+ /* printf( "binding...\n" ); */
+ rc = ldap_simple_bind_s( ld, ctl->bindDN, ctl->bindPass );
+ /* printf( "rc=%d\n", rc ); */
+ if( rc != LDAP_SUCCESS ) {
+ /*
+ printf( "LDAP Error: ldap_simple_bind_s: %s\n",
+ ldap_err2string( rc ) );
+ */
+ ldap_unbind( ld );
+ qry->retVal = LDAPRC_BIND;
+ return qry->retVal;
+ }
+ }
+ }
+ if( ldapqry_get_stop_flag( qry ) ) {
+ ldap_unbind( ld );
+ qry->retVal = LDAPRC_SUCCESS;
+ return qry->retVal;
+ }
+ ldapqry_touch( qry );
+
+ /* Define all attributes we are interested in. */
+ attribs = ldapctl_attribute_array( ctl );
+
+ /* Create LDAP search string */
+ criteria = ldapctl_format_criteria( ctl, qry->searchValue );
+ /* printf( "Search criteria ::%s::\n", criteria ); */
+
+ /*
+ * Execute the search - this step may take some time to complete
+ * depending on network traffic and server response time.
+ */
+ rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
+ attribs, 0, NULL, NULL, &timeout, 0, &result );
+ ldapctl_free_attribute_array( attribs );
+ g_free( criteria );
+ criteria = NULL;
+ if( rc == LDAP_TIMEOUT ) {
+ ldap_unbind( ld );
+ qry->retVal = LDAPRC_TIMEOUT;
+ return qry->retVal;
+ }
+ if( rc != LDAP_SUCCESS ) {
+ /*
+ printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
+ */
+ ldap_unbind( ld );
+ qry->retVal = LDAPRC_SEARCH;
+ return qry->retVal;
+ }
+ if( ldapqry_get_stop_flag( qry ) ) {
+ qry->retVal = LDAPRC_SUCCESS;
+ return qry->retVal;
+ }
+ ldapqry_touch( qry );
+
+ /*
+ printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
+ */
+
+ if( ldapqry_get_stop_flag( qry ) ) {
+ qry->retVal = LDAPRC_SUCCESS;
+ return qry->retVal;
+ }
+
+ /* Process results */
+ first = TRUE;
+ while( TRUE ) {
+ ldapqry_touch( qry );
+ if( qry->entriesRead >= ctl->maxEntries ) break;
+
+ /* Test for stop */
+ if( ldapqry_get_stop_flag( qry ) ) {
+ break;
+ }
+
+ /* Retrieve entry */
+ if( first ) {
+ first = FALSE;
+ e = ldap_first_entry( ld, result );
+ }
+ else {
+ e = ldap_next_entry( ld, e );
+ }
+ if( e == NULL ) break;
+
+ entriesFound = TRUE;
+
+ /* Setup a critical section here */
+ pthread_mutex_lock( qry->mutexEntry );
+
+ /* Process entry */
+ listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
+
+ /* Process callback */
+ if( qry->callBackEntry ) {
+ qry->callBackEntry( qry, listEMail );
+ }
+ else {
+ g_list_free( listEMail );
+ }
+
+ pthread_mutex_unlock( qry->mutexEntry );
+ }
+
+ /* Free up and disconnect */
+ ldap_msgfree( result );
+ ldap_unbind( ld );
+ ldapqry_touch( qry );
+ tend = qry->touchTime;
+ qry->elapsedTime = tend - tstart;
+
+ if( entriesFound ) {
+ qry->retVal = LDAPRC_SUCCESS;
+ }
+ else {
+ qry->retVal = LDAPRC_NOENTRIES;
+ }
+
+ return qry->retVal;
+}
+
+/**
+ * Wrapper around search.
+ * \param qry Query object to process.
+ * \return Error/status code.
+ */
+gint ldapqry_search( LdapQuery *qry ) {
+ gint retVal;
+
+ g_return_val_if_fail( qry != NULL, -1 );
+ g_return_val_if_fail( qry->control != NULL, -1 );
+
+ ldapqry_touch( qry );
+ qry->completed = FALSE;
+
+ /* Process callback */
+ if( qry->callBackStart ) {
+ qry->callBackStart( qry );
+ }
+
+ /* Setup pointer to thread specific area */
+ pthread_setspecific( _queryThreadKey_, qry );
+
+ pthread_detach( pthread_self() );
+
+ /* Now perform the search */
+ qry->entriesRead = 0;
+ qry->retVal = LDAPRC_SUCCESS;
+ ldapqry_set_busy_flag( qry, TRUE );
+ ldapqry_set_stop_flag( qry, FALSE );
+ retVal = ldapqry_perform_search( qry );
+ if( retVal == LDAPRC_SUCCESS ) {
+ qry->server->addressCache->dataRead = TRUE;
+ qry->server->addressCache->accessFlag = FALSE;
+ if( ldapqry_get_stop_flag( qry ) ) {
+ /*
+ printf( "Search was terminated prematurely\n" );
+ */
+ }
+ else {
+ ldapqry_touch( qry );
+ qry->completed = TRUE;
+ /*
+ printf( "Search ran to completion\n" );
+ */
+ }
+ }
+ ldapqry_set_stop_flag( qry, TRUE );
+ ldapqry_set_busy_flag( qry, FALSE );
+
+ /* Process callback */
+ if( qry->callBackEnd ) {
+ qry->callBackEnd( qry );
+ }
+
+ return qry->retVal;
+}
+
+/**
+ * Read data into list using a background thread. Callback function will be
+ * notified when search is complete.
+ * \param qry Query object to process.
+ * \return Error/status code.
+ */
+gint ldapqry_read_data_th( LdapQuery *qry ) {
+ g_return_val_if_fail( qry != NULL, -1 );
+ g_return_val_if_fail( qry->control != NULL, -1 );
+
+ ldapqry_set_stop_flag( qry, FALSE );
+ ldapqry_touch( qry );
+ if( ldapqry_check_search( qry ) ) {
+ if( qry->retVal == LDAPRC_SUCCESS ) {
+ /*
+ printf( "Starting LDAP search thread\n");
+ */
+ ldapqry_set_busy_flag( qry, TRUE );
+ qry->thread = g_malloc0( sizeof( pthread_t ) );
+
+ /* Setup thread */
+ pthread_create( qry->thread, NULL,
+ (void *) ldapqry_search, (void *) qry );
+ }
+ }
+ return qry->retVal;
+}
+
+/**
+ * Join the thread associated with the query. This should probably be removed
+ * to prevent joining threads.
+ * \param qry Query object to process.
+ */
+void ldapqry_join_thread( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+
+ /* Wait for thread */
+ /* printf( "ldapqry_join_thread::Joining thread...\n" ); */
+ pthread_join( * qry->thread, NULL );
+ /* printf( "ldapqry_join_thread::Thread terminated\n" ); */
+}
+
+/**
+ * Cleanup LDAP thread data. This function will be called when each thread
+ * exits.
+ * \param ptr Pointer to object being destroyed (a query object in this case).
+ */
+static void ldapqry_destroyer( void * ptr ) {
+ LdapQuery *qry;
+
+ qry = ( LdapQuery * ) ptr;
+ /*
+ printf( "ldapqry_destroyer::%d::%s\n", (int) pthread_self(), qry->queryName );
+ */
+
+ /* Perform any destruction here */
+ if( qry->control != NULL ) {
+ ldapctl_free( qry->control );
+ }
+ qry->control = NULL;
+
+ if( qry->thread ) {
+ g_free( qry->thread );
+ }
+ qry->thread = NULL;
+ ldapqry_set_busy_flag( qry, FALSE );
+ /*
+ printf( "...destroy exiting\n" );
+ */
+}
+
+/**
+ * Cancel thread associated with query.
+ * \param qry Query object to process.
+ */
+void ldapqry_cancel( LdapQuery *qry ) {
+ g_return_if_fail( qry != NULL );
+
+ /*
+ printf( "cancelling::%d::%s\n", (int) pthread_self(), qry->queryName );
+ */
+ if( ldapqry_get_busy_flag( qry ) ) {
+ if( qry->thread ) {
+ pthread_cancel( * qry->thread );
+ }
+ }
+}
+
+/**
+ * Initialize LDAP query. This function should be called once before executing
+ * any LDAP queries to initialize thread specific data.
+ */
+void ldapqry_initialize( void ) {
+ /* printf( "ldapqry_initialize...\n" ); */
+ if( ! _queryThreadInit_ ) {
+ /*
+ printf( "ldapqry_initialize::creating thread specific area\n" );
+ */
+ pthread_key_create( &_queryThreadKey_, ldapqry_destroyer );
+ _queryThreadInit_ = TRUE;
+ }
+ /* printf( "ldapqry_initialize... done!\n" ); */
+}
+
+/**
+ * Age the query based on LDAP control parameters.
+ * \param qry Query object to process.
+ * \param maxAge Maximum age of query (in seconds).
+ */
+void ldapqry_age( LdapQuery *qry, gint maxAge ) {
+ gint age;
+
+ g_return_if_fail( qry != NULL );
+
+ /* Limit the time that queries can hang around */
+ if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
+
+ /* Check age of query */
+ age = time( NULL ) - qry->touchTime;
+ if( age > maxAge ) {
+ qry->agedFlag = TRUE;
+ }
+}
+
+/**
+ * Delete folder associated with query results.
+ * \param qry Query object to process.
+ */
+void ldapqry_delete_folder( LdapQuery *qry ) {
+ AddressCache *cache;
+ ItemFolder *folder;
+
+ g_return_if_fail( qry != NULL );
+
+ folder = qry->folder;
+ if( folder ) {
+ cache = qry->server->addressCache;
+ folder = addrcache_remove_folder_delete( cache, folder );
+ if( folder ) {
+ addritem_free_item_folder( folder );
+ }
+ qry->folder = NULL;
+ }
+}
+
+#endif /* USE_LDAP */
+
+/*
+ * End of Source.
+ */
+
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions necessary to define an LDAP query.
+ */
+
+#ifndef __LDAPQUERY_H__
+#define __LDAPQUERY_H__
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+#include "ldapctrl.h"
+#include "ldapserver.h"
+#include "addritem.h"
+#include "addrcache.h"
+
+/*
+ * Constants.
+ */
+#define LDAPQUERY_NONE 0
+#define LDAPQUERY_STATIC 1
+#define LDAPQUERY_DYNAMIC 2
+
+/* Error codes */
+#define LDAPRC_SUCCESS 0
+#define LDAPRC_CONNECT -1
+#define LDAPRC_INIT -2
+#define LDAPRC_BIND -3
+#define LDAPRC_SEARCH -4
+#define LDAPRC_TIMEOUT -5
+#define LDAPRC_CRITERIA -6
+#define LDAPRC_NOENTRIES -7
+
+typedef struct _LdapQuery LdapQuery;
+struct _LdapQuery {
+ LdapControl *control;
+ gint retVal;
+ gint queryType;
+ gchar *queryName;
+ gchar *searchValue;
+ gint queryID;
+ gint entriesRead;
+ gint elapsedTime;
+ gboolean stopFlag;
+ gboolean busyFlag;
+ gboolean agedFlag;
+ gboolean completed;
+ time_t touchTime;
+ pthread_t *thread;
+ pthread_mutex_t *mutexStop;
+ pthread_mutex_t *mutexBusy;
+ pthread_mutex_t *mutexEntry;
+ void (*callBackStart)( void * );
+ void (*callBackEntry)( void *, void * );
+ void (*callBackEnd)( void * );
+ ItemFolder *folder; /* Reference to folder in cache */
+ LdapServer *server; /* Reference to (parent) LDAP server */
+ // SyldapServer *server; /* Reference to (parent) LDAP server */
+};
+
+/* Function prototypes */
+void ldapqry_initialize ( void );
+LdapQuery *ldapqry_create ( void );
+void ldapqry_set_control ( LdapQuery *qry, LdapControl *ctl );
+void ldapqry_set_name ( LdapQuery* qry, const gchar *value );
+void ldapqry_set_search_value ( LdapQuery *qry, const gchar *value );
+void ldapqry_set_error_status ( LdapQuery* qry, const gint value );
+void ldapqry_set_query_type ( LdapQuery* qry, const gint value );
+void ldapqry_set_query_id ( LdapQuery* qry, const gint value );
+void ldapqry_set_entries_read ( LdapQuery* qry, const gint value );
+void ldapqry_set_callback_start ( LdapQuery *qry, void *func );
+void ldapqry_set_callback_entry ( LdapQuery *qry, void *func );
+void ldapqry_set_callback_end ( LdapQuery *qry, void *func );
+void ldapqry_clear ( LdapQuery *qry );
+void ldapqry_release_thread ( LdapQuery *qry );
+void ldapqry_free ( LdapQuery *qry );
+void ldapqry_print ( const LdapQuery *qry, FILE *stream );
+void ldapqry_set_stop_flag ( LdapQuery *qry, const gboolean value );
+gboolean ldapqry_get_stop_flag ( LdapQuery *qry );
+void ldapqry_set_busy_flag ( LdapQuery *qry, const gboolean value );
+gboolean ldapqry_get_busy_flag ( LdapQuery *qry );
+void ldapqry_set_aged_flag ( LdapQuery *qry, const gboolean value );
+gboolean ldapqry_get_aged_flag ( LdapQuery *qry );
+
+gboolean ldapqry_check_search ( LdapQuery *qry );
+void ldapqry_touch ( LdapQuery *qry );
+gint ldapqry_search ( LdapQuery *qry );
+gint ldapqry_read_data_th ( LdapQuery *qry );
+void ldapqry_join_thread ( LdapQuery *qry );
+void ldapqry_cancel ( LdapQuery *qry );
+void ldapqry_age ( LdapQuery *qry, gint maxAge );
+void ldapqry_delete_folder ( LdapQuery *qry );
+
+#endif /* USE_LDAP */
+
+#endif /* __LDAPQUERY_H__ */
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions necessary to access LDAP servers.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <ldap.h>
+#include <lber.h>
+
+#include "mgutils.h"
+#include "addritem.h"
+#include "addrcache.h"
+#include "ldapctrl.h"
+#include "ldapquery.h"
+#include "ldapserver.h"
+#include "utils.h"
+#include "adbookbase.h"
+
+/**
+ * Create new LDAP server interface object.
+ * \return Initialized LDAP server object.
+ */
+LdapServer *ldapsvr_create() {
+ LdapServer *server;
+
+ server = g_new0( LdapServer, 1 );
+ server->type = ADBOOKTYPE_LDAP;
+ server->addressCache = addrcache_create();
+ server->retVal = MGU_SUCCESS;
+ server->control = ldapctl_create();
+ server->listQuery = NULL;
+ server->searchFlag = FALSE;
+ return server;
+}
+
+/**
+ * Return name of server.
+ * \param server Server object.
+ * \return Name for server.
+ */
+gchar *ldapsvr_get_name( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, NULL );
+ return addrcache_get_name( server->addressCache );
+}
+
+/**
+ * Specify name to be used.
+ * \param server Server object.
+ * \param value Name for server.
+ */
+void ldapsvr_set_name( LdapServer* server, const gchar *value ) {
+ g_return_if_fail( server != NULL );
+ addrcache_set_name( server->addressCache, value );
+}
+
+/**
+ * Refresh internal variables to force a file read.
+ * \param server Server object.
+ */
+void ldapsvr_force_refresh( LdapServer *server ) {
+ addrcache_refresh( server->addressCache );
+}
+
+/**
+ * Return status/error code.
+ * \param server Server object.
+ * \return Status/error code.
+ */
+gint ldapsvr_get_status( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, -1 );
+ return server->retVal;
+}
+
+/**
+ * Return reference to root level folder.
+ * \param server Server object.
+ * \return Root level folder.
+ */
+ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, NULL );
+ /*
+ printf( "ldapsvr_get_root_folder/start\n" );
+ ldapsvr_print_data( server, stdout );
+ printf( "ldapsvr_get_root_folder/done\n" );
+ */
+ return addrcache_get_root_folder( server->addressCache );
+}
+
+/**
+ * Test whether server data has been accessed.
+ * \param server Server object.
+ * \return <i>TRUE</i> if data was accessed.
+ */
+gboolean ldapsvr_get_accessed( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, FALSE );
+ return server->addressCache->accessFlag;
+}
+
+/**
+ * Specify that server's data whas beed accessed.
+ * \param server Server object.
+ * \param value Value for flag.
+ */
+void ldapsvr_set_accessed( LdapServer *server, const gboolean value ) {
+ g_return_if_fail( server != NULL );
+ server->addressCache->accessFlag = value;
+}
+
+/**
+ * Test whether server data has been modified.
+ * \param server Server object.
+ * \return <i>TRUE</i> if data was modified.
+ */
+gboolean ldapsvr_get_modified( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, FALSE );
+ return server->addressCache->modified;
+}
+
+/**
+ * Specify modify flag.
+ * \param server Server object.
+ * \param value Value for flag.
+ */
+void ldapsvr_set_modified( LdapServer *server, const gboolean value ) {
+ g_return_if_fail( server != NULL );
+ server->addressCache->modified = value;
+}
+
+/**
+ * Test whether data was read from server.
+ * \param server Server object.
+ * \return <i>TRUE</i> if data was read.
+ */
+gboolean ldapsvr_get_read_flag( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, FALSE );
+ return server->addressCache->dataRead;
+}
+
+/**
+ * Test whether server is to be used for dynamic searches.
+ * \param server Server object.
+ * \return <i>TRUE</i> if server is used for dynamic searches.
+ */
+gboolean ldapsvr_get_search_flag( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, FALSE );
+ return server->searchFlag;
+}
+
+/**
+ * Specify that server is to be used for dynamic searches.
+ * \param server Server object.
+ * \param value Name for server.
+ */
+void ldapsvr_set_search_flag( LdapServer *server, const gboolean value ) {
+ g_return_if_fail( server != NULL );
+ server->searchFlag = value;
+}
+
+/**
+ * Specify the reference to control data that will be used for the query. The calling
+ * module should be responsible for creating and destroying this control object.
+ * \param server Server object.
+ * \param ctl Control data.
+ */
+void ldapsvr_set_control( LdapServer *server, LdapControl *ctl ) {
+ g_return_if_fail( server != NULL );
+ addrcache_refresh( server->addressCache );
+ server->control = ctl;
+}
+
+/**
+ * Release LDAP control object.
+ * \param server Server object.
+ */
+static void ldapsvr_release_control( LdapServer *server ) {
+ g_return_if_fail( server != NULL );
+ ldapctl_free( server->control );
+ server->control = NULL;
+}
+
+/**
+ * Free up LDAP server interface object by releasing internal memory.
+ * \param server Server object.
+ */
+void ldapsvr_free( LdapServer *server ) {
+ g_return_if_fail( server != NULL );
+
+ /* Stop and cancel any queries that may be active */
+ ldapsvr_stop_all_query( server );
+ ldapsvr_cancel_all_query( server );
+
+ /* Clear cache */
+ addrcache_clear( server->addressCache );
+ addrcache_free( server->addressCache );
+
+ /* Free LDAP control block */
+ ldapctl_free( server->control );
+ server->control = NULL;
+
+ /* Clear pointers */
+ server->type = ADBOOKTYPE_NONE;
+ server->addressCache = NULL;
+ server->retVal = MGU_SUCCESS;
+ server->listQuery = NULL;
+ server->searchFlag = FALSE;
+
+ /* Now release LDAP object */
+ g_free( server );
+}
+
+/**
+ * Display object to specified stream.
+ * \param server Server object.
+ * \param stream Output stream.
+ */
+void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
+ GList *node;
+ gint i;
+
+ g_return_if_fail( server != NULL );
+
+ fprintf( stream, "LdapServer:\n" );
+ fprintf( stream, " ret val: %d\n", server->retVal );
+ fprintf( stream, "srch flag: %s\n",
+ server->searchFlag ? "yes" : "no" );
+ if( server->control ) {
+ ldapctl_print( server->control, stream );
+ }
+ else {
+ fprintf( stream, " control: NULL\n" );
+ }
+ addrcache_print( server->addressCache, stream );
+ addritem_print_item_folder( server->addressCache->rootFolder, stream );
+
+ /* Dump queries */
+ i = 1;
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+ fprintf( stream, " query: %2d : %s\n", i, qry->queryName );
+ i++;
+ node = g_list_next( node );
+ }
+}
+
+/**
+ * Add query to server.
+ * \param server Server object.
+ * \param qry Query object.
+ */
+void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
+ g_return_if_fail( server != NULL );
+ g_return_if_fail( qry != NULL );
+
+ server->listQuery = g_list_append( server->listQuery, qry );
+ qry->server = server;
+}
+
+/**
+ * Free all queries.
+ * \param server Server object.
+ */
+void ldapsvr_free_all_query( LdapServer *server ) {
+ GList *node;
+ g_return_if_fail( server != NULL );
+
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+ ldapqry_free( qry );
+ node->data = NULL;
+ node = g_list_next( node );
+ }
+ g_list_free( server->listQuery );
+ server->listQuery = NULL;
+}
+
+/**
+ * Return link list of persons.
+ * \param server Server object.
+ * \return List of persons.
+ */
+GList *ldapsvr_get_list_person( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, NULL );
+ return addrcache_get_list_person( server->addressCache );
+}
+
+/**
+ * Return link list of folders. There are no "real" folders that are returned
+ * from the server.
+ * \param server Server object.
+ * \return List of folders.
+ */
+GList *ldapsvr_get_list_folder( LdapServer *server ) {
+ g_return_val_if_fail( server != NULL, NULL );
+ /* return addrcache_get_list_folder( server->addressCache ); */
+ return NULL;
+}
+
+/**
+ * Execute specified query.
+ * \param server LDAP server.
+ * \param qry LDAP query.
+ */
+void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
+ LdapControl *ctlCopy;
+
+ g_return_if_fail( server != NULL );
+ g_return_if_fail( qry != NULL );
+
+ /* Copy server's control data to the query */
+ ctlCopy = ldapctl_create();
+ ldapctl_copy( server->control, ctlCopy );
+ ldapqry_set_control( qry, ctlCopy );
+ ldapqry_initialize();
+
+ /* Perform query */
+ printf( "ldapsvr_execute_query::reading with thread...\n" );
+ if( ldapqry_check_search( qry ) ) {
+ ldapqry_read_data_th( qry );
+ if( qry->retVal == LDAPRC_SUCCESS ) {
+ printf( "ldapsvr_execute_query::SUCCESS with thread...\n" );
+ }
+ }
+ printf( "ldapsvr_execute_query... terminated\n" );
+}
+
+/**
+ * Stop all queries for specified ID.
+ * \param server Server object.
+ * \param queryID Query ID to stop.
+ */
+void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
+ GList *node;
+ g_return_if_fail( server != NULL );
+
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+ if( qry->queryID == queryID ) {
+ /* Notify thread to stop */
+ ldapqry_set_stop_flag( qry, TRUE );
+ }
+ node = g_list_next( node );
+ }
+}
+
+/**
+ * Stop all queries by notifying each thread to stop.
+ * \param server Server object.
+ */
+void ldapsvr_stop_all_query( LdapServer *server ) {
+ GList *node;
+ g_return_if_fail( server != NULL );
+
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+ ldapqry_set_stop_flag( qry, TRUE );
+ node = g_list_next( node );
+ }
+}
+
+/**
+ * Cancel all query threads for server.
+ * \param server Server object.
+ */
+void ldapsvr_cancel_all_query( LdapServer *server ) {
+ GList *node;
+ g_return_if_fail( server != NULL );
+
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+ /* Notify thread to stop */
+ ldapqry_set_stop_flag( qry, TRUE );
+ /* Now cancel thread */
+ ldapqry_cancel( qry );
+ node = g_list_next( node );
+ }
+}
+
+/**
+ * Search most recent query for specified search term. The most recent
+ * completed query is returned. If no completed query is found, the most recent
+ * incomplete is returned.
+ * \param server LdapServer.
+ * \param searchTerm Search term to locate.
+ * \return Query object, or <i>NULL</i> if none found.
+ */
+LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm )
+{
+ LdapQuery *incomplete = NULL;
+ GList *node;
+ g_return_if_fail( server != NULL );
+
+ node = server->listQuery;
+ node = g_list_last( node );
+ /* Search backwards for query */
+ while( node ) {
+ LdapQuery *qry = node->data;
+ if( g_strcasecmp( qry->searchValue, searchTerm ) == 0 ) {
+ if( qry->agedFlag ) continue;
+ if( qry->completed ) {
+ /* Found */
+ return qry;
+ }
+ if( ! incomplete ) {
+ incomplete = qry;
+ }
+ }
+ node = g_list_previous( node );
+ }
+ return incomplete;
+}
+
+/**
+ * Retire aged queries.
+ * \param server LdapServer.
+ */
+void ldapsvr_retire_query( LdapServer *server ) {
+ GList *node;
+ GList *listDelete;
+ GList *listQuery;
+ gint maxAge;
+ LdapControl *ctl;
+
+ g_return_if_fail( server != NULL );
+ ctl = server->control;
+ maxAge = ctl->maxQueryAge;
+
+ /* Identify queries to age and move to deletion list */
+ listDelete = NULL;
+ node = server->listQuery;
+ while( node ) {
+ LdapQuery *qry = node->data;
+
+ ldapqry_age( qry, maxAge );
+ if( qry->agedFlag ) {
+ /* Delete folder associated with query */
+ ldapqry_delete_folder( qry );
+ listDelete = g_list_append( listDelete, qry );
+ }
+ node = g_list_next( node );
+ }
+
+ /* Delete queries */
+ listQuery = server->listQuery;
+ node = listDelete;
+ while( node ) {
+ LdapQuery *qry = node->data;
+
+ listQuery = g_list_remove( listQuery, qry );
+ ldapqry_free( qry );
+ node->data = NULL;
+ node = g_list_next( node );
+ }
+ server->listQuery = listQuery;
+
+ /* Free up deletion list */
+ g_list_free( listDelete );
+}
+
+#endif /* USE_LDAP */
+
+/*
+ * End of Source.
+ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Definitions necessary to access LDAP servers.
+ */
+
+#ifndef __LDAPSERVER_H__
+#define __LDAPSERVER_H__
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+
+#include "ldapctrl.h"
+#include "addritem.h"
+#include "addrcache.h"
+#include "adbookbase.h"
+
+#define MGU_LDAP_CONNECT -51
+#define MGU_LDAP_INIT -52
+#define MGU_LDAP_BIND -53
+#define MGU_LDAP_SEARCH -54
+#define MGU_LDAP_TIMEOUT -55
+#define MGU_LDAP_CRITERIA -56
+#define MGU_LDAP_NOENTRIES -57
+
+typedef struct _LdapServer LdapServer;
+struct _LdapServer {
+ AddressBookType type;
+ AddressCache *addressCache;
+ gint retVal;
+ LdapControl *control;
+ gboolean searchFlag;
+ GList *listQuery;
+};
+
+/* Function prototypes */
+LdapServer *ldapsvr_create ( void );
+void ldapsvr_set_name ( LdapServer *server, const gchar *value );
+void ldapsvr_set_accessed ( LdapServer *server, const gboolean value );
+void ldapsvr_force_refresh ( LdapServer *server );
+void ldapsvr_free ( LdapServer *server );
+gint ldapsvr_get_status ( LdapServer *server );
+gboolean ldapsvr_get_accessed ( LdapServer *server );
+gchar *ldapsvr_get_name ( LdapServer *server );
+gboolean ldapsvr_get_modified ( LdapServer *server );
+void ldapsvr_set_modified ( LdapServer *server, const gboolean value );
+gboolean ldapsvr_get_read_flag ( LdapServer *server );
+gboolean ldapsvr_get_search_flag( LdapServer *server );
+void ldapsvr_set_search_flag ( LdapServer *server, const gboolean value );
+
+void ldapsvr_print_data ( LdapServer *server, FILE *stream );
+void ldapsvr_cancel_read ( LdapServer *server );
+
+ItemFolder *ldapsvr_get_root_folder ( LdapServer *server );
+GList *ldapsvr_get_list_person ( LdapServer *server );
+GList *ldapsvr_get_list_folder ( LdapServer *server );
+
+void ldapsvr_stop_query_id ( LdapServer *server, const gint queryID );
+void ldapsvr_stop_all_query ( LdapServer *server );
+void ldapsvr_cancel_all_query ( LdapServer *server );
+void ldapsvr_retire_query ( LdapServer *server );
+
+#endif /* USE_LDAP */
+
+#endif /* __LDAPSERVER_H__ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Some utility functions to access LDAP servers.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <ldap.h>
+#include <lber.h>
+
+#define SYLDAP_TEST_FILTER "(objectclass=*)"
+#define SYLDAP_SEARCHBASE_V2 "cn=config"
+#define SYLDAP_SEARCHBASE_V3 ""
+#define SYLDAP_V2_TEST_ATTR "database"
+#define SYLDAP_V3_TEST_ATTR "namingcontexts"
+
+/**
+ * Attempt to discover the base DN for a server using LDAP version 3.
+ * \param ld LDAP handle for a connected server.
+ * \param tov Timeout value (seconds), or 0 for none, default 30 secs.
+ * \return List of Base DN's, or NULL if could not read. List should be
+ * g_free() when done.
+ */
+static GList *ldaputil_test_v3( LDAP *ld, gint tov ) {
+ GList *baseDN = NULL;
+ gint rc, i;
+ LDAPMessage *result, *e;
+ gchar *attribs[2];
+ BerElement *ber;
+ gchar *attribute;
+ gchar **vals;
+ struct timeval timeout;
+
+ /* Set timeout */
+ timeout.tv_usec = 0L;
+ if( tov > 0 ) {
+ timeout.tv_sec = tov;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ /* Test for LDAP version 3 */
+ attribs[0] = SYLDAP_V3_TEST_ATTR;
+ attribs[1] = NULL;
+ rc = ldap_search_ext_s(
+ ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER,
+ attribs, 0, NULL, NULL, &timeout, 0, &result );
+
+ if( rc == LDAP_SUCCESS ) {
+ /* Process entries */
+ for( e = ldap_first_entry( ld, result );
+ e != NULL;
+ e = ldap_next_entry( ld, e ) )
+ {
+ /* Process attributes */
+ for( attribute = ldap_first_attribute( ld, e, &ber );
+ attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) )
+ {
+ if( strcasecmp(
+ attribute, SYLDAP_V3_TEST_ATTR ) == 0 )
+ {
+ vals = ldap_get_values( ld, e, attribute );
+ if( vals != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ baseDN = g_list_append(
+ baseDN, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ ldap_memfree( attribute );
+ }
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ ber = NULL;
+ }
+ }
+ ldap_msgfree( result );
+ return baseDN;
+}
+
+/**
+ * Attempt to discover the base DN for a server using LDAP version 2.
+ * \param ld LDAP handle for a connected server.
+ * \param tov Timeout value (seconds), or 0 for none, default 30 secs.
+ * \return List of Base DN's, or NULL if could not read. List should be
+ * g_free() when done.
+ */
+static GList *ldaputil_test_v2( LDAP *ld, gint tov ) {
+ GList *baseDN = NULL;
+ gint rc, i;
+ LDAPMessage *result, *e;
+ gchar *attribs[1];
+ BerElement *ber;
+ gchar *attribute;
+ gchar **vals;
+ struct timeval timeout;
+
+ /* Set timeout */
+ timeout.tv_usec = 0L;
+ if( tov > 0 ) {
+ timeout.tv_sec = tov;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ attribs[0] = NULL;
+ rc = ldap_search_ext_s(
+ ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER,
+ attribs, 0, NULL, NULL, &timeout, 0, &result );
+
+ if( rc == LDAP_SUCCESS ) {
+ /* Process entries */
+ for( e = ldap_first_entry( ld, result );
+ e != NULL;
+ e = ldap_next_entry( ld, e ) )
+ {
+ /* Process attributes */
+ for( attribute = ldap_first_attribute( ld, e, &ber );
+ attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) )
+ {
+ if( strcasecmp(
+ attribute,
+ SYLDAP_V2_TEST_ATTR ) == 0 ) {
+ vals = ldap_get_values( ld, e, attribute );
+ if( vals != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ char *ch;
+ /*
+