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