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