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