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