fix bug where opening folder has massive slowdown when using the 'Display sender...
[claws.git] / src / addrindex.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2003 Match Grun
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * General functions for accessing address index file.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "defs.h"
29
30 #include <glib.h>
31
32 #include "intl.h"
33 #include "mgutils.h"
34 #include "addritem.h"
35 #include "addrcache.h"
36 #include "addrbook.h"
37 #include "addrindex.h"
38 #include "xml.h"
39 #include "addrquery.h"
40
41 #ifndef DEV_STANDALONE
42 #include "prefs_gtk.h"
43 #include "codeconv.h"
44 #endif
45
46 #include "vcard.h"
47
48 #ifdef USE_JPILOT
49 #include "jpilot.h"
50 #endif
51
52 #ifdef USE_LDAP
53 #include "ldapserver.h"
54 #include "ldapctrl.h"
55 #include "ldapquery.h"
56 #endif
57
58 #define TAG_ADDRESS_INDEX    "addressbook"
59
60 #define TAG_IF_ADDRESS_BOOK  "book_list"
61 #define TAG_IF_VCARD         "vcard_list"
62 #define TAG_IF_JPILOT        "jpilot_list"
63 #define TAG_IF_LDAP          "ldap_list"
64
65 #define TAG_DS_ADDRESS_BOOK  "book"
66 #define TAG_DS_VCARD         "vcard"
67 #define TAG_DS_JPILOT        "jpilot"
68 #define TAG_DS_LDAP          "server"
69
70 /* XML Attribute names */
71 #define ATTAG_BOOK_NAME       "name"
72 #define ATTAG_BOOK_FILE       "file"
73
74 #define ATTAG_VCARD_NAME      "name"
75 #define ATTAG_VCARD_FILE      "file"
76
77 #define ATTAG_JPILOT_NAME     "name"
78 #define ATTAG_JPILOT_FILE     "file"
79 #define ATTAG_JPILOT_CUSTOM_1 "custom-1"
80 #define ATTAG_JPILOT_CUSTOM_2 "custom-2"
81 #define ATTAG_JPILOT_CUSTOM_3 "custom-3"
82 #define ATTAG_JPILOT_CUSTOM_4 "custom-4"
83 #define ATTAG_JPILOT_CUSTOM   "custom-"
84
85 #define ATTAG_LDAP_NAME       "name"
86 #define ATTAG_LDAP_HOST       "host"
87 #define ATTAG_LDAP_PORT       "port"
88 #define ATTAG_LDAP_BASE_DN    "base-dn"
89 #define ATTAG_LDAP_BIND_DN    "bind-dn"
90 #define ATTAG_LDAP_BIND_PASS  "bind-pass"
91 #define ATTAG_LDAP_CRITERIA   "criteria"
92 #define ATTAG_LDAP_MAX_ENTRY  "max-entry"
93 #define ATTAG_LDAP_TIMEOUT    "timeout"
94 #define ATTAG_LDAP_MAX_AGE    "max-age"
95 #define ATTAG_LDAP_DYN_SEARCH "dyn-search"
96
97 #define ELTAG_LDAP_ATTR_SRCH  "attribute"
98 #define ATTAG_LDAP_ATTR_NAME  "name"
99
100 /* New attributes */
101 #define ATTAG_LDAP_DEFAULT    "default"
102
103 #if 0
104 N_("Common address")
105 N_("Personal address")
106 #endif
107
108 #define DISP_NEW_COMMON       _("Common address")
109 #define DISP_NEW_PERSONAL     _("Personal address")
110
111 /* Old address book */
112 #define TAG_IF_OLD_COMMON     "common_address"
113 #define TAG_IF_OLD_PERSONAL   "personal_address"
114
115 #define DISP_OLD_COMMON       _("Common address")
116 #define DISP_OLD_PERSONAL     _("Personal address")
117
118 /*
119  * Define attribute name-value pair.
120  */
121 typedef struct _AddressIfAttr AddressIfAttrib;
122 struct _AddressIfAttr {
123         gchar *name;
124         gchar *value;
125 };
126
127 /*
128  * Define DOM fragment.
129  */
130 typedef struct _AddressIfFrag AddressIfFragment;
131 struct _AddressIfFrag {
132         gchar *name;
133         GList *children;
134         GList *attributes;
135 };
136
137 /**
138  * Build interface with default values.
139  *
140  * \param type Interface type.
141  * \param name Interface name.
142  * \param tagIf XML tag name for interface in address index file.
143  * \param tagDS XML tag name for datasource in address index file.
144  * \return Address interface object.
145 */
146 static AddressInterface *addrindex_create_interface(
147                 gint type, gchar *name, gchar *tagIf, gchar *tagDS )
148 {
149         AddressInterface *iface = g_new0( AddressInterface, 1 );
150
151         ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
152         ADDRITEM_ID(iface) = NULL;
153         ADDRITEM_NAME(iface) = g_strdup( name );
154         ADDRITEM_PARENT(iface) = NULL;
155         ADDRITEM_SUBTYPE(iface) = type;
156         iface->type = type;
157         iface->name = g_strdup( name );
158         iface->listTag = g_strdup( tagIf );
159         iface->itemTag = g_strdup( tagDS );
160         iface->legacyFlag = FALSE;
161         iface->haveLibrary = TRUE;
162         iface->useInterface = TRUE;
163         iface->readOnly      = TRUE;
164
165         /* Set callbacks to NULL values - override for each interface */
166         iface->getAccessFlag = NULL;
167         iface->getModifyFlag = NULL;
168         iface->getReadFlag   = NULL;
169         iface->getStatusCode = NULL;
170         iface->getReadData   = NULL;
171         iface->getRootFolder = NULL;
172         iface->getListFolder = NULL;
173         iface->getListPerson = NULL;
174         iface->getAllPersons = NULL;
175         iface->getAllGroups  = NULL;
176         iface->getName       = NULL;
177         iface->listSource = NULL;
178
179         /* Search stuff */
180         iface->externalQuery = FALSE;
181         iface->searchOrder = 0;         /* Ignored */
182         iface->startSearch = NULL;
183         iface->stopSearch = NULL;
184
185         return iface;
186 }
187
188 /**
189  * Build table of of all address book interfaces.
190  * \param addrIndex Address index object.
191  */
192 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
193         AddressInterface *iface;
194
195         /* Create intrinsic XML address book interface */
196         iface = addrindex_create_interface(
197                         ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK,
198                         TAG_DS_ADDRESS_BOOK );
199         iface->readOnly      = FALSE;
200         iface->getModifyFlag = ( void * ) addrbook_get_modified;
201         iface->getAccessFlag = ( void * ) addrbook_get_accessed;
202         iface->getReadFlag   = ( void * ) addrbook_get_read_flag;
203         iface->getStatusCode = ( void * ) addrbook_get_status;
204         iface->getReadData   = ( void * ) addrbook_read_data;
205         iface->getRootFolder = ( void * ) addrbook_get_root_folder;
206         iface->getListFolder = ( void * ) addrbook_get_list_folder;
207         iface->getListPerson = ( void * ) addrbook_get_list_person;
208         iface->getAllPersons = ( void * ) addrbook_get_all_persons;
209         iface->getName       = ( void * ) addrbook_get_name;
210         iface->setAccessFlag = ( void * ) addrbook_set_accessed;
211         iface->searchOrder   = 2;
212
213         /* Add to list of interfaces in address book */ 
214         addrIndex->interfaceList =
215                 g_list_append( addrIndex->interfaceList, iface );
216         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
217
218         /* Create vCard interface */
219         iface = addrindex_create_interface(
220                         ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
221         iface->getModifyFlag = ( void * ) vcard_get_modified;
222         iface->getAccessFlag = ( void * ) vcard_get_accessed;
223         iface->getReadFlag   = ( void * ) vcard_get_read_flag;
224         iface->getStatusCode = ( void * ) vcard_get_status;
225         iface->getReadData   = ( void * ) vcard_read_data;
226         iface->getRootFolder = ( void * ) vcard_get_root_folder;
227         iface->getListFolder = ( void * ) vcard_get_list_folder;
228         iface->getListPerson = ( void * ) vcard_get_list_person;
229         iface->getAllPersons = ( void * ) vcard_get_all_persons;
230         iface->getName       = ( void * ) vcard_get_name;
231         iface->setAccessFlag = ( void * ) vcard_set_accessed;
232         iface->searchOrder   = 3;
233         addrIndex->interfaceList =
234                 g_list_append( addrIndex->interfaceList, iface );
235         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
236
237         /* Create JPilot interface */
238         iface = addrindex_create_interface(
239                         ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT,
240                         TAG_DS_JPILOT );
241 #ifdef USE_JPILOT
242         iface->haveLibrary = jpilot_test_pilot_lib();
243         iface->useInterface = iface->haveLibrary;
244         iface->getModifyFlag = ( void * ) jpilot_get_modified;
245         iface->getAccessFlag = ( void * ) jpilot_get_accessed;
246         iface->getReadFlag   = ( void * ) jpilot_get_read_flag;
247         iface->getStatusCode = ( void * ) jpilot_get_status;
248         iface->getReadData   = ( void * ) jpilot_read_data;
249         iface->getRootFolder = ( void * ) jpilot_get_root_folder;
250         iface->getListFolder = ( void * ) jpilot_get_list_folder;
251         iface->getListPerson = ( void * ) jpilot_get_list_person;
252         iface->getAllPersons = ( void * ) jpilot_get_all_persons;
253         iface->getName       = ( void * ) jpilot_get_name;
254         iface->setAccessFlag = ( void * ) jpilot_set_accessed;
255         iface->searchOrder   = 3;
256 #else
257         iface->useInterface = FALSE;
258         iface->haveLibrary = FALSE;
259 #endif
260         addrIndex->interfaceList =
261                 g_list_append( addrIndex->interfaceList, iface );
262         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
263
264         /* Create LDAP interface */
265         iface = addrindex_create_interface(
266                         ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
267 #ifdef USE_LDAP
268         /* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
269         iface->haveLibrary = ldaputil_test_ldap_lib();
270         iface->useInterface = iface->haveLibrary;
271         /* iface->getModifyFlag = ( void * ) ldapsvr_get_modified; */
272         iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
273         /* iface->getReadFlag   = ( void * ) ldapsvr_get_read_flag; */
274         iface->getStatusCode = ( void * ) ldapsvr_get_status;
275         /* iface->getReadData   = ( void * ) ldapsvr_read_data; */
276         iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
277         iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
278         iface->getListPerson = ( void * ) ldapsvr_get_list_person;
279         iface->getName       = ( void * ) ldapsvr_get_name;
280         iface->setAccessFlag = ( void * ) ldapsvr_set_accessed;
281         iface->externalQuery = TRUE;
282         iface->searchOrder   = 1;
283 #else
284         iface->useInterface = FALSE;
285         iface->haveLibrary = FALSE;
286 #endif
287         addrIndex->interfaceList =
288                 g_list_append( addrIndex->interfaceList, iface );
289         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
290
291         /* Two old legacy data sources (pre 0.7.0) */
292         iface = addrindex_create_interface(
293                         ADDR_IF_COMMON, "Old Address - common",
294                         TAG_IF_OLD_COMMON, NULL );
295         iface->legacyFlag = TRUE;
296         addrIndex->interfaceList =
297                 g_list_append( addrIndex->interfaceList, iface );
298         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
299
300         iface = addrindex_create_interface(
301                         ADDR_IF_COMMON, "Old Address - personal",
302                         TAG_IF_OLD_PERSONAL, NULL );
303         iface->legacyFlag = TRUE;
304         addrIndex->interfaceList =
305                 g_list_append( addrIndex->interfaceList, iface );
306         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
307
308 }
309
310 /**
311  * Free DOM fragment.
312  * \param fragment Fragment to free.
313  */
314 static addrindex_free_fragment( AddressIfFragment *fragment ) {
315         GList *node;
316
317         /* Free children */
318         node = fragment->children;
319         while( node ) {
320                 AddressIfFragment *child = node->data;
321                 addrindex_free_fragment( child );
322                 node->data = NULL;
323                 node = g_list_next( node );
324         }
325         g_list_free( fragment->children );
326
327         /* Free attributes */
328         node = fragment->attributes;
329         while( node ) {
330                 AddressIfAttrib *nv = node->data;
331                 g_free( nv->name );
332                 g_free( nv->value );
333                 g_free( nv );
334                 node->data = NULL;
335                 node = g_list_next( node );
336         }
337         g_list_free( fragment->attributes );
338
339         g_free( fragment->name );
340         fragment->name = NULL;
341         fragment->attributes = NULL;
342         fragment->children = NULL;
343
344         g_free( fragment );
345 }
346
347 /**
348  * Create a new data source.
349  * \param ifType Interface type to create.
350  * \return Initialized data source.
351  */
352 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
353         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
354
355         ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
356         ADDRITEM_ID(ds) = NULL;
357         ADDRITEM_NAME(ds) = NULL;
358         ADDRITEM_PARENT(ds) = NULL;
359         ADDRITEM_SUBTYPE(ds) = 0;
360         ds->type = ifType;
361         ds->rawDataSource = NULL;
362         ds->interface = NULL;
363         return ds;
364 }
365
366 /**
367  * Free up data source.
368  * \param ds Data source to free.
369  */
370 void addrindex_free_datasource( AddressDataSource *ds ) {
371         AddressInterface *iface;
372         AddressCache *cache;
373
374         g_return_if_fail( ds != NULL );
375
376         iface = ds->interface;
377         if( ds->rawDataSource != NULL ) {
378                 if( iface != NULL ) {
379                         if( iface->useInterface ) {
380                                 if( iface->type == ADDR_IF_BOOK ) {
381                                         AddressBookFile *abf = ds->rawDataSource;
382                                         addrbook_free_book( abf );
383                                 }
384                                 else if( iface->type == ADDR_IF_VCARD ) {
385                                         VCardFile *vcf = ds->rawDataSource;
386                                         vcard_free( vcf );
387                                 }
388 #ifdef USE_JPILOT
389                                 else if( iface->type == ADDR_IF_JPILOT ) {
390                                         JPilotFile *jpf = ds->rawDataSource;
391                                         jpilot_free( jpf );
392                                 }
393 #endif
394 #ifdef USE_LDAP
395                                 else if( iface->type == ADDR_IF_LDAP ) {
396                                         LdapServer *server = ds->rawDataSource;
397                                         cache = server->addressCache;
398                                         addrcache_use_index( cache, FALSE );
399                                         ldapsvr_free( server );
400                                 }
401 #endif
402                                 else {
403                                 }
404                         }
405                         else {
406                                 AddressIfFragment *fragment = ds->rawDataSource;
407                                 addrindex_free_fragment( fragment );
408                         }
409                 }
410         }
411
412         ADDRITEM_TYPE(ds) = ITEMTYPE_NONE;
413         ADDRITEM_ID(ds) = NULL;
414         ADDRITEM_NAME(ds) = NULL;
415         ADDRITEM_PARENT(ds) = NULL;
416         ADDRITEM_SUBTYPE(ds) = 0;
417         ds->type = ADDR_IF_NONE;
418         ds->interface = NULL;
419         ds->rawDataSource = NULL;
420
421         g_free( ds );
422 }
423
424 /**
425  * Free up all data sources for specified interface.
426  * \param iface Address interface to process.
427  */
428 static void addrindex_free_all_datasources( AddressInterface *iface ) {
429         GList *node = iface->listSource;
430         while( node ) {
431                 AddressDataSource *ds = node->data;
432                 addrindex_free_datasource( ds );
433                 node->data = NULL;
434                 node = g_list_next( node );
435         }
436 }
437
438 /**
439  * Free up specified interface.
440  * \param iface Interface to process.
441  */
442 static void addrindex_free_interface( AddressInterface *iface ) {
443         /* Free up data sources */
444         addrindex_free_all_datasources( iface );
445         g_list_free( iface->listSource );
446
447         /* Free internal storage */
448         g_free( ADDRITEM_ID(iface) );
449         g_free( ADDRITEM_NAME(iface) );
450         g_free( iface->name );
451         g_free( iface->listTag );
452         g_free( iface->itemTag );
453
454         /* Clear all pointers */
455         ADDRITEM_TYPE(iface) = ITEMTYPE_NONE;
456         ADDRITEM_ID(iface) = NULL;
457         ADDRITEM_NAME(iface) = NULL;
458         ADDRITEM_PARENT(iface) = NULL;
459         ADDRITEM_SUBTYPE(iface) = 0;
460         iface->type = ADDR_IF_NONE;
461         iface->name = NULL;
462         iface->listTag = NULL;
463         iface->itemTag = NULL;
464         iface->legacyFlag = FALSE;
465         iface->useInterface = FALSE;
466         iface->haveLibrary = FALSE;
467         iface->listSource = NULL;
468
469         /* Search stuff */
470         iface->searchOrder = 0;
471         iface->startSearch = NULL;
472         iface->stopSearch = NULL;
473
474         g_free( iface );
475 }
476
477 /**
478  * Return cache ID for specified data source.
479  *
480  * \param  addrIndex Address index.
481  * \param  ds        Data source.
482  * \return ID or NULL if not found. This should be <code>g_free()</code>
483  *         when done.
484  */
485 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
486         gchar *cacheID = NULL;
487         AddrBookBase *adbase;
488         AddressCache *cache;
489
490         g_return_val_if_fail( addrIndex != NULL, NULL );
491         g_return_val_if_fail( ds != NULL, NULL );
492
493         adbase = ( AddrBookBase * ) ds->rawDataSource;
494         if( adbase ) {
495                 cache = adbase->addressCache;
496                 if( cache ) {
497                         cacheID = g_strdup( cache->cacheID );
498                 }
499         }
500
501         return cacheID;
502 }
503
504 /**
505  * Return reference to data source for specified cacheID.
506  * \param addrIndex Address index.
507  * \param cacheID   ID.
508  * \return Data source, or NULL if not found.
509  */
510 AddressDataSource *addrindex_get_datasource(
511                 AddressIndex *addrIndex, const gchar *cacheID )
512 {
513         g_return_val_if_fail( addrIndex != NULL, NULL );
514         g_return_val_if_fail( cacheID != NULL, NULL );
515         return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
516 }
517
518 /**
519  * Return reference to address cache for specified cacheID.
520  * \param addrIndex Address index.
521  * \param cacheID   ID.
522  * \return Address cache, or NULL if not found.
523  */
524 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
525         AddressDataSource *ds;
526         AddrBookBase *adbase;
527         AddressCache *cache;
528
529         g_return_val_if_fail( addrIndex != NULL, NULL );
530         g_return_val_if_fail( cacheID != NULL, NULL );
531
532         cache = NULL;
533         ds = addrindex_get_datasource( addrIndex, cacheID );
534         if( ds ) {
535                 adbase = ( AddrBookBase * ) ds->rawDataSource;
536                 cache = adbase->addressCache;
537         }
538         return cache;
539 }
540
541 /**
542  * Add data source into hash table.
543  * \param addrIndex Address index.
544  * \param ds        Data source.
545  */
546 static void addrindex_hash_add_cache(
547                 AddressIndex *addrIndex, AddressDataSource *ds )
548 {
549         gchar *cacheID;
550
551         cacheID = addrindex_get_cache_id( addrIndex, ds );
552         if( cacheID ) {
553                 g_hash_table_insert( addrIndex->hashCache, cacheID, ds );
554         }
555 }
556
557 /*
558  * Free hash table callback function.
559  */
560 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
561         g_free( key );
562         key = NULL;
563         value = NULL;
564         return TRUE;
565 }
566
567 /*
568  * Free hash table of address cache items.
569  */
570 static void addrindex_free_cache_hash( GHashTable *table ) {
571         g_hash_table_freeze( table );
572         g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
573         g_hash_table_thaw( table );
574         g_hash_table_destroy( table );
575 }
576
577 /*
578  * Remove data source from internal hashtable.
579  * \param addrIndex Address index.
580  * \param ds        Data source to remove.
581  */
582 static void addrindex_hash_remove_cache(
583                 AddressIndex *addrIndex, AddressDataSource *ds )
584 {
585         gchar *cacheID;
586
587         cacheID = addrindex_get_cache_id( addrIndex, ds );
588         if( cacheID ) {
589                 g_hash_table_remove( addrIndex->hashCache, cacheID );
590                 g_free( cacheID );
591                 cacheID = NULL;
592         }
593 }
594
595 /*
596  * Create a new address index.
597  * \return Initialized address index object.
598  */
599 AddressIndex *addrindex_create_index( void ) {
600         AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
601
602         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_INDEX;
603         ADDRITEM_ID(addrIndex) = NULL;
604         ADDRITEM_NAME(addrIndex) = g_strdup( "Address Index" );
605         ADDRITEM_PARENT(addrIndex) = NULL;
606         ADDRITEM_SUBTYPE(addrIndex) = 0;
607         addrIndex->filePath = NULL;
608         addrIndex->fileName = NULL;
609         addrIndex->retVal = MGU_SUCCESS;
610         addrIndex->needsConversion = FALSE;
611         addrIndex->wasConverted = FALSE;
612         addrIndex->conversionError = FALSE;
613         addrIndex->interfaceList = NULL;
614         addrIndex->lastType = ADDR_IF_NONE;
615         addrIndex->dirtyFlag = FALSE;
616         addrIndex->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
617         addrIndex->loadedFlag = FALSE;
618         addrIndex->searchOrder = NULL;
619         addrindex_build_if_list( addrIndex );
620         return addrIndex;
621 }
622
623 /**
624  * Property - Specify file path to address index file.
625  * \param addrIndex Address index.
626  * \param value Path to index file.
627  */
628 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
629         g_return_if_fail( addrIndex != NULL );
630         addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
631 }
632
633 /**
634  * Property - Specify file name to address index file.
635  * \param addrIndex Address index.
636  * \param value File name.
637  */
638 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
639         g_return_if_fail( addrIndex != NULL );
640         addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
641 }
642
643 /**
644  * Property - Specify file path to be used.
645  * \param addrIndex Address index.
646  * \param value Path to JPilot file.
647  */
648 void addrindex_set_dirty( AddressIndex *addrIndex, const gboolean value ) {
649         g_return_if_fail( addrIndex != NULL );
650         addrIndex->dirtyFlag = value;
651 }
652
653 /**
654  * Property - get loaded flag. Note that this flag is set after reading data
655  * from the address books.
656  * \param addrIndex Address index.
657  * \return <i>TRUE</i> if address index data was loaded.
658  */
659 gboolean addrindex_get_loaded( AddressIndex *addrIndex ) {
660         g_return_val_if_fail( addrIndex != NULL, FALSE );
661         return addrIndex->loadedFlag;
662 }
663
664 /**
665  * Return list of address interfaces.
666  * \param addrIndex Address index.
667  * \return List of address interfaces.
668  */
669 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
670         g_return_val_if_fail( addrIndex != NULL, NULL );
671         return addrIndex->interfaceList;
672 }
673
674 /**
675  * Perform any other initialization of address index.
676  * \param addrIndex Address index.
677  */
678 void addrindex_initialize( AddressIndex *addrIndex ) {
679         addrcompl_initialize();
680 }
681
682 /**
683  * Perform any other teardown of address index.
684  * \param addrIndex Address index.
685  */
686 void addrindex_teardown( AddressIndex *addrIndex ) {
687         addrcompl_teardown();
688 }
689
690 /**
691  * Free up address index.
692  * \param addrIndex Address index.
693  */
694 void addrindex_free_index( AddressIndex *addrIndex ) {
695         GList *node;
696
697         g_return_if_fail( addrIndex != NULL );
698
699         /* Search stuff */
700         g_list_free( addrIndex->searchOrder );
701         addrIndex->searchOrder = NULL;
702
703         /* Free internal storage */
704         g_free( ADDRITEM_ID(addrIndex) );
705         g_free( ADDRITEM_NAME(addrIndex) );
706         g_free( addrIndex->filePath );
707         g_free( addrIndex->fileName );
708
709         /* Clear pointers */    
710         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
711         ADDRITEM_ID(addrIndex) = NULL;
712         ADDRITEM_NAME(addrIndex) = NULL;
713         ADDRITEM_PARENT(addrIndex) = NULL;
714         ADDRITEM_SUBTYPE(addrIndex) = 0;
715         addrIndex->filePath = NULL;
716         addrIndex->fileName = NULL;
717         addrIndex->retVal = MGU_SUCCESS;
718         addrIndex->needsConversion = FALSE;
719         addrIndex->wasConverted = FALSE;
720         addrIndex->conversionError = FALSE;
721         addrIndex->lastType = ADDR_IF_NONE;
722         addrIndex->dirtyFlag = FALSE;
723
724         /* Free up interfaces */        
725         node = addrIndex->interfaceList;
726         while( node ) {
727                 AddressInterface *iface = node->data;
728                 addrindex_free_interface( iface );
729                 node = g_list_next( node );
730         }
731         g_list_free( addrIndex->interfaceList );
732         addrIndex->interfaceList = NULL;
733
734         /* Free up hash cache */
735         addrindex_free_cache_hash( addrIndex->hashCache );
736         addrIndex->hashCache = NULL;
737
738         addrIndex->loadedFlag = FALSE;
739
740         g_free( addrIndex );
741 }
742
743 /**
744  * Print address index.
745  * \param addrIndex Address index.
746  * \parem stream    Stream to print.
747 */
748 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
749         g_return_if_fail( addrIndex != NULL );
750         fprintf( stream, "AddressIndex:\n" );
751         fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
752         fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
753         fprintf( stream, "\t   status: %d\n", addrIndex->retVal );
754         fprintf( stream, "\tconverted: '%s'\n",
755                         addrIndex->wasConverted ? "yes" : "no" );
756         fprintf( stream, "\tcvt error: '%s'\n",
757                         addrIndex->conversionError ? "yes" : "no" );
758         fprintf( stream, "\t---\n" );
759 }
760
761 /**
762  * Retrieve reference to address interface for specified interface type.
763  * \param  addrIndex Address index.
764  * \param  ifType Interface type.
765  * \return Address interface, or NULL if not found.
766  */
767 AddressInterface *addrindex_get_interface(
768         AddressIndex *addrIndex, AddressIfType ifType )
769 {
770         AddressInterface *retVal = NULL;
771         GList *node;
772
773         g_return_val_if_fail( addrIndex != NULL, NULL );
774
775         node = addrIndex->interfaceList;
776         while( node ) {
777                 AddressInterface *iface = node->data;
778                 node = g_list_next( node );
779                 if( iface->type == ifType ) {
780                         retVal = iface;
781                         break;
782                 }
783         }
784         return retVal;
785 }
786
787 /**
788  * Add raw data source to index. The raw data object (an AddressBookFile or
789  * VCardFile object, for example) should be supplied as the raw dataSource
790  * argument.
791  *
792  * \param  addrIndex Address index.
793  * \param ifType     Interface type to add.
794  * \param dataSource Actual raw data source to add. 
795  * \return Data source added, or NULL if invalid interface type.
796  */
797 AddressDataSource *addrindex_index_add_datasource(
798         AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
799 {
800         AddressInterface *iface;
801         AddressDataSource *ds = NULL;
802
803         g_return_val_if_fail( addrIndex != NULL, NULL );
804         g_return_val_if_fail( dataSource != NULL, NULL );
805
806         iface = addrindex_get_interface( addrIndex, ifType );
807         if( iface ) {
808                 ds = addrindex_create_datasource( ifType );
809                 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
810                 ds->type = ifType;
811                 ds->rawDataSource = dataSource;
812                 ds->interface = iface;
813                 iface->listSource = g_list_append( iface->listSource, ds );
814                 addrIndex->dirtyFlag = TRUE;
815
816                 addrindex_hash_add_cache( addrIndex, ds );
817         }
818         return ds;
819 }
820
821 /**
822  * Remove specified data source from index.
823  * \param  addrIndex Address index.
824  * \param  dataSource Data source to add. 
825  * \return Reference to data source if removed, or NULL if data source was not
826  *         found in index. Note the this object must still be freed.
827  */
828 AddressDataSource *addrindex_index_remove_datasource(
829         AddressIndex *addrIndex, AddressDataSource *dataSource )
830 {
831         AddressDataSource *retVal = FALSE;
832         AddressInterface *iface;
833
834         g_return_val_if_fail( addrIndex != NULL, NULL );
835         g_return_val_if_fail( dataSource != NULL, NULL );
836
837         iface = addrindex_get_interface( addrIndex, dataSource->type );
838         if( iface ) {
839                 iface->listSource = g_list_remove( iface->listSource, dataSource );
840                 addrIndex->dirtyFlag = TRUE;
841                 dataSource->interface = NULL;
842
843                 /* Remove cache from hash table */
844                 addrindex_hash_remove_cache( addrIndex, dataSource );
845
846                 retVal = dataSource;
847         }
848         return retVal;
849 }
850
851 /**
852  * Retrieve a reference to address interface for specified interface type and
853  * XML interface tag name.
854  * \param  addrIndex Address index.
855  * \param  tag       XML interface tag name to match.
856  * \param  ifType    Interface type to match.
857  * \return Reference to address index, or NULL if not found in index.
858  */
859 static AddressInterface *addrindex_tag_get_interface(
860         AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
861 {
862         AddressInterface *retVal = NULL;
863         GList *node = addrIndex->interfaceList;
864
865         while( node ) {
866                 AddressInterface *iface = node->data;
867                 node = g_list_next( node );
868                 if( tag ) {
869                         if( strcmp( iface->listTag, tag ) == 0 ) {
870                                 retVal = iface;
871                                 break;
872                         }
873                 }
874                 else {
875                         if( iface->type == ifType ) {
876                                 retVal = iface;
877                                 break;
878                         }
879                 }
880         }
881         return retVal;
882 }
883
884 /**
885  * Retrieve a reference to address interface for specified interface type and
886  * XML datasource tag name.
887  * \param  addrIndex Address index.
888  * \param  ifType    Interface type to match.
889  * \param  tag       XML datasource tag name to match.
890  * \return Reference to address index, or NULL if not found in index.
891  */
892 static AddressInterface *addrindex_tag_get_datasource(
893         AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
894 {
895         AddressInterface *retVal = NULL;
896         GList *node = addrIndex->interfaceList;
897
898         while( node ) {
899                 AddressInterface *iface = node->data;
900                 node = g_list_next( node );
901                 if( iface->type == ifType && iface->itemTag ) {
902                         if( strcmp( iface->itemTag, tag ) == 0 ) {
903                                 retVal = iface;
904                                 break;
905                         }
906                 }
907         }
908         return retVal;
909 }
910
911 /* **********************************************************************
912 * Interface XML parsing functions.
913 * ***********************************************************************
914 */
915
916 /**
917  * Write start of XML element to file.
918  * \param fp   File.
919  * \param lvl  Indentation level.
920  * \param name Element name.
921  */
922 static void addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
923         gint i;
924         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
925         fputs( "<", fp );
926         fputs( name, fp );
927 }
928
929 /**
930  * Write end of XML element to file.
931  * \param fp   File.
932  * \param lvl  Indentation level.
933  * \param name Element name.
934  */
935 static void addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
936         gint i;
937         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
938         fputs( "</", fp );
939         fputs( name, fp );
940         fputs( ">\n", fp );
941 }
942
943 /**
944  * Write XML attribute to file.
945  * \param fp    File.
946  * \param name  Attribute name.
947  * \param value Attribute value.
948  */
949 static void addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
950         fputs( " ", fp );
951         fputs( name, fp );
952         fputs( "=\"", fp );
953         xml_file_put_escape_str( fp, value );
954         fputs( "\"", fp );
955 }
956
957 /**
958  * Return DOM fragment for current XML tag from file.
959  * \param  file XML file being processed.
960  * \return Fragment representing DOM fragment for configuration element.
961  */
962 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
963         AddressIfFragment *fragment;
964         AddressIfFragment *child;
965         AddressIfAttrib *nv;
966         XMLTag *xtag;
967         GList *list;
968         GList *attr;
969         gchar *name;
970         gchar *value;
971         guint prevLevel;
972         gint rc;
973
974         prevLevel = file->level;
975
976         /* Get current tag name */
977         xtag = xml_get_current_tag( file );
978
979         /* Create new fragment */
980         fragment = g_new0( AddressIfFragment, 1 );
981         fragment->name = g_strdup( xtag->tag );
982         fragment->children = NULL;
983         fragment->attributes = NULL;
984
985         /* Read attributes */
986         list = NULL;
987         attr = xml_get_current_tag_attr( file );
988         while( attr ) {
989                 name = ((XMLAttr *)attr->data)->name;
990                 value = ((XMLAttr *)attr->data)->value;
991                 nv = g_new0( AddressIfAttrib, 1 );
992                 nv->name = g_strdup( name );
993                 nv->value = g_strdup( value );
994                 list = g_list_append( list, nv );
995                 attr = g_list_next( attr );
996         }
997         fragment->attributes = list;
998
999         /* Now read the children */
1000         while( TRUE ) {
1001                 rc = xml_parse_next_tag( file );
1002                 if( rc != 0 ) {
1003                         /* End of file? */
1004                         break;
1005                 }
1006                 if( file->level < prevLevel ) {
1007                         /* We must be above level we start at */
1008                         break;
1009                 }
1010                 child = addrindex_read_fragment( file );
1011                 fragment->children = g_list_append( fragment->children, child );
1012         }
1013
1014         return fragment;
1015 }
1016
1017 /**
1018  * Write DOM fragment to file.
1019  * \param fp       File to write.
1020  * \param fragment DOM fragment for configuration element.
1021  * \param lvl      Indent level.
1022  */
1023 static void addrindex_write_fragment(
1024                 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1025 {
1026         GList *node;
1027
1028         if( fragment ) {
1029                 addrindex_write_elem_s( fp, lvl, fragment->name );
1030                 node = fragment->attributes;
1031                 while( node ) {
1032                         AddressIfAttrib *nv = node->data;
1033                         addrindex_write_attr( fp, nv->name, nv->value );
1034                         node = g_list_next( node );
1035                 }
1036                 if( fragment->children ) {
1037                         fputs(" >\n", fp);
1038
1039                         /* Output children */
1040                         node = fragment->children;
1041                         while( node ) {
1042                                 AddressIfFragment *child = node->data;
1043                                 addrindex_write_fragment( fp, child, 1+lvl );
1044                                 node = g_list_next( node );
1045                         }
1046
1047                         /* Output closing tag */
1048                         addrindex_write_elem_e( fp, lvl, fragment->name );
1049                 }
1050                 else {
1051                         fputs(" />\n", fp);
1052                 }
1053         }
1054 }
1055
1056 /*
1057 static void addrindex_print_fragment_r(
1058                 const AddressIfFragment *fragment, FILE *stream, gint lvl )
1059 {
1060         GList *node;
1061         gint i;
1062
1063         for( i = 0; i < lvl; i++ )
1064                 fprintf( stream, "  " );
1065         fprintf( stream, "Element:%s:\n", fragment->name );
1066         node = fragment->attributes;
1067         while( node ) {
1068                 AddressIfAttrib *nv = node->data;
1069                 for( i = 0; i < lvl; i++ )
1070                         fprintf( stream, "  " );
1071                 fprintf( stream, "    %s : %s\n", nv->name, nv->value );
1072                 node = g_list_next( node );
1073         }
1074         node = fragment->children;
1075         while( node ) {
1076                 AddressIfFragment *child = node->data;
1077                 addrindex_print_fragment_r( child, stream, 1+lvl );
1078                 node = g_list_next( node );
1079         }
1080 }
1081
1082 static void addrindex_print_fragment( const AddressIfFragment *fragment, FILE *stream ) {
1083         addrindex_print_fragment_r( fragment, stream, 0 );
1084 }
1085 */
1086
1087 /**
1088  * Read/parse address index file, creating a data source for a regular
1089  * intrinsic XML addressbook.
1090  * \param  file Address index file.
1091  * \return Data source.
1092  */
1093 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1094         AddressDataSource *ds;
1095         AddressBookFile *abf;
1096         GList *attr;
1097
1098         ds = addrindex_create_datasource( ADDR_IF_BOOK );
1099         abf = addrbook_create_book();
1100         attr = xml_get_current_tag_attr( file );
1101         while( attr ) {
1102                 gchar *name = ((XMLAttr *)attr->data)->name;
1103                 gchar *value = ((XMLAttr *)attr->data)->value;
1104                 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1105                         addrbook_set_name( abf, value );
1106                 }
1107                 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1108                         addrbook_set_file( abf, value );
1109                 }
1110                 attr = g_list_next( attr );
1111         }
1112         ds->rawDataSource = abf;
1113         return ds;
1114 }
1115
1116 static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1117         AddressBookFile *abf = ds->rawDataSource;
1118         if( abf ) {
1119                 addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK );
1120                 addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) );
1121                 addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName );
1122                 fputs( " />\n", fp );
1123         }
1124 }
1125
1126 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1127         AddressDataSource *ds;
1128         VCardFile *vcf;
1129         GList *attr;
1130
1131         ds = addrindex_create_datasource( ADDR_IF_VCARD );
1132         vcf = vcard_create();
1133         attr = xml_get_current_tag_attr( file );
1134         while( attr ) {
1135                 gchar *name = ((XMLAttr *)attr->data)->name;
1136                 gchar *value = ((XMLAttr *)attr->data)->value;
1137                 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1138                         vcard_set_name( vcf, value );
1139                 }
1140                 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1141                         vcard_set_file( vcf, value );
1142                 }
1143                 attr = g_list_next( attr );
1144         }
1145         ds->rawDataSource = vcf;
1146         return ds;
1147 }
1148
1149 static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1150         VCardFile *vcf = ds->rawDataSource;
1151         if( vcf ) {
1152                 addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD );
1153                 addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) );
1154                 addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path );
1155                 fputs( " />\n", fp );
1156         }
1157 }
1158
1159 #ifdef USE_JPILOT
1160 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1161         AddressDataSource *ds;
1162         JPilotFile *jpf;
1163         GList *attr;
1164
1165         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1166         jpf = jpilot_create();
1167         attr = xml_get_current_tag_attr( file );
1168         while( attr ) {
1169                 gchar *name = ((XMLAttr *)attr->data)->name;
1170                 gchar *value = ((XMLAttr *)attr->data)->value;
1171                 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1172                         jpilot_set_name( jpf, value );
1173                 }
1174                 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1175                         jpilot_set_file( jpf, value );
1176                 }
1177                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1178                         jpilot_add_custom_label( jpf, value );
1179                 }
1180                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1181                         jpilot_add_custom_label( jpf, value );
1182                 }
1183                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1184                         jpilot_add_custom_label( jpf, value );
1185                 }
1186                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1187                         jpilot_add_custom_label( jpf, value );
1188                 }
1189                 attr = g_list_next( attr );
1190         }
1191         ds->rawDataSource = jpf;
1192         return ds;
1193 }
1194
1195 static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1196         JPilotFile *jpf = ds->rawDataSource;
1197         if( jpf ) {
1198                 gint ind;
1199                 GList *node;
1200                 GList *customLbl = jpilot_get_custom_labels( jpf );
1201                 addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT );
1202                 addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) );
1203                 addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path );
1204                 node = customLbl;
1205                 ind = 1;
1206                 while( node ) {
1207                         gchar name[256];
1208                         g_snprintf( name, sizeof(name), "%s%d",
1209                                     ATTAG_JPILOT_CUSTOM, ind );
1210                         addrindex_write_attr( fp, name, node->data );
1211                         ind++;
1212                         node = g_list_next( node );
1213                 }
1214                 fputs( " />\n", fp );
1215         }
1216 }
1217
1218 #else
1219 /*
1220  * Just read/write DOM fragments (preserve data found in file).
1221  */
1222 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1223         AddressDataSource *ds;
1224
1225         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1226         ds->rawDataSource = addrindex_read_fragment( file );
1227         return ds;
1228 }
1229
1230 static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1231         AddressIfFragment *fragment = ds->rawDataSource;
1232         if( fragment ) {
1233                 addrindex_write_fragment( fp, fragment, lvl );
1234         }
1235 }
1236 #endif
1237
1238 #ifdef USE_LDAP
1239 /**
1240  * Parse LDAP criteria attribute data from XML file.
1241  * \param file Index file.
1242  * \param ctl  LDAP control object to populate.
1243  */
1244 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1245         guint prevLevel;
1246         XMLTag *xtag;
1247         XMLTag *xtagPrev;
1248         gint rc;
1249         GList *attr;
1250         GList *list;
1251         GList *node;
1252
1253         if( file == NULL ) {
1254                 return;
1255         }
1256
1257         list = NULL;
1258         prevLevel = file->level;
1259         xtagPrev = xml_get_current_tag( file );
1260         while( TRUE ) {
1261                 rc = xml_parse_next_tag( file );
1262                 if( rc != 0 ) {
1263                         /* Terminate prematurely */
1264                         mgu_free_dlist( list );
1265                         list = NULL;
1266                         return;
1267                 }
1268                 if( file->level < prevLevel ) {
1269                         /* We must be above level we start at */
1270                         break;
1271                 }
1272
1273                 /* Get a tag (element) */
1274                 xtag = xml_get_current_tag( file );
1275                 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1276                         /* LDAP criteria attribute */
1277                         attr = xml_get_current_tag_attr( file );
1278                         while( attr ) {
1279                                 gchar *name = ((XMLAttr *)attr->data)->name;
1280                                 gchar *value = ((XMLAttr *)attr->data)->value;
1281                                 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1282                                         if( value && strlen( value ) > 0 ) {
1283                                                 list = g_list_append(
1284                                                         list, g_strdup( value ) );
1285                                         }
1286                                 }
1287                                 attr = g_list_next( attr );
1288                         }
1289                 }
1290                 else {
1291                         if( xtag != xtagPrev ) {
1292                                 /* Found a new tag */
1293                                 break;
1294                         }
1295                 }
1296                 xtag = xtagPrev;
1297         }
1298
1299         /* Build list of search attributes */
1300         ldapctl_criteria_list_clear( ctl );
1301         node = list;
1302         while( node ) {
1303                 ldapctl_criteria_list_add( ctl, node->data );
1304                 g_free( node->data );
1305                 node->data = NULL;
1306                 node = g_list_next( node );
1307         }
1308         g_list_free( list );
1309         list = NULL;
1310
1311 }
1312
1313 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1314         AddressDataSource *ds;
1315         LdapServer *server;
1316         LdapControl *ctl;
1317         GList *attr;
1318         gchar *serverName = NULL;
1319         gchar *criteria = NULL;
1320         gboolean bSearch = FALSE;
1321         gboolean cvtFlag = TRUE;
1322
1323         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1324         ctl = ldapctl_create();
1325         attr = xml_get_current_tag_attr( file );
1326         while( attr ) {
1327                 gchar *name = ((XMLAttr *)attr->data)->name;
1328                 gchar *value = ((XMLAttr *)attr->data)->value;
1329                 gint ivalue = atoi( value );
1330
1331                 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
1332                         if( serverName ) g_free( serverName );
1333                         serverName = g_strdup( value );
1334                 }
1335                 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
1336                         ldapctl_set_host( ctl, value );
1337                 }
1338                 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
1339                         ldapctl_set_port( ctl, ivalue );
1340                 }
1341                 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
1342                         ldapctl_set_base_dn( ctl, value );
1343                 }
1344                 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
1345                         ldapctl_set_bind_dn( ctl, value );
1346                 }
1347                 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
1348                         ldapctl_set_bind_password( ctl, value );
1349                 }
1350                 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
1351                         if( criteria ) g_free( criteria );
1352                         criteria = g_strdup( value );
1353                 }
1354                 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
1355                         ldapctl_set_max_entries( ctl, ivalue );
1356                 }
1357                 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
1358                         ldapctl_set_timeout( ctl, ivalue );
1359                 }
1360                 else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
1361                         ldapctl_set_max_query_age( ctl, ivalue );
1362                 }
1363                 else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
1364                         bSearch = FALSE;
1365                         cvtFlag = FALSE;
1366                         if( strcmp( value, "yes" ) == 0 ) {
1367                                 bSearch = TRUE;
1368                         }
1369                 }
1370                 attr = g_list_next( attr );
1371         }
1372
1373         server = ldapsvr_create_noctl();
1374         ldapsvr_set_name( server, serverName );
1375         ldapsvr_set_search_flag( server, bSearch );
1376         g_free( serverName );
1377         ldapsvr_set_control( server, ctl );
1378         ds->rawDataSource = server;
1379
1380         addrindex_parse_ldap_attrlist( file, ctl );
1381         /*
1382          * If criteria have been specified and no attributes were listed, then
1383          * convert old style criteria into an attribute list. Any criteria will
1384          * be dropped when saving data.
1385          */
1386         if( criteria ) {
1387                 if( ! ldapctl_get_criteria_list( ctl ) ) {
1388                         ldapctl_parse_ldap_search( ctl, criteria );
1389                 }
1390                 g_free( criteria );
1391         }
1392         /*
1393          * If no search flag was found, then we are converting from old format
1394          * server data to new format.
1395          */
1396         if( cvtFlag ) {
1397                 ldapsvr_set_search_flag( server, TRUE );
1398         }
1399         /* ldapsvr_print_data( server, stdout ); */
1400
1401         return ds;
1402 }
1403
1404 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1405         LdapServer *server = ds->rawDataSource;
1406         LdapControl *ctl = NULL;
1407         GList *node;
1408         gchar value[256];
1409
1410         if( server ) {
1411                 ctl = server->control;
1412         }
1413         if( ctl == NULL ) return;
1414
1415         /* Output start element with attributes */
1416         addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
1417         addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) );
1418         addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName );
1419
1420         sprintf( value, "%d", ctl->port );      
1421         addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
1422
1423         addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN );
1424         addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN );
1425         addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, ctl->bindPass );
1426
1427         sprintf( value, "%d", ctl->maxEntries );
1428         addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
1429         sprintf( value, "%d", ctl->timeOut );
1430         addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
1431         sprintf( value, "%d", ctl->maxQueryAge );
1432         addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value );
1433
1434         addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
1435                         server->searchFlag ? "yes" : "no" );
1436
1437         fputs(" >\n", fp);
1438
1439         /* Output attributes */
1440         node = ldapctl_get_criteria_list( ctl );
1441         while( node ) {
1442                 addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH );
1443                 addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data );
1444                 fputs(" />\n", fp);
1445                 node = g_list_next( node );
1446         }
1447
1448         /* End of element */    
1449         addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP );
1450
1451 }
1452
1453 #else
1454 /*
1455  * Just read/write DOM fragments (preserve data found in file).
1456  */
1457 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1458         AddressDataSource *ds;
1459
1460         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1461         ds->rawDataSource = addrindex_read_fragment( file );
1462         return ds;
1463 }
1464
1465 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1466         AddressIfFragment *fragment = ds->rawDataSource;
1467         if( fragment ) {
1468                 addrindex_write_fragment( fp, fragment, lvl );
1469         }
1470 }
1471 #endif
1472
1473 /* **********************************************************************
1474 * Address index I/O functions.
1475 * ***********************************************************************
1476 */
1477 /**
1478  * Read address index file, creating appropriate data sources for each address
1479  * index file entry.
1480  *
1481  * \param  addrIndex Address index.
1482  * \param  file Address index file.
1483  */
1484 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
1485         guint prev_level;
1486         XMLTag *xtag;
1487         AddressInterface *iface = NULL, *dsIFace = NULL;
1488         AddressDataSource *ds;
1489         gint rc;
1490
1491         addrIndex->loadedFlag = FALSE;
1492         for (;;) {
1493                 prev_level = file->level;
1494                 rc = xml_parse_next_tag( file );
1495                 if( file->level == 0 ) return;
1496
1497                 xtag = xml_get_current_tag( file );
1498
1499                 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
1500                 if( iface ) {
1501                         addrIndex->lastType = iface->type;
1502                         if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
1503                 }
1504                 else {
1505                         dsIFace = addrindex_tag_get_datasource(
1506                                         addrIndex, addrIndex->lastType, xtag->tag );
1507                         if( dsIFace ) {
1508                                 /* Add data source to list */
1509                                 ds = NULL;
1510                                 if( addrIndex->lastType == ADDR_IF_BOOK ) {
1511                                         ds = addrindex_parse_book( file );
1512                                         if( ds->rawDataSource ) {
1513                                                 addrbook_set_path( ds->rawDataSource,
1514                                                         addrIndex->filePath );
1515                                         }
1516                                 }
1517                                 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
1518                                         ds = addrindex_parse_vcard( file );
1519                                 }
1520                                 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
1521                                         ds = addrindex_parse_jpilot( file );
1522                                 }
1523 #ifdef USE_LDAP
1524                                 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
1525                                         ds = addrindex_parse_ldap( file );
1526                                 }
1527 #endif
1528                                 if( ds ) {
1529                                         ds->interface = dsIFace;
1530                                         addrindex_hash_add_cache( addrIndex, ds );
1531                                         dsIFace->listSource =
1532                                                 g_list_append( dsIFace->listSource, ds );
1533                                 }
1534                         }
1535                 }
1536         }
1537 }
1538
1539 /*
1540  * Search order sorting comparison function for building search order list.
1541  */
1542 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
1543         AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
1544         AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
1545
1546         return ifaceA->searchOrder - ifaceB->searchOrder;
1547 }
1548
1549 /**
1550  * Build list of data sources to process.
1551  * \param addrIndex Address index object.
1552  */
1553 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
1554         AddressInterface *iface;
1555         GList *nodeIf;
1556
1557         /* Clear existing list */
1558         g_list_free( addrIndex->searchOrder );
1559         addrIndex->searchOrder = NULL;
1560
1561         /* Build new list */
1562         nodeIf = addrIndex->interfaceList;
1563         while( nodeIf ) {
1564                 AddressInterface *iface = nodeIf->data;
1565                 if( iface->searchOrder > 0 ) {
1566                         /* Add to search order list */
1567                         addrIndex->searchOrder = g_list_insert_sorted(
1568                                 addrIndex->searchOrder, iface,
1569                                 addrindex_search_order_compare );
1570                 }
1571                 nodeIf = g_list_next( nodeIf );
1572         }
1573
1574         nodeIf = addrIndex->searchOrder;
1575         while( nodeIf ) {
1576                 AddressInterface *iface = nodeIf->data;
1577                 nodeIf = g_list_next( nodeIf );
1578         }
1579
1580 }
1581
1582 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1583         XMLFile *file = NULL;
1584         gchar *fileSpec = NULL;
1585
1586         g_return_val_if_fail( addrIndex != NULL, -1 );
1587
1588         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1589         addrIndex->retVal = MGU_NO_FILE;
1590         file = xml_open_file( fileSpec );
1591         g_free( fileSpec );
1592
1593         if( file == NULL ) {
1594                 /*
1595                 fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
1596                 */
1597                 return addrIndex->retVal;
1598         }
1599
1600         addrIndex->retVal = MGU_BAD_FORMAT;
1601         if( xml_get_dtd( file ) == 0 ) {
1602                 if( xml_parse_next_tag( file ) == 0 ) {
1603                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1604                                 addrindex_read_index( addrIndex, file );
1605                                 addrIndex->retVal = MGU_SUCCESS;
1606                         }
1607                 }
1608         }
1609         xml_close_file( file );
1610
1611         addrindex_build_search_order( addrIndex );
1612
1613         return addrIndex->retVal;
1614 }
1615
1616 static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1617         GList *nodeIF, *nodeDS;
1618         gint lvlList = 1;
1619         gint lvlItem = 1 + lvlList;
1620
1621         nodeIF = addrIndex->interfaceList;
1622         while( nodeIF ) {
1623                 AddressInterface *iface = nodeIF->data;
1624                 if( ! iface->legacyFlag ) {
1625                         nodeDS = iface->listSource;
1626                         addrindex_write_elem_s( fp, lvlList, iface->listTag );
1627                         fputs( ">\n", fp );
1628                         while( nodeDS ) {
1629                                 AddressDataSource *ds = nodeDS->data;
1630                                 if( ds ) {
1631                                         if( iface->type == ADDR_IF_BOOK ) {
1632                                                 addrindex_write_book( fp, ds, lvlItem );
1633                                         }
1634                                         if( iface->type == ADDR_IF_VCARD ) {
1635                                                 addrindex_write_vcard( fp, ds, lvlItem );
1636                                         }
1637                                         if( iface->type == ADDR_IF_JPILOT ) {
1638                                                 addrindex_write_jpilot( fp, ds, lvlItem );
1639                                         }
1640 #ifdef USE_LDAP
1641                                         if( iface->type == ADDR_IF_LDAP ) {
1642                                                 addrindex_write_ldap( fp, ds, lvlItem );
1643                                         }
1644 #endif
1645                                 }
1646                                 nodeDS = g_list_next( nodeDS );
1647                         }
1648                         addrindex_write_elem_e( fp, lvlList, iface->listTag );
1649                 }
1650                 nodeIF = g_list_next( nodeIF );
1651         }
1652 }
1653
1654 /*
1655 * Write data to specified file.
1656 * Enter: addrIndex Address index object.
1657 *        newFile   New file name.
1658 * return: Status code, from addrIndex->retVal.
1659 * Note: File will be created in directory specified by addrIndex.
1660 */
1661 gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1662         FILE *fp;
1663         gchar *fileSpec;
1664 #ifndef DEV_STANDALONE
1665         PrefFile *pfile;
1666 #endif
1667
1668         g_return_val_if_fail( addrIndex != NULL, -1 );
1669
1670         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1671         addrIndex->retVal = MGU_OPEN_FILE;
1672 #ifdef DEV_STANDALONE
1673         fp = fopen( fileSpec, "wb" );
1674         g_free( fileSpec );
1675         if( fp ) {
1676                 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1677 #else
1678         pfile = prefs_write_open( fileSpec );
1679         g_free( fileSpec );
1680         if( pfile ) {
1681                 fp = pfile->fp;
1682                 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1683                                 conv_get_current_charset_str() );
1684 #endif
1685                 addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX );
1686                 fputs( ">\n", fp );
1687
1688                 addrindex_write_index( addrIndex, fp );
1689                 addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX );
1690
1691                 addrIndex->retVal = MGU_SUCCESS;
1692 #ifdef DEV_STANDALONE
1693                 fclose( fp );
1694 #else
1695                 if( prefs_file_close( pfile ) < 0 ) {
1696                         addrIndex->retVal = MGU_ERROR_WRITE;
1697                 }
1698 #endif
1699         }
1700
1701         fileSpec = NULL;
1702         return addrIndex->retVal;
1703 }
1704
1705 /*
1706 * Save address index data to original file.
1707 * return: Status code, from addrIndex->retVal.
1708 */
1709 gint addrindex_save_data( AddressIndex *addrIndex ) {
1710         g_return_val_if_fail( addrIndex != NULL, -1 );
1711
1712         addrIndex->retVal = MGU_NO_FILE;
1713         if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1714         if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1715
1716         addrindex_write_to( addrIndex, addrIndex->fileName );
1717         if( addrIndex->retVal == MGU_SUCCESS ) {
1718                 addrIndex->dirtyFlag = FALSE;
1719         }
1720         return addrIndex->retVal;
1721 }
1722
1723 /*
1724 * Save all address book files which may have changed.
1725 * Return: Status code, set if there was a problem saving data.
1726 */
1727 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1728         gint retVal = MGU_SUCCESS;
1729         GList *nodeIf, *nodeDS;
1730
1731         nodeIf = addrIndex->interfaceList;
1732         while( nodeIf ) {
1733                 AddressInterface *iface = nodeIf->data;
1734                 if( iface->type == ADDR_IF_BOOK ) {
1735                         nodeDS = iface->listSource;
1736                         while( nodeDS ) {
1737                                 AddressDataSource *ds = nodeDS->data;
1738                                 AddressBookFile *abf = ds->rawDataSource;
1739                                 if( addrbook_get_dirty( abf ) ) {
1740                                         if( addrbook_get_read_flag( abf ) ) {
1741                                                 addrbook_save_data( abf );
1742                                                 if( abf->retVal != MGU_SUCCESS ) {
1743                                                         retVal = abf->retVal;
1744                                                 }
1745                                         }
1746                                 }
1747                                 nodeDS = g_list_next( nodeDS );
1748                         }
1749                         break;
1750                 }
1751                 nodeIf = g_list_next( nodeIf );
1752         }
1753         return retVal;
1754 }
1755
1756
1757 /* **********************************************************************
1758 * Address book conversion to new format.
1759 * ***********************************************************************
1760 */
1761
1762 #define ELTAG_IF_OLD_FOLDER   "folder"
1763 #define ELTAG_IF_OLD_GROUP    "group"
1764 #define ELTAG_IF_OLD_ITEM     "item"
1765 #define ELTAG_IF_OLD_NAME     "name"
1766 #define ELTAG_IF_OLD_ADDRESS  "address"
1767 #define ELTAG_IF_OLD_REMARKS  "remarks"
1768 #define ATTAG_IF_OLD_NAME     "name"
1769
1770 #define TEMPNODE_ROOT         0
1771 #define TEMPNODE_FOLDER       1
1772 #define TEMPNODE_GROUP        2
1773 #define TEMPNODE_ADDRESS      3
1774
1775 typedef struct _AddressCvt_Node AddressCvtNode;
1776 struct _AddressCvt_Node {
1777         gint  type;
1778         gchar *name;
1779         gchar *address;
1780         gchar *remarks;
1781         GList *list;
1782 };
1783
1784 /*
1785 * Parse current address item.
1786 */
1787 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1788         gchar *element;
1789         guint level;
1790         AddressCvtNode *nn;
1791
1792         nn = g_new0( AddressCvtNode, 1 );
1793         nn->type = TEMPNODE_ADDRESS;
1794         nn->list = NULL;
1795
1796         level = file->level;
1797
1798         for (;;) {
1799                 xml_parse_next_tag(file);
1800                 if (file->level < level) return nn;
1801
1802                 element = xml_get_element( file );
1803                 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1804                         nn->name = g_strdup( element );
1805                 }
1806                 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1807                         nn->address = g_strdup( element );
1808                 }
1809                 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1810                         nn->remarks = g_strdup( element );
1811                 }
1812                 xml_parse_next_tag(file);
1813         }
1814 }
1815
1816 /*
1817 * Create a temporary node below specified node.
1818 */
1819 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1820         AddressCvtNode *nn;
1821         nn = g_new0( AddressCvtNode, 1 );
1822         nn->type = type;
1823         nn->name = g_strdup( name );
1824         nn->remarks = g_strdup( rem );
1825         node->list = g_list_append( node->list, nn );
1826         return nn;
1827 }
1828
1829 /*
1830 * Process current temporary node.
1831 */
1832 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1833         GList *attr;
1834         guint prev_level;
1835         AddressCvtNode *newNode = NULL;
1836         gchar *name;
1837         gchar *value;
1838
1839         for (;;) {
1840                 prev_level = file->level;
1841                 xml_parse_next_tag( file );
1842                 if (file->level < prev_level) return;
1843                 name = NULL;
1844                 value = NULL;
1845
1846                 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1847                         attr = xml_get_current_tag_attr(file);
1848                         if (attr) {
1849                                 name = ((XMLAttr *)attr->data)->name;
1850                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1851                                         value = ((XMLAttr *)attr->data)->value;
1852                                 }
1853                         }
1854                         newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1855                         addrindex_add_obj( file, newNode );
1856
1857                 }
1858                 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1859                         attr = xml_get_current_tag_attr(file);
1860                         if (attr) {
1861                                 name = ((XMLAttr *)attr->data)->name;
1862                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1863                                         value = ((XMLAttr *)attr->data)->value;
1864                                 }
1865                         }
1866                         newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
1867                         addrindex_add_obj( file, newNode );
1868                 }
1869                 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
1870                         newNode = addrindex_parse_item( file );
1871                         node->list = g_list_append( node->list, newNode );
1872                 }
1873                 else {
1874                         /* printf( "invalid: !!! \n" ); */
1875                         attr = xml_get_current_tag_attr( file );
1876                 }
1877         }
1878 }
1879
1880 /*
1881 * Consume all nodes below current tag.
1882 */
1883 static void addrindex_consume_tree( XMLFile *file ) {
1884         guint prev_level;
1885         gchar *element;
1886         GList *attr;
1887         XMLTag *xtag;
1888
1889         for (;;) {
1890                 prev_level = file->level;
1891                 xml_parse_next_tag( file );
1892                 if (file->level < prev_level) return;
1893
1894                 xtag = xml_get_current_tag( file );
1895                 /* printf( "tag : %s\n", xtag->tag ); */
1896                 element = xml_get_element( file );
1897                 attr = xml_get_current_tag_attr( file );
1898                 /* show_attribs( attr ); */
1899                 /* printf( "\ttag  value : %s :\n", element ); */
1900                 addrindex_consume_tree( file );
1901         }
1902 }
1903
1904 /*
1905 * Print temporary tree.
1906 */
1907 static void addrindex_print_node( AddressCvtNode *node, FILE *stream  ) {
1908         GList *list;
1909
1910         fprintf( stream, "Node:\ttype :%d:\n", node->type );
1911         fprintf( stream, "\tname :%s:\n", node->name );
1912         fprintf( stream, "\taddr :%s:\n", node->address );
1913         fprintf( stream, "\trems :%s:\n", node->remarks );
1914         if( node->list ) {
1915                 fprintf( stream, "\t--list----\n" );
1916         }
1917         list = node->list;
1918         while( list ) {
1919                 AddressCvtNode *lNode = list->data;
1920                 list = g_list_next( list );
1921                 addrindex_print_node( lNode, stream );
1922         }
1923         fprintf( stream, "\t==list-%d==\n", node->type );
1924 }
1925
1926 /*
1927 * Free up temporary tree.
1928 */
1929 static void addrindex_free_node( AddressCvtNode *node ) {
1930         GList *list = node->list;
1931
1932         while( list ) {
1933                 AddressCvtNode *lNode = list->data;
1934                 list = g_list_next( list );
1935                 addrindex_free_node( lNode );
1936         }
1937         node->type = TEMPNODE_ROOT;
1938         g_free( node->name );
1939         g_free( node->address );
1940         g_free( node->remarks );
1941         g_list_free( node->list );
1942         g_free( node );
1943 }
1944
1945 /*
1946 * Process address book for specified node.
1947 */
1948 static void addrindex_process_node(
1949                 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
1950                 ItemGroup *parentGrp, ItemFolder *folderGrp )
1951 {
1952         GList *list;
1953         ItemFolder *itemFolder = NULL;
1954         ItemGroup *itemGParent = parentGrp;
1955         ItemFolder *itemGFolder = folderGrp;
1956         AddressCache *cache = abf->addressCache;
1957
1958         if( node->type == TEMPNODE_ROOT ) {
1959                 itemFolder = parent;
1960         }
1961         else if( node->type == TEMPNODE_FOLDER ) {
1962                 itemFolder = addritem_create_item_folder();
1963                 addritem_folder_set_name( itemFolder, node->name );
1964                 addrcache_id_folder( cache, itemFolder );
1965                 addrcache_folder_add_folder( cache, parent, itemFolder );
1966                 itemGFolder = NULL;
1967         }
1968         else if( node->type == TEMPNODE_GROUP ) {
1969                 ItemGroup *itemGroup;
1970                 gchar *fName;
1971
1972                 /* Create a folder for group */
1973                 fName = g_strdup_printf( "Cvt - %s", node->name );
1974                 itemGFolder = addritem_create_item_folder();
1975                 addritem_folder_set_name( itemGFolder, fName );
1976                 addrcache_id_folder( cache, itemGFolder );
1977                 addrcache_folder_add_folder( cache, parent, itemGFolder );
1978                 g_free( fName );
1979
1980                 /* Add group into folder */
1981                 itemGroup = addritem_create_item_group();
1982                 addritem_group_set_name( itemGroup, node->name );
1983                 addrcache_id_group( cache, itemGroup );
1984                 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
1985                 itemGParent = itemGroup;
1986         }
1987         else if( node->type == TEMPNODE_ADDRESS ) {
1988                 ItemPerson *itemPerson;
1989                 ItemEMail *itemEMail;
1990
1991                 /* Create person and email objects */
1992                 itemPerson = addritem_create_item_person();
1993                 addritem_person_set_common_name( itemPerson, node->name );
1994                 addrcache_id_person( cache, itemPerson );
1995                 itemEMail = addritem_create_item_email();
1996                 addritem_email_set_address( itemEMail, node->address );
1997                 addritem_email_set_remarks( itemEMail, node->remarks );
1998                 addrcache_id_email( cache, itemEMail );
1999                 addrcache_person_add_email( cache, itemPerson, itemEMail );
2000
2001                 /* Add person into appropriate folder */
2002                 if( itemGFolder ) {
2003                         addrcache_folder_add_person( cache, itemGFolder, itemPerson );
2004                 }
2005                 else {
2006                         addrcache_folder_add_person( cache, parent, itemPerson );
2007                 }
2008
2009                 /* Add email address only into group */
2010                 if( parentGrp ) {
2011                         addrcache_group_add_email( cache, parentGrp, itemEMail );
2012                 }
2013         }
2014
2015         list = node->list;
2016         while( list ) {
2017                 AddressCvtNode *lNode = list->data;
2018                 list = g_list_next( list );
2019                 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
2020         }
2021 }
2022
2023 /*
2024 * Process address book to specified file number.
2025 */
2026 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
2027         gboolean retVal = FALSE;
2028         AddressBookFile *abf = NULL;
2029         AddressCvtNode *rootNode = NULL;
2030         gchar *newFile = NULL;
2031         GList *fileList = NULL;
2032         gint fileNum  = 0;
2033
2034         /* Setup root node */
2035         rootNode = g_new0( AddressCvtNode, 1 );
2036         rootNode->type = TEMPNODE_ROOT;
2037         rootNode->name = g_strdup( "root" );
2038         rootNode->list = NULL;
2039         addrindex_add_obj( file, rootNode );
2040         /* addrindex_print_node( rootNode, stdout ); */
2041
2042         /* Create new address book */
2043         abf = addrbook_create_book();
2044         addrbook_set_name( abf, displayName );
2045         addrbook_set_path( abf, addrIndex->filePath );
2046
2047         /* Determine next available file number */
2048         fileList = addrbook_get_bookfile_list( abf );
2049         if( fileList ) {
2050                 fileNum = 1 + abf->maxValue;
2051         }
2052         g_list_free( fileList );
2053         fileList = NULL;
2054
2055         newFile = addrbook_gen_new_file_name( fileNum );
2056         if( newFile ) {
2057                 addrbook_set_file( abf, newFile );
2058         }
2059
2060         addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
2061
2062         /* addrbook_dump_book( abf, stdout ); */
2063         addrbook_save_data( abf );
2064         addrIndex->retVal = abf->retVal;
2065         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2066
2067         addrbook_free_book( abf );
2068         abf = NULL;
2069         addrindex_free_node( rootNode );
2070         rootNode = NULL;
2071
2072         /* Create entries in address index */
2073         if( retVal ) {
2074                 abf = addrbook_create_book();
2075                 addrbook_set_name( abf, displayName );
2076                 addrbook_set_path( abf, addrIndex->filePath );
2077                 addrbook_set_file( abf, newFile );
2078                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2079         }
2080
2081         return retVal;
2082 }
2083
2084 /*
2085 * Process tree converting data.
2086 */
2087 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
2088         guint prev_level;
2089         gchar *element;
2090         GList *attr;
2091         XMLTag *xtag;
2092
2093         /* Process file */
2094         for (;;) {
2095                 prev_level = file->level;
2096                 xml_parse_next_tag( file );
2097                 if (file->level < prev_level) return;
2098
2099                 xtag = xml_get_current_tag( file );
2100                 /* printf( "tag : %d : %s\n", prev_level, xtag->tag ); */
2101                 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
2102                         if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
2103                                 addrIndex->needsConversion = FALSE;
2104                                 addrIndex->wasConverted = TRUE;
2105                                 continue;
2106                         }
2107                         return;
2108                 }
2109                 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
2110                         if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
2111                                 addrIndex->needsConversion = FALSE;
2112                                 addrIndex->wasConverted = TRUE;
2113                                 continue;
2114                         }
2115                         return;
2116                 }
2117                 element = xml_get_element( file );
2118                 attr = xml_get_current_tag_attr( file );
2119                 /* show_attribs( attr ); */
2120                 /* printf( "\ttag  value : %s :\n", element ); */
2121                 addrindex_consume_tree( file );
2122         }
2123 }
2124
2125 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
2126         XMLFile *file = NULL;
2127         gchar *fileSpec;
2128
2129         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
2130         addrIndex->retVal = MGU_NO_FILE;
2131         file = xml_open_file( fileSpec );
2132         g_free( fileSpec );
2133
2134         if( file == NULL ) {
2135                 /* fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); */
2136                 return addrIndex->retVal;
2137         }
2138
2139         addrIndex->retVal = MGU_BAD_FORMAT;
2140         if( xml_get_dtd( file ) == 0 ) {
2141                 if( xml_parse_next_tag( file ) == 0 ) {
2142                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
2143                                 addrindex_convert_tree( addrIndex, file );
2144                         }
2145                 }
2146         }
2147         xml_close_file( file );
2148         return addrIndex->retVal;
2149 }
2150
2151 /*
2152 * Create a new address book file.
2153 */
2154 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
2155         gboolean retVal = FALSE;
2156         AddressBookFile *abf = NULL;
2157         gchar *newFile = NULL;
2158         GList *fileList = NULL;
2159         gint fileNum = 0;
2160
2161         /* Create new address book */
2162         abf = addrbook_create_book();
2163         addrbook_set_name( abf, displayName );
2164         addrbook_set_path( abf, addrIndex->filePath );
2165
2166         /* Determine next available file number */
2167         fileList = addrbook_get_bookfile_list( abf );
2168         if( fileList ) {
2169                 fileNum = 1 + abf->maxValue;
2170         }
2171         g_list_free( fileList );
2172         fileList = NULL;
2173
2174         newFile = addrbook_gen_new_file_name( fileNum );
2175         if( newFile ) {
2176                 addrbook_set_file( abf, newFile );
2177         }
2178
2179         addrbook_save_data( abf );
2180         addrIndex->retVal = abf->retVal;
2181         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2182         addrbook_free_book( abf );
2183         abf = NULL;
2184
2185         /* Create entries in address index */
2186         if( retVal ) {
2187                 abf = addrbook_create_book();
2188                 addrbook_set_name( abf, displayName );
2189                 addrbook_set_path( abf, addrIndex->filePath );
2190                 addrbook_set_file( abf, newFile );
2191                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2192         }
2193
2194         return retVal;
2195 }
2196
2197 /*
2198 * Read data for address index performing a conversion if necesary.
2199 * Enter: addrIndex Address index object.
2200 * return: Status code, from addrIndex->retVal.
2201 * Note: New address book files will be created in directory specified by
2202 * addrIndex. Three files will be created, for the following:
2203 *       "Common addresses"
2204 *       "Personal addresses"
2205 *       "Gathered addresses" - a new address book.
2206 */
2207 gint addrindex_read_data( AddressIndex *addrIndex ) {
2208         g_return_val_if_fail( addrIndex != NULL, -1 );
2209
2210         addrIndex->conversionError = FALSE;
2211         addrindex_read_file( addrIndex );
2212         if( addrIndex->retVal == MGU_SUCCESS ) {
2213                 if( addrIndex->needsConversion ) {
2214                         if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) {
2215                                 addrIndex->conversionError = TRUE;
2216                         }
2217                         else {
2218                                 addrIndex->conversionError = TRUE;
2219                         }
2220                 }
2221                 addrIndex->dirtyFlag = TRUE;
2222         }
2223         return addrIndex->retVal;
2224 }
2225
2226 /*
2227 * Create new address books for a new address index.
2228 * Enter: addrIndex Address index object.
2229 * return: Status code, from addrIndex->retVal.
2230 * Note: New address book files will be created in directory specified by
2231 * addrIndex. Three files will be created, for the following:
2232 *       "Common addresses"
2233 *       "Personal addresses"
2234 *       "Gathered addresses" - a new address book.
2235 */
2236 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
2237         gboolean flg;
2238
2239         g_return_val_if_fail( addrIndex != NULL, -1 );
2240
2241         flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
2242         if( flg ) {
2243                 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
2244                 addrIndex->dirtyFlag = TRUE;
2245         }
2246         return addrIndex->retVal;
2247 }
2248
2249 /* **********************************************************************
2250 * New interface stuff.
2251 * ***********************************************************************
2252 */
2253
2254 /*
2255  * Return modified flag for specified data source.
2256  */
2257 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
2258         gboolean retVal = FALSE;
2259         AddressInterface *iface;
2260
2261         if( ds == NULL ) return retVal;
2262         iface = ds->interface;
2263         if( iface == NULL ) return retVal;
2264         if( iface->getModifyFlag ) {
2265                 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
2266         }
2267         return retVal;
2268 }
2269
2270 /*
2271  * Return accessed flag for specified data source.
2272  */
2273 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
2274         gboolean retVal = FALSE;
2275         AddressInterface *iface;
2276
2277         if( ds == NULL ) return retVal;
2278         iface = ds->interface;
2279         if( iface == NULL ) return retVal;
2280         if( iface->getAccessFlag ) {
2281                 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
2282         }
2283         return retVal;
2284 }
2285
2286 /*
2287  * Return data read flag for specified data source.
2288  */
2289 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
2290         gboolean retVal = TRUE;
2291         AddressInterface *iface;
2292
2293         if( ds == NULL ) return retVal;
2294         iface = ds->interface;
2295         if( iface == NULL ) return retVal;
2296         if( iface->getReadFlag ) {
2297                 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
2298         }
2299         return retVal;
2300 }
2301
2302 /*
2303  * Return status code for specified data source.
2304  */
2305 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
2306         gint retVal = MGU_SUCCESS;
2307         AddressInterface *iface;
2308
2309         if( ds == NULL ) return retVal;
2310         iface = ds->interface;
2311         if( iface == NULL ) return retVal;
2312         if( iface->getStatusCode ) {
2313                 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
2314         }
2315         return retVal;
2316 }
2317
2318 /*
2319  * Return data read flag for specified data source.
2320  */
2321 gint addrindex_ds_read_data( AddressDataSource *ds ) {
2322         gint retVal = MGU_SUCCESS;
2323         AddressInterface *iface;
2324
2325         if( ds == NULL ) return retVal;
2326         iface = ds->interface;
2327         if( iface == NULL ) return retVal;
2328         if( iface->getReadData ) {
2329                 retVal = ( iface->getReadData ) ( ds->rawDataSource );
2330         }
2331         return retVal;
2332 }
2333
2334 /*
2335  * Return data read flag for specified data source.
2336  */
2337 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
2338         ItemFolder *retVal = NULL;
2339         AddressInterface *iface;
2340
2341         if( ds == NULL ) return retVal;
2342         iface = ds->interface;
2343         if( iface == NULL ) return retVal;
2344         if( iface->getRootFolder ) {
2345                 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
2346         }
2347         return retVal;
2348 }
2349
2350 /*
2351  * Return list of folders for specified data source.
2352  */
2353 GList *addrindex_ds_get_list_folder( AddressDataSource *ds ) {
2354         GList *retVal = FALSE;
2355         AddressInterface *iface;
2356
2357         if( ds == NULL ) return retVal;
2358         iface = ds->interface;
2359         if( iface == NULL ) return retVal;
2360         if( iface->getListFolder ) {
2361                 retVal = ( iface->getListFolder ) ( ds->rawDataSource );
2362         }
2363         return retVal;
2364 }
2365
2366 /*
2367  * Return list of persons in root folder for specified data source.
2368  */
2369 GList *addrindex_ds_get_list_person( AddressDataSource *ds ) {
2370         GList *retVal = FALSE;
2371         AddressInterface *iface;
2372
2373         if( ds == NULL ) return retVal;
2374         iface = ds->interface;
2375         if( iface == NULL ) return retVal;
2376         if( iface->getListPerson ) {
2377                 retVal = ( iface->getListPerson ) ( ds->rawDataSource );
2378         }
2379         return retVal;
2380 }
2381
2382 /*
2383  * Return name for specified data source.
2384  */
2385 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
2386         gchar *retVal = FALSE;
2387         AddressInterface *iface;
2388
2389         if( ds == NULL ) return retVal;
2390         iface = ds->interface;
2391         if( iface == NULL ) return retVal;
2392         if( iface->getName ) {
2393                 retVal = ( iface->getName ) ( ds->rawDataSource );
2394         }
2395         return retVal;
2396 }
2397
2398 /*
2399  * Set the access flag inside the data source.
2400  */
2401 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
2402         AddressInterface *iface;
2403
2404         if( ds == NULL ) return;
2405         iface = ds->interface;
2406         if( iface == NULL ) return;
2407         if( iface->setAccessFlag ) {
2408                 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
2409         }
2410 }
2411
2412 /*
2413  * Return read only flag for specified data source.
2414  */
2415 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
2416         AddressInterface *iface;
2417         if( ds == NULL ) return TRUE;
2418         iface = ds->interface;
2419         if( iface == NULL ) return TRUE;
2420         return iface->readOnly;
2421 }
2422
2423 /*
2424  * Return list of all persons for specified data source.
2425  */
2426 GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
2427         GList *retVal = NULL;
2428         AddressInterface *iface;
2429
2430         if( ds == NULL ) return retVal;
2431         iface = ds->interface;
2432         if( iface == NULL ) return retVal;
2433         if( iface->getAllPersons ) {
2434                 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
2435         }
2436         return retVal;
2437 }
2438
2439 /*
2440  * Return list of all groups for specified data source.
2441  */
2442 GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
2443         GList *retVal = NULL;
2444         AddressInterface *iface;
2445
2446         if( ds == NULL ) return retVal;
2447         iface = ds->interface;
2448         if( iface == NULL ) return retVal;
2449         if( iface->getAllGroups ) {
2450                 retVal = ( iface->getAllGroups ) ( ds->rawDataSource );
2451         }
2452         return retVal;
2453 }
2454
2455 /* **********************************************************************
2456 * Address search stuff.
2457 * ***********************************************************************
2458 */
2459
2460 /**
2461  * Current query ID. This is incremented for each query created.
2462  */
2463 static gint _currentQueryID_ = 0;
2464
2465 /*
2466  * Variables for the search that is being performed.
2467  */
2468 static gchar *_searchTerm_ = NULL;
2469 static gpointer _searchTarget_ = NULL;
2470 static AddrSearchCallbackFunc *_searchCallback_ = NULL;
2471
2472 /**
2473  * Setup or register the search that will be performed.
2474  * \param addrIndex  Address index object.
2475  * \param searchTerm Search term. A private copy will be made.
2476  * \param target     Target object that will receive data.
2477  * \param callBack   Callback function.
2478  * \return ID allocated to query that will be executed.
2479  */
2480 gint addrindex_setup_search(
2481         AddressIndex *addrIndex, const gchar *searchTerm,
2482         const gpointer target, AddrSearchCallbackFunc callBack )
2483 {
2484         gint queryID;
2485
2486         /* printf( "search term ::%s::\n", searchTerm ); */
2487         g_free( _searchTerm_ );
2488         _searchTerm_ = g_strdup( searchTerm );
2489
2490         queryID = ++_currentQueryID_;
2491         _searchTarget_ = target;
2492         _searchCallback_ = callBack;
2493         /* printf( "query ID ::%d::\n", queryID ); */
2494         return queryID;
2495 }
2496
2497 /**
2498  * Perform the search for specified address cache.
2499  * \param cache Cache to be searched.
2500  * \param queryID ID of search query to be executed.
2501  */
2502 static void addrindex_search_cache( AddressCache *cache, const gint queryID ) {
2503         AddrCacheIndex *index;
2504         GList *listEMail;
2505
2506         index = cache->searchIndex;
2507         if( index == NULL ) return;
2508         if( index->invalid ) {
2509                 addrcache_build_index( cache );
2510         }
2511
2512         /*
2513         printf( "query ::%d:: searching index for ::%s::\n", queryID, _searchTerm_ );
2514         */
2515         listEMail = addrcindex_search( index, _searchTerm_ );
2516         ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
2517         g_list_free( listEMail );
2518         listEMail = NULL;
2519         /* printf( "searching index done\n" ); */
2520 }
2521
2522 #ifdef USE_LDAP
2523 /**
2524  * LDAP callback entry point for each address entry found.
2525  * \param qry       LDAP query.
2526  * \param listEMail List of Item EMail objects found.
2527  */
2528 static void addrindex_ldap_entry_cb( LdapQuery *qry, GList *listEMail ) {
2529         GList *node;
2530
2531         /*
2532         printf( "\naddrindex::addrindex_ldap_entry_cb ::%s::\n", qry->queryName );
2533         */
2534         node = listEMail;
2535         while( node ) {
2536                 ItemEMail *email = node->data;
2537                 /* printf( "\temail ::%s::\n", email->address ); */
2538                 node = g_list_next( node );
2539         }
2540         if( _searchCallback_ ) {
2541                 ( _searchCallback_ ) ( qry->queryID, listEMail, _searchTarget_ );
2542         }
2543         g_list_free( listEMail );
2544 }
2545
2546 /**
2547  * LDAP callback entry point for completion of search.
2548  * \param qry LDAP query.
2549  */
2550 static void addrindex_ldap_end_cb( LdapQuery *qry ) {
2551         /* printf( "\naddrindex::addrindex_ldap_end_cb ::%s::\n", qry->queryName ); */
2552 }
2553
2554 /**
2555  * Return results of previous query.
2556  * \param folder.
2557  * \return List of ItemEMail objects.
2558  */
2559 static void addrindex_ldap_use_previous( const ItemFolder *folder, const gint queryID )
2560 {
2561         GList *listEMail;
2562         GList *node;
2563         GList *nodeEM;
2564
2565         listEMail = NULL;
2566         if( _searchCallback_ ) {
2567                 node = folder->listPerson;
2568                 while( node ) {
2569                         AddrItemObject *aio = node->data;
2570                         if( aio &&  aio->type == ITEMTYPE_PERSON ) {
2571                                 ItemPerson *person = node->data;
2572                                 nodeEM = person->listEMail;
2573                                 while( nodeEM ) {
2574                                         ItemEMail *email = nodeEM->data;
2575                                         nodeEM = g_list_next( nodeEM );
2576                                         listEMail = g_list_append( listEMail, email );
2577                                 }
2578                         }
2579                         node = g_list_next( node );
2580                 }
2581                 ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
2582                 g_list_free( listEMail );
2583         }
2584 }
2585
2586 LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
2587
2588 /**
2589  * Construct an LDAP query and initiate an LDAP search.
2590  * \param server  LDAP server object.
2591  * \param queryID ID of search query to be executed.
2592  */
2593 static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
2594         LdapQuery *qry;
2595         gchar *name;
2596
2597         if( ! server->searchFlag ) return;
2598         /* printf( "Searching ::%s::\n", ldapsvr_get_name( server ) ); */
2599
2600         /* Retire any aged queries */
2601         ldapsvr_retire_query( server );
2602
2603         /* Test whether any queries for the same term exist */
2604         qry = ldapsvr_locate_query( server, _searchTerm_ );
2605         if( qry ) {
2606                 ItemFolder *folder = qry->folder;
2607
2608                 /* Touch query to ensure it hangs around for a bit longer */            
2609                 ldapqry_touch( qry );
2610                 if( folder ) {
2611                         addrindex_ldap_use_previous( folder, queryID );
2612                         return;
2613                 }
2614         }
2615
2616         /* Construct a query */
2617         qry = ldapqry_create();
2618         ldapqry_set_query_id( qry, queryID );
2619         ldapqry_set_search_value( qry, _searchTerm_ );
2620         ldapqry_set_query_type( qry, LDAPQUERY_DYNAMIC );
2621         ldapqry_set_callback_entry( qry, addrindex_ldap_entry_cb );
2622         ldapqry_set_callback_end( qry, addrindex_ldap_end_cb );
2623
2624         /* Name the query */
2625         name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
2626         ldapqry_set_name( qry, name );
2627         g_free( name );
2628
2629         ldapsvr_add_query( server, qry );
2630         /* printf( "addrindex_search_ldap::executing dynamic search...\n" ); */
2631         ldapsvr_execute_query( server, qry );
2632 }
2633
2634 /**
2635  * Construct an LDAP query and initiate an LDAP search.
2636  * \param server      LDAP server object to search.
2637  * \param searchTerm  Search term to locate.
2638  * \param callbackEnd Function to call when search has terminated.
2639  *
2640  */
2641 void addrindex_search_ldap_noid(
2642         LdapServer *server, const gchar *searchTerm, void * callbackEnd )
2643 {
2644         LdapQuery *qry;
2645         gchar *name;
2646
2647         /* Construct a query */
2648         qry = ldapqry_create();
2649         ldapqry_set_search_value( qry, searchTerm );
2650         ldapqry_set_query_type( qry, LDAPQUERY_STATIC );
2651         ldapqry_set_callback_end( qry, callbackEnd );
2652
2653         /* Name the query */
2654         name = g_strdup_printf( "Static Search for '%s'", searchTerm );
2655         ldapqry_set_name( qry, name );
2656         g_free( name );
2657
2658         ldapsvr_add_query( server, qry );
2659         /* printf( "addrindex_search_ldap_noid::executing static search...\n" ); */
2660         ldapsvr_execute_query( server, qry );
2661 }
2662 #endif
2663
2664 /**
2665  * Perform the previously registered search.
2666  * \param  addrIndex  Address index object.
2667  * \param  queryID    ID of search query to be executed.
2668  * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2669  *         failed.
2670  */
2671 gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
2672         AddressInterface *iface;
2673         AddressDataSource *ds;
2674         AddressCache *cache;
2675         GList *nodeIf;
2676         GList *nodeDS;
2677         gint type;
2678
2679         /* printf( "addrindex_start_search::%d::\n", queryID ); */
2680         nodeIf = addrIndex->searchOrder;
2681         while( nodeIf ) {
2682                 iface = nodeIf->data;
2683                 nodeIf = g_list_next( nodeIf );
2684
2685                 if( ! iface->useInterface ) {
2686                         continue;
2687                 }
2688
2689                 type = iface->type;
2690                 nodeDS = iface->listSource;
2691                 while( nodeDS ) {
2692                         ds = nodeDS->data;
2693                         nodeDS = g_list_next( nodeDS );
2694                         cache = NULL;
2695
2696                         if( type == ADDR_IF_BOOK ) {
2697                                 AddressBookFile *abf = ds->rawDataSource;
2698                                 cache = abf->addressCache;
2699                         }
2700                         else if( type == ADDR_IF_VCARD ) {
2701                                 VCardFile *vcf = ds->rawDataSource;
2702                                 cache = vcf->addressCache;
2703                         }
2704 #ifdef USE_JPILOT
2705                         else if( type == ADDR_IF_JPILOT ) {
2706                                 JPilotFile *jpf = ds->rawDataSource;
2707                                 cache = jpf->addressCache;
2708                         }
2709 #endif
2710 #ifdef USE_LDAP
2711                         else if( type == ADDR_IF_LDAP ) {
2712                                 LdapServer *server = ds->rawDataSource;
2713                                 addrindex_search_ldap( server, queryID );
2714                         }
2715 #endif
2716                         if( cache ) {
2717                                 addrindex_search_cache( cache, queryID );
2718                         }
2719                 }
2720         }
2721         return TRUE;
2722 }
2723
2724 /**
2725  * Stop the previously registered search.
2726  * \param addrIndex Address index object.
2727  * \param queryID ID of search query to stop.
2728  */
2729 void addrindex_stop_search( AddressIndex *addrIndex, const gint queryID ){
2730 #ifdef USE_LDAP
2731         AddressInterface *iface;
2732         AddressDataSource *ds;
2733         GList *nodeIf;
2734         GList *nodeDS;
2735         gint type;
2736
2737         /* If query ID does not match, search has not been setup */
2738         /* if( queryID != _queryID_ ) return; */
2739
2740         /* printf( "addrindex_stop_search::%d::\n", queryID ); */
2741         nodeIf = addrIndex->searchOrder;
2742         while( nodeIf ) {
2743                 iface = nodeIf->data;
2744                 nodeIf = g_list_next( nodeIf );
2745
2746                 if( ! iface->useInterface ) {
2747                         continue;
2748                 }
2749
2750                 type = iface->type;
2751                 nodeDS = iface->listSource;
2752                 while( nodeDS ) {
2753                         ds = nodeDS->data;
2754                         nodeDS = g_list_next( nodeDS );
2755                         if( type == ADDR_IF_LDAP ) {
2756                                 LdapServer *server = ds->rawDataSource;
2757                                 ldapsvr_stop_all_query( server );
2758                         }
2759                 }
2760         }
2761 #endif
2762 }
2763
2764 /**
2765  * Read all address books that do not support dynamic queries.
2766  * \param addrIndex Address index object.
2767  */
2768 void addrindex_read_all( AddressIndex *addrIndex ) {
2769         AddressInterface *iface;
2770         AddressDataSource *ds;
2771         GList *nodeIf;
2772         GList *nodeDS;
2773
2774         nodeIf = addrIndex->searchOrder;
2775         while( nodeIf ) {
2776                 iface = nodeIf->data;
2777                 nodeIf = g_list_next( nodeIf );
2778
2779                 if( ! iface->useInterface ) {
2780                         continue;
2781                 }
2782                 if( iface->externalQuery ) {
2783                         continue;
2784                 }
2785                 nodeDS = iface->listSource;
2786                 while( nodeDS ) {
2787                         ds = nodeDS->data;
2788                         nodeDS = g_list_next( nodeDS );
2789
2790                         /* Read address book */
2791                         if( addrindex_ds_get_modify_flag( ds ) ) {
2792                                 addrindex_ds_read_data( ds );
2793                                 continue;
2794                         }
2795
2796                         if( ! addrindex_ds_get_read_flag( ds ) ) {
2797                                 addrindex_ds_read_data( ds );
2798                                 continue;
2799                         }
2800                 }
2801         }
2802         addrIndex->loadedFlag = TRUE;
2803 }
2804
2805 /**
2806  * Perform a simple search of all non-query type data sources for specified
2807  * search term. If several entries are found, only the first item is
2808  * returned. Interfaces that require a time-consuming "external query" are
2809  * ignored for this search.
2810  *
2811  * \param  addrIndex  Address index object.
2812  * \param  searchTerm Search term to find. Typically an email address.
2813  * \return List of references to zero or mail E-Mail object that was found in
2814  *         the address books, or <i>NULL</i> if nothing found. This list
2815  *         *SHOULD* be freed when done.
2816  */
2817 GList *addrindex_quick_search_list(
2818                 AddressIndex *addrIndex, const gchar *searchTerm )
2819 {
2820         GList *listRet = NULL;
2821         GList *listEMail;
2822         AddressInterface *iface;
2823         AddressDataSource *ds;
2824         AddressCache *cache;
2825         AddrCacheIndex *index;
2826         ItemEMail *email;
2827         GList *nodeIf;
2828         GList *nodeDS;
2829         GList *nodeEM;
2830         gint type;
2831
2832         nodeIf = addrIndex->searchOrder;
2833         while( nodeIf ) {
2834                 iface = nodeIf->data;
2835                 nodeIf = g_list_next( nodeIf );
2836
2837                 if( ! iface->useInterface ) {
2838                         /* Ignore interfaces that don't have a library */
2839                         continue;
2840                 }
2841                 if( iface->externalQuery ) {
2842                         /* Ignore interfaces that require a "query" */
2843                         continue;
2844                 }
2845
2846                 type = iface->type;
2847                 nodeDS = iface->listSource;
2848                 while( nodeDS ) {
2849                         ds = nodeDS->data;
2850                         nodeDS = g_list_next( nodeDS );
2851                         cache = NULL;
2852
2853                         if( type == ADDR_IF_BOOK ) {
2854                                 AddressBookFile *abf = ds->rawDataSource;
2855                                 cache = abf->addressCache;
2856                         }
2857                         else if( type == ADDR_IF_VCARD ) {
2858                                 VCardFile *vcf = ds->rawDataSource;
2859                                 cache = vcf->addressCache;
2860                         }
2861 #ifdef USE_JPILOT
2862                         else if( type == ADDR_IF_JPILOT ) {
2863                                 JPilotFile *jpf = ds->rawDataSource;
2864                                 cache = jpf->addressCache;
2865                         }
2866 #endif
2867                         if( cache ) {
2868                                 index = cache->searchIndex;
2869                                 if( index == NULL ) {
2870                                         continue;
2871                                 }
2872                                 if( index->invalid ) {
2873                                         addrcache_build_index( cache );
2874                                 }
2875                                 listEMail = addrcindex_search( index, searchTerm );
2876                                 nodeEM = listEMail;
2877                                 while( nodeEM ) {
2878                                         email = listEMail->data;
2879                                         listRet = g_list_append( listRet, email );
2880                                         nodeEM = g_list_next( nodeEM );
2881                                 }
2882                                 g_list_free( listEMail );
2883                         }
2884                 }
2885         }
2886         return listRet;
2887 }
2888
2889 /**
2890  * Perform a simple search of all non-query type data sources for specified
2891  * search term. If several entries are found, only the first item is
2892  * returned. Interfaces that require a time-consuming "external query" are
2893  * ignored for this search.
2894  *
2895  * \param  addrIndex  Address index object.
2896  * \param  searchTerm Search term to find. Typically an email address.
2897  * \return Reference to a single E-Mail object that was found in the address
2898  *         book, or <i>NULL</i> if nothing found. This should *NOT* be freed
2899  *         when done.
2900  */
2901 ItemEMail *addrindex_quick_search_single(
2902                 AddressIndex *addrIndex, const gchar *searchTerm )
2903 {
2904         ItemEMail *email = NULL;
2905         AddressInterface *iface;
2906         AddressDataSource *ds;
2907         AddressCache *cache;
2908         AddrCacheIndex *index;
2909         GList *listEMail;
2910         GList *nodeIf;
2911         GList *nodeDS;
2912         gint type;
2913
2914         /* printf( "addrindex_quick_search::%s::\n", searchTerm ); */
2915         nodeIf = addrIndex->searchOrder;
2916         while( nodeIf ) {
2917                 iface = nodeIf->data;
2918                 nodeIf = g_list_next( nodeIf );
2919
2920                 if( ! iface->useInterface ) {
2921                         continue;
2922                 }
2923                 if( iface->externalQuery ) {
2924                         continue;
2925                 }
2926
2927                 type = iface->type;
2928                 nodeDS = iface->listSource;
2929                 while( nodeDS ) {
2930                         ds = nodeDS->data;
2931                         nodeDS = g_list_next( nodeDS );
2932                         cache = NULL;
2933
2934                         if( type == ADDR_IF_BOOK ) {
2935                                 AddressBookFile *abf = ds->rawDataSource;
2936                                 cache = abf->addressCache;
2937                         }
2938                         else if( type == ADDR_IF_VCARD ) {
2939                                 VCardFile *vcf = ds->rawDataSource;
2940                                 cache = vcf->addressCache;
2941                         }
2942 #ifdef USE_JPILOT
2943                         else if( type == ADDR_IF_JPILOT ) {
2944                                 JPilotFile *jpf = ds->rawDataSource;
2945                                 cache = jpf->addressCache;
2946                         }
2947 #endif
2948                         if( cache ) {
2949                                 index = cache->searchIndex;
2950                                 if( index == NULL ) {
2951                                         continue;
2952                                 }
2953                                 if( index->invalid ) {
2954                                         addrcache_build_index( cache );
2955                                 }
2956
2957                                 listEMail = addrcindex_search( index, searchTerm );
2958                                 if( listEMail ) {
2959                                         email = listEMail->data;
2960                                 }
2961                                 g_list_free( listEMail );
2962                                 if( email ) break;
2963                         }
2964                 }
2965         }
2966         return email;
2967 }
2968
2969 /*
2970  * End of Source.
2971  */
2972
2973