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