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