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