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