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