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