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