7de4fda13cb76156df5eb2ec74d05176ffb22fc1
[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  * Free up address index.
676  * \param addrIndex Address index.
677  */
678 void addrindex_free_index( AddressIndex *addrIndex ) {
679         GList *node;
680
681         g_return_if_fail( addrIndex != NULL );
682
683         /* Search stuff */
684         g_list_free( addrIndex->searchOrder );
685         addrIndex->searchOrder = NULL;
686
687         /* Free internal storage */
688         g_free( ADDRITEM_ID(addrIndex) );
689         g_free( ADDRITEM_NAME(addrIndex) );
690         g_free( addrIndex->filePath );
691         g_free( addrIndex->fileName );
692
693         /* Clear pointers */    
694         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
695         ADDRITEM_ID(addrIndex) = NULL;
696         ADDRITEM_NAME(addrIndex) = NULL;
697         ADDRITEM_PARENT(addrIndex) = NULL;
698         ADDRITEM_SUBTYPE(addrIndex) = 0;
699         addrIndex->filePath = NULL;
700         addrIndex->fileName = NULL;
701         addrIndex->retVal = MGU_SUCCESS;
702         addrIndex->needsConversion = FALSE;
703         addrIndex->wasConverted = FALSE;
704         addrIndex->conversionError = FALSE;
705         addrIndex->lastType = ADDR_IF_NONE;
706         addrIndex->dirtyFlag = FALSE;
707
708         /* Free up interfaces */        
709         node = addrIndex->interfaceList;
710         while( node ) {
711                 AddressInterface *iface = node->data;
712                 addrindex_free_interface( iface );
713                 node = g_list_next( node );
714         }
715         g_list_free( addrIndex->interfaceList );
716         addrIndex->interfaceList = NULL;
717
718         /* Free up hash cache */
719         addrindex_free_cache_hash( addrIndex->hashCache );
720         addrIndex->hashCache = NULL;
721
722         addrIndex->loadedFlag = FALSE;
723
724         g_free( addrIndex );
725 }
726
727 /**
728  * Print address index.
729  * \param addrIndex Address index.
730  * \parem stream    Stream to print.
731 */
732 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
733         g_return_if_fail( addrIndex != NULL );
734         fprintf( stream, "AddressIndex:\n" );
735         fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
736         fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
737         fprintf( stream, "\t   status: %d\n", addrIndex->retVal );
738         fprintf( stream, "\tconverted: '%s'\n",
739                         addrIndex->wasConverted ? "yes" : "no" );
740         fprintf( stream, "\tcvt error: '%s'\n",
741                         addrIndex->conversionError ? "yes" : "no" );
742         fprintf( stream, "\t---\n" );
743 }
744
745 /**
746  * Retrieve reference to address interface for specified interface type.
747  * \param  addrIndex Address index.
748  * \param  ifType Interface type.
749  * \return Address interface, or NULL if not found.
750  */
751 AddressInterface *addrindex_get_interface(
752         AddressIndex *addrIndex, AddressIfType ifType )
753 {
754         AddressInterface *retVal = NULL;
755         GList *node;
756
757         g_return_val_if_fail( addrIndex != NULL, NULL );
758
759         node = addrIndex->interfaceList;
760         while( node ) {
761                 AddressInterface *iface = node->data;
762                 node = g_list_next( node );
763                 if( iface->type == ifType ) {
764                         retVal = iface;
765                         break;
766                 }
767         }
768         return retVal;
769 }
770
771 /**
772  * Add raw data source to index. The raw data object (an AddressBookFile or
773  * VCardFile object, for example) should be supplied as the raw dataSource
774  * argument.
775  *
776  * \param  addrIndex Address index.
777  * \param ifType     Interface type to add.
778  * \param dataSource Actual raw data source to add. 
779  * \return Data source added, or NULL if invalid interface type.
780  */
781 AddressDataSource *addrindex_index_add_datasource(
782         AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
783 {
784         AddressInterface *iface;
785         AddressDataSource *ds = NULL;
786
787         g_return_val_if_fail( addrIndex != NULL, NULL );
788         g_return_val_if_fail( dataSource != NULL, NULL );
789
790         iface = addrindex_get_interface( addrIndex, ifType );
791         if( iface ) {
792                 ds = addrindex_create_datasource( ifType );
793                 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
794                 ds->type = ifType;
795                 ds->rawDataSource = dataSource;
796                 ds->interface = iface;
797                 iface->listSource = g_list_append( iface->listSource, ds );
798                 addrIndex->dirtyFlag = TRUE;
799
800                 addrindex_hash_add_cache( addrIndex, ds );
801         }
802         return ds;
803 }
804
805 /**
806  * Remove specified data source from index.
807  * \param  addrIndex Address index.
808  * \param  dataSource Data source to add. 
809  * \return Reference to data source if removed, or NULL if data source was not
810  *         found in index. Note the this object must still be freed.
811  */
812 AddressDataSource *addrindex_index_remove_datasource(
813         AddressIndex *addrIndex, AddressDataSource *dataSource )
814 {
815         AddressDataSource *retVal = FALSE;
816         AddressInterface *iface;
817
818         g_return_val_if_fail( addrIndex != NULL, NULL );
819         g_return_val_if_fail( dataSource != NULL, NULL );
820
821         iface = addrindex_get_interface( addrIndex, dataSource->type );
822         if( iface ) {
823                 iface->listSource = g_list_remove( iface->listSource, dataSource );
824                 addrIndex->dirtyFlag = TRUE;
825                 dataSource->interface = NULL;
826
827                 /* Remove cache from hash table */
828                 addrindex_hash_remove_cache( addrIndex, dataSource );
829
830                 retVal = dataSource;
831         }
832         return retVal;
833 }
834
835 /**
836  * Retrieve a reference to address interface for specified interface type and
837  * XML interface tag name.
838  * \param  addrIndex Address index.
839  * \param  tag       XML interface tag name to match.
840  * \param  ifType    Interface type to match.
841  * \return Reference to address index, or NULL if not found in index.
842  */
843 static AddressInterface *addrindex_tag_get_interface(
844         AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
845 {
846         AddressInterface *retVal = NULL;
847         GList *node = addrIndex->interfaceList;
848
849         while( node ) {
850                 AddressInterface *iface = node->data;
851                 node = g_list_next( node );
852                 if( tag ) {
853                         if( strcmp( iface->listTag, tag ) == 0 ) {
854                                 retVal = iface;
855                                 break;
856                         }
857                 }
858                 else {
859                         if( iface->type == ifType ) {
860                                 retVal = iface;
861                                 break;
862                         }
863                 }
864         }
865         return retVal;
866 }
867
868 /**
869  * Retrieve a reference to address interface for specified interface type and
870  * XML datasource tag name.
871  * \param  addrIndex Address index.
872  * \param  ifType    Interface type to match.
873  * \param  tag       XML datasource tag name to match.
874  * \return Reference to address index, or NULL if not found in index.
875  */
876 static AddressInterface *addrindex_tag_get_datasource(
877         AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
878 {
879         AddressInterface *retVal = NULL;
880         GList *node = addrIndex->interfaceList;
881
882         while( node ) {
883                 AddressInterface *iface = node->data;
884                 node = g_list_next( node );
885                 if( iface->type == ifType && iface->itemTag ) {
886                         if( strcmp( iface->itemTag, tag ) == 0 ) {
887                                 retVal = iface;
888                                 break;
889                         }
890                 }
891         }
892         return retVal;
893 }
894
895 /* **********************************************************************
896 * Interface XML parsing functions.
897 * ***********************************************************************
898 */
899
900 /**
901  * Write start of XML element to file.
902  * \param fp   File.
903  * \param lvl  Indentation level.
904  * \param name Element name.
905  */
906 static void addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
907         gint i;
908         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
909         fputs( "<", fp );
910         fputs( name, fp );
911 }
912
913 /**
914  * Write end of XML element to file.
915  * \param fp   File.
916  * \param lvl  Indentation level.
917  * \param name Element name.
918  */
919 static void addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
920         gint i;
921         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
922         fputs( "</", fp );
923         fputs( name, fp );
924         fputs( ">\n", fp );
925 }
926
927 /**
928  * Write XML attribute to file.
929  * \param fp    File.
930  * \param name  Attribute name.
931  * \param value Attribute value.
932  */
933 static void addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
934         fputs( " ", fp );
935         fputs( name, fp );
936         fputs( "=\"", fp );
937         xml_file_put_escape_str( fp, value );
938         fputs( "\"", fp );
939 }
940
941 /**
942  * Return DOM fragment for current XML tag from file.
943  * \param  file XML file being processed.
944  * \return Fragment representing DOM fragment for configuration element.
945  */
946 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
947         AddressIfFragment *fragment;
948         AddressIfFragment *child;
949         AddressIfAttrib *nv;
950         XMLTag *xtag;
951         GList *list;
952         GList *attr;
953         gchar *name;
954         gchar *value;
955         guint prevLevel;
956         gint rc;
957
958         prevLevel = file->level;
959
960         /* Get current tag name */
961         xtag = xml_get_current_tag( file );
962
963         /* Create new fragment */
964         fragment = g_new0( AddressIfFragment, 1 );
965         fragment->name = g_strdup( xtag->tag );
966         fragment->children = NULL;
967         fragment->attributes = NULL;
968
969         /* Read attributes */
970         list = NULL;
971         attr = xml_get_current_tag_attr( file );
972         while( attr ) {
973                 name = ((XMLAttr *)attr->data)->name;
974                 value = ((XMLAttr *)attr->data)->value;
975                 nv = g_new0( AddressIfAttrib, 1 );
976                 nv->name = g_strdup( name );
977                 nv->value = g_strdup( value );
978                 list = g_list_append( list, nv );
979                 attr = g_list_next( attr );
980         }
981         fragment->attributes = list;
982
983         /* Now read the children */
984         while( TRUE ) {
985                 rc = xml_parse_next_tag( file );
986                 if( rc != 0 ) {
987                         /* End of file? */
988                         break;
989                 }
990                 if( file->level < prevLevel ) {
991                         /* We must be above level we start at */
992                         break;
993                 }
994                 child = addrindex_read_fragment( file );
995                 fragment->children = g_list_append( fragment->children, child );
996         }
997
998         return fragment;
999 }
1000
1001 /**
1002  * Write DOM fragment to file.
1003  * \param fp       File to write.
1004  * \param fragment DOM fragment for configuration element.
1005  * \param lvl      Indent level.
1006  */
1007 static void addrindex_write_fragment(
1008                 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1009 {
1010         GList *node;
1011
1012         if( fragment ) {
1013                 addrindex_write_elem_s( fp, lvl, fragment->name );
1014                 node = fragment->attributes;
1015                 while( node ) {
1016                         AddressIfAttrib *nv = node->data;
1017                         addrindex_write_attr( fp, nv->name, nv->value );
1018                         node = g_list_next( node );
1019                 }
1020                 if( fragment->children ) {
1021                         fputs(" >\n", fp);
1022
1023                         /* Output children */
1024                         node = fragment->children;
1025                         while( node ) {
1026                                 AddressIfFragment *child = node->data;
1027                                 addrindex_write_fragment( fp, child, 1+lvl );
1028                                 node = g_list_next( node );
1029                         }
1030
1031                         /* Output closing tag */
1032                         addrindex_write_elem_e( fp, lvl, fragment->name );
1033                 }
1034                 else {
1035                         fputs(" />\n", fp);
1036                 }
1037         }
1038 }
1039
1040 /*
1041 static void addrindex_print_fragment_r(
1042                 const AddressIfFragment *fragment, FILE *stream, gint lvl )
1043 {
1044         GList *node;
1045         gint i;
1046
1047         for( i = 0; i < lvl; i++ )
1048                 fprintf( stream, "  " );
1049         fprintf( stream, "Element:%s:\n", fragment->name );
1050         node = fragment->attributes;
1051         while( node ) {
1052                 AddressIfAttrib *nv = node->data;
1053                 for( i = 0; i < lvl; i++ )
1054                         fprintf( stream, "  " );
1055                 fprintf( stream, "    %s : %s\n", nv->name, nv->value );
1056                 node = g_list_next( node );
1057         }
1058         node = fragment->children;
1059         while( node ) {
1060                 AddressIfFragment *child = node->data;
1061                 addrindex_print_fragment_r( child, stream, 1+lvl );
1062                 node = g_list_next( node );
1063         }
1064 }
1065
1066 static void addrindex_print_fragment( const AddressIfFragment *fragment, FILE *stream ) {
1067         addrindex_print_fragment_r( fragment, stream, 0 );
1068 }
1069 */
1070
1071 /**
1072  * Read/parse address index file, creating a data source for a regular
1073  * intrinsic XML addressbook.
1074  * \param  file Address index file.
1075  * \return Data source.
1076  */
1077 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1078         AddressDataSource *ds;
1079         AddressBookFile *abf;
1080         GList *attr;
1081
1082         ds = addrindex_create_datasource( ADDR_IF_BOOK );
1083         abf = addrbook_create_book();
1084         attr = xml_get_current_tag_attr( file );
1085         while( attr ) {
1086                 gchar *name = ((XMLAttr *)attr->data)->name;
1087                 gchar *value = ((XMLAttr *)attr->data)->value;
1088                 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1089                         addrbook_set_name( abf, value );
1090                 }
1091                 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1092                         addrbook_set_file( abf, value );
1093                 }
1094                 attr = g_list_next( attr );
1095         }
1096         ds->rawDataSource = abf;
1097         return ds;
1098 }
1099
1100 static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1101         AddressBookFile *abf = ds->rawDataSource;
1102         if( abf ) {
1103                 addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK );
1104                 addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) );
1105                 addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName );
1106                 fputs( " />\n", fp );
1107         }
1108 }
1109
1110 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1111         AddressDataSource *ds;
1112         VCardFile *vcf;
1113         GList *attr;
1114
1115         ds = addrindex_create_datasource( ADDR_IF_VCARD );
1116         vcf = vcard_create();
1117         attr = xml_get_current_tag_attr( file );
1118         while( attr ) {
1119                 gchar *name = ((XMLAttr *)attr->data)->name;
1120                 gchar *value = ((XMLAttr *)attr->data)->value;
1121                 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1122                         vcard_set_name( vcf, value );
1123                 }
1124                 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1125                         vcard_set_file( vcf, value );
1126                 }
1127                 attr = g_list_next( attr );
1128         }
1129         ds->rawDataSource = vcf;
1130         return ds;
1131 }
1132
1133 static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1134         VCardFile *vcf = ds->rawDataSource;
1135         if( vcf ) {
1136                 addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD );
1137                 addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) );
1138                 addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path );
1139                 fputs( " />\n", fp );
1140         }
1141 }
1142
1143 #ifdef USE_JPILOT
1144 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1145         AddressDataSource *ds;
1146         JPilotFile *jpf;
1147         GList *attr;
1148
1149         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1150         jpf = jpilot_create();
1151         attr = xml_get_current_tag_attr( file );
1152         while( attr ) {
1153                 gchar *name = ((XMLAttr *)attr->data)->name;
1154                 gchar *value = ((XMLAttr *)attr->data)->value;
1155                 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1156                         jpilot_set_name( jpf, value );
1157                 }
1158                 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1159                         jpilot_set_file( jpf, value );
1160                 }
1161                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1162                         jpilot_add_custom_label( jpf, value );
1163                 }
1164                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1165                         jpilot_add_custom_label( jpf, value );
1166                 }
1167                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1168                         jpilot_add_custom_label( jpf, value );
1169                 }
1170                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1171                         jpilot_add_custom_label( jpf, value );
1172                 }
1173                 attr = g_list_next( attr );
1174         }
1175         ds->rawDataSource = jpf;
1176         return ds;
1177 }
1178
1179 static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1180         JPilotFile *jpf = ds->rawDataSource;
1181         if( jpf ) {
1182                 gint ind;
1183                 GList *node;
1184                 GList *customLbl = jpilot_get_custom_labels( jpf );
1185                 addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT );
1186                 addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) );
1187                 addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path );
1188                 node = customLbl;
1189                 ind = 1;
1190                 while( node ) {
1191                         gchar name[256];
1192                         g_snprintf( name, sizeof(name), "%s%d",
1193                                     ATTAG_JPILOT_CUSTOM, ind );
1194                         addrindex_write_attr( fp, name, node->data );
1195                         ind++;
1196                         node = g_list_next( node );
1197                 }
1198                 fputs( " />\n", fp );
1199         }
1200 }
1201
1202 #else
1203 /*
1204  * Just read/write DOM fragments (preserve data found in file).
1205  */
1206 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1207         AddressDataSource *ds;
1208
1209         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1210         ds->rawDataSource = addrindex_read_fragment( file );
1211         return ds;
1212 }
1213
1214 static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1215         AddressIfFragment *fragment = ds->rawDataSource;
1216         if( fragment ) {
1217                 addrindex_write_fragment( fp, fragment, lvl );
1218         }
1219 }
1220 #endif
1221
1222 #ifdef USE_LDAP
1223 /**
1224  * Parse LDAP criteria attribute data from XML file.
1225  * \param file Index file.
1226  * \param ctl  LDAP control object to populate.
1227  */
1228 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1229         guint prevLevel;
1230         XMLTag *xtag;
1231         XMLTag *xtagPrev;
1232         gint rc;
1233         GList *attr;
1234         GList *list;
1235         GList *node;
1236
1237         if( file == NULL ) {
1238                 return;
1239         }
1240
1241         list = NULL;
1242         prevLevel = file->level;
1243         xtagPrev = xml_get_current_tag( file );
1244         while( TRUE ) {
1245                 rc = xml_parse_next_tag( file );
1246                 if( rc != 0 ) {
1247                         /* Terminate prematurely */
1248                         mgu_free_dlist( list );
1249                         list = NULL;
1250                         return;
1251                 }
1252                 if( file->level < prevLevel ) {
1253                         /* We must be above level we start at */
1254                         break;
1255                 }
1256
1257                 /* Get a tag (element) */
1258                 xtag = xml_get_current_tag( file );
1259                 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1260                         /* LDAP criteria attribute */
1261                         attr = xml_get_current_tag_attr( file );
1262                         while( attr ) {
1263                                 gchar *name = ((XMLAttr *)attr->data)->name;
1264                                 gchar *value = ((XMLAttr *)attr->data)->value;
1265                                 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1266                                         if( value && strlen( value ) > 0 ) {
1267                                                 list = g_list_append(
1268                                                         list, g_strdup( value ) );
1269                                         }
1270                                 }
1271                                 attr = g_list_next( attr );
1272                         }
1273                 }
1274                 else {
1275                         if( xtag != xtagPrev ) {
1276                                 /* Found a new tag */
1277                                 break;
1278                         }
1279                 }
1280                 xtag = xtagPrev;
1281         }
1282
1283         /* Build list of search attributes */
1284         ldapctl_criteria_list_clear( ctl );
1285         node = list;
1286         while( node ) {
1287                 ldapctl_criteria_list_add( ctl, node->data );
1288                 g_free( node->data );
1289                 node->data = NULL;
1290                 node = g_list_next( node );
1291         }
1292         g_list_free( list );
1293         list = NULL;
1294
1295 }
1296
1297 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1298         AddressDataSource *ds;
1299         LdapServer *server;
1300         LdapControl *ctl;
1301         GList *attr;
1302         gchar *serverName = NULL;
1303         gchar *criteria = NULL;
1304         gboolean bSearch = FALSE;
1305         gboolean cvtFlag = TRUE;
1306
1307         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1308         ctl = ldapctl_create();
1309         attr = xml_get_current_tag_attr( file );
1310         while( attr ) {
1311                 gchar *name = ((XMLAttr *)attr->data)->name;
1312                 gchar *value = ((XMLAttr *)attr->data)->value;
1313                 gint ivalue = atoi( value );
1314
1315                 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
1316                         if( serverName ) g_free( serverName );
1317                         serverName = g_strdup( value );
1318                 }
1319                 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
1320                         ldapctl_set_host( ctl, value );
1321                 }
1322                 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
1323                         ldapctl_set_port( ctl, ivalue );
1324                 }
1325                 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
1326                         ldapctl_set_base_dn( ctl, value );
1327                 }
1328                 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
1329                         ldapctl_set_bind_dn( ctl, value );
1330                 }
1331                 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
1332                         ldapctl_set_bind_password( ctl, value );
1333                 }
1334                 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
1335                         if( criteria ) g_free( criteria );
1336                         criteria = g_strdup( value );
1337                 }
1338                 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
1339                         ldapctl_set_max_entries( ctl, ivalue );
1340                 }
1341                 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
1342                         ldapctl_set_timeout( ctl, ivalue );
1343                 }
1344                 else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
1345                         ldapctl_set_max_query_age( ctl, ivalue );
1346                 }
1347                 else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
1348                         bSearch = FALSE;
1349                         cvtFlag = FALSE;
1350                         if( strcmp( value, "yes" ) == 0 ) {
1351                                 bSearch = TRUE;
1352                         }
1353                 }
1354                 attr = g_list_next( attr );
1355         }
1356
1357         server = ldapsvr_create();
1358         ldapsvr_set_name( server, serverName );
1359         ldapsvr_set_search_flag( server, bSearch );
1360         g_free( serverName );
1361         ldapsvr_set_control( server, ctl );
1362         ds->rawDataSource = server;
1363
1364         addrindex_parse_ldap_attrlist( file, ctl );
1365         /*
1366          * If criteria have been specified and no attributes were listed, then
1367          * convert old style criteria into an attribute list. Any criteria will
1368          * be dropped when saving data.
1369          */
1370         if( criteria ) {
1371                 if( ! ldapctl_get_criteria_list( ctl ) ) {
1372                         ldapctl_parse_ldap_search( ctl, criteria );
1373                 }
1374                 g_free( criteria );
1375         }
1376         /*
1377          * If no search flag was found, then we are converting from old format
1378          * server data to new format.
1379          */
1380         if( cvtFlag ) {
1381                 ldapsvr_set_search_flag( server, TRUE );
1382         }
1383         /* ldapsvr_print_data( server, stdout ); */
1384
1385         return ds;
1386 }
1387
1388 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1389         LdapServer *server = ds->rawDataSource;
1390         LdapControl *ctl = NULL;
1391         GList *node;
1392         gchar value[256];
1393
1394         if( server ) {
1395                 ctl = server->control;
1396         }
1397         if( ctl == NULL ) return;
1398
1399         /* Output start element with attributes */
1400         addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
1401         addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) );
1402         addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName );
1403
1404         sprintf( value, "%d", ctl->port );      
1405         addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
1406
1407         addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN );
1408         addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN );
1409         addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, ctl->bindPass );
1410
1411         sprintf( value, "%d", ctl->maxEntries );
1412         addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
1413         sprintf( value, "%d", ctl->timeOut );
1414         addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
1415         sprintf( value, "%d", ctl->maxQueryAge );
1416         addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value );
1417
1418         addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
1419                         server->searchFlag ? "yes" : "no" );
1420
1421         fputs(" >\n", fp);
1422
1423         /* Output attributes */
1424         node = ldapctl_get_criteria_list( ctl );
1425         while( node ) {
1426                 addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH );
1427                 addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data );
1428                 fputs(" />\n", fp);
1429                 node = g_list_next( node );
1430         }
1431
1432         /* End of element */    
1433         addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP );
1434
1435 }
1436
1437 #else
1438 /*
1439  * Just read/write DOM fragments (preserve data found in file).
1440  */
1441 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1442         AddressDataSource *ds;
1443
1444         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1445         ds->rawDataSource = addrindex_read_fragment( file );
1446         return ds;
1447 }
1448
1449 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1450         AddressIfFragment *fragment = ds->rawDataSource;
1451         if( fragment ) {
1452                 addrindex_write_fragment( fp, fragment, lvl );
1453         }
1454 }
1455 #endif
1456
1457 /* **********************************************************************
1458 * Address index I/O functions.
1459 * ***********************************************************************
1460 */
1461 /**
1462  * Read address index file, creating appropriate data sources for each address
1463  * index file entry.
1464  *
1465  * \param  addrIndex Address index.
1466  * \param  file Address index file.
1467  */
1468 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
1469         guint prev_level;
1470         XMLTag *xtag;
1471         AddressInterface *iface = NULL, *dsIFace = NULL;
1472         AddressDataSource *ds;
1473         gint rc;
1474
1475         addrIndex->loadedFlag = FALSE;
1476         for (;;) {
1477                 prev_level = file->level;
1478                 rc = xml_parse_next_tag( file );
1479                 if( file->level == 0 ) return;
1480
1481                 xtag = xml_get_current_tag( file );
1482
1483                 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
1484                 if( iface ) {
1485                         addrIndex->lastType = iface->type;
1486                         if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
1487                 }
1488                 else {
1489                         dsIFace = addrindex_tag_get_datasource(
1490                                         addrIndex, addrIndex->lastType, xtag->tag );
1491                         if( dsIFace ) {
1492                                 /* Add data source to list */
1493                                 ds = NULL;
1494                                 if( addrIndex->lastType == ADDR_IF_BOOK ) {
1495                                         ds = addrindex_parse_book( file );
1496                                         if( ds->rawDataSource ) {
1497                                                 addrbook_set_path( ds->rawDataSource,
1498                                                         addrIndex->filePath );
1499                                         }
1500                                 }
1501                                 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
1502                                         ds = addrindex_parse_vcard( file );
1503                                 }
1504                                 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
1505                                         ds = addrindex_parse_jpilot( file );
1506                                 }
1507                                 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
1508                                         ds = addrindex_parse_ldap( file );
1509                                 }
1510                                 if( ds ) {
1511                                         ds->interface = dsIFace;
1512                                         addrindex_hash_add_cache( addrIndex, ds );
1513                                         dsIFace->listSource =
1514                                                 g_list_append( dsIFace->listSource, ds );
1515                                 }
1516                         }
1517                 }
1518         }
1519 }
1520
1521 /*
1522  * Search order sorting comparison function for building search order list.
1523  */
1524 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
1525         AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
1526         AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
1527
1528         return ifaceA->searchOrder - ifaceB->searchOrder;
1529 }
1530
1531 /**
1532  * Build list of data sources to process.
1533  * \param addrIndex Address index object.
1534  */
1535 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
1536         AddressInterface *iface;
1537         GList *nodeIf;
1538
1539         /* Clear existing list */
1540         g_list_free( addrIndex->searchOrder );
1541         addrIndex->searchOrder = NULL;
1542
1543         /* Build new list */
1544         nodeIf = addrIndex->interfaceList;
1545         while( nodeIf ) {
1546                 AddressInterface *iface = nodeIf->data;
1547                 if( iface->searchOrder > 0 ) {
1548                         /* Add to search order list */
1549                         addrIndex->searchOrder = g_list_insert_sorted(
1550                                 addrIndex->searchOrder, iface,
1551                                 addrindex_search_order_compare );
1552                 }
1553                 nodeIf = g_list_next( nodeIf );
1554         }
1555
1556         nodeIf = addrIndex->searchOrder;
1557         while( nodeIf ) {
1558                 AddressInterface *iface = nodeIf->data;
1559                 nodeIf = g_list_next( nodeIf );
1560         }
1561
1562 }
1563
1564 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1565         XMLFile *file = NULL;
1566         gchar *fileSpec = NULL;
1567
1568         g_return_val_if_fail( addrIndex != NULL, -1 );
1569
1570         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1571         addrIndex->retVal = MGU_NO_FILE;
1572         file = xml_open_file( fileSpec );
1573         g_free( fileSpec );
1574
1575         if( file == NULL ) {
1576                 /*
1577                 fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
1578                 */
1579                 return addrIndex->retVal;
1580         }
1581
1582         addrIndex->retVal = MGU_BAD_FORMAT;
1583         if( xml_get_dtd( file ) == 0 ) {
1584                 if( xml_parse_next_tag( file ) == 0 ) {
1585                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1586                                 addrindex_read_index( addrIndex, file );
1587                                 addrIndex->retVal = MGU_SUCCESS;
1588                         }
1589                 }
1590         }
1591         xml_close_file( file );
1592
1593         addrindex_build_search_order( addrIndex );
1594
1595         return addrIndex->retVal;
1596 }
1597
1598 static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1599         GList *nodeIF, *nodeDS;
1600         gint lvlList = 1;
1601         gint lvlItem = 1 + lvlList;
1602
1603         nodeIF = addrIndex->interfaceList;
1604         while( nodeIF ) {
1605                 AddressInterface *iface = nodeIF->data;
1606                 if( ! iface->legacyFlag ) {
1607                         nodeDS = iface->listSource;
1608                         addrindex_write_elem_s( fp, lvlList, iface->listTag );
1609                         fputs( ">\n", fp );
1610                         while( nodeDS ) {
1611                                 AddressDataSource *ds = nodeDS->data;
1612                                 if( ds ) {
1613                                         if( iface->type == ADDR_IF_BOOK ) {
1614                                                 addrindex_write_book( fp, ds, lvlItem );
1615                                         }
1616                                         if( iface->type == ADDR_IF_VCARD ) {
1617                                                 addrindex_write_vcard( fp, ds, lvlItem );
1618                                         }
1619                                         if( iface->type == ADDR_IF_JPILOT ) {
1620                                                 addrindex_write_jpilot( fp, ds, lvlItem );
1621                                         }
1622                                         if( iface->type == ADDR_IF_LDAP ) {
1623                                                 addrindex_write_ldap( fp, ds, lvlItem );
1624                                         }
1625                                 }
1626                                 nodeDS = g_list_next( nodeDS );
1627                         }
1628                         addrindex_write_elem_e( fp, lvlList, iface->listTag );
1629                 }
1630                 nodeIF = g_list_next( nodeIF );
1631         }
1632 }
1633
1634 /*
1635 * Write data to specified file.
1636 * Enter: addrIndex Address index object.
1637 *        newFile   New file name.
1638 * return: Status code, from addrIndex->retVal.
1639 * Note: File will be created in directory specified by addrIndex.
1640 */
1641 gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1642         FILE *fp;
1643         gchar *fileSpec;
1644 #ifndef DEV_STANDALONE
1645         PrefFile *pfile;
1646 #endif
1647
1648         g_return_val_if_fail( addrIndex != NULL, -1 );
1649
1650         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1651         addrIndex->retVal = MGU_OPEN_FILE;
1652 #ifdef DEV_STANDALONE
1653         fp = fopen( fileSpec, "wb" );
1654         g_free( fileSpec );
1655         if( fp ) {
1656                 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1657 #else
1658         pfile = prefs_write_open( fileSpec );
1659         g_free( fileSpec );
1660         if( pfile ) {
1661                 fp = pfile->fp;
1662                 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1663                                 conv_get_current_charset_str() );
1664 #endif
1665                 addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX );
1666                 fputs( ">\n", fp );
1667
1668                 addrindex_write_index( addrIndex, fp );
1669                 addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX );
1670
1671                 addrIndex->retVal = MGU_SUCCESS;
1672 #ifdef DEV_STANDALONE
1673                 fclose( fp );
1674 #else
1675                 if( prefs_file_close( pfile ) < 0 ) {
1676                         addrIndex->retVal = MGU_ERROR_WRITE;
1677                 }
1678 #endif
1679         }
1680
1681         fileSpec = NULL;
1682         return addrIndex->retVal;
1683 }
1684
1685 /*
1686 * Save address index data to original file.
1687 * return: Status code, from addrIndex->retVal.
1688 */
1689 gint addrindex_save_data( AddressIndex *addrIndex ) {
1690         g_return_val_if_fail( addrIndex != NULL, -1 );
1691
1692         addrIndex->retVal = MGU_NO_FILE;
1693         if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1694         if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1695
1696         addrindex_write_to( addrIndex, addrIndex->fileName );
1697         if( addrIndex->retVal == MGU_SUCCESS ) {
1698                 addrIndex->dirtyFlag = FALSE;
1699         }
1700         return addrIndex->retVal;
1701 }
1702
1703 /*
1704 * Save all address book files which may have changed.
1705 * Return: Status code, set if there was a problem saving data.
1706 */
1707 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1708         gint retVal = MGU_SUCCESS;
1709         GList *nodeIf, *nodeDS;
1710
1711         nodeIf = addrIndex->interfaceList;
1712         while( nodeIf ) {
1713                 AddressInterface *iface = nodeIf->data;
1714                 if( iface->type == ADDR_IF_BOOK ) {
1715                         nodeDS = iface->listSource;
1716                         while( nodeDS ) {
1717                                 AddressDataSource *ds = nodeDS->data;
1718                                 AddressBookFile *abf = ds->rawDataSource;
1719                                 if( addrbook_get_dirty( abf ) ) {
1720                                         if( addrbook_get_read_flag( abf ) ) {
1721                                                 addrbook_save_data( abf );
1722                                                 if( abf->retVal != MGU_SUCCESS ) {
1723                                                         retVal = abf->retVal;
1724                                                 }
1725                                         }
1726                                 }
1727                                 nodeDS = g_list_next( nodeDS );
1728                         }
1729                         break;
1730                 }
1731                 nodeIf = g_list_next( nodeIf );
1732         }
1733         return retVal;
1734 }
1735
1736
1737 /* **********************************************************************
1738 * Address book conversion to new format.
1739 * ***********************************************************************
1740 */
1741
1742 #define ELTAG_IF_OLD_FOLDER   "folder"
1743 #define ELTAG_IF_OLD_GROUP    "group"
1744 #define ELTAG_IF_OLD_ITEM     "item"
1745 #define ELTAG_IF_OLD_NAME     "name"
1746 #define ELTAG_IF_OLD_ADDRESS  "address"
1747 #define ELTAG_IF_OLD_REMARKS  "remarks"
1748 #define ATTAG_IF_OLD_NAME     "name"
1749
1750 #define TEMPNODE_ROOT         0
1751 #define TEMPNODE_FOLDER       1
1752 #define TEMPNODE_GROUP        2
1753 #define TEMPNODE_ADDRESS      3
1754
1755 typedef struct _AddressCvt_Node AddressCvtNode;
1756 struct _AddressCvt_Node {
1757         gint  type;
1758         gchar *name;
1759         gchar *address;
1760         gchar *remarks;
1761         GList *list;
1762 };
1763
1764 /*
1765 * Parse current address item.
1766 */
1767 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1768         gchar *element;
1769         guint level;
1770         AddressCvtNode *nn;
1771
1772         nn = g_new0( AddressCvtNode, 1 );
1773         nn->type = TEMPNODE_ADDRESS;
1774         nn->list = NULL;
1775
1776         level = file->level;
1777
1778         for (;;) {
1779                 xml_parse_next_tag(file);
1780                 if (file->level < level) return nn;
1781
1782                 element = xml_get_element( file );
1783                 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1784                         nn->name = g_strdup( element );
1785                 }
1786                 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1787                         nn->address = g_strdup( element );
1788                 }
1789                 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1790                         nn->remarks = g_strdup( element );
1791                 }
1792                 xml_parse_next_tag(file);
1793         }
1794 }
1795
1796 /*
1797 * Create a temporary node below specified node.
1798 */
1799 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1800         AddressCvtNode *nn;
1801         nn = g_new0( AddressCvtNode, 1 );
1802         nn->type = type;
1803         nn->name = g_strdup( name );
1804         nn->remarks = g_strdup( rem );
1805         node->list = g_list_append( node->list, nn );
1806         return nn;
1807 }
1808
1809 /*
1810 * Process current temporary node.
1811 */
1812 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1813         GList *attr;
1814         guint prev_level;
1815         AddressCvtNode *newNode = NULL;
1816         gchar *name;
1817         gchar *value;
1818
1819         for (;;) {
1820                 prev_level = file->level;
1821                 xml_parse_next_tag( file );
1822                 if (file->level < prev_level) return;
1823                 name = NULL;
1824                 value = NULL;
1825
1826                 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1827                         attr = xml_get_current_tag_attr(file);
1828                         if (attr) {
1829                                 name = ((XMLAttr *)attr->data)->name;
1830                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1831                                         value = ((XMLAttr *)attr->data)->value;
1832                                 }
1833                         }
1834                         newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1835                         addrindex_add_obj( file, newNode );
1836
1837                 }
1838                 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1839                         attr = xml_get_current_tag_attr(file);
1840                         if (attr) {
1841                                 name = ((XMLAttr *)attr->data)->name;
1842                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1843                                         value = ((XMLAttr *)attr->data)->value;
1844                                 }
1845                         }
1846                         newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
1847                         addrindex_add_obj( file, newNode );
1848                 }
1849                 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
1850                         newNode = addrindex_parse_item( file );
1851                         node->list = g_list_append( node->list, newNode );
1852                 }
1853                 else {
1854                         /* printf( "invalid: !!! \n" ); */
1855                         attr = xml_get_current_tag_attr( file );
1856                 }
1857         }
1858 }
1859
1860 /*
1861 * Consume all nodes below current tag.
1862 */
1863 static void addrindex_consume_tree( XMLFile *file ) {
1864         guint prev_level;
1865         gchar *element;
1866         GList *attr;
1867         XMLTag *xtag;
1868
1869         for (;;) {
1870                 prev_level = file->level;
1871                 xml_parse_next_tag( file );
1872                 if (file->level < prev_level) return;
1873
1874                 xtag = xml_get_current_tag( file );
1875                 /* printf( "tag : %s\n", xtag->tag ); */
1876                 element = xml_get_element( file );
1877                 attr = xml_get_current_tag_attr( file );
1878                 /* show_attribs( attr ); */
1879                 /* printf( "\ttag  value : %s :\n", element ); */
1880                 addrindex_consume_tree( file );
1881         }
1882 }
1883
1884 /*
1885 * Print temporary tree.
1886 */
1887 static void addrindex_print_node( AddressCvtNode *node, FILE *stream  ) {
1888         GList *list;
1889
1890         fprintf( stream, "Node:\ttype :%d:\n", node->type );
1891         fprintf( stream, "\tname :%s:\n", node->name );
1892         fprintf( stream, "\taddr :%s:\n", node->address );
1893         fprintf( stream, "\trems :%s:\n", node->remarks );
1894         if( node->list ) {
1895                 fprintf( stream, "\t--list----\n" );
1896         }
1897         list = node->list;
1898         while( list ) {
1899                 AddressCvtNode *lNode = list->data;
1900                 list = g_list_next( list );
1901                 addrindex_print_node( lNode, stream );
1902         }
1903         fprintf( stream, "\t==list-%d==\n", node->type );
1904 }
1905
1906 /*
1907 * Free up temporary tree.
1908 */
1909 static void addrindex_free_node( AddressCvtNode *node ) {
1910         GList *list = node->list;
1911
1912         while( list ) {
1913                 AddressCvtNode *lNode = list->data;
1914                 list = g_list_next( list );
1915                 addrindex_free_node( lNode );
1916         }
1917         node->type = TEMPNODE_ROOT;
1918         g_free( node->name );
1919         g_free( node->address );
1920         g_free( node->remarks );
1921         g_list_free( node->list );
1922         g_free( node );
1923 }
1924
1925 /*
1926 * Process address book for specified node.
1927 */
1928 static void addrindex_process_node(
1929                 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
1930                 ItemGroup *parentGrp, ItemFolder *folderGrp )
1931 {
1932         GList *list;
1933         ItemFolder *itemFolder = NULL;
1934         ItemGroup *itemGParent = parentGrp;
1935         ItemFolder *itemGFolder = folderGrp;
1936         AddressCache *cache = abf->addressCache;
1937
1938         if( node->type == TEMPNODE_ROOT ) {
1939                 itemFolder = parent;
1940         }
1941         else if( node->type == TEMPNODE_FOLDER ) {
1942                 itemFolder = addritem_create_item_folder();
1943                 addritem_folder_set_name( itemFolder, node->name );
1944                 addrcache_id_folder( cache, itemFolder );
1945                 addrcache_folder_add_folder( cache, parent, itemFolder );
1946                 itemGFolder = NULL;
1947         }
1948         else if( node->type == TEMPNODE_GROUP ) {
1949                 ItemGroup *itemGroup;
1950                 gchar *fName;
1951
1952                 /* Create a folder for group */
1953                 fName = g_strdup_printf( "Cvt - %s", node->name );
1954                 itemGFolder = addritem_create_item_folder();
1955                 addritem_folder_set_name( itemGFolder, fName );
1956                 addrcache_id_folder( cache, itemGFolder );
1957                 addrcache_folder_add_folder( cache, parent, itemGFolder );
1958                 g_free( fName );
1959
1960                 /* Add group into folder */
1961                 itemGroup = addritem_create_item_group();
1962                 addritem_group_set_name( itemGroup, node->name );
1963                 addrcache_id_group( cache, itemGroup );
1964                 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
1965                 itemGParent = itemGroup;
1966         }
1967         else if( node->type == TEMPNODE_ADDRESS ) {
1968                 ItemPerson *itemPerson;
1969                 ItemEMail *itemEMail;
1970
1971                 /* Create person and email objects */
1972                 itemPerson = addritem_create_item_person();
1973                 addritem_person_set_common_name( itemPerson, node->name );
1974                 addrcache_id_person( cache, itemPerson );
1975                 itemEMail = addritem_create_item_email();
1976                 addritem_email_set_address( itemEMail, node->address );
1977                 addritem_email_set_remarks( itemEMail, node->remarks );
1978                 addrcache_id_email( cache, itemEMail );
1979                 addrcache_person_add_email( cache, itemPerson, itemEMail );
1980
1981                 /* Add person into appropriate folder */
1982                 if( itemGFolder ) {
1983                         addrcache_folder_add_person( cache, itemGFolder, itemPerson );
1984                 }
1985                 else {
1986                         addrcache_folder_add_person( cache, parent, itemPerson );
1987                 }
1988
1989                 /* Add email address only into group */
1990                 if( parentGrp ) {
1991                         addrcache_group_add_email( cache, parentGrp, itemEMail );
1992                 }
1993         }
1994
1995         list = node->list;
1996         while( list ) {
1997                 AddressCvtNode *lNode = list->data;
1998                 list = g_list_next( list );
1999                 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
2000         }
2001 }
2002
2003 /*
2004 * Process address book to specified file number.
2005 */
2006 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
2007         gboolean retVal = FALSE;
2008         AddressBookFile *abf = NULL;
2009         AddressCvtNode *rootNode = NULL;
2010         gchar *newFile = NULL;
2011         GList *fileList = NULL;
2012         gint fileNum  = 0;
2013
2014         /* Setup root node */
2015         rootNode = g_new0( AddressCvtNode, 1 );
2016         rootNode->type = TEMPNODE_ROOT;
2017         rootNode->name = g_strdup( "root" );
2018         rootNode->list = NULL;
2019         addrindex_add_obj( file, rootNode );
2020         /* addrindex_print_node( rootNode, stdout ); */
2021
2022         /* Create new address book */
2023         abf = addrbook_create_book();
2024         addrbook_set_name( abf, displayName );
2025         addrbook_set_path( abf, addrIndex->filePath );
2026
2027         /* Determine next available file number */
2028         fileList = addrbook_get_bookfile_list( abf );
2029         if( fileList ) {
2030                 fileNum = 1 + abf->maxValue;
2031         }
2032         g_list_free( fileList );
2033         fileList = NULL;
2034
2035         newFile = addrbook_gen_new_file_name( fileNum );
2036         if( newFile ) {
2037                 addrbook_set_file( abf, newFile );
2038         }
2039
2040         addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
2041
2042         /* addrbook_dump_book( abf, stdout ); */
2043         addrbook_save_data( abf );
2044         addrIndex->retVal = abf->retVal;
2045         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2046
2047         addrbook_free_book( abf );
2048         abf = NULL;
2049         addrindex_free_node( rootNode );
2050         rootNode = NULL;
2051
2052         /* Create entries in address index */
2053         if( retVal ) {
2054                 abf = addrbook_create_book();
2055                 addrbook_set_name( abf, displayName );
2056                 addrbook_set_path( abf, addrIndex->filePath );
2057                 addrbook_set_file( abf, newFile );
2058                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2059         }
2060
2061         return retVal;
2062 }
2063
2064 /*
2065 * Process tree converting data.
2066 */
2067 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
2068         guint prev_level;
2069         gchar *element;
2070         GList *attr;
2071         XMLTag *xtag;
2072
2073         /* Process file */
2074         for (;;) {
2075                 prev_level = file->level;
2076                 xml_parse_next_tag( file );
2077                 if (file->level < prev_level) return;
2078
2079                 xtag = xml_get_current_tag( file );
2080                 /* printf( "tag : %d : %s\n", prev_level, xtag->tag ); */
2081                 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
2082                         if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
2083                                 addrIndex->needsConversion = FALSE;
2084                                 addrIndex->wasConverted = TRUE;
2085                                 continue;
2086                         }
2087                         return;
2088                 }
2089                 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
2090                         if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
2091                                 addrIndex->needsConversion = FALSE;
2092                                 addrIndex->wasConverted = TRUE;
2093                                 continue;
2094                         }
2095                         return;
2096                 }
2097                 element = xml_get_element( file );
2098                 attr = xml_get_current_tag_attr( file );
2099                 /* show_attribs( attr ); */
2100                 /* printf( "\ttag  value : %s :\n", element ); */
2101                 addrindex_consume_tree( file );
2102         }
2103 }
2104
2105 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
2106         XMLFile *file = NULL;
2107         gchar *fileSpec;
2108
2109         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
2110         addrIndex->retVal = MGU_NO_FILE;
2111         file = xml_open_file( fileSpec );
2112         g_free( fileSpec );
2113
2114         if( file == NULL ) {
2115                 /* fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); */
2116                 return addrIndex->retVal;
2117         }
2118
2119         addrIndex->retVal = MGU_BAD_FORMAT;
2120         if( xml_get_dtd( file ) == 0 ) {
2121                 if( xml_parse_next_tag( file ) == 0 ) {
2122                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
2123                                 addrindex_convert_tree( addrIndex, file );
2124                         }
2125                 }
2126         }
2127         xml_close_file( file );
2128         return addrIndex->retVal;
2129 }
2130
2131 /*
2132 * Create a new address book file.
2133 */
2134 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
2135         gboolean retVal = FALSE;
2136         AddressBookFile *abf = NULL;
2137         gchar *newFile = NULL;
2138         GList *fileList = NULL;
2139         gint fileNum = 0;
2140
2141         /* Create new address book */
2142         abf = addrbook_create_book();
2143         addrbook_set_name( abf, displayName );
2144         addrbook_set_path( abf, addrIndex->filePath );
2145
2146         /* Determine next available file number */
2147         fileList = addrbook_get_bookfile_list( abf );
2148         if( fileList ) {
2149                 fileNum = 1 + abf->maxValue;
2150         }
2151         g_list_free( fileList );
2152         fileList = NULL;
2153
2154         newFile = addrbook_gen_new_file_name( fileNum );
2155         if( newFile ) {
2156                 addrbook_set_file( abf, newFile );
2157         }
2158
2159         addrbook_save_data( abf );
2160         addrIndex->retVal = abf->retVal;
2161         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2162         addrbook_free_book( abf );
2163         abf = NULL;
2164
2165         /* Create entries in address index */
2166         if( retVal ) {
2167                 abf = addrbook_create_book();
2168                 addrbook_set_name( abf, displayName );
2169                 addrbook_set_path( abf, addrIndex->filePath );
2170                 addrbook_set_file( abf, newFile );
2171                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2172         }
2173
2174         return retVal;
2175 }
2176
2177 /*
2178 * Read data for address index performing a conversion if necesary.
2179 * Enter: addrIndex Address index object.
2180 * return: Status code, from addrIndex->retVal.
2181 * Note: New address book files will be created in directory specified by
2182 * addrIndex. Three files will be created, for the following:
2183 *       "Common addresses"
2184 *       "Personal addresses"
2185 *       "Gathered addresses" - a new address book.
2186 */
2187 gint addrindex_read_data( AddressIndex *addrIndex ) {
2188         g_return_val_if_fail( addrIndex != NULL, -1 );
2189
2190         addrIndex->conversionError = FALSE;
2191         addrindex_read_file( addrIndex );
2192         if( addrIndex->retVal == MGU_SUCCESS ) {
2193                 if( addrIndex->needsConversion ) {
2194                         if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) {
2195                                 addrIndex->conversionError = TRUE;
2196                         }
2197                         else {
2198                                 addrIndex->conversionError = TRUE;
2199                         }
2200                 }
2201                 addrIndex->dirtyFlag = TRUE;
2202         }
2203         return addrIndex->retVal;
2204 }
2205
2206 /*
2207 * Create new address books for a new address index.
2208 * Enter: addrIndex Address index object.
2209 * return: Status code, from addrIndex->retVal.
2210 * Note: New address book files will be created in directory specified by
2211 * addrIndex. Three files will be created, for the following:
2212 *       "Common addresses"
2213 *       "Personal addresses"
2214 *       "Gathered addresses" - a new address book.
2215 */
2216 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
2217         gboolean flg;
2218
2219         g_return_val_if_fail( addrIndex != NULL, -1 );
2220
2221         flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
2222         if( flg ) {
2223                 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
2224                 addrIndex->dirtyFlag = TRUE;
2225         }
2226         return addrIndex->retVal;
2227 }
2228
2229 /* **********************************************************************
2230 * New interface stuff.
2231 * ***********************************************************************
2232 */
2233
2234 /*
2235  * Return modified flag for specified data source.
2236  */
2237 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
2238         gboolean retVal = FALSE;
2239         AddressInterface *iface;
2240
2241         if( ds == NULL ) return retVal;
2242         iface = ds->interface;
2243         if( iface == NULL ) return retVal;
2244         if( iface->getModifyFlag ) {
2245                 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
2246         }
2247         return retVal;
2248 }
2249
2250 /*
2251  * Return accessed flag for specified data source.
2252  */
2253 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
2254         gboolean retVal = FALSE;
2255         AddressInterface *iface;
2256
2257         if( ds == NULL ) return retVal;
2258         iface = ds->interface;
2259         if( iface == NULL ) return retVal;
2260         if( iface->getAccessFlag ) {
2261                 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
2262         }
2263         return retVal;
2264 }
2265
2266 /*
2267  * Return data read flag for specified data source.
2268  */
2269 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
2270         gboolean retVal = TRUE;
2271         AddressInterface *iface;
2272
2273         if( ds == NULL ) return retVal;
2274         iface = ds->interface;
2275         if( iface == NULL ) return retVal;
2276         if( iface->getReadFlag ) {
2277                 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
2278         }
2279         return retVal;
2280 }
2281
2282 /*
2283  * Return status code for specified data source.
2284  */
2285 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
2286         gint retVal = MGU_SUCCESS;
2287         AddressInterface *iface;
2288
2289         if( ds == NULL ) return retVal;
2290         iface = ds->interface;
2291         if( iface == NULL ) return retVal;
2292         if( iface->getStatusCode ) {
2293                 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
2294         }
2295         return retVal;
2296 }
2297
2298 /*
2299  * Return data read flag for specified data source.
2300  */
2301 gint addrindex_ds_read_data( AddressDataSource *ds ) {
2302         gint retVal = MGU_SUCCESS;
2303         AddressInterface *iface;
2304
2305         if( ds == NULL ) return retVal;
2306         iface = ds->interface;
2307         if( iface == NULL ) return retVal;
2308         if( iface->getReadData ) {
2309                 retVal = ( iface->getReadData ) ( ds->rawDataSource );
2310         }
2311         return retVal;
2312 }
2313
2314 /*
2315  * Return data read flag for specified data source.
2316  */
2317 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
2318         ItemFolder *retVal = NULL;
2319         AddressInterface *iface;
2320
2321         if( ds == NULL ) return retVal;
2322         iface = ds->interface;
2323         if( iface == NULL ) return retVal;
2324         if( iface->getRootFolder ) {
2325                 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
2326         }
2327         return retVal;
2328 }
2329
2330 /*
2331  * Return list of folders for specified data source.
2332  */
2333 GList *addrindex_ds_get_list_folder( AddressDataSource *ds ) {
2334         GList *retVal = FALSE;
2335         AddressInterface *iface;
2336
2337         if( ds == NULL ) return retVal;
2338         iface = ds->interface;
2339         if( iface == NULL ) return retVal;
2340         if( iface->getListFolder ) {
2341                 retVal = ( iface->getListFolder ) ( ds->rawDataSource );
2342         }
2343         return retVal;
2344 }
2345
2346 /*
2347  * Return list of persons in root folder for specified data source.
2348  */
2349 GList *addrindex_ds_get_list_person( AddressDataSource *ds ) {
2350         GList *retVal = FALSE;
2351         AddressInterface *iface;
2352
2353         if( ds == NULL ) return retVal;
2354         iface = ds->interface;
2355         if( iface == NULL ) return retVal;
2356         if( iface->getListPerson ) {
2357                 retVal = ( iface->getListPerson ) ( ds->rawDataSource );
2358         }
2359         return retVal;
2360 }
2361
2362 /*
2363  * Return name for specified data source.
2364  */
2365 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
2366         gchar *retVal = FALSE;
2367         AddressInterface *iface;
2368
2369         if( ds == NULL ) return retVal;
2370         iface = ds->interface;
2371         if( iface == NULL ) return retVal;
2372         if( iface->getName ) {
2373                 retVal = ( iface->getName ) ( ds->rawDataSource );
2374         }
2375         return retVal;
2376 }
2377
2378 /*
2379  * Set the access flag inside the data source.
2380  */
2381 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
2382         AddressInterface *iface;
2383
2384         if( ds == NULL ) return;
2385         iface = ds->interface;
2386         if( iface == NULL ) return;
2387         if( iface->setAccessFlag ) {
2388                 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
2389         }
2390 }
2391
2392 /*
2393  * Return read only flag for specified data source.
2394  */
2395 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
2396         AddressInterface *iface;
2397         if( ds == NULL ) return TRUE;
2398         iface = ds->interface;
2399         if( iface == NULL ) return TRUE;
2400         return iface->readOnly;
2401 }
2402
2403 /*
2404  * Return list of all persons for specified data source.
2405  */
2406 GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
2407         GList *retVal = NULL;
2408         AddressInterface *iface;
2409
2410         if( ds == NULL ) return retVal;
2411         iface = ds->interface;
2412         if( iface == NULL ) return retVal;
2413         if( iface->getAllPersons ) {
2414                 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
2415         }
2416         return retVal;
2417 }
2418
2419 /*
2420  * Return list of all groups for specified data source.
2421  */
2422 GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
2423         GList *retVal = NULL;
2424         AddressInterface *iface;
2425
2426         if( ds == NULL ) return retVal;
2427         iface = ds->interface;
2428         if( iface == NULL ) return retVal;
2429         if( iface->getAllGroups ) {
2430                 retVal = ( iface->getAllGroups ) ( ds->rawDataSource );
2431         }
2432         return retVal;
2433 }
2434
2435 /* **********************************************************************
2436 * Address search stuff.
2437 * ***********************************************************************
2438 */
2439
2440 /**
2441  * Current query ID. This is incremented for each query created.
2442  */
2443 static gint _currentQueryID_ = 0;
2444
2445 /*
2446  * Variables for the search that is being performed.
2447  */
2448 static gchar *_searchTerm_ = NULL;
2449 static gpointer _searchTarget_ = NULL;
2450 static AddrSearchCallbackFunc *_searchCallback_ = NULL;
2451
2452 /**
2453  * Setup or register the search that will be performed.
2454  * \param addrIndex  Address index object.
2455  * \param searchTerm Search term. A private copy will be made.
2456  * \param target     Target object that will receive data.
2457  * \param callBack   Callback function.
2458  * \return ID allocated to query that will be executed.
2459  */
2460 gint addrindex_setup_search(
2461         AddressIndex *addrIndex, const gchar *searchTerm,
2462         const gpointer target, AddrSearchCallbackFunc callBack )
2463 {
2464         gint queryID;
2465
2466         /* printf( "search term ::%s::\n", searchTerm ); */
2467         g_free( _searchTerm_ );
2468         _searchTerm_ = g_strdup( searchTerm );
2469
2470         queryID = ++_currentQueryID_;
2471         _searchTarget_ = target;
2472         _searchCallback_ = callBack;
2473         /* printf( "query ID ::%d::\n", queryID ); */
2474         return queryID;
2475 }
2476
2477 /**
2478  * Perform the search for specified address cache.
2479  * \param cache Cache to be searched.
2480  * \param queryID ID of search query to be executed.
2481  */
2482 static void addrindex_search_cache( AddressCache *cache, const gint queryID ) {
2483         AddrCacheIndex *index;
2484         GList *listEMail;
2485
2486         index = cache->searchIndex;
2487         if( index == NULL ) return;
2488         if( index->invalid ) {
2489                 addrcache_build_index( cache );
2490         }
2491
2492         /*
2493         printf( "query ::%d:: searching index for ::%s::\n", queryID, _searchTerm_ );
2494         */
2495         listEMail = addrcindex_search( index, _searchTerm_ );
2496         ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
2497         g_list_free( listEMail );
2498         listEMail = NULL;
2499         /* printf( "searching index done\n" ); */
2500 }
2501
2502 #ifdef USE_LDAP
2503 /**
2504  * LDAP callback entry point for each address entry found.
2505  * \param qry       LDAP query.
2506  * \param listEMail List of Item EMail objects found.
2507  */
2508 static void addrindex_ldap_entry_cb( LdapQuery *qry, GList *listEMail ) {
2509         GList *node;
2510
2511         /*
2512         printf( "\naddrindex::addrindex_ldap_entry_cb ::%s::\n", qry->queryName );
2513         */
2514         node = listEMail;
2515         while( node ) {
2516                 ItemEMail *email = node->data;
2517                 /* printf( "\temail ::%s::\n", email->address ); */
2518                 node = g_list_next( node );
2519         }
2520         if( _searchCallback_ ) {
2521                 ( _searchCallback_ ) ( qry->queryID, listEMail, _searchTarget_ );
2522         }
2523         g_list_free( listEMail );
2524 }
2525
2526 /**
2527  * LDAP callback entry point for completion of search.
2528  * \param qry LDAP query.
2529  */
2530 static void addrindex_ldap_end_cb( LdapQuery *qry ) {
2531         /* printf( "\naddrindex::addrindex_ldap_end_cb ::%s::\n", qry->queryName ); */
2532 }
2533
2534 /**
2535  * Return results of previous query.
2536  * \param folder.
2537  * \return List of ItemEMail objects.
2538  */
2539 static void addrindex_ldap_use_previous( const ItemFolder *folder, const gint queryID )
2540 {
2541         GList *listEMail;
2542         GList *node;
2543         GList *nodeEM;
2544
2545         listEMail = NULL;
2546         if( _searchCallback_ ) {
2547                 node = folder->listPerson;
2548                 while( node ) {
2549                         AddrItemObject *aio = node->data;
2550                         if( aio &&  aio->type == ITEMTYPE_PERSON ) {
2551                                 ItemPerson *person = node->data;
2552                                 nodeEM = person->listEMail;
2553                                 while( nodeEM ) {
2554                                         ItemEMail *email = nodeEM->data;
2555                                         nodeEM = g_list_next( nodeEM );
2556                                         listEMail = g_list_append( listEMail, email );
2557                                 }
2558                         }
2559                         node = g_list_next( node );
2560                 }
2561                 ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
2562                 g_list_free( listEMail );
2563         }
2564 }
2565
2566 LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
2567
2568 /**
2569  * Construct an LDAP query and initiate an LDAP search.
2570  * \param server  LDAP server object.
2571  * \param queryID ID of search query to be executed.
2572  */
2573 static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
2574         LdapQuery *qry;
2575         gchar *name;
2576
2577         if( ! server->searchFlag ) return;
2578         printf( "Searching ::%s::\n", ldapsvr_get_name( server ) );
2579
2580         /* Retire any aged queries */
2581         ldapsvr_retire_query( server );
2582
2583         /* Test whether any queries for the same term exist */
2584         qry = ldapsvr_locate_query( server, _searchTerm_ );
2585         if( qry ) {
2586                 ItemFolder *folder = qry->folder;
2587
2588                 /* Touch query to ensure it hangs around for a bit longer */            
2589                 ldapqry_touch( qry );
2590                 if( folder ) {
2591                         addrindex_ldap_use_previous( folder, queryID );
2592                         return;
2593                 }
2594         }
2595
2596         /* Construct a query */
2597         qry = ldapqry_create();
2598         ldapqry_set_query_id( qry, queryID );
2599         ldapqry_set_search_value( qry, _searchTerm_ );
2600         ldapqry_set_query_type( qry, LDAPQUERY_DYNAMIC );
2601         ldapqry_set_callback_entry( qry, addrindex_ldap_entry_cb );
2602         ldapqry_set_callback_end( qry, addrindex_ldap_end_cb );
2603
2604         /* Name the query */
2605         name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
2606         ldapqry_set_name( qry, name );
2607         g_free( name );
2608
2609         ldapsvr_add_query( server, qry );
2610         /* printf( "addrindex_search_ldap::executing dynamic search...\n" ); */
2611         ldapsvr_execute_query( server, qry );
2612 }
2613
2614 /**
2615  * Construct an LDAP query and initiate an LDAP search.
2616  * \param server      LDAP server object to search.
2617  * \param searchTerm  Search term to locate.
2618  * \param callbackEnd Function to call when search has terminated.
2619  *
2620  */
2621 void addrindex_search_ldap_noid(
2622         LdapServer *server, const gchar *searchTerm, void * callbackEnd )
2623 {
2624         LdapQuery *qry;
2625         gchar *name;
2626
2627         /* Construct a query */
2628         qry = ldapqry_create();
2629         ldapqry_set_search_value( qry, searchTerm );
2630         ldapqry_set_query_type( qry, LDAPQUERY_STATIC );
2631         ldapqry_set_callback_end( qry, callbackEnd );
2632
2633         /* Name the query */
2634         name = g_strdup_printf( "Static Search for '%s'", searchTerm );
2635         ldapqry_set_name( qry, name );
2636         g_free( name );
2637
2638         ldapsvr_add_query( server, qry );
2639         /* printf( "addrindex_search_ldap_noid::executing static search...\n" ); */
2640         ldapsvr_execute_query( server, qry );
2641 }
2642 #endif
2643
2644 /**
2645  * Perform the previously registered search.
2646  * \param  addrIndex  Address index object.
2647  * \param  queryID    ID of search query to be executed.
2648  * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2649  *         failed.
2650  */
2651 gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
2652         AddressInterface *iface;
2653         AddressDataSource *ds;
2654         AddressCache *cache;
2655         GList *nodeIf;
2656         GList *nodeDS;
2657         gint type;
2658
2659         /* printf( "addrindex_start_search::%d::\n", queryID ); */
2660         nodeIf = addrIndex->searchOrder;
2661         while( nodeIf ) {
2662                 iface = nodeIf->data;
2663                 nodeIf = g_list_next( nodeIf );
2664
2665                 if( ! iface->useInterface ) {
2666                         continue;
2667                 }
2668
2669                 type = iface->type;
2670                 nodeDS = iface->listSource;
2671                 while( nodeDS ) {
2672                         ds = nodeDS->data;
2673                         nodeDS = g_list_next( nodeDS );
2674                         cache = NULL;
2675
2676                         if( type == ADDR_IF_BOOK ) {
2677                                 AddressBookFile *abf = ds->rawDataSource;
2678                                 cache = abf->addressCache;
2679                         }
2680                         else if( type == ADDR_IF_VCARD ) {
2681                                 VCardFile *vcf = ds->rawDataSource;
2682                                 cache = vcf->addressCache;
2683                         }
2684 #ifdef USE_JPILOT
2685                         else if( type == ADDR_IF_JPILOT ) {
2686                                 JPilotFile *jpf = ds->rawDataSource;
2687                                 cache = jpf->addressCache;
2688                         }
2689 #endif
2690 #ifdef USE_LDAP
2691                         else if( type == ADDR_IF_LDAP ) {
2692                                 LdapServer *server = ds->rawDataSource;
2693                                 addrindex_search_ldap( server, queryID );
2694                         }
2695 #endif
2696                         if( cache ) {
2697                                 addrindex_search_cache( cache, queryID );
2698                         }
2699                 }
2700         }
2701         return TRUE;
2702 }
2703
2704 /**
2705  * Stop the previously registered search.
2706  * \param addrIndex Address index object.
2707  * \param queryID ID of search query to stop.
2708  */
2709 void addrindex_stop_search( AddressIndex *addrIndex, const gint queryID ){
2710 #ifdef USE_LDAP
2711         AddressInterface *iface;
2712         AddressDataSource *ds;
2713         GList *nodeIf;
2714         GList *nodeDS;
2715         gint type;
2716
2717         /* If query ID does not match, search has not been setup */
2718         /* if( queryID != _queryID_ ) return; */
2719
2720         /* printf( "addrindex_stop_search::%d::\n", queryID ); */
2721         nodeIf = addrIndex->searchOrder;
2722         while( nodeIf ) {
2723                 iface = nodeIf->data;
2724                 nodeIf = g_list_next( nodeIf );
2725
2726                 if( ! iface->useInterface ) {
2727                         continue;
2728                 }
2729
2730                 type = iface->type;
2731                 nodeDS = iface->listSource;
2732                 while( nodeDS ) {
2733                         ds = nodeDS->data;
2734                         nodeDS = g_list_next( nodeDS );
2735                         if( type == ADDR_IF_LDAP ) {
2736                                 LdapServer *server = ds->rawDataSource;
2737                                 ldapsvr_stop_all_query( server );
2738                         }
2739                 }
2740         }
2741 #endif
2742 }
2743
2744 /**
2745  * Read all address books that do not support dynamic queries.
2746  * \param addrIndex Address index object.
2747  */
2748 void addrindex_read_all( AddressIndex *addrIndex ) {
2749         AddressInterface *iface;
2750         AddressDataSource *ds;
2751         GList *nodeIf;
2752         GList *nodeDS;
2753
2754         nodeIf = addrIndex->searchOrder;
2755         while( nodeIf ) {
2756                 iface = nodeIf->data;
2757                 nodeIf = g_list_next( nodeIf );
2758
2759                 if( ! iface->useInterface ) {
2760                         continue;
2761                 }
2762                 if( iface->externalQuery ) {
2763                         continue;
2764                 }
2765                 nodeDS = iface->listSource;
2766                 while( nodeDS ) {
2767                         ds = nodeDS->data;
2768                         nodeDS = g_list_next( nodeDS );
2769
2770                         /* Read address book */
2771                         if( addrindex_ds_get_modify_flag( ds ) ) {
2772                                 addrindex_ds_read_data( ds );
2773                                 continue;
2774                         }
2775
2776                         if( ! addrindex_ds_get_read_flag( ds ) ) {
2777                                 addrindex_ds_read_data( ds );
2778                                 continue;
2779                         }
2780                 }
2781         }
2782         addrIndex->loadedFlag = TRUE;
2783 }
2784
2785 /**
2786  * Perform a simple search of all non-query type data sources for specified
2787  * search term. If several entries are found, only the first item is
2788  * returned. Interfaces that require a time-consuming "external query" are
2789  * ignored for this search.
2790  *
2791  * \param  addrIndex  Address index object.
2792  * \param  searchTerm Search term to find. Typically an email address.
2793  * \return List of references to zero or mail E-Mail object that was found in
2794  *         the address books, or <i>NULL</i> if nothing found. This list
2795  *         *SHOULD* be freed when done.
2796  */
2797 GList *addrindex_quick_search_list(
2798                 AddressIndex *addrIndex, const gchar *searchTerm )
2799 {
2800         GList *listRet = NULL;
2801         GList *listEMail;
2802         AddressInterface *iface;
2803         AddressDataSource *ds;
2804         AddressCache *cache;
2805         AddrCacheIndex *index;
2806         ItemEMail *email;
2807         GList *nodeIf;
2808         GList *nodeDS;
2809         GList *nodeEM;
2810         gint type;
2811
2812         nodeIf = addrIndex->searchOrder;
2813         while( nodeIf ) {
2814                 iface = nodeIf->data;
2815                 nodeIf = g_list_next( nodeIf );
2816
2817                 if( ! iface->useInterface ) {
2818                         /* Ignore interfaces that don't have a library */
2819                         continue;
2820                 }
2821                 if( iface->externalQuery ) {
2822                         /* Ignore interfaces that require a "query" */
2823                         continue;
2824                 }
2825
2826                 type = iface->type;
2827                 nodeDS = iface->listSource;
2828                 while( nodeDS ) {
2829                         ds = nodeDS->data;
2830                         nodeDS = g_list_next( nodeDS );
2831                         cache = NULL;
2832
2833                         if( type == ADDR_IF_BOOK ) {
2834                                 AddressBookFile *abf = ds->rawDataSource;
2835                                 cache = abf->addressCache;
2836                         }
2837                         else if( type == ADDR_IF_VCARD ) {
2838                                 VCardFile *vcf = ds->rawDataSource;
2839                                 cache = vcf->addressCache;
2840                         }
2841 #ifdef USE_JPILOT
2842                         else if( type == ADDR_IF_JPILOT ) {
2843                                 JPilotFile *jpf = ds->rawDataSource;
2844                                 cache = jpf->addressCache;
2845                         }
2846 #endif
2847                         if( cache ) {
2848                                 index = cache->searchIndex;
2849                                 if( index == NULL ) {
2850                                         continue;
2851                                 }
2852                                 if( index->invalid ) {
2853                                         addrcache_build_index( cache );
2854                                 }
2855                                 listEMail = addrcindex_search( index, searchTerm );
2856                                 nodeEM = listEMail;
2857                                 while( nodeEM ) {
2858                                         email = listEMail->data;
2859                                         listRet = g_list_append( listRet, email );
2860                                         nodeEM = g_list_next( nodeEM );
2861                                 }
2862                                 g_list_free( listEMail );
2863                         }
2864                 }
2865         }
2866         return listRet;
2867 }
2868
2869 /**
2870  * Perform a simple search of all non-query type data sources for specified
2871  * search term. If several entries are found, only the first item is
2872  * returned. Interfaces that require a time-consuming "external query" are
2873  * ignored for this search.
2874  *
2875  * \param  addrIndex  Address index object.
2876  * \param  searchTerm Search term to find. Typically an email address.
2877  * \return Reference to a single E-Mail object that was found in the address
2878  *         book, or <i>NULL</i> if nothing found. This should *NOT* be freed
2879  *         when done.
2880  */
2881 ItemEMail *addrindex_quick_search_single(
2882                 AddressIndex *addrIndex, const gchar *searchTerm )
2883 {
2884         ItemEMail *email = NULL;
2885         AddressInterface *iface;
2886         AddressDataSource *ds;
2887         AddressCache *cache;
2888         AddrCacheIndex *index;
2889         GList *listEMail;
2890         GList *nodeIf;
2891         GList *nodeDS;
2892         gint type;
2893
2894         /* printf( "addrindex_quick_search::%s::\n", searchTerm ); */
2895         nodeIf = addrIndex->searchOrder;
2896         while( nodeIf ) {
2897                 iface = nodeIf->data;
2898                 nodeIf = g_list_next( nodeIf );
2899
2900                 if( ! iface->useInterface ) {
2901                         continue;
2902                 }
2903                 if( iface->externalQuery ) {
2904                         continue;
2905                 }
2906
2907                 type = iface->type;
2908                 nodeDS = iface->listSource;
2909                 while( nodeDS ) {
2910                         ds = nodeDS->data;
2911                         nodeDS = g_list_next( nodeDS );
2912                         cache = NULL;
2913
2914                         if( type == ADDR_IF_BOOK ) {
2915                                 AddressBookFile *abf = ds->rawDataSource;
2916                                 cache = abf->addressCache;
2917                         }
2918                         else if( type == ADDR_IF_VCARD ) {
2919                                 VCardFile *vcf = ds->rawDataSource;
2920                                 cache = vcf->addressCache;
2921                         }
2922 #ifdef USE_JPILOT
2923                         else if( type == ADDR_IF_JPILOT ) {
2924                                 JPilotFile *jpf = ds->rawDataSource;
2925                                 cache = jpf->addressCache;
2926                         }
2927 #endif
2928                         if( cache ) {
2929                                 index = cache->searchIndex;
2930                                 if( index == NULL ) {
2931                                         continue;
2932                                 }
2933                                 if( index->invalid ) {
2934                                         addrcache_build_index( cache );
2935                                 }
2936
2937                                 listEMail = addrcindex_search( index, searchTerm );
2938                                 if( listEMail ) {
2939                                         email = listEMail->data;
2940                                 }
2941                                 g_list_free( listEMail );
2942                                 if( email ) break;
2943                         }
2944                 }
2945         }
2946         return email;
2947 }
2948
2949 /*
2950  * End of Source.
2951  */
2952
2953