f1adf01be739f54cfbef2006b5290a30ea51311c
[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 #include "claws_io.h"
47
48 #ifndef DEV_STANDALONE
49 #include "prefs_gtk.h"
50 #include "codeconv.h"
51 #endif
52
53 #include "vcard.h"
54
55 #ifdef USE_JPILOT
56 #include "jpilot.h"
57 #endif
58
59 #ifdef USE_LDAP
60 #include "ldapserver.h"
61 #include "ldapctrl.h"
62 #include "ldapquery.h"
63 #include "ldapupdate.h"
64 #include "ldaputil.h"
65 #endif
66
67 #ifdef G_OS_WIN32
68 #undef interface
69 #endif
70
71 #define TAG_ADDRESS_INDEX    "addressbook"
72
73 #define TAG_IF_ADDRESS_BOOK  "book_list"
74 #define TAG_IF_VCARD         "vcard_list"
75 #define TAG_IF_JPILOT        "jpilot_list"
76 #define TAG_IF_LDAP          "ldap_list"
77
78 #define TAG_DS_ADDRESS_BOOK  "book"
79 #define TAG_DS_VCARD         "vcard"
80 #define TAG_DS_JPILOT        "jpilot"
81 #define TAG_DS_LDAP          "server"
82
83 /* XML Attribute names */
84 #define ATTAG_BOOK_NAME       "name"
85 #define ATTAG_BOOK_FILE       "file"
86
87 #define ATTAG_VCARD_NAME      "name"
88 #define ATTAG_VCARD_FILE      "file"
89
90 #define ATTAG_JPILOT_NAME     "name"
91 #define ATTAG_JPILOT_FILE     "file"
92 #define ATTAG_JPILOT_CUSTOM_1 "custom-1"
93 #define ATTAG_JPILOT_CUSTOM_2 "custom-2"
94 #define ATTAG_JPILOT_CUSTOM_3 "custom-3"
95 #define ATTAG_JPILOT_CUSTOM_4 "custom-4"
96 #define ATTAG_JPILOT_CUSTOM   "custom-"
97
98 #define ATTAG_LDAP_NAME       "name"
99 #define ATTAG_LDAP_HOST       "host"
100 #define ATTAG_LDAP_PORT       "port"
101 #define ATTAG_LDAP_BASE_DN    "base-dn"
102 #define ATTAG_LDAP_BIND_DN    "bind-dn"
103 #define ATTAG_LDAP_BIND_PASS  "bind-pass"
104 #define ATTAG_LDAP_CRITERIA   "criteria"
105 #define ATTAG_LDAP_MAX_ENTRY  "max-entry"
106 #define ATTAG_LDAP_TIMEOUT    "timeout"
107 #define ATTAG_LDAP_MAX_AGE    "max-age"
108 #define ATTAG_LDAP_DYN_SEARCH "dyn-search"
109 #define ATTAG_LDAP_MATCH_OPT  "match-opt"
110 #define ATTAG_LDAP_ENABLE_TLS "enable-tls"
111 #define ATTAG_LDAP_ENABLE_SSL "enable-ssl"
112
113 #define ELTAG_LDAP_ATTR_SRCH  "attribute"
114 #define ATTAG_LDAP_ATTR_NAME  "name"
115
116 /* Attribute values */
117 #define ATVAL_BOOLEAN_YES         "yes"
118 #define ATVAL_BOOLEAN_NO          "no"
119 #define ATVAL_LDAP_MATCH_BEGIN    "begin-with"
120 #define ATVAL_LDAP_MATCH_CONTAINS "contains"
121
122 /* New attributes */
123 #define ATTAG_LDAP_DEFAULT    "default"
124
125 #define DISP_NEW_COMMON       _("Common addresses")
126 #define DISP_NEW_PERSONAL     _("Personal addresses")
127
128 /* Old address book */
129 #define TAG_IF_OLD_COMMON     "common_address"
130 #define TAG_IF_OLD_PERSONAL   "personal_address"
131
132 #define DISP_OLD_COMMON       _("Common address")
133 #define DISP_OLD_PERSONAL     _("Personal address")
134
135 /**
136  * Singleton object.
137  */
138 static AddressIndex *_addressIndex_ = NULL;
139
140 /*
141  * Define attribute name-value pair.
142  */
143 typedef struct _AddressIfAttr AddressIfAttrib;
144 struct _AddressIfAttr {
145         gchar *name;
146         gchar *value;
147 };
148
149 static AddressDataSource *addrindex_create_datasource   ( AddressIfType ifType );
150
151 static GList *addrindex_ds_get_all_persons      ( AddressDataSource *ds );
152 static GList *addrindex_ds_get_all_groups       ( AddressDataSource *ds );
153 static AddressDataSource *addrindex_get_datasource      ( AddressIndex *addrIndex,
154                                                   const gchar *cacheID );
155 static AddressInterface *addrindex_get_interface        ( AddressIndex *addrIndex,
156                                                   AddressIfType ifType );
157 static gint addrindex_write_to                  ( AddressIndex *addrIndex,
158                                           const gchar *newFile );
159
160 /*
161  * Define DOM fragment.
162  */
163 typedef struct _AddressIfFrag AddressIfFragment;
164 struct _AddressIfFrag {
165         gchar *name;
166         GList *children;
167         GList *attributes;
168 };
169
170 /**
171  * Build interface with default values.
172  *
173  * \param type Interface type.
174  * \param name Interface name.
175  * \param tagIf XML tag name for interface in address index file.
176  * \param tagDS XML tag name for datasource in address index file.
177  * \return Address interface object.
178 */
179 static AddressInterface *addrindex_create_interface(
180                 gint type, gchar *name, gchar *tagIf, gchar *tagDS )
181 {
182         AddressInterface *iface = g_new0( AddressInterface, 1 );
183
184         ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
185         ADDRITEM_ID(iface) = NULL;
186         ADDRITEM_NAME(iface) = g_strdup( name );
187         ADDRITEM_PARENT(iface) = NULL;
188         ADDRITEM_SUBTYPE(iface) = type;
189         iface->type = type;
190         iface->name = g_strdup( name );
191         iface->listTag = g_strdup( tagIf );
192         iface->itemTag = g_strdup( tagDS );
193         iface->legacyFlag = FALSE;
194         iface->haveLibrary = TRUE;
195         iface->useInterface = TRUE;
196         iface->readOnly      = TRUE;
197
198         /* Set callbacks to NULL values - override for each interface */
199         iface->getAccessFlag = NULL;
200         iface->getModifyFlag = NULL;
201         iface->getReadFlag   = NULL;
202         iface->getStatusCode = NULL;
203         iface->getReadData   = NULL;
204         iface->getRootFolder = NULL;
205         iface->getListFolder = NULL;
206         iface->getListPerson = NULL;
207         iface->getAllPersons = NULL;
208         iface->getAllGroups  = NULL;
209         iface->getName       = NULL;
210         iface->listSource = NULL;
211
212         /* Search stuff */
213         iface->externalQuery = FALSE;
214         iface->searchOrder = 0;         /* Ignored */
215         iface->startSearch = NULL;
216         iface->stopSearch = NULL;
217
218         return iface;
219 }
220
221 /**
222  * Build table of of all address book interfaces.
223  * \param addrIndex Address index object.
224  */
225 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
226         AddressInterface *iface;
227
228         /* Create intrinsic XML address book interface */
229         iface = addrindex_create_interface(
230                         ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK,
231                         TAG_DS_ADDRESS_BOOK );
232         iface->readOnly      = FALSE;
233         iface->getModifyFlag = ( void * ) addrbook_get_modified;
234         iface->getAccessFlag = ( void * ) addrbook_get_accessed;
235         iface->getReadFlag   = ( void * ) addrbook_get_read_flag;
236         iface->getStatusCode = ( void * ) addrbook_get_status;
237         iface->getReadData   = ( void * ) addrbook_read_data;
238         iface->getRootFolder = ( void * ) addrbook_get_root_folder;
239         iface->getListFolder = ( void * ) addrbook_get_list_folder;
240         iface->getListPerson = ( void * ) addrbook_get_list_person;
241         iface->getAllPersons = ( void * ) addrbook_get_all_persons;
242         iface->getAllGroups  = ( void * ) addrbook_get_all_groups;
243         iface->getName       = ( void * ) addrbook_get_name;
244         iface->setAccessFlag = ( void * ) addrbook_set_accessed;
245         iface->searchOrder   = 0;
246
247         /* Add to list of interfaces in address book */ 
248         addrIndex->interfaceList =
249                 g_list_append( addrIndex->interfaceList, iface );
250         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
251
252         /* Create vCard interface */
253         iface = addrindex_create_interface(
254                         ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
255         iface->getModifyFlag = ( void * ) vcard_get_modified;
256         iface->getAccessFlag = ( void * ) vcard_get_accessed;
257         iface->getReadFlag   = ( void * ) vcard_get_read_flag;
258         iface->getStatusCode = ( void * ) vcard_get_status;
259         iface->getReadData   = ( void * ) vcard_read_data;
260         iface->getRootFolder = ( void * ) vcard_get_root_folder;
261         iface->getListFolder = ( void * ) vcard_get_list_folder;
262         iface->getListPerson = ( void * ) vcard_get_list_person;
263         iface->getAllPersons = ( void * ) vcard_get_all_persons;
264         iface->getName       = ( void * ) vcard_get_name;
265         iface->setAccessFlag = ( void * ) vcard_set_accessed;
266         iface->searchOrder   = 0;
267         addrIndex->interfaceList =
268                 g_list_append( addrIndex->interfaceList, iface );
269         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
270
271         /* Create JPilot interface */
272         iface = addrindex_create_interface(
273                         ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT,
274                         TAG_DS_JPILOT );
275 #ifdef USE_JPILOT
276         iface->haveLibrary = jpilot_test_pilot_lib();
277         iface->useInterface = iface->haveLibrary;
278         iface->getModifyFlag = ( void * ) jpilot_get_modified;
279         iface->getAccessFlag = ( void * ) jpilot_get_accessed;
280         iface->getReadFlag   = ( void * ) jpilot_get_read_flag;
281         iface->getStatusCode = ( void * ) jpilot_get_status;
282         iface->getReadData   = ( void * ) jpilot_read_data;
283         iface->getRootFolder = ( void * ) jpilot_get_root_folder;
284         iface->getListFolder = ( void * ) jpilot_get_list_folder;
285         iface->getListPerson = ( void * ) jpilot_get_list_person;
286         iface->getAllPersons = ( void * ) jpilot_get_all_persons;
287         iface->getName       = ( void * ) jpilot_get_name;
288         iface->setAccessFlag = ( void * ) jpilot_set_accessed;
289         iface->searchOrder   = 0;
290 #else
291         iface->useInterface = FALSE;
292         iface->haveLibrary = FALSE;
293 #endif
294         addrIndex->interfaceList =
295                 g_list_append( addrIndex->interfaceList, iface );
296         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
297
298         /* Create LDAP interface */
299         iface = addrindex_create_interface(
300                         ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
301 #ifdef USE_LDAP
302         iface->readOnly = FALSE;
303         /* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
304         iface->haveLibrary = ldaputil_test_ldap_lib();
305         iface->useInterface = iface->haveLibrary;
306         iface->getModifyFlag = ( void * ) ldapsvr_get_modified;
307         iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
308         iface->getReadFlag   = ( void * ) ldapsvr_get_read_flag;
309         iface->getStatusCode = ( void * ) ldapsvr_get_status;
310         iface->getReadData   = ( void * ) ldapsvr_read_data;
311         iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
312         iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
313         iface->getListPerson = ( void * ) ldapsvr_get_list_person;
314         iface->getName       = ( void * ) ldapsvr_get_name;
315         iface->setAccessFlag = ( void * ) ldapsvr_set_accessed;
316         iface->externalQuery = TRUE;
317         iface->searchOrder   = 1;
318 #else
319         iface->useInterface = FALSE;
320         iface->haveLibrary = FALSE;
321 #endif
322         addrIndex->interfaceList =
323                 g_list_append( addrIndex->interfaceList, iface );
324         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
325
326         /* Two old legacy data sources (pre 0.7.0) */
327         iface = addrindex_create_interface(
328                         ADDR_IF_COMMON, "Old Address - common",
329                         TAG_IF_OLD_COMMON, NULL );
330         iface->legacyFlag = TRUE;
331         addrIndex->interfaceList =
332                 g_list_append( addrIndex->interfaceList, iface );
333         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
334
335         iface = addrindex_create_interface(
336                         ADDR_IF_COMMON, "Old Address - personal",
337                         TAG_IF_OLD_PERSONAL, NULL );
338         iface->legacyFlag = TRUE;
339         addrIndex->interfaceList =
340                 g_list_append( addrIndex->interfaceList, iface );
341         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
342
343 }
344
345 /**
346  * Free DOM fragment.
347  * \param fragment Fragment to free.
348  */
349 static void addrindex_free_fragment( AddressIfFragment *fragment ) {
350         GList *node;
351
352         /* Free children */
353         node = fragment->children;
354         while( node ) {
355                 AddressIfFragment *child = node->data;
356                 addrindex_free_fragment( child );
357                 node->data = NULL;
358                 node = g_list_next( node );
359         }
360         g_list_free( fragment->children );
361
362         /* Free attributes */
363         node = fragment->attributes;
364         while( node ) {
365                 AddressIfAttrib *nv = node->data;
366                 g_free( nv->name );
367                 g_free( nv->value );
368                 g_free( nv );
369                 node->data = NULL;
370                 node = g_list_next( node );
371         }
372         g_list_free( fragment->attributes );
373
374         g_free( fragment->name );
375         fragment->name = NULL;
376         fragment->attributes = NULL;
377         fragment->children = NULL;
378
379         g_free( fragment );
380 }
381
382 /**
383  * Create a new data source.
384  * \param ifType Interface type to create.
385  * \return Initialized data source.
386  */
387 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
388         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
389
390         ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
391         ADDRITEM_ID(ds) = NULL;
392         ADDRITEM_NAME(ds) = NULL;
393         ADDRITEM_PARENT(ds) = NULL;
394         ADDRITEM_SUBTYPE(ds) = 0;
395         ds->type = ifType;
396         ds->rawDataSource = NULL;
397         ds->interface = NULL;
398         return ds;
399 }
400
401 /**
402  * Free up data source.
403  * \param ds Data source to free.
404  */
405 void addrindex_free_datasource( AddressDataSource *ds ) {
406         AddressInterface *iface;
407
408         cm_return_if_fail( ds != NULL );
409
410         iface = ds->interface;
411         if( ds->rawDataSource != NULL ) {
412                 if( iface != NULL ) {
413                         if( iface->useInterface ) {
414                                 if( iface->type == ADDR_IF_BOOK ) {
415                                         AddressBookFile *abf = ds->rawDataSource;
416                                         addrbook_free_book( abf );
417                                 }
418                                 else if( iface->type == ADDR_IF_VCARD ) {
419                                         VCardFile *vcf = ds->rawDataSource;
420                                         vcard_free( vcf );
421                                 }
422 #ifdef USE_JPILOT
423                                 else if( iface->type == ADDR_IF_JPILOT ) {
424                                         JPilotFile *jpf = ds->rawDataSource;
425                                         jpilot_free( jpf );
426                                 }
427 #endif
428 #ifdef USE_LDAP
429                                 else if( iface->type == ADDR_IF_LDAP ) {
430                                         LdapServer *server = ds->rawDataSource;
431                                         ldapsvr_free( server );
432                                 }
433 #endif
434                                 else {
435                                 }
436                         }
437                         else {
438                                 AddressIfFragment *fragment = ds->rawDataSource;
439                                 addrindex_free_fragment( fragment );
440                         }
441                 }
442         }
443
444         ADDRITEM_TYPE(ds) = ITEMTYPE_NONE;
445         ADDRITEM_ID(ds) = NULL;
446         ADDRITEM_NAME(ds) = NULL;
447         ADDRITEM_PARENT(ds) = NULL;
448         ADDRITEM_SUBTYPE(ds) = 0;
449         ds->type = ADDR_IF_NONE;
450         ds->interface = NULL;
451         ds->rawDataSource = NULL;
452
453         g_free( ds );
454 }
455
456 /**
457  * Free up all data sources for specified interface.
458  * \param iface Address interface to process.
459  */
460 static void addrindex_free_all_datasources( AddressInterface *iface ) {
461         GList *node = iface->listSource;
462         while( node ) {
463                 AddressDataSource *ds = node->data;
464                 addrindex_free_datasource( ds );
465                 node->data = NULL;
466                 node = g_list_next( node );
467         }
468 }
469
470 /**
471  * Free up specified interface.
472  * \param iface Interface to process.
473  */
474 static void addrindex_free_interface( AddressInterface *iface ) {
475         /* Free up data sources */
476         addrindex_free_all_datasources( iface );
477         g_list_free( iface->listSource );
478
479         /* Free internal storage */
480         g_free( ADDRITEM_ID(iface) );
481         g_free( ADDRITEM_NAME(iface) );
482         g_free( iface->name );
483         g_free( iface->listTag );
484         g_free( iface->itemTag );
485
486         /* Clear all pointers */
487         ADDRITEM_TYPE(iface) = ITEMTYPE_NONE;
488         ADDRITEM_ID(iface) = NULL;
489         ADDRITEM_NAME(iface) = NULL;
490         ADDRITEM_PARENT(iface) = NULL;
491         ADDRITEM_SUBTYPE(iface) = 0;
492         iface->type = ADDR_IF_NONE;
493         iface->name = NULL;
494         iface->listTag = NULL;
495         iface->itemTag = NULL;
496         iface->legacyFlag = FALSE;
497         iface->useInterface = FALSE;
498         iface->haveLibrary = FALSE;
499         iface->listSource = NULL;
500
501         /* Search stuff */
502         iface->searchOrder = 0;
503         iface->startSearch = NULL;
504         iface->stopSearch = NULL;
505
506         g_free( iface );
507 }
508
509 /**
510  * Return cache ID for specified data source.
511  *
512  * \param  addrIndex Address index.
513  * \param  ds        Data source.
514  * \return ID or NULL if not found. This should be <code>g_free()</code>
515  *         when done.
516  */
517 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
518         gchar *cacheID = NULL;
519         AddrBookBase *adbase;
520         AddressCache *cache;
521
522         cm_return_val_if_fail( addrIndex != NULL, NULL );
523         cm_return_val_if_fail( ds != NULL, NULL );
524
525         adbase = ( AddrBookBase * ) ds->rawDataSource;
526         if( adbase ) {
527                 cache = adbase->addressCache;
528                 if( cache ) {
529                         cacheID = g_strdup( cache->cacheID );
530                 }
531         }
532
533         return cacheID;
534 }
535
536 /**
537  * Return reference to data source for specified cacheID.
538  * \param addrIndex Address index.
539  * \param cacheID   ID.
540  * \return Data source, or NULL if not found.
541  */
542 static AddressDataSource *addrindex_get_datasource(
543                 AddressIndex *addrIndex, const gchar *cacheID )
544 {
545         cm_return_val_if_fail( addrIndex != NULL, NULL );
546         cm_return_val_if_fail( cacheID != NULL, NULL );
547         return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
548 }
549
550 /**
551  * Return reference to address cache for specified cacheID.
552  * \param addrIndex Address index.
553  * \param cacheID   ID.
554  * \return Address cache, or NULL if not found.
555  */
556 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
557         AddressDataSource *ds;
558         AddrBookBase *adbase;
559         AddressCache *cache;
560
561         cm_return_val_if_fail( addrIndex != NULL, NULL );
562         cm_return_val_if_fail( cacheID != NULL, NULL );
563
564         cache = NULL;
565         ds = addrindex_get_datasource( addrIndex, cacheID );
566         if( ds ) {
567                 adbase = ( AddrBookBase * ) ds->rawDataSource;
568                 cache = adbase->addressCache;
569         }
570         return cache;
571 }
572
573 /**
574  * Add data source into hash table.
575  * \param addrIndex Address index.
576  * \param ds        Data source.
577  */
578 static void addrindex_hash_add_cache(
579                 AddressIndex *addrIndex, AddressDataSource *ds )
580 {
581         gchar *cacheID;
582
583         cacheID = addrindex_get_cache_id( addrIndex, ds );
584         if( cacheID ) {
585                 g_hash_table_insert( addrIndex->hashCache, cacheID, ds );
586         }
587 }
588
589 /*
590  * Free hash table callback function.
591  */
592 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
593         g_free( key );
594         key = NULL;
595         value = NULL;
596         return TRUE;
597 }
598
599 /*
600  * Free hash table of address cache items.
601  */
602 static void addrindex_free_cache_hash( GHashTable *table ) {
603         g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
604         g_hash_table_destroy( table );
605 }
606
607 /**
608  * Remove data source from internal hashtable.
609  * \param addrIndex Address index.
610  * \param ds        Data source to remove.
611  */
612 static void addrindex_hash_remove_cache(
613                 AddressIndex *addrIndex, AddressDataSource *ds )
614 {
615         gchar *cacheID;
616
617         cacheID = addrindex_get_cache_id( addrIndex, ds );
618         if( cacheID ) {
619                 g_hash_table_remove( addrIndex->hashCache, cacheID );
620                 g_free( cacheID );
621                 cacheID = NULL;
622         }
623 }
624
625 /**
626  * Create a new address index. This is created as a singleton object.
627  * \return Initialized address index object.
628  */
629 AddressIndex *addrindex_create_index( void ) {
630         AddressIndex *index;
631
632         if( _addressIndex_ == NULL ) {
633                 index = g_new0( AddressIndex, 1 );
634                 ADDRITEM_TYPE(index) = ITEMTYPE_INDEX;
635                 ADDRITEM_ID(index) = NULL;
636                 ADDRITEM_NAME(index) = g_strdup( "Address Index" );
637                 ADDRITEM_PARENT(index) = NULL;
638                 ADDRITEM_SUBTYPE(index) = 0;
639                 index->filePath = NULL;
640                 index->fileName = NULL;
641                 index->retVal = MGU_SUCCESS;
642                 index->needsConversion = FALSE;
643                 index->wasConverted = FALSE;
644                 index->conversionError = FALSE;
645                 index->interfaceList = NULL;
646                 index->lastType = ADDR_IF_NONE;
647                 index->dirtyFlag = FALSE;
648                 index->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
649                 index->loadedFlag = FALSE;
650                 index->searchOrder = NULL;
651                 addrindex_build_if_list( index );
652                 _addressIndex_ = index;
653         }
654         return _addressIndex_;
655 }
656
657 /**
658  * Property - Specify file path to address index file.
659  * \param addrIndex Address index.
660  * \param value Path to index file.
661  */
662 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
663         cm_return_if_fail( addrIndex != NULL );
664         addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
665 }
666
667 /**
668  * Property - Specify file name to address index file.
669  * \param addrIndex Address index.
670  * \param value File name.
671  */
672 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
673         cm_return_if_fail( addrIndex != NULL );
674         addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
675 }
676
677 /**
678  * Return list of address interfaces.
679  * \param addrIndex Address index.
680  * \return List of address interfaces.
681  */
682 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
683         cm_return_val_if_fail( addrIndex != NULL, NULL );
684         return addrIndex->interfaceList;
685 }
686
687 /**
688  * Perform any other initialization of address index.
689  */
690 void addrindex_initialize( void ) {
691         qrymgr_initialize();
692         addrcompl_initialize();
693 }
694
695 /**
696  * Perform any other teardown of address index.
697  */
698 void addrindex_teardown( void ) {
699         addrcompl_teardown();
700         qrymgr_teardown();
701 }
702
703 /**
704  * Free up address index.
705  * \param addrIndex Address index.
706  */
707 void addrindex_free_index( AddressIndex *addrIndex ) {
708         GList *node;
709
710         cm_return_if_fail( addrIndex != NULL );
711
712         /* Search stuff */
713         g_list_free( addrIndex->searchOrder );
714         addrIndex->searchOrder = NULL;
715
716         /* Free internal storage */
717         g_free( ADDRITEM_ID(addrIndex) );
718         g_free( ADDRITEM_NAME(addrIndex) );
719         g_free( addrIndex->filePath );
720         g_free( addrIndex->fileName );
721
722         /* Clear pointers */    
723         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
724         ADDRITEM_ID(addrIndex) = NULL;
725         ADDRITEM_NAME(addrIndex) = NULL;
726         ADDRITEM_PARENT(addrIndex) = NULL;
727         ADDRITEM_SUBTYPE(addrIndex) = 0;
728         addrIndex->filePath = NULL;
729         addrIndex->fileName = NULL;
730         addrIndex->retVal = MGU_SUCCESS;
731         addrIndex->needsConversion = FALSE;
732         addrIndex->wasConverted = FALSE;
733         addrIndex->conversionError = FALSE;
734         addrIndex->lastType = ADDR_IF_NONE;
735         addrIndex->dirtyFlag = FALSE;
736
737         /* Free up interfaces */        
738         node = addrIndex->interfaceList;
739         while( node ) {
740                 AddressInterface *iface = node->data;
741                 addrindex_free_interface( iface );
742                 node = g_list_next( node );
743         }
744         g_list_free( addrIndex->interfaceList );
745         addrIndex->interfaceList = NULL;
746
747         /* Free up hash cache */
748         addrindex_free_cache_hash( addrIndex->hashCache );
749         addrIndex->hashCache = NULL;
750
751         addrIndex->loadedFlag = FALSE;
752
753         g_free( addrIndex );
754         addrIndex = NULL;
755         _addressIndex_ = NULL;
756 }
757
758 /**
759  * Print address index.
760  * \param addrIndex Address index.
761  * \parem stream    Stream to print.
762 */
763 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
764         cm_return_if_fail( addrIndex != NULL );
765         fprintf( stream, "AddressIndex:\n" );
766         fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
767         fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
768         fprintf( stream, "\t   status: %d\n", addrIndex->retVal );
769         fprintf( stream, "\tconverted: '%s'\n",
770                         addrIndex->wasConverted ? "yes" : "no" );
771         fprintf( stream, "\tcvt error: '%s'\n",
772                         addrIndex->conversionError ? "yes" : "no" );
773         fprintf( stream, "\t---\n" );
774 }
775
776 /**
777  * Retrieve reference to address interface for specified interface type.
778  * \param  addrIndex Address index.
779  * \param  ifType Interface type.
780  * \return Address interface, or NULL if not found.
781  */
782 static AddressInterface *addrindex_get_interface(
783         AddressIndex *addrIndex, AddressIfType ifType )
784 {
785         AddressInterface *retVal = NULL;
786         GList *node;
787
788         cm_return_val_if_fail( addrIndex != NULL, NULL );
789
790         node = addrIndex->interfaceList;
791         while( node ) {
792                 AddressInterface *iface = node->data;
793                 node = g_list_next( node );
794                 if( iface->type == ifType ) {
795                         retVal = iface;
796                         break;
797                 }
798         }
799         return retVal;
800 }
801
802 /**
803  * Add raw data source to index. The raw data object (an AddressBookFile or
804  * VCardFile object, for example) should be supplied as the raw dataSource
805  * argument.
806  *
807  * \param  addrIndex Address index.
808  * \param ifType     Interface type to add.
809  * \param dataSource Actual raw data source to add. 
810  * \return Data source added, or NULL if invalid interface type.
811  */
812 AddressDataSource *addrindex_index_add_datasource(
813         AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
814 {
815         AddressInterface *iface;
816         AddressDataSource *ds = NULL;
817
818         cm_return_val_if_fail( addrIndex != NULL, NULL );
819         cm_return_val_if_fail( dataSource != NULL, NULL );
820
821         iface = addrindex_get_interface( addrIndex, ifType );
822         if( iface ) {
823                 ds = addrindex_create_datasource( ifType );
824                 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
825                 ds->type = ifType;
826                 ds->rawDataSource = dataSource;
827                 ds->interface = iface;
828                 iface->listSource = g_list_append( iface->listSource, ds );
829                 addrIndex->dirtyFlag = TRUE;
830
831                 addrindex_hash_add_cache( addrIndex, ds );
832         }
833         return ds;
834 }
835
836 /**
837  * Remove specified data source from index.
838  * \param  addrIndex Address index.
839  * \param  dataSource Data source to add. 
840  * \return Reference to data source if removed, or NULL if data source was not
841  *         found in index. Note the this object must still be freed.
842  */
843 AddressDataSource *addrindex_index_remove_datasource(
844         AddressIndex *addrIndex, AddressDataSource *dataSource )
845 {
846         AddressDataSource *retVal = FALSE;
847         AddressInterface *iface;
848
849         cm_return_val_if_fail( addrIndex != NULL, NULL );
850         cm_return_val_if_fail( dataSource != NULL, NULL );
851
852         iface = addrindex_get_interface( addrIndex, dataSource->type );
853         if( iface ) {
854                 iface->listSource = g_list_remove( iface->listSource, dataSource );
855                 addrIndex->dirtyFlag = TRUE;
856                 dataSource->interface = NULL;
857
858                 /* Remove cache from hash table */
859                 addrindex_hash_remove_cache( addrIndex, dataSource );
860
861                 retVal = dataSource;
862         }
863         return retVal;
864 }
865
866 /**
867  * Retrieve a reference to address interface for specified interface type and
868  * XML interface tag name.
869  * \param  addrIndex Address index.
870  * \param  tag       XML interface tag name to match.
871  * \param  ifType    Interface type to match.
872  * \return Reference to address index, or NULL if not found in index.
873  */
874 static AddressInterface *addrindex_tag_get_interface(
875         AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
876 {
877         AddressInterface *retVal = NULL;
878         GList *node = addrIndex->interfaceList;
879
880         while( node ) {
881                 AddressInterface *iface = node->data;
882                 node = g_list_next( node );
883                 if( tag ) {
884                         if( strcmp( iface->listTag, tag ) == 0 ) {
885                                 retVal = iface;
886                                 break;
887                         }
888                 }
889                 else {
890                         if( iface->type == ifType ) {
891                                 retVal = iface;
892                                 break;
893                         }
894                 }
895         }
896         return retVal;
897 }
898
899 /**
900  * Retrieve a reference to address interface for specified interface type and
901  * XML datasource tag name.
902  * \param  addrIndex Address index.
903  * \param  ifType    Interface type to match.
904  * \param  tag       XML datasource tag name to match.
905  * \return Reference to address index, or NULL if not found in index.
906  */
907 static AddressInterface *addrindex_tag_get_datasource(
908         AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
909 {
910         AddressInterface *retVal = NULL;
911         GList *node = addrIndex->interfaceList;
912
913         while( node ) {
914                 AddressInterface *iface = node->data;
915                 node = g_list_next( node );
916                 if( iface->type == ifType && iface->itemTag ) {
917                         if( strcmp( iface->itemTag, tag ) == 0 ) {
918                                 retVal = iface;
919                                 break;
920                         }
921                 }
922         }
923         return retVal;
924 }
925
926 /* **********************************************************************
927 * Interface XML parsing functions.
928 * ***********************************************************************
929 */
930
931 /**
932  * Write start of XML element to file.
933  * \param fp   File.
934  * \param lvl  Indentation level.
935  * \param name Element name.
936  */
937 static int addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
938         gint i;
939         for( i = 0; i < lvl; i++ ) 
940                 if (fputs( "  ", fp ) == EOF)
941                         return -1;
942         if (fputs( "<", fp ) == EOF)
943                 return -1;
944         if (fputs( name, fp ) == EOF)
945                 return -1;
946         return 0;
947 }
948
949 /**
950  * Write end of XML element to file.
951  * \param fp   File.
952  * \param lvl  Indentation level.
953  * \param name Element name.
954  */
955 static int addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
956         gint i;
957         for( i = 0; i < lvl; i++ ) 
958                 if (fputs( "  ", fp ) == EOF)
959                         return -1;
960         if (fputs( "</", fp ) == EOF)
961                 return -1;
962         if (fputs( name, fp ) == EOF)
963                 return -1;
964         if (fputs( ">\n", fp ) == EOF)
965                 return -1;
966         return 0;
967 }
968
969 /**
970  * Write XML attribute to file.
971  * \param fp    File.
972  * \param name  Attribute name.
973  * \param value Attribute value.
974  */
975 static int addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
976         if (fputs( " ", fp ) == EOF)
977                 return -1;
978         if (fputs( name, fp ) == EOF)
979                 return -1;
980         if (fputs( "=\"", fp ) == EOF)
981                 return -1;
982         if (xml_file_put_escape_str( fp, value ) < 0)
983                 return -1;
984         if (fputs( "\"", fp ) == EOF)
985                 return -1;
986         return 0;
987 }
988
989 #if !defined(USE_LDAP) || !defined(USE_JPILOT)
990 /**
991  * Return DOM fragment for current XML tag from file.
992  * \param  file XML file being processed.
993  * \return Fragment representing DOM fragment for configuration element.
994  */
995 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
996         AddressIfFragment *fragment;
997         AddressIfFragment *child;
998         AddressIfAttrib *nv;
999         XMLTag *xtag;
1000         GList *list;
1001         GList *attr;
1002         gchar *name;
1003         gchar *value;
1004         guint prevLevel;
1005         gint rc;
1006
1007         /* g_print( "addrindex_read_fragment\n" ); */
1008
1009         prevLevel = file->level;
1010
1011         /* Get current tag name */
1012         xtag = xml_get_current_tag( file );
1013
1014         /* Create new fragment */
1015         fragment = g_new0( AddressIfFragment, 1 );
1016         fragment->name = g_strdup( xtag->tag );
1017         fragment->children = NULL;
1018         fragment->attributes = NULL;
1019
1020         /* Read attributes */
1021         list = NULL;
1022         attr = xml_get_current_tag_attr( file );
1023         while( attr ) {
1024                 name = ((XMLAttr *)attr->data)->name;
1025                 value = ((XMLAttr *)attr->data)->value;
1026                 nv = g_new0( AddressIfAttrib, 1 );
1027                 nv->name = g_strdup( name );
1028                 nv->value = g_strdup( value );
1029                 list = g_list_append( list, nv );
1030                 attr = g_list_next( attr );
1031         }
1032         fragment->attributes = list;
1033
1034         /* Now read the children */
1035         while( TRUE ) {
1036                 rc = xml_parse_next_tag( file );
1037                 if( rc != 0 ) {
1038                         /* End of file? */
1039                         break;
1040                 }
1041                 if( file->level < prevLevel ) {
1042                         /* We must be above level we start at */
1043                         break;
1044                 }
1045                 child = addrindex_read_fragment( file );
1046                 fragment->children = g_list_append( fragment->children, child );
1047         }
1048
1049         return fragment;
1050 }
1051
1052 /**
1053  * Write DOM fragment to file.
1054  * \param fp       File to write.
1055  * \param fragment DOM fragment for configuration element.
1056  * \param lvl      Indent level.
1057  */
1058 static int addrindex_write_fragment(
1059                 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1060 {
1061         GList *node;
1062
1063         if( fragment ) {
1064                 if (addrindex_write_elem_s( fp, lvl, fragment->name ) < 0)
1065                         return -1;
1066                 node = fragment->attributes;
1067                 while( node ) {
1068                         AddressIfAttrib *nv = node->data;
1069                         if (addrindex_write_attr( fp, nv->name, nv->value ) < 0)
1070                                 return -1;
1071                         node = g_list_next( node );
1072                 }
1073                 if( fragment->children ) {
1074                         if (fputs(" >\n", fp) == EOF)
1075                                 return -1;
1076
1077                         /* Output children */
1078                         node = fragment->children;
1079                         while( node ) {
1080                                 AddressIfFragment *child = node->data;
1081                                 if (addrindex_write_fragment( fp, child, 1+lvl ) < 0)
1082                                         return -1;
1083                                 node = g_list_next( node );
1084                         }
1085
1086                         /* Output closing tag */
1087                         if (addrindex_write_elem_e( fp, lvl, fragment->name ) < 0)
1088                                 return -1;
1089                 }
1090                 else {
1091                         if (fputs(" />\n", fp) == EOF)
1092                                 return -1;
1093                 }
1094         }
1095         
1096         return 0;
1097 }
1098 #endif
1099 /**
1100  * Read/parse address index file, creating a data source for a regular
1101  * intrinsic XML addressbook.
1102  * \param  file Address index file.
1103  * \return Data source.
1104  */
1105 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1106         AddressDataSource *ds;
1107         AddressBookFile *abf;
1108         GList *attr;
1109
1110         ds = addrindex_create_datasource( ADDR_IF_BOOK );
1111         abf = addrbook_create_book();
1112         attr = xml_get_current_tag_attr( file );
1113         while( attr ) {
1114                 gchar *name = ((XMLAttr *)attr->data)->name;
1115                 gchar *value = ((XMLAttr *)attr->data)->value;
1116                 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1117                         addrbook_set_name( abf, value );
1118                 }
1119                 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1120                         addrbook_set_file( abf, value );
1121                 }
1122                 attr = g_list_next( attr );
1123         }
1124         ds->rawDataSource = abf;
1125         return ds;
1126 }
1127
1128 static int addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1129         AddressBookFile *abf = ds->rawDataSource;
1130         if( abf ) {
1131                 if (addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK ) < 0)
1132                         return -1;
1133                 if (addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) ) < 0)
1134                         return -1;
1135                 if (addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName ) < 0)
1136                         return -1;
1137                 if (fputs( " />\n", fp ) == EOF)
1138                         return -1;
1139         }
1140         return 0;
1141 }
1142
1143 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1144         AddressDataSource *ds;
1145         VCardFile *vcf;
1146         GList *attr;
1147
1148         ds = addrindex_create_datasource( ADDR_IF_VCARD );
1149         vcf = vcard_create();
1150         attr = xml_get_current_tag_attr( file );
1151         while( attr ) {
1152                 gchar *name = ((XMLAttr *)attr->data)->name;
1153                 gchar *value = ((XMLAttr *)attr->data)->value;
1154                 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1155                         vcard_set_name( vcf, value );
1156                 }
1157                 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1158                         vcard_set_file( vcf, value );
1159                 }
1160                 attr = g_list_next( attr );
1161         }
1162         ds->rawDataSource = vcf;
1163         return ds;
1164 }
1165
1166 static int addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1167         VCardFile *vcf = ds->rawDataSource;
1168         if( vcf ) {
1169                 if (addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD ) < 0)
1170                         return -1;
1171                 if (addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) ) < 0)
1172                         return -1;
1173                 if (addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path ) < 0)
1174                         return -1;
1175                 if (fputs( " />\n", fp ) == EOF)
1176                         return -1;
1177         }
1178         return 0;
1179 }
1180
1181 #ifdef USE_JPILOT
1182 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1183         AddressDataSource *ds;
1184         JPilotFile *jpf;
1185         GList *attr;
1186
1187         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1188         jpf = jpilot_create();
1189         attr = xml_get_current_tag_attr( file );
1190         while( attr ) {
1191                 gchar *name = ((XMLAttr *)attr->data)->name;
1192                 gchar *value = ((XMLAttr *)attr->data)->value;
1193                 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1194                         jpilot_set_name( jpf, value );
1195                 }
1196                 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1197                         jpilot_set_file( jpf, value );
1198                 }
1199                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1200                         jpilot_add_custom_label( jpf, value );
1201                 }
1202                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1203                         jpilot_add_custom_label( jpf, value );
1204                 }
1205                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1206                         jpilot_add_custom_label( jpf, value );
1207                 }
1208                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1209                         jpilot_add_custom_label( jpf, value );
1210                 }
1211                 attr = g_list_next( attr );
1212         }
1213         ds->rawDataSource = jpf;
1214         return ds;
1215 }
1216
1217 static int addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1218         JPilotFile *jpf = ds->rawDataSource;
1219         if( jpf ) {
1220                 gint ind;
1221                 GList *node;
1222                 GList *customLbl = jpilot_get_custom_labels( jpf );
1223                 if (addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT ) < 0)
1224                         return -1;
1225                 if (addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) ) < 0)
1226                         return -1;
1227                 if (addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path ) < 0)
1228                         return -1;
1229                 node = customLbl;
1230                 ind = 1;
1231                 while( node ) {
1232                         gchar name[256];
1233                         g_snprintf( name, sizeof(name), "%s%d",
1234                                     ATTAG_JPILOT_CUSTOM, ind );
1235                         if (addrindex_write_attr( fp, name, node->data ) < 0)
1236                                 return -1;
1237                         ind++;
1238                         node = g_list_next( node );
1239                 }
1240                 if (fputs( " />\n", fp ) == EOF)
1241                         return -1;
1242         }
1243         return 0;
1244 }
1245
1246 #else
1247 /*
1248  * Just read/write DOM fragments (preserve data found in file).
1249  */
1250 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1251         AddressDataSource *ds;
1252
1253         ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1254         ds->rawDataSource = addrindex_read_fragment( file );
1255         return ds;
1256 }
1257
1258 static int addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1259         AddressIfFragment *fragment = ds->rawDataSource;
1260         if( fragment ) {
1261                 if (addrindex_write_fragment( fp, fragment, lvl ) < 0)
1262                         return -1;
1263         }
1264         return 0;
1265 }
1266 #endif
1267
1268 #ifdef USE_LDAP
1269 /**
1270  * Parse LDAP criteria attribute data from XML file.
1271  * \param file Index file.
1272  * \param ctl  LDAP control object to populate.
1273  */
1274 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1275         guint prevLevel;
1276         XMLTag *xtag;
1277         XMLTag *xtagPrev;
1278         gint rc;
1279         GList *attr;
1280         GList *list;
1281         GList *node;
1282
1283         if( file == NULL ) {
1284                 return;
1285         }
1286
1287         list = NULL;
1288         prevLevel = file->level;
1289         xtagPrev = xml_get_current_tag( file );
1290         while( TRUE ) {
1291                 rc = xml_parse_next_tag( file );
1292                 if( rc != 0 ) {
1293                         /* Terminate prematurely */
1294                         mgu_free_dlist( list );
1295                         list = NULL;
1296                         return;
1297                 }
1298                 if( file->level < prevLevel ) {
1299                         /* We must be above level we start at */
1300                         break;
1301                 }
1302
1303                 /* Get a tag (element) */
1304                 xtag = xml_get_current_tag( file );
1305                 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1306                         /* LDAP criteria attribute */
1307                         attr = xml_get_current_tag_attr( file );
1308                         while( attr ) {
1309                                 gchar *name = ((XMLAttr *)attr->data)->name;
1310                                 gchar *value = ((XMLAttr *)attr->data)->value;
1311                                 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1312                                         if( value && strlen( value ) > 0 ) {
1313                                                 list = g_list_append(
1314                                                         list, g_strdup( value ) );
1315                                         }
1316                                 }
1317                                 attr = g_list_next( attr );
1318                         }
1319                 }
1320                 else {
1321                         if( xtag != xtagPrev ) {
1322                                 /* Found a new tag */
1323                                 break;
1324                         }
1325                 }
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                 safe_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, ALERTFOCUS_FIRST );
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 #ifdef USE_LDAP
3205 GSList *addrindex_get_password_protected_ldap_servers()
3206 {
3207         AddressInterface *iface;
3208         AddressDataSource *ds;
3209         GList *nodeIf;
3210         GList *nodeDS;
3211         GSList *list = NULL;
3212         LdapServer *server;
3213         LdapControl *ctl;
3214
3215         nodeIf = _addressIndex_->searchOrder;
3216         while (nodeIf) {
3217                 iface = nodeIf->data;
3218                 nodeIf = g_list_next(nodeIf);
3219
3220                 if (!iface->useInterface)
3221                         continue;
3222                 if (!iface->externalQuery)
3223                         continue;
3224                 if (iface->type != ADDR_IF_LDAP)
3225                         continue;
3226
3227                 nodeDS = iface->listSource;
3228                 while (nodeDS) {
3229                         ds = nodeDS->data;
3230                         nodeDS = g_list_next(nodeDS);
3231                         server = ds->rawDataSource;
3232                         if (!server->searchFlag)
3233                                 continue;
3234
3235                         ctl = server->control;
3236
3237                         if (!ctl)
3238                                 continue;
3239
3240                         if (ctl->bindDN != NULL && strlen(ctl->bindDN)) {
3241                                 list = g_slist_append(list, server);
3242                         }
3243                 }
3244         }
3245
3246         return list;
3247 }
3248 #endif /* USE_LDAP */
3249
3250 /*
3251  * End of Source.
3252  */