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