Implemented a progress bar that counts the number of completed tasks when the action...
[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         addrcompl_initialize( addrIndex );
678 }
679
680 /**
681  * Perform any other teardown of address index.
682  * \param addrIndex Address index.
683  */
684 void addrindex_teardown( AddressIndex *addrIndex ) {
685         addrcompl_teardown();
686 }
687
688 /**
689  * Free up address index.
690  * \param addrIndex Address index.
691  */
692 void addrindex_free_index( AddressIndex *addrIndex ) {
693         GList *node;
694
695         g_return_if_fail( addrIndex != NULL );
696
697         /* Search stuff */
698         g_list_free( addrIndex->searchOrder );
699         addrIndex->searchOrder = NULL;
700
701         /* Free internal storage */
702         g_free( ADDRITEM_ID(addrIndex) );
703         g_free( ADDRITEM_NAME(addrIndex) );
704         g_free( addrIndex->filePath );
705         g_free( addrIndex->fileName );
706
707         /* Clear pointers */    
708         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
709         ADDRITEM_ID(addrIndex) = NULL;
710         ADDRITEM_NAME(addrIndex) = NULL;
711         ADDRITEM_PARENT(addrIndex) = NULL;
712         ADDRITEM_SUBTYPE(addrIndex) = 0;
713         addrIndex->filePath = NULL;
714         addrIndex->fileName = NULL;
715         addrIndex->retVal = MGU_SUCCESS;
716         addrIndex->needsConversion = FALSE;
717         addrIndex->wasConverted = FALSE;
718         addrIndex->conversionError = FALSE;
719         addrIndex->lastType = ADDR_IF_NONE;
720         addrIndex->dirtyFlag = FALSE;
721
722         /* Free up interfaces */        
723         node = addrIndex->interfaceList;
724         while( node ) {
725                 AddressInterface *iface = node->data;
726                 addrindex_free_interface( iface );
727                 node = g_list_next( node );
728         }
729         g_list_free( addrIndex->interfaceList );
730         addrIndex->interfaceList = NULL;
731
732         /* Free up hash cache */
733         addrindex_free_cache_hash( addrIndex->hashCache );
734         addrIndex->hashCache = NULL;
735
736         addrIndex->loadedFlag = FALSE;
737
738         g_free( addrIndex );
739 }
740
741 /**
742  * Print address index.
743  * \param addrIndex Address index.
744  * \parem stream    Stream to print.
745 */
746 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
747         g_return_if_fail( addrIndex != NULL );
748         fprintf( stream, "AddressIndex:\n" );
749         fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
750         fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
751         fprintf( stream, "\t   status: %d\n", addrIndex->retVal );
752         fprintf( stream, "\tconverted: '%s'\n",
753                         addrIndex->wasConverted ? "yes" : "no" );
754         fprintf( stream, "\tcvt error: '%s'\n",
755                         addrIndex->conversionError ? "yes" : "no" );
756         fprintf( stream, "\t---\n" );
757 }
758
759 /**
760  * Retrieve reference to address interface for specified interface type.
761  * \param  addrIndex Address index.
762  * \param  ifType Interface type.
763  * \return Address interface, or NULL if not found.
764  */
765 AddressInterface *addrindex_get_interface(
766         AddressIndex *addrIndex, AddressIfType ifType )
767 {
768         AddressInterface *retVal = NULL;
769         GList *node;
770
771         g_return_val_if_fail( addrIndex != NULL, NULL );
772
773         node = addrIndex->interfaceList;
774         while( node ) {
775                 AddressInterface *iface = node->data;
776                 node = g_list_next( node );
777                 if( iface->type == ifType ) {
778                         retVal = iface;
779                         break;
780                 }
781         }
782         return retVal;
783 }
784
785 /**
786  * Add raw data source to index. The raw data object (an AddressBookFile or
787  * VCardFile object, for example) should be supplied as the raw dataSource
788  * argument.
789  *
790  * \param  addrIndex Address index.
791  * \param ifType     Interface type to add.
792  * \param dataSource Actual raw data source to add. 
793  * \return Data source added, or NULL if invalid interface type.
794  */
795 AddressDataSource *addrindex_index_add_datasource(
796         AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
797 {
798         AddressInterface *iface;
799         AddressDataSource *ds = NULL;
800
801         g_return_val_if_fail( addrIndex != NULL, NULL );
802         g_return_val_if_fail( dataSource != NULL, NULL );
803
804         iface = addrindex_get_interface( addrIndex, ifType );
805         if( iface ) {
806                 ds = addrindex_create_datasource( ifType );
807                 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
808                 ds->type = ifType;
809                 ds->rawDataSource = dataSource;
810                 ds->interface = iface;
811                 iface->listSource = g_list_append( iface->listSource, ds );
812                 addrIndex->dirtyFlag = TRUE;
813
814                 addrindex_hash_add_cache( addrIndex, ds );
815         }
816         return ds;
817 }
818
819 /**
820  * Remove specified data source from index.
821  * \param  addrIndex Address index.
822  * \param  dataSource Data source to add. 
823  * \return Reference to data source if removed, or NULL if data source was not
824  *         found in index. Note the this object must still be freed.
825  */
826 AddressDataSource *addrindex_index_remove_datasource(
827         AddressIndex *addrIndex, AddressDataSource *dataSource )
828 {
829         AddressDataSource *retVal = FALSE;
830         AddressInterface *iface;
831
832         g_return_val_if_fail( addrIndex != NULL, NULL );
833         g_return_val_if_fail( dataSource != NULL, NULL );
834
835         iface = addrindex_get_interface( addrIndex, dataSource->type );
836         if( iface ) {
837                 iface->listSource = g_list_remove( iface->listSource, dataSource );
838                 addrIndex->dirtyFlag = TRUE;
839                 dataSource->interface = NULL;
840
841                 /* Remove cache from hash table */
842                 addrindex_hash_remove_cache( addrIndex, dataSource );
843
844                 retVal = dataSource;
845         }
846         return retVal;
847 }
848
849 /**
850  * Retrieve a reference to address interface for specified interface type and
851  * XML interface tag name.
852  * \param  addrIndex Address index.
853  * \param  tag       XML interface tag name to match.
854  * \param  ifType    Interface type to match.
855  * \return Reference to address index, or NULL if not found in index.
856  */
857 static AddressInterface *addrindex_tag_get_interface(
858         AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
859 {
860         AddressInterface *retVal = NULL;
861         GList *node = addrIndex->interfaceList;
862
863         while( node ) {
864                 AddressInterface *iface = node->data;
865                 node = g_list_next( node );
866                 if( tag ) {
867                         if( strcmp( iface->listTag, tag ) == 0 ) {
868                                 retVal = iface;
869                                 break;
870                         }
871                 }
872                 else {
873                         if( iface->type == ifType ) {
874                                 retVal = iface;
875                                 break;
876                         }
877                 }
878         }
879         return retVal;
880 }
881
882 /**
883  * Retrieve a reference to address interface for specified interface type and
884  * XML datasource tag name.
885  * \param  addrIndex Address index.
886  * \param  ifType    Interface type to match.
887  * \param  tag       XML datasource tag name to match.
888  * \return Reference to address index, or NULL if not found in index.
889  */
890 static AddressInterface *addrindex_tag_get_datasource(
891         AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
892 {
893         AddressInterface *retVal = NULL;
894         GList *node = addrIndex->interfaceList;
895
896         while( node ) {
897                 AddressInterface *iface = node->data;
898                 node = g_list_next( node );
899                 if( iface->type == ifType && iface->itemTag ) {
900                         if( strcmp( iface->itemTag, tag ) == 0 ) {
901                                 retVal = iface;
902                                 break;
903                         }
904                 }
905         }
906         return retVal;
907 }
908
909 /* **********************************************************************
910 * Interface XML parsing functions.
911 * ***********************************************************************
912 */
913
914 /**
915  * Write start of XML element to file.
916  * \param fp   File.
917  * \param lvl  Indentation level.
918  * \param name Element name.
919  */
920 static void addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
921         gint i;
922         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
923         fputs( "<", fp );
924         fputs( name, fp );
925 }
926
927 /**
928  * Write end of XML element to file.
929  * \param fp   File.
930  * \param lvl  Indentation level.
931  * \param name Element name.
932  */
933 static void addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
934         gint i;
935         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
936         fputs( "</", fp );
937         fputs( name, fp );
938         fputs( ">\n", fp );
939 }
940
941 /**
942  * Write XML attribute to file.
943  * \param fp    File.
944  * \param name  Attribute name.
945  * \param value Attribute value.
946  */
947 static void addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
948         fputs( " ", fp );
949         fputs( name, fp );
950         fputs( "=\"", fp );
951         xml_file_put_escape_str( fp, value );
952         fputs( "\"", fp );
953 }
954
955 /**
956  * Return DOM fragment for current XML tag from file.
957  * \param  file XML file being processed.
958  * \return Fragment representing DOM fragment for configuration element.
959  */
960 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
961         AddressIfFragment *fragment;
962         AddressIfFragment *child;
963         AddressIfAttrib *nv;
964         XMLTag *xtag;
965         GList *list;
966         GList *attr;
967         gchar *name;
968         gchar *value;
969         guint prevLevel;
970         gint rc;
971
972         /* printf( "addrindex_read_fragment\n" ); */
973
974         prevLevel = file->level;
975
976         /* Get current tag name */
977         xtag = xml_get_current_tag( file );
978
979         /* Create new fragment */
980         fragment = g_new0( AddressIfFragment, 1 );
981         fragment->name = g_strdup( xtag->tag );
982         fragment->children = NULL;
983         fragment->attributes = NULL;
984
985         /* Read attributes */
986         list = NULL;
987         attr = xml_get_current_tag_attr( file );
988         while( attr ) {
989                 name = ((XMLAttr *)attr->data)->name;
990                 value = ((XMLAttr *)attr->data)->value;
991                 nv = g_new0( AddressIfAttrib, 1 );
992                 nv->name = g_strdup( name );
993                 nv->value = g_strdup( value );
994                 list = g_list_append( list, nv );
995                 attr = g_list_next( attr );
996         }
997         fragment->attributes = list;
998
999         /* Now read the children */
1000         while( TRUE ) {
1001                 rc = xml_parse_next_tag( file );
1002                 if( rc != 0 ) {
1003                         /* End of file? */
1004                         break;
1005                 }
1006                 if( file->level < prevLevel ) {
1007                         /* We must be above level we start at */
1008                         break;
1009                 }
1010                 child = addrindex_read_fragment( file );
1011                 fragment->children = g_list_append( fragment->children, child );
1012         }
1013
1014         return fragment;
1015 }
1016
1017 /**
1018  * Write DOM fragment to file.
1019  * \param fp       File to write.
1020  * \param fragment DOM fragment for configuration element.
1021  * \param lvl      Indent level.
1022  */
1023 static void addrindex_write_fragment(
1024                 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1025 {
1026         GList *node;
1027
1028         if( fragment ) {
1029                 addrindex_write_elem_s( fp, lvl, fragment->name );
1030                 node = fragment->attributes;
1031                 while( node ) {
1032                         AddressIfAttrib *nv = node->data;
1033                         addrindex_write_attr( fp, nv->name, nv->value );
1034                         node = g_list_next( node );
1035                 }
1036                 if( fragment->children ) {
1037                         fputs(" >\n", fp);
1038
1039                         /* Output children */
1040                         node = fragment->children;
1041                         while( node ) {
1042                                 AddressIfFragment *child = node->data;
1043                                 addrindex_write_fragment( fp, child, 1+lvl );
1044                                 node = g_list_next( node );
1045                         }
1046
1047                         /* Output closing tag */
1048                         addrindex_write_elem_e( fp, lvl, fragment->name );
1049                 }
1050                 else {
1051                         fputs(" />\n", fp);
1052                 }
1053         }
1054 }
1055
1056 /*
1057 static void addrindex_print_fragment_r(
1058                 const AddressIfFragment *fragment, FILE *stream, gint lvl )
1059 {
1060         GList *node;
1061         gint i;
1062
1063         for( i = 0; i < lvl; i++ )
1064                 fprintf( stream, "  " );
1065         fprintf( stream, "Element:%s:\n", fragment->name );
1066         node = fragment->attributes;
1067         while( node ) {
1068                 AddressIfAttrib *nv = node->data;
1069                 for( i = 0; i < lvl; i++ )
1070                         fprintf( stream, "  " );
1071                 fprintf( stream, "    %s : %s\n", nv->name, nv->value );
1072                 node = g_list_next( node );
1073         }
1074         node = fragment->children;
1075         while( node ) {
1076                 AddressIfFragment *child = node->data;
1077                 addrindex_print_fragment_r( child, stream, 1+lvl );
1078                 node = g_list_next( node );
1079         }
1080 }
1081
1082 static void addrindex_print_fragment( const AddressIfFragment *fragment, FILE *stream ) {
1083         addrindex_print_fragment_r( fragment, stream, 0 );
1084 }
1085 */
1086
1087 /**
1088  * Read/parse address index file, creating a data source for a regular
1089  * intrinsic XML addressbook.
1090  * \param  file Address index file.
1091  * \return Data source.
1092  */
1093 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1094         AddressDataSource *ds;
1095         AddressBookFile *abf;
1096         GList *attr;
1097
1098         ds = addrindex_create_datasource( ADDR_IF_BOOK );
1099         abf = addrbook_create_book();
1100         attr = xml_get_current_tag_attr( file );
1101         while( attr ) {
1102                 gchar *name = ((XMLAttr *)attr->data)->name;
1103                 gchar *value = ((XMLAttr *)attr->data)->value;
1104                 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1105                         addrbook_set_name( abf, value );
1106                 }
1107                 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1108                         addrbook_set_file( abf, value );
1109                 }
1110                 attr = g_list_next( attr );
1111         }
1112         ds->rawDataSource = abf;
1113         return ds;
1114 }
1115
1116 static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1117         AddressBookFile *abf = ds->rawDataSource;
1118         if( abf ) {
1119                 addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK );
1120                 addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) );
1121                 addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName );
1122                 fputs( " />\n", fp );
1123         }
1124 }
1125
1126 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1127         AddressDataSource *ds;
1128         VCardFile *vcf;
1129         GList *attr;
1130
1131         ds = addrindex_create_datasource( ADDR_IF_VCARD );
1132         vcf = vcard_create();
1133         attr = xml_get_current_tag_attr( file );
1134         while( attr ) {
1135                 gchar *name = ((XMLAttr *)attr->data)->name;
1136                 gchar *value = ((XMLAttr *)attr->data)->value;
1137                 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1138                         vcard_set_name( vcf, value );
1139                 }
1140                 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1141                         vcard_set_file( vcf, value );
1142                 }
1143                 attr = g_list_next( attr );
1144         }
1145         ds->rawDataSource = vcf;
1146         return ds;
1147 }
1148
1149 static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1150         VCardFile *vcf = ds->rawDataSource;
1151         if( vcf ) {
1152                 addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD );
1153                 addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) );
1154                 addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path );
1155                 fputs( " />\n", fp );
1156         }
1157 }
1158
1159 #ifdef USE_JPILOT
1160 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1161         AddressDataSource *ds;
1162         JPilotFile *jpf;
1163         GList *attr;
1164
1165         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1166         jpf = jpilot_create();
1167         attr = xml_get_current_tag_attr( file );
1168         while( attr ) {
1169                 gchar *name = ((XMLAttr *)attr->data)->name;
1170                 gchar *value = ((XMLAttr *)attr->data)->value;
1171                 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1172                         jpilot_set_name( jpf, value );
1173                 }
1174                 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1175                         jpilot_set_file( jpf, value );
1176                 }
1177                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1178                         jpilot_add_custom_label( jpf, value );
1179                 }
1180                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1181                         jpilot_add_custom_label( jpf, value );
1182                 }
1183                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1184                         jpilot_add_custom_label( jpf, value );
1185                 }
1186                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1187                         jpilot_add_custom_label( jpf, value );
1188                 }
1189                 attr = g_list_next( attr );
1190         }
1191         ds->rawDataSource = jpf;
1192         return ds;
1193 }
1194
1195 static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1196         JPilotFile *jpf = ds->rawDataSource;
1197         if( jpf ) {
1198                 gint ind;
1199                 GList *node;
1200                 GList *customLbl = jpilot_get_custom_labels( jpf );
1201                 addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT );
1202                 addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) );
1203                 addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path );
1204                 node = customLbl;
1205                 ind = 1;
1206                 while( node ) {
1207                         gchar name[256];
1208                         g_snprintf( name, sizeof(name), "%s%d",
1209                                     ATTAG_JPILOT_CUSTOM, ind );
1210                         addrindex_write_attr( fp, name, node->data );
1211                         ind++;
1212                         node = g_list_next( node );
1213                 }
1214                 fputs( " />\n", fp );
1215         }
1216 }
1217
1218 #else
1219 /*
1220  * Just read/write DOM fragments (preserve data found in file).
1221  */
1222 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1223         AddressDataSource *ds;
1224
1225         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1226         ds->rawDataSource = addrindex_read_fragment( file );
1227         return ds;
1228 }
1229
1230 static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1231         AddressIfFragment *fragment = ds->rawDataSource;
1232         if( fragment ) {
1233                 addrindex_write_fragment( fp, fragment, lvl );
1234         }
1235 }
1236 #endif
1237
1238 #ifdef USE_LDAP
1239 /**
1240  * Parse LDAP criteria attribute data from XML file.
1241  * \param file Index file.
1242  * \param ctl  LDAP control object to populate.
1243  */
1244 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1245         guint prevLevel;
1246         XMLTag *xtag;
1247         XMLTag *xtagPrev;
1248         gint rc;
1249         GList *attr;
1250         GList *list;
1251         GList *node;
1252
1253         if( file == NULL ) {
1254                 return;
1255         }
1256
1257         list = NULL;
1258         prevLevel = file->level;
1259         xtagPrev = xml_get_current_tag( file );
1260         while( TRUE ) {
1261                 rc = xml_parse_next_tag( file );
1262                 if( rc != 0 ) {
1263                         /* Terminate prematurely */
1264                         mgu_free_dlist( list );
1265                         list = NULL;
1266                         return;
1267                 }
1268                 if( file->level < prevLevel ) {
1269                         /* We must be above level we start at */
1270                         break;
1271                 }
1272
1273                 /* Get a tag (element) */
1274                 xtag = xml_get_current_tag( file );
1275                 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1276                         /* LDAP criteria attribute */
1277                         attr = xml_get_current_tag_attr( file );
1278                         while( attr ) {
1279                                 gchar *name = ((XMLAttr *)attr->data)->name;
1280                                 gchar *value = ((XMLAttr *)attr->data)->value;
1281                                 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1282                                         if( value && strlen( value ) > 0 ) {
1283                                                 list = g_list_append(
1284                                                         list, g_strdup( value ) );
1285                                         }
1286                                 }
1287                                 attr = g_list_next( attr );
1288                         }
1289                 }
1290                 else {
1291                         if( xtag != xtagPrev ) {
1292                                 /* Found a new tag */
1293                                 break;
1294                         }
1295                 }
1296                 xtag = xtagPrev;
1297         }
1298
1299         /* Build list of search attributes */
1300         ldapctl_criteria_list_clear( ctl );
1301         node = list;
1302         while( node ) {
1303                 ldapctl_criteria_list_add( ctl, node->data );
1304                 g_free( node->data );
1305                 node->data = NULL;
1306                 node = g_list_next( node );
1307         }
1308         g_list_free( list );
1309         list = NULL;
1310
1311 }
1312
1313 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1314         AddressDataSource *ds;
1315         LdapServer *server;
1316         LdapControl *ctl;
1317         GList *attr;
1318         gchar *serverName = NULL;
1319         gchar *criteria = NULL;
1320         gboolean bSearch = FALSE;
1321         gboolean cvtFlag = TRUE;
1322
1323         /* printf( "addrindex_parse_ldap\n" ); */
1324
1325         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1326         ctl = ldapctl_create();
1327         attr = xml_get_current_tag_attr( file );
1328         while( attr ) {
1329                 gchar *name = ((XMLAttr *)attr->data)->name;
1330                 gchar *value = ((XMLAttr *)attr->data)->value;
1331                 gint ivalue = atoi( value );
1332
1333                 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
1334                         if( serverName ) g_free( serverName );
1335                         serverName = g_strdup( value );
1336                 }
1337                 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
1338                         ldapctl_set_host( ctl, value );
1339                 }
1340                 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
1341                         ldapctl_set_port( ctl, ivalue );
1342                 }
1343                 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
1344                         ldapctl_set_base_dn( ctl, value );
1345                 }
1346                 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
1347                         ldapctl_set_bind_dn( ctl, value );
1348                 }
1349                 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
1350                         ldapctl_set_bind_password( ctl, value );
1351                 }
1352                 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
1353                         if( criteria ) g_free( criteria );
1354                         criteria = g_strdup( value );
1355                 }
1356                 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
1357                         ldapctl_set_max_entries( ctl, ivalue );
1358                 }
1359                 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
1360                         ldapctl_set_timeout( ctl, ivalue );
1361                 }
1362                 else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
1363                         ldapctl_set_max_query_age( ctl, ivalue );
1364                 }
1365                 else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
1366                         bSearch = FALSE;
1367                         cvtFlag = FALSE;
1368                         if( strcmp( value, "yes" ) == 0 ) {
1369                                 bSearch = TRUE;
1370                         }
1371                 }
1372                 attr = g_list_next( attr );
1373         }
1374
1375         server = ldapsvr_create_noctl();
1376         ldapsvr_set_name( server, serverName );
1377         ldapsvr_set_search_flag( server, bSearch );
1378         g_free( serverName );
1379         ldapsvr_set_control( server, ctl );
1380         ds->rawDataSource = server;
1381
1382         addrindex_parse_ldap_attrlist( file, ctl );
1383         /*
1384          * If criteria have been specified and no attributes were listed, then
1385          * convert old style criteria into an attribute list. Any criteria will
1386          * be dropped when saving data.
1387          */
1388         if( criteria ) {
1389                 if( ! ldapctl_get_criteria_list( ctl ) ) {
1390                         ldapctl_parse_ldap_search( ctl, criteria );
1391                 }
1392                 g_free( criteria );
1393         }
1394         /*
1395          * If no search flag was found, then we are converting from old format
1396          * server data to new format.
1397          */
1398         if( cvtFlag ) {
1399                 ldapsvr_set_search_flag( server, TRUE );
1400         }
1401         /* ldapsvr_print_data( server, stdout ); */
1402
1403         return ds;
1404 }
1405
1406 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1407         LdapServer *server = ds->rawDataSource;
1408         LdapControl *ctl = NULL;
1409         GList *node;
1410         gchar value[256];
1411
1412         if( server ) {
1413                 ctl = server->control;
1414         }
1415         if( ctl == NULL ) return;
1416
1417         /* Output start element with attributes */
1418         addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
1419         addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) );
1420         addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName );
1421
1422         sprintf( value, "%d", ctl->port );      
1423         addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
1424
1425         addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN );
1426         addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN );
1427         addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, ctl->bindPass );
1428
1429         sprintf( value, "%d", ctl->maxEntries );
1430         addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
1431         sprintf( value, "%d", ctl->timeOut );
1432         addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
1433         sprintf( value, "%d", ctl->maxQueryAge );
1434         addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value );
1435
1436         addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
1437                         server->searchFlag ? "yes" : "no" );
1438
1439         fputs(" >\n", fp);
1440
1441         /* Output attributes */
1442         node = ldapctl_get_criteria_list( ctl );
1443         while( node ) {
1444                 addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH );
1445                 addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data );
1446                 fputs(" />\n", fp);
1447                 node = g_list_next( node );
1448         }
1449
1450         /* End of element */    
1451         addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP );
1452
1453 }
1454
1455 #else
1456 /*
1457  * Just read/write DOM fragments (preserve data found in file).
1458  */
1459 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1460         AddressDataSource *ds;
1461
1462         ds = addrindex_create_datasource( ADDR_IF_LDAP );
1463         ds->rawDataSource = addrindex_read_fragment( file );
1464         return ds;
1465 }
1466
1467 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1468         AddressIfFragment *fragment = ds->rawDataSource;
1469         if( fragment ) {
1470                 addrindex_write_fragment( fp, fragment, lvl );
1471         }
1472 }
1473 #endif
1474
1475 /* **********************************************************************
1476 * Address index I/O functions.
1477 * ***********************************************************************
1478 */
1479 /**
1480  * Read address index file, creating appropriate data sources for each address
1481  * index file entry.
1482  *
1483  * \param  addrIndex Address index.
1484  * \param  file Address index file.
1485  */
1486 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
1487         guint prev_level;
1488         XMLTag *xtag;
1489         AddressInterface *iface = NULL, *dsIFace = NULL;
1490         AddressDataSource *ds;
1491         gint rc;
1492
1493         addrIndex->loadedFlag = FALSE;
1494         for (;;) {
1495                 prev_level = file->level;
1496                 rc = xml_parse_next_tag( file );
1497                 if( file->level == 0 ) return;
1498
1499                 xtag = xml_get_current_tag( file );
1500
1501                 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
1502                 if( iface ) {
1503                         addrIndex->lastType = iface->type;
1504                         if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
1505                 }
1506                 else {
1507                         dsIFace = addrindex_tag_get_datasource(
1508                                         addrIndex, addrIndex->lastType, xtag->tag );
1509                         if( dsIFace ) {
1510                                 /* Add data source to list */
1511                                 ds = NULL;
1512                                 if( addrIndex->lastType == ADDR_IF_BOOK ) {
1513                                         ds = addrindex_parse_book( file );
1514                                         if( ds->rawDataSource ) {
1515                                                 addrbook_set_path( ds->rawDataSource,
1516                                                         addrIndex->filePath );
1517                                         }
1518                                 }
1519                                 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
1520                                         ds = addrindex_parse_vcard( file );
1521                                 }
1522                                 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
1523                                         ds = addrindex_parse_jpilot( file );
1524                                 }
1525                                 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
1526                                         ds = addrindex_parse_ldap( file );
1527                                 }
1528                                 if( ds ) {
1529                                         ds->interface = dsIFace;
1530                                         addrindex_hash_add_cache( addrIndex, ds );
1531                                         dsIFace->listSource =
1532                                                 g_list_append( dsIFace->listSource, ds );
1533                                 }
1534                         }
1535                 }
1536         }
1537 }
1538
1539 /*
1540  * Search order sorting comparison function for building search order list.
1541  */
1542 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
1543         AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
1544         AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
1545
1546         return ifaceA->searchOrder - ifaceB->searchOrder;
1547 }
1548
1549 /**
1550  * Build list of data sources to process.
1551  * \param addrIndex Address index object.
1552  */
1553 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
1554         GList *nodeIf;
1555
1556         /* Clear existing list */
1557         g_list_free( addrIndex->searchOrder );
1558         addrIndex->searchOrder = NULL;
1559
1560         /* Build new list */
1561         nodeIf = addrIndex->interfaceList;
1562         while( nodeIf ) {
1563                 AddressInterface *iface = nodeIf->data;
1564                 if( iface->useInterface ) {
1565                         if( iface->searchOrder > 0 ) {
1566                                 /* Add to search order list */
1567                                 addrIndex->searchOrder = g_list_insert_sorted(
1568                                         addrIndex->searchOrder, iface,
1569                                         addrindex_search_order_compare );
1570                         }
1571                 }
1572                 nodeIf = g_list_next( nodeIf );
1573         }
1574 }
1575
1576 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1577         XMLFile *file = NULL;
1578         gchar *fileSpec = NULL;
1579
1580         g_return_val_if_fail( addrIndex != NULL, -1 );
1581
1582         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1583         addrIndex->retVal = MGU_NO_FILE;
1584         file = xml_open_file( fileSpec );
1585         g_free( fileSpec );
1586
1587         if( file == NULL ) {
1588                 /*
1589                 fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
1590                 */
1591                 return addrIndex->retVal;
1592         }
1593
1594         addrIndex->retVal = MGU_BAD_FORMAT;
1595         if( xml_get_dtd( file ) == 0 ) {
1596                 if( xml_parse_next_tag( file ) == 0 ) {
1597                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1598                                 addrindex_read_index( addrIndex, file );
1599                                 addrIndex->retVal = MGU_SUCCESS;
1600                         }
1601                 }
1602         }
1603         xml_close_file( file );
1604
1605         addrindex_build_search_order( addrIndex );
1606
1607         return addrIndex->retVal;
1608 }
1609
1610 static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1611         GList *nodeIF, *nodeDS;
1612         gint lvlList = 1;
1613         gint lvlItem = 1 + lvlList;
1614
1615         nodeIF = addrIndex->interfaceList;
1616         while( nodeIF ) {
1617                 AddressInterface *iface = nodeIF->data;
1618                 if( ! iface->legacyFlag ) {
1619                         nodeDS = iface->listSource;
1620                         addrindex_write_elem_s( fp, lvlList, iface->listTag );
1621                         fputs( ">\n", fp );
1622                         while( nodeDS ) {
1623                                 AddressDataSource *ds = nodeDS->data;
1624                                 if( ds ) {
1625                                         if( iface->type == ADDR_IF_BOOK ) {
1626                                                 addrindex_write_book( fp, ds, lvlItem );
1627                                         }
1628                                         if( iface->type == ADDR_IF_VCARD ) {
1629                                                 addrindex_write_vcard( fp, ds, lvlItem );
1630                                         }
1631                                         if( iface->type == ADDR_IF_JPILOT ) {
1632                                                 addrindex_write_jpilot( fp, ds, lvlItem );
1633                                         }
1634                                         if( iface->type == ADDR_IF_LDAP ) {
1635                                                 addrindex_write_ldap( fp, ds, lvlItem );
1636                                         }
1637                                 }
1638                                 nodeDS = g_list_next( nodeDS );
1639                         }
1640                         addrindex_write_elem_e( fp, lvlList, iface->listTag );
1641                 }
1642                 nodeIF = g_list_next( nodeIF );
1643         }
1644 }
1645
1646 /*
1647 * Write data to specified file.
1648 * Enter: addrIndex Address index object.
1649 *        newFile   New file name.
1650 * return: Status code, from addrIndex->retVal.
1651 * Note: File will be created in directory specified by addrIndex.
1652 */
1653 gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1654         FILE *fp;
1655         gchar *fileSpec;
1656 #ifndef DEV_STANDALONE
1657         PrefFile *pfile;
1658 #endif
1659
1660         g_return_val_if_fail( addrIndex != NULL, -1 );
1661
1662         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1663         addrIndex->retVal = MGU_OPEN_FILE;
1664 #ifdef DEV_STANDALONE
1665         fp = fopen( fileSpec, "wb" );
1666         g_free( fileSpec );
1667         if( fp ) {
1668                 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1669 #else
1670         pfile = prefs_write_open( fileSpec );
1671         g_free( fileSpec );
1672         if( pfile ) {
1673                 fp = pfile->fp;
1674                 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1675                                 conv_get_current_charset_str() );
1676 #endif
1677                 addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX );
1678                 fputs( ">\n", fp );
1679
1680                 addrindex_write_index( addrIndex, fp );
1681                 addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX );
1682
1683                 addrIndex->retVal = MGU_SUCCESS;
1684 #ifdef DEV_STANDALONE
1685                 fclose( fp );
1686 #else
1687                 if( prefs_file_close( pfile ) < 0 ) {
1688                         addrIndex->retVal = MGU_ERROR_WRITE;
1689                 }
1690 #endif
1691         }
1692
1693         fileSpec = NULL;
1694         return addrIndex->retVal;
1695 }
1696
1697 /*
1698 * Save address index data to original file.
1699 * return: Status code, from addrIndex->retVal.
1700 */
1701 gint addrindex_save_data( AddressIndex *addrIndex ) {
1702         g_return_val_if_fail( addrIndex != NULL, -1 );
1703
1704         addrIndex->retVal = MGU_NO_FILE;
1705         if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1706         if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1707
1708         addrindex_write_to( addrIndex, addrIndex->fileName );
1709         if( addrIndex->retVal == MGU_SUCCESS ) {
1710                 addrIndex->dirtyFlag = FALSE;
1711         }
1712         return addrIndex->retVal;
1713 }
1714
1715 /*
1716 * Save all address book files which may have changed.
1717 * Return: Status code, set if there was a problem saving data.
1718 */
1719 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1720         gint retVal = MGU_SUCCESS;
1721         GList *nodeIf, *nodeDS;
1722
1723         nodeIf = addrIndex->interfaceList;
1724         while( nodeIf ) {
1725                 AddressInterface *iface = nodeIf->data;
1726                 if( iface->type == ADDR_IF_BOOK ) {
1727                         nodeDS = iface->listSource;
1728                         while( nodeDS ) {
1729                                 AddressDataSource *ds = nodeDS->data;
1730                                 AddressBookFile *abf = ds->rawDataSource;
1731                                 if( addrbook_get_dirty( abf ) ) {
1732                                         if( addrbook_get_read_flag( abf ) ) {
1733                                                 addrbook_save_data( abf );
1734                                                 if( abf->retVal != MGU_SUCCESS ) {
1735                                                         retVal = abf->retVal;
1736                                                 }
1737                                         }
1738                                 }
1739                                 nodeDS = g_list_next( nodeDS );
1740                         }
1741                         break;
1742                 }
1743                 nodeIf = g_list_next( nodeIf );
1744         }
1745         return retVal;
1746 }
1747
1748
1749 /* **********************************************************************
1750 * Address book conversion to new format.
1751 * ***********************************************************************
1752 */
1753
1754 #define ELTAG_IF_OLD_FOLDER   "folder"
1755 #define ELTAG_IF_OLD_GROUP    "group"
1756 #define ELTAG_IF_OLD_ITEM     "item"
1757 #define ELTAG_IF_OLD_NAME     "name"
1758 #define ELTAG_IF_OLD_ADDRESS  "address"
1759 #define ELTAG_IF_OLD_REMARKS  "remarks"
1760 #define ATTAG_IF_OLD_NAME     "name"
1761
1762 #define TEMPNODE_ROOT         0
1763 #define TEMPNODE_FOLDER       1
1764 #define TEMPNODE_GROUP        2
1765 #define TEMPNODE_ADDRESS      3
1766
1767 typedef struct _AddressCvt_Node AddressCvtNode;
1768 struct _AddressCvt_Node {
1769         gint  type;
1770         gchar *name;
1771         gchar *address;
1772         gchar *remarks;
1773         GList *list;
1774 };
1775
1776 /*
1777 * Parse current address item.
1778 */
1779 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1780         gchar *element;
1781         guint level;
1782         AddressCvtNode *nn;
1783
1784         nn = g_new0( AddressCvtNode, 1 );
1785         nn->type = TEMPNODE_ADDRESS;
1786         nn->list = NULL;
1787
1788         level = file->level;
1789
1790         for (;;) {
1791                 xml_parse_next_tag(file);
1792                 if (file->level < level) return nn;
1793
1794                 element = xml_get_element( file );
1795                 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1796                         nn->name = g_strdup( element );
1797                 }
1798                 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1799                         nn->address = g_strdup( element );
1800                 }
1801                 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1802                         nn->remarks = g_strdup( element );
1803                 }
1804                 xml_parse_next_tag(file);
1805         }
1806 }
1807
1808 /*
1809 * Create a temporary node below specified node.
1810 */
1811 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1812         AddressCvtNode *nn;
1813         nn = g_new0( AddressCvtNode, 1 );
1814         nn->type = type;
1815         nn->name = g_strdup( name );
1816         nn->remarks = g_strdup( rem );
1817         node->list = g_list_append( node->list, nn );
1818         return nn;
1819 }
1820
1821 /*
1822 * Process current temporary node.
1823 */
1824 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1825         GList *attr;
1826         guint prev_level;
1827         AddressCvtNode *newNode = NULL;
1828         gchar *name;
1829         gchar *value;
1830
1831         for (;;) {
1832                 prev_level = file->level;
1833                 xml_parse_next_tag( file );
1834                 if (file->level < prev_level) return;
1835                 name = NULL;
1836                 value = NULL;
1837
1838                 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1839                         attr = xml_get_current_tag_attr(file);
1840                         if (attr) {
1841                                 name = ((XMLAttr *)attr->data)->name;
1842                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1843                                         value = ((XMLAttr *)attr->data)->value;
1844                                 }
1845                         }
1846                         newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1847                         addrindex_add_obj( file, newNode );
1848
1849                 }
1850                 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1851                         attr = xml_get_current_tag_attr(file);
1852                         if (attr) {
1853                                 name = ((XMLAttr *)attr->data)->name;
1854                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1855                                         value = ((XMLAttr *)attr->data)->value;
1856                                 }
1857                         }
1858                         newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
1859                         addrindex_add_obj( file, newNode );
1860                 }
1861                 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
1862                         newNode = addrindex_parse_item( file );
1863                         node->list = g_list_append( node->list, newNode );
1864                 }
1865                 else {
1866                         /* printf( "invalid: !!! \n" ); */
1867                         attr = xml_get_current_tag_attr( file );
1868                 }
1869         }
1870 }
1871
1872 /*
1873 * Consume all nodes below current tag.
1874 */
1875 static void addrindex_consume_tree( XMLFile *file ) {
1876         guint prev_level;
1877         gchar *element;
1878         GList *attr;
1879         XMLTag *xtag;
1880
1881         for (;;) {
1882                 prev_level = file->level;
1883                 xml_parse_next_tag( file );
1884                 if (file->level < prev_level) return;
1885
1886                 xtag = xml_get_current_tag( file );
1887                 /* printf( "tag : %s\n", xtag->tag ); */
1888                 element = xml_get_element( file );
1889                 attr = xml_get_current_tag_attr( file );
1890                 /* show_attribs( attr ); */
1891                 /* printf( "\ttag  value : %s :\n", element ); */
1892                 addrindex_consume_tree( file );
1893         }
1894 }
1895
1896 /*
1897 * Print temporary tree.
1898 */
1899 static void addrindex_print_node( AddressCvtNode *node, FILE *stream  ) {
1900         GList *list;
1901
1902         fprintf( stream, "Node:\ttype :%d:\n", node->type );
1903         fprintf( stream, "\tname :%s:\n", node->name );
1904         fprintf( stream, "\taddr :%s:\n", node->address );
1905         fprintf( stream, "\trems :%s:\n", node->remarks );
1906         if( node->list ) {
1907                 fprintf( stream, "\t--list----\n" );
1908         }
1909         list = node->list;
1910         while( list ) {
1911                 AddressCvtNode *lNode = list->data;
1912                 list = g_list_next( list );
1913                 addrindex_print_node( lNode, stream );
1914         }
1915         fprintf( stream, "\t==list-%d==\n", node->type );
1916 }
1917
1918 /*
1919 * Free up temporary tree.
1920 */
1921 static void addrindex_free_node( AddressCvtNode *node ) {
1922         GList *list = node->list;
1923
1924         while( list ) {
1925                 AddressCvtNode *lNode = list->data;
1926                 list = g_list_next( list );
1927                 addrindex_free_node( lNode );
1928         }
1929         node->type = TEMPNODE_ROOT;
1930         g_free( node->name );
1931         g_free( node->address );
1932         g_free( node->remarks );
1933         g_list_free( node->list );
1934         g_free( node );
1935 }
1936
1937 /*
1938 * Process address book for specified node.
1939 */
1940 static void addrindex_process_node(
1941                 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
1942                 ItemGroup *parentGrp, ItemFolder *folderGrp )
1943 {
1944         GList *list;
1945         ItemFolder *itemFolder = NULL;
1946         ItemGroup *itemGParent = parentGrp;
1947         ItemFolder *itemGFolder = folderGrp;
1948         AddressCache *cache = abf->addressCache;
1949
1950         if( node->type == TEMPNODE_ROOT ) {
1951                 itemFolder = parent;
1952         }
1953         else if( node->type == TEMPNODE_FOLDER ) {
1954                 itemFolder = addritem_create_item_folder();
1955                 addritem_folder_set_name( itemFolder, node->name );
1956                 addrcache_id_folder( cache, itemFolder );
1957                 addrcache_folder_add_folder( cache, parent, itemFolder );
1958                 itemGFolder = NULL;
1959         }
1960         else if( node->type == TEMPNODE_GROUP ) {
1961                 ItemGroup *itemGroup;
1962                 gchar *fName;
1963
1964                 /* Create a folder for group */
1965                 fName = g_strdup_printf( "Cvt - %s", node->name );
1966                 itemGFolder = addritem_create_item_folder();
1967                 addritem_folder_set_name( itemGFolder, fName );
1968                 addrcache_id_folder( cache, itemGFolder );
1969                 addrcache_folder_add_folder( cache, parent, itemGFolder );
1970                 g_free( fName );
1971
1972                 /* Add group into folder */
1973                 itemGroup = addritem_create_item_group();
1974                 addritem_group_set_name( itemGroup, node->name );
1975                 addrcache_id_group( cache, itemGroup );
1976                 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
1977                 itemGParent = itemGroup;
1978         }
1979         else if( node->type == TEMPNODE_ADDRESS ) {
1980                 ItemPerson *itemPerson;
1981                 ItemEMail *itemEMail;
1982
1983                 /* Create person and email objects */
1984                 itemPerson = addritem_create_item_person();
1985                 addritem_person_set_common_name( itemPerson, node->name );
1986                 addrcache_id_person( cache, itemPerson );
1987                 itemEMail = addritem_create_item_email();
1988                 addritem_email_set_address( itemEMail, node->address );
1989                 addritem_email_set_remarks( itemEMail, node->remarks );
1990                 addrcache_id_email( cache, itemEMail );
1991                 addrcache_person_add_email( cache, itemPerson, itemEMail );
1992
1993                 /* Add person into appropriate folder */
1994                 if( itemGFolder ) {
1995                         addrcache_folder_add_person( cache, itemGFolder, itemPerson );
1996                 }
1997                 else {
1998                         addrcache_folder_add_person( cache, parent, itemPerson );
1999                 }
2000
2001                 /* Add email address only into group */
2002                 if( parentGrp ) {
2003                         addrcache_group_add_email( cache, parentGrp, itemEMail );
2004                 }
2005         }
2006
2007         list = node->list;
2008         while( list ) {
2009                 AddressCvtNode *lNode = list->data;
2010                 list = g_list_next( list );
2011                 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
2012         }
2013 }
2014
2015 /*
2016 * Process address book to specified file number.
2017 */
2018 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
2019         gboolean retVal = FALSE;
2020         AddressBookFile *abf = NULL;
2021         AddressCvtNode *rootNode = NULL;
2022         gchar *newFile = NULL;
2023         GList *fileList = NULL;
2024         gint fileNum  = 0;
2025
2026         /* Setup root node */
2027         rootNode = g_new0( AddressCvtNode, 1 );
2028         rootNode->type = TEMPNODE_ROOT;
2029         rootNode->name = g_strdup( "root" );
2030         rootNode->list = NULL;
2031         addrindex_add_obj( file, rootNode );
2032         /* addrindex_print_node( rootNode, stdout ); */
2033
2034         /* Create new address book */
2035         abf = addrbook_create_book();
2036         addrbook_set_name( abf, displayName );
2037         addrbook_set_path( abf, addrIndex->filePath );
2038
2039         /* Determine next available file number */
2040         fileList = addrbook_get_bookfile_list( abf );
2041         if( fileList ) {
2042                 fileNum = 1 + abf->maxValue;
2043         }
2044         g_list_free( fileList );
2045         fileList = NULL;
2046
2047         newFile = addrbook_gen_new_file_name( fileNum );
2048         if( newFile ) {
2049                 addrbook_set_file( abf, newFile );
2050         }
2051
2052         addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
2053
2054         /* addrbook_dump_book( abf, stdout ); */
2055         addrbook_save_data( abf );
2056         addrIndex->retVal = abf->retVal;
2057         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2058
2059         addrbook_free_book( abf );
2060         abf = NULL;
2061         addrindex_free_node( rootNode );
2062         rootNode = NULL;
2063
2064         /* Create entries in address index */
2065         if( retVal ) {
2066                 abf = addrbook_create_book();
2067                 addrbook_set_name( abf, displayName );
2068                 addrbook_set_path( abf, addrIndex->filePath );
2069                 addrbook_set_file( abf, newFile );
2070                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2071         }
2072
2073         return retVal;
2074 }
2075
2076 /*
2077 * Process tree converting data.
2078 */
2079 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
2080         guint prev_level;
2081         gchar *element;
2082         GList *attr;
2083         XMLTag *xtag;
2084
2085         /* Process file */
2086         for (;;) {
2087                 prev_level = file->level;
2088                 xml_parse_next_tag( file );
2089                 if (file->level < prev_level) return;
2090
2091                 xtag = xml_get_current_tag( file );
2092                 /* printf( "tag : %d : %s\n", prev_level, xtag->tag ); */
2093                 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
2094                         if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
2095                                 addrIndex->needsConversion = FALSE;
2096                                 addrIndex->wasConverted = TRUE;
2097                                 continue;
2098                         }
2099                         return;
2100                 }
2101                 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
2102                         if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
2103                                 addrIndex->needsConversion = FALSE;
2104                                 addrIndex->wasConverted = TRUE;
2105                                 continue;
2106                         }
2107                         return;
2108                 }
2109                 element = xml_get_element( file );
2110                 attr = xml_get_current_tag_attr( file );
2111                 /* show_attribs( attr ); */
2112                 /* printf( "\ttag  value : %s :\n", element ); */
2113                 addrindex_consume_tree( file );
2114         }
2115 }
2116
2117 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
2118         XMLFile *file = NULL;
2119         gchar *fileSpec;
2120
2121         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
2122         addrIndex->retVal = MGU_NO_FILE;
2123         file = xml_open_file( fileSpec );
2124         g_free( fileSpec );
2125
2126         if( file == NULL ) {
2127                 /* fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); */
2128                 return addrIndex->retVal;
2129         }
2130
2131         addrIndex->retVal = MGU_BAD_FORMAT;
2132         if( xml_get_dtd( file ) == 0 ) {
2133                 if( xml_parse_next_tag( file ) == 0 ) {
2134                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
2135                                 addrindex_convert_tree( addrIndex, file );
2136                         }
2137                 }
2138         }
2139         xml_close_file( file );
2140         return addrIndex->retVal;
2141 }
2142
2143 /*
2144 * Create a new address book file.
2145 */
2146 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
2147         gboolean retVal = FALSE;
2148         AddressBookFile *abf = NULL;
2149         gchar *newFile = NULL;
2150         GList *fileList = NULL;
2151         gint fileNum = 0;
2152
2153         /* Create new address book */
2154         abf = addrbook_create_book();
2155         addrbook_set_name( abf, displayName );
2156         addrbook_set_path( abf, addrIndex->filePath );
2157
2158         /* Determine next available file number */
2159         fileList = addrbook_get_bookfile_list( abf );
2160         if( fileList ) {
2161                 fileNum = 1 + abf->maxValue;
2162         }
2163         g_list_free( fileList );
2164         fileList = NULL;
2165
2166         newFile = addrbook_gen_new_file_name( fileNum );
2167         if( newFile ) {
2168                 addrbook_set_file( abf, newFile );
2169         }
2170
2171         addrbook_save_data( abf );
2172         addrIndex->retVal = abf->retVal;
2173         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2174         addrbook_free_book( abf );
2175         abf = NULL;
2176
2177         /* Create entries in address index */
2178         if( retVal ) {
2179                 abf = addrbook_create_book();
2180                 addrbook_set_name( abf, displayName );
2181                 addrbook_set_path( abf, addrIndex->filePath );
2182                 addrbook_set_file( abf, newFile );
2183                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2184         }
2185
2186         return retVal;
2187 }
2188
2189 /*
2190 * Read data for address index performing a conversion if necesary.
2191 * Enter: addrIndex Address index object.
2192 * return: Status code, from addrIndex->retVal.
2193 * Note: New address book files will be created in directory specified by
2194 * addrIndex. Three files will be created, for the following:
2195 *       "Common addresses"
2196 *       "Personal addresses"
2197 *       "Gathered addresses" - a new address book.
2198 */
2199 gint addrindex_read_data( AddressIndex *addrIndex ) {
2200         g_return_val_if_fail( addrIndex != NULL, -1 );
2201
2202         addrIndex->conversionError = FALSE;
2203         addrindex_read_file( addrIndex );
2204         if( addrIndex->retVal == MGU_SUCCESS ) {
2205                 if( addrIndex->needsConversion ) {
2206                         if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) {
2207                                 addrIndex->conversionError = TRUE;
2208                         }
2209                         else {
2210                                 addrIndex->conversionError = TRUE;
2211                         }
2212                 }
2213                 addrIndex->dirtyFlag = TRUE;
2214         }
2215         return addrIndex->retVal;
2216 }
2217
2218 /*
2219 * Create new address books for a new address index.
2220 * Enter: addrIndex Address index object.
2221 * return: Status code, from addrIndex->retVal.
2222 * Note: New address book files will be created in directory specified by
2223 * addrIndex. Three files will be created, for the following:
2224 *       "Common addresses"
2225 *       "Personal addresses"
2226 *       "Gathered addresses" - a new address book.
2227 */
2228 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
2229         gboolean flg;
2230
2231         g_return_val_if_fail( addrIndex != NULL, -1 );
2232
2233         flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
2234         if( flg ) {
2235                 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
2236                 addrIndex->dirtyFlag = TRUE;
2237         }
2238         return addrIndex->retVal;
2239 }
2240
2241 /* **********************************************************************
2242 * New interface stuff.
2243 * ***********************************************************************
2244 */
2245
2246 /*
2247  * Return modified flag for specified data source.
2248  */
2249 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
2250         gboolean retVal = FALSE;
2251         AddressInterface *iface;
2252
2253         if( ds == NULL ) return retVal;
2254         iface = ds->interface;
2255         if( iface == NULL ) return retVal;
2256         if( iface->getModifyFlag ) {
2257                 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
2258         }
2259         return retVal;
2260 }
2261
2262 /*
2263  * Return accessed flag for specified data source.
2264  */
2265 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
2266         gboolean retVal = FALSE;
2267         AddressInterface *iface;
2268
2269         if( ds == NULL ) return retVal;
2270         iface = ds->interface;
2271         if( iface == NULL ) return retVal;
2272         if( iface->getAccessFlag ) {
2273                 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
2274         }
2275         return retVal;
2276 }
2277
2278 /*
2279  * Return data read flag for specified data source.
2280  */
2281 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
2282         gboolean retVal = TRUE;
2283         AddressInterface *iface;
2284
2285         if( ds == NULL ) return retVal;
2286         iface = ds->interface;
2287         if( iface == NULL ) return retVal;
2288         if( iface->getReadFlag ) {
2289                 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
2290         }
2291         return retVal;
2292 }
2293
2294 /*
2295  * Return status code for specified data source.
2296  */
2297 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
2298         gint retVal = MGU_SUCCESS;
2299         AddressInterface *iface;
2300
2301         if( ds == NULL ) return retVal;
2302         iface = ds->interface;
2303         if( iface == NULL ) return retVal;
2304         if( iface->getStatusCode ) {
2305                 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
2306         }
2307         return retVal;
2308 }
2309
2310 /*
2311  * Return data read flag for specified data source.
2312  */
2313 gint addrindex_ds_read_data( AddressDataSource *ds ) {
2314         gint retVal = MGU_SUCCESS;
2315         AddressInterface *iface;
2316
2317         if( ds == NULL ) return retVal;
2318         iface = ds->interface;
2319         if( iface == NULL ) return retVal;
2320         if( iface->getReadData ) {
2321                 /*
2322                 gchar *name = ( iface->getName ) ( ds->rawDataSource );
2323                 printf( "addrindex_ds_read_data...reading:::%s:::\n", name );
2324                 */
2325                 retVal = ( iface->getReadData ) ( ds->rawDataSource );
2326         }
2327         return retVal;
2328 }
2329
2330 /*
2331  * Return data read flag for specified data source.
2332  */
2333 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
2334         ItemFolder *retVal = NULL;
2335         AddressInterface *iface;
2336
2337         if( ds == NULL ) return retVal;
2338         iface = ds->interface;
2339         if( iface == NULL ) return retVal;
2340         if( iface->getRootFolder ) {
2341                 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
2342         }
2343         return retVal;
2344 }
2345
2346 /*
2347  * Return list of folders for specified data source.
2348  */
2349 GList *addrindex_ds_get_list_folder( AddressDataSource *ds ) {
2350         GList *retVal = FALSE;
2351         AddressInterface *iface;
2352
2353         if( ds == NULL ) return retVal;
2354         iface = ds->interface;
2355         if( iface == NULL ) return retVal;
2356         if( iface->getListFolder ) {
2357                 retVal = ( iface->getListFolder ) ( ds->rawDataSource );
2358         }
2359         return retVal;
2360 }
2361
2362 /*
2363  * Return list of persons in root folder for specified data source.
2364  */
2365 GList *addrindex_ds_get_list_person( AddressDataSource *ds ) {
2366         GList *retVal = FALSE;
2367         AddressInterface *iface;
2368
2369         if( ds == NULL ) return retVal;
2370         iface = ds->interface;
2371         if( iface == NULL ) return retVal;
2372         if( iface->getListPerson ) {
2373                 retVal = ( iface->getListPerson ) ( ds->rawDataSource );
2374         }
2375         return retVal;
2376 }
2377
2378 /*
2379  * Return name for specified data source.
2380  */
2381 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
2382         gchar *retVal = FALSE;
2383         AddressInterface *iface;
2384
2385         if( ds == NULL ) return retVal;
2386         iface = ds->interface;
2387         if( iface == NULL ) return retVal;
2388         if( iface->getName ) {
2389                 retVal = ( iface->getName ) ( ds->rawDataSource );
2390         }
2391         return retVal;
2392 }
2393
2394 /*
2395  * Set the access flag inside the data source.
2396  */
2397 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
2398         AddressInterface *iface;
2399
2400         if( ds == NULL ) return;
2401         iface = ds->interface;
2402         if( iface == NULL ) return;
2403         if( iface->setAccessFlag ) {
2404                 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
2405         }
2406 }
2407
2408 /*
2409  * Return read only flag for specified data source.
2410  */
2411 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
2412         AddressInterface *iface;
2413         if( ds == NULL ) return TRUE;
2414         iface = ds->interface;
2415         if( iface == NULL ) return TRUE;
2416         return iface->readOnly;
2417 }
2418
2419 /*
2420  * Return list of all persons for specified data source.
2421  */
2422 GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
2423         GList *retVal = NULL;
2424         AddressInterface *iface;
2425
2426         if( ds == NULL ) return retVal;
2427         iface = ds->interface;
2428         if( iface == NULL ) return retVal;
2429         if( iface->getAllPersons ) {
2430                 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
2431         }
2432         return retVal;
2433 }
2434
2435 /*
2436  * Return list of all groups for specified data source.
2437  */
2438 GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
2439         GList *retVal = NULL;
2440         AddressInterface *iface;
2441
2442         if( ds == NULL ) return retVal;
2443         iface = ds->interface;
2444         if( iface == NULL ) return retVal;
2445         if( iface->getAllGroups ) {
2446                 retVal = ( iface->getAllGroups ) ( ds->rawDataSource );
2447         }
2448         return retVal;
2449 }
2450
2451 /* **********************************************************************
2452 * Address search stuff.
2453 * ***********************************************************************
2454 */
2455
2456 /**
2457  * Current query ID. This is incremented for each query created.
2458  */
2459 static gint _currentQueryID_ = 0;
2460
2461 /*
2462  * Variables for the search that is being performed.
2463  */
2464 static gchar *_searchTerm_ = NULL;
2465 static gpointer _searchTarget_ = NULL;
2466 static AddrSearchCallbackFunc *_searchCallback_ = NULL;
2467
2468 /**
2469  * Setup or register the search that will be performed.
2470  * \param addrIndex  Address index object.
2471  * \param searchTerm Search term. A private copy will be made.
2472  * \param target     Target object that will receive data.
2473  * \param callBack   Callback function.
2474  * \return ID allocated to query that will be executed.
2475  */
2476 gint addrindex_setup_search(
2477         AddressIndex *addrIndex, const gchar *searchTerm,
2478         const gpointer target, AddrSearchCallbackFunc callBack )
2479 {
2480         gint queryID;
2481
2482         /* printf( "search term ::%s::\n", searchTerm ); */
2483         g_free( _searchTerm_ );
2484         _searchTerm_ = g_strdup( searchTerm );
2485
2486         queryID = ++_currentQueryID_;
2487         _searchTarget_ = target;
2488         _searchCallback_ = callBack;
2489         /* printf( "query ID ::%d::\n", queryID ); */
2490         return queryID;
2491 }
2492
2493 #ifdef USE_LDAP
2494 /**
2495  * LDAP callback entry point for each address entry found.
2496  * \param qry       LDAP query.
2497  * \param listEMail List of Item EMail objects found.
2498  */
2499 static void addrindex_ldap_entry_cb( LdapQuery *qry, GList *listEMail ) {
2500         /*
2501         GList *node;
2502
2503         printf( "\naddrindex::addrindex_ldap_entry_cb ::%s::\n", qry->queryName );
2504         node = listEMail;
2505         while( node ) {
2506                 ItemEMail *email = node->data;
2507                 printf( "\temail ::%s::\n", email->address );
2508                 node = g_list_next( node );
2509         }
2510         */
2511         if( _searchCallback_ ) {
2512                 ( _searchCallback_ ) ( qry->queryID, listEMail, _searchTarget_ );
2513         }
2514         g_list_free( listEMail );
2515 }
2516
2517 /**
2518  * LDAP callback entry point for completion of search.
2519  * \param qry LDAP query.
2520  */
2521 static void addrindex_ldap_end_cb( LdapQuery *qry ) {
2522         /* printf( "\naddrindex::addrindex_ldap_end_cb ::%s::\n", qry->queryName ); */
2523 }
2524
2525 /**
2526  * Return results of previous query.
2527  * \param folder.
2528  * \return List of ItemEMail objects.
2529  */
2530 static void addrindex_ldap_use_previous( const ItemFolder *folder, const gint queryID )
2531 {
2532         GList *listEMail;
2533         GList *node;
2534         GList *nodeEM;
2535
2536         listEMail = NULL;
2537         if( _searchCallback_ ) {
2538                 node = folder->listPerson;
2539                 while( node ) {
2540                         AddrItemObject *aio = node->data;
2541                         if( aio &&  aio->type == ITEMTYPE_PERSON ) {
2542                                 ItemPerson *person = node->data;
2543                                 nodeEM = person->listEMail;
2544                                 while( nodeEM ) {
2545                                         ItemEMail *email = nodeEM->data;
2546                                         nodeEM = g_list_next( nodeEM );
2547                                         listEMail = g_list_append( listEMail, email );
2548                                 }
2549                         }
2550                         node = g_list_next( node );
2551                 }
2552                 ( _searchCallback_ ) ( queryID, listEMail, _searchTarget_ );
2553                 g_list_free( listEMail );
2554         }
2555 }
2556
2557 LdapQuery *ldapsvr_locate_query( LdapServer *server, const gchar *searchTerm );
2558
2559 /**
2560  * Construct an LDAP query and initiate an LDAP search.
2561  * \param server  LDAP server object.
2562  * \param queryID ID of search query to be executed.
2563  */
2564 static void addrindex_search_ldap( LdapServer *server, const gint queryID ) {
2565         LdapQuery *qry;
2566         gchar *name;
2567
2568         if( ! server->searchFlag ) return;
2569
2570         /* Retire any aged queries */
2571         ldapsvr_retire_query( server );
2572
2573         /* Test whether any queries for the same term exist */
2574         qry = ldapsvr_locate_query( server, _searchTerm_ );
2575         if( qry ) {
2576                 ItemFolder *folder = qry->folder;
2577
2578                 /* Touch query to ensure it hangs around for a bit longer */
2579                 ldapqry_touch( qry );
2580                 if( folder ) {
2581                         addrindex_ldap_use_previous( folder, queryID );
2582                         return;
2583                 }
2584         }
2585
2586         /* Construct a query */
2587         qry = ldapqry_create();
2588         ldapqry_set_query_id( qry, queryID );
2589         ldapqry_set_search_value( qry, _searchTerm_ );
2590         ldapqry_set_query_type( qry, LDAPQUERY_DYNAMIC );
2591         ldapqry_set_callback_entry( qry, addrindex_ldap_entry_cb );
2592         ldapqry_set_callback_end( qry, addrindex_ldap_end_cb );
2593
2594         /* Name the query */
2595         name = g_strdup_printf( "Search for '%s'", _searchTerm_ );
2596         ldapqry_set_name( qry, name );
2597         g_free( name );
2598
2599         ldapsvr_add_query( server, qry );
2600         ldapsvr_execute_query( server, qry );
2601 }
2602
2603 /**
2604  * Construct an LDAP query and initiate an LDAP search.
2605  * \param server      LDAP server object to search.
2606  * \param searchTerm  Search term to locate.
2607  * \param callbackEnd Function to call when search has terminated.
2608  *
2609  */
2610 void addrindex_search_ldap_noid(
2611         LdapServer *server, const gchar *searchTerm, void * callbackEnd )
2612 {
2613         LdapQuery *qry;
2614         gchar *name;
2615
2616         /* Construct a query */
2617         qry = ldapqry_create();
2618         ldapqry_set_search_value( qry, searchTerm );
2619         ldapqry_set_query_type( qry, LDAPQUERY_STATIC );
2620         ldapqry_set_callback_end( qry, callbackEnd );
2621
2622         /* Name the query */
2623         name = g_strdup_printf( "Static Search for '%s'", searchTerm );
2624         ldapqry_set_name( qry, name );
2625         g_free( name );
2626
2627         ldapsvr_add_query( server, qry );
2628         /* printf( "addrindex_search_ldap_noid::executing static search...\n" ); */
2629         ldapsvr_execute_query( server, qry );
2630 }
2631 #endif
2632
2633 /**
2634  * Perform the previously registered search.
2635  * \param  addrIndex  Address index object.
2636  * \param  queryID    ID of search query to be executed.
2637  * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2638  *         failed.
2639  */
2640 gboolean addrindex_start_search( AddressIndex *addrIndex, const gint queryID ) {
2641         AddressInterface *iface;
2642         AddressDataSource *ds;
2643         GList *nodeIf;
2644         GList *nodeDS;
2645         gint type;
2646
2647         /* printf( "addrindex_start_search::%d::\n", queryID ); */
2648         nodeIf = addrIndex->searchOrder;
2649         while( nodeIf ) {
2650                 iface = nodeIf->data;
2651                 nodeIf = g_list_next( nodeIf );
2652
2653                 if( ! iface->useInterface ) {
2654                         continue;
2655                 }
2656
2657                 if( ! iface->externalQuery ) {
2658                         continue;
2659                 }
2660
2661                 type = iface->type;
2662                 nodeDS = iface->listSource;
2663                 while( nodeDS ) {
2664                         ds = nodeDS->data;
2665                         nodeDS = g_list_next( nodeDS );
2666 #ifdef USE_LDAP
2667                         if( type == ADDR_IF_LDAP ) {
2668                                 LdapServer *server = ds->rawDataSource;
2669                                 addrindex_search_ldap( server, queryID );
2670                         }
2671 #endif
2672                 }
2673         }
2674         return TRUE;
2675 }
2676
2677 /**
2678  * Stop the previously registered search.
2679  * \param addrIndex Address index object.
2680  * \param queryID ID of search query to stop.
2681  */
2682 void addrindex_stop_search( AddressIndex *addrIndex, const gint queryID ){
2683 #ifdef USE_LDAP
2684         AddressInterface *iface;
2685         AddressDataSource *ds;
2686         GList *nodeIf;
2687         GList *nodeDS;
2688         gint type;
2689
2690         /* If query ID does not match, search has not been setup */
2691         /* if( queryID != _queryID_ ) return; */
2692
2693         /* printf( "addrindex_stop_search::%d::\n", queryID ); */
2694         nodeIf = addrIndex->searchOrder;
2695         while( nodeIf ) {
2696                 iface = nodeIf->data;
2697                 nodeIf = g_list_next( nodeIf );
2698
2699                 if( ! iface->useInterface ) {
2700                         continue;
2701                 }
2702
2703                 type = iface->type;
2704                 nodeDS = iface->listSource;
2705                 while( nodeDS ) {
2706                         ds = nodeDS->data;
2707                         nodeDS = g_list_next( nodeDS );
2708                         if( type == ADDR_IF_LDAP ) {
2709                                 LdapServer *server = ds->rawDataSource;
2710                                 ldapsvr_stop_all_query( server );
2711                         }
2712                 }
2713         }
2714 #endif
2715 }
2716
2717 /**
2718  * Read all address books that do not support dynamic queries.
2719  * \param addrIndex Address index object.
2720  */
2721 void addrindex_read_all( AddressIndex *addrIndex ) {
2722         AddressInterface *iface;
2723         AddressDataSource *ds;
2724         GList *nodeIf;
2725         GList *nodeDS;
2726
2727         nodeIf = addrIndex->searchOrder;
2728         while( nodeIf ) {
2729                 iface = nodeIf->data;
2730                 nodeIf = g_list_next( nodeIf );
2731
2732                 if( ! iface->useInterface ) {
2733                         continue;
2734                 }
2735                 if( iface->externalQuery ) {
2736                         continue;
2737                 }
2738                 nodeDS = iface->listSource;
2739                 while( nodeDS ) {
2740                         ds = nodeDS->data;
2741                         nodeDS = g_list_next( nodeDS );
2742
2743                         /* Read address book */
2744                         if( addrindex_ds_get_modify_flag( ds ) ) {
2745                                 addrindex_ds_read_data( ds );
2746                                 continue;
2747                         }
2748
2749                         if( ! addrindex_ds_get_read_flag( ds ) ) {
2750                                 addrindex_ds_read_data( ds );
2751                                 continue;
2752                         }
2753                 }
2754         }
2755         addrIndex->loadedFlag = TRUE;
2756 }
2757
2758 /**
2759  * This function is used by the address completion function to load
2760  * addresses for all non-external address book interfaces.
2761  *
2762  * \param addrIndex Address index object.
2763  * \param callBackFunc Function to be called when an address is
2764  *                     to be loaded.
2765  * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded.
2766  */
2767 gboolean addrindex_load_completion(
2768                 AddressIndex *addrIndex,
2769                 gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) )
2770 {
2771         AddressDataSource *ds;
2772         GList *nodeIf, *nodeDS;
2773         GList *listP, *nodeP;
2774         GList *nodeM;
2775         gchar *sName, *sAddress, *sAlias, *sFriendly;
2776
2777         if( addrIndex == NULL ) return FALSE;
2778
2779         nodeIf = addrindex_get_interface_list( addrIndex );
2780         while( nodeIf ) {
2781                 AddressInterface *iface = nodeIf->data;
2782
2783                 nodeIf = g_list_next( nodeIf );
2784                 if( ! iface->useInterface ) {
2785                         continue;
2786                 }
2787                 if( iface->externalQuery ) {
2788                         continue;
2789                 }
2790                 nodeDS = iface->listSource;
2791                 while( nodeDS ) {
2792                         ds = nodeDS->data;
2793
2794                         /* Read address book */
2795                         if( addrindex_ds_get_modify_flag( ds ) ) {
2796                                 addrindex_ds_read_data( ds );
2797                         }
2798
2799                         if( ! addrindex_ds_get_read_flag( ds ) ) {
2800                                 addrindex_ds_read_data( ds );
2801                         }
2802
2803                         /* Get all persons */
2804                         listP = addrindex_ds_get_all_persons( ds );
2805                         nodeP = listP;
2806                         while( nodeP ) {
2807                                 ItemPerson *person = nodeP->data;
2808                                 nodeM = person->listEMail;
2809
2810                                 /* Figure out name to use */
2811                                 sName = person->nickName;
2812                                 if( sName == NULL || *sName == '\0' ) {
2813                                         sName = ADDRITEM_NAME(person);
2814                                 }
2815
2816                                 /* Process each E-Mail address */
2817                                 while( nodeM ) {
2818                                         ItemEMail *email = nodeM->data;
2819                                         /* Have mail */
2820                                         sFriendly = sName;
2821                                         sAddress = email->address;
2822                                         if( sAddress || *sAddress != '\0' ) {
2823                                                 sAlias = ADDRITEM_NAME(email);
2824                                                 if( sAlias && *sAlias != '\0' ) {
2825                                                         sFriendly = sAlias;
2826                                                 }
2827                                                 ( callBackFunc ) ( sFriendly, sAddress, sName );
2828                                         }
2829
2830                                         nodeM = g_list_next( nodeM );
2831                                 }
2832                                 nodeP = g_list_next( nodeP );
2833                         }
2834                         /* Free up the list */
2835                         g_list_free( listP );
2836
2837                         nodeDS = g_list_next( nodeDS );
2838                 }
2839         }
2840
2841         return TRUE;
2842 }
2843
2844 /*
2845  * End of Source.
2846  */
2847
2848