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