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