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