2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2012 Match Grun and the Claws Mail team
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.
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.
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/>.
21 * General functions for accessing address index file.
26 #include "claws-features.h"
32 #include <glib/gi18n.h>
36 #include "addrcache.h"
38 #include "addressbook.h"
39 #include "addrindex.h"
41 #include "addrquery.h"
42 #include "addr_compl.h"
44 #include "alertpanel.h"
45 #include "passwordstore.h"
48 #ifndef DEV_STANDALONE
49 #include "prefs_gtk.h"
60 #include "ldapserver.h"
62 #include "ldapquery.h"
63 #include "ldapupdate.h"
71 #define TAG_ADDRESS_INDEX "addressbook"
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"
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"
83 /* XML Attribute names */
84 #define ATTAG_BOOK_NAME "name"
85 #define ATTAG_BOOK_FILE "file"
87 #define ATTAG_VCARD_NAME "name"
88 #define ATTAG_VCARD_FILE "file"
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-"
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"
113 #define ELTAG_LDAP_ATTR_SRCH "attribute"
114 #define ATTAG_LDAP_ATTR_NAME "name"
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"
123 #define ATTAG_LDAP_DEFAULT "default"
125 #define DISP_NEW_COMMON _("Common addresses")
126 #define DISP_NEW_PERSONAL _("Personal addresses")
128 /* Old address book */
129 #define TAG_IF_OLD_COMMON "common_address"
130 #define TAG_IF_OLD_PERSONAL "personal_address"
132 #define DISP_OLD_COMMON _("Common address")
133 #define DISP_OLD_PERSONAL _("Personal address")
138 static AddressIndex *_addressIndex_ = NULL;
141 * Define attribute name-value pair.
143 typedef struct _AddressIfAttr AddressIfAttrib;
144 struct _AddressIfAttr {
149 static AddressDataSource *addrindex_create_datasource ( AddressIfType ifType );
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 );
161 * Define DOM fragment.
163 typedef struct _AddressIfFrag AddressIfFragment;
164 struct _AddressIfFrag {
171 * Build interface with default values.
173 * \param type Interface type.
174 * \param name Interface name.
175 * \param tagIf XML tag name for interface in address index file.
176 * \param tagDS XML tag name for datasource in address index file.
177 * \return Address interface object.
179 static AddressInterface *addrindex_create_interface(
180 gint type, gchar *name, gchar *tagIf, gchar *tagDS )
182 AddressInterface *iface = g_new0( AddressInterface, 1 );
184 ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
185 ADDRITEM_ID(iface) = NULL;
186 ADDRITEM_NAME(iface) = g_strdup( name );
187 ADDRITEM_PARENT(iface) = NULL;
188 ADDRITEM_SUBTYPE(iface) = type;
190 iface->name = g_strdup( name );
191 iface->listTag = g_strdup( tagIf );
192 iface->itemTag = g_strdup( tagDS );
193 iface->legacyFlag = FALSE;
194 iface->haveLibrary = TRUE;
195 iface->useInterface = TRUE;
196 iface->readOnly = TRUE;
198 /* Set callbacks to NULL values - override for each interface */
199 iface->getAccessFlag = NULL;
200 iface->getModifyFlag = NULL;
201 iface->getReadFlag = NULL;
202 iface->getStatusCode = NULL;
203 iface->getReadData = NULL;
204 iface->getRootFolder = NULL;
205 iface->getListFolder = NULL;
206 iface->getListPerson = NULL;
207 iface->getAllPersons = NULL;
208 iface->getAllGroups = NULL;
209 iface->getName = NULL;
210 iface->listSource = NULL;
213 iface->externalQuery = FALSE;
214 iface->searchOrder = 0; /* Ignored */
215 iface->startSearch = NULL;
216 iface->stopSearch = NULL;
222 * Build table of of all address book interfaces.
223 * \param addrIndex Address index object.
225 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
226 AddressInterface *iface;
228 /* Create intrinsic XML address book interface */
229 iface = addrindex_create_interface(
230 ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK,
231 TAG_DS_ADDRESS_BOOK );
232 iface->readOnly = FALSE;
233 iface->getModifyFlag = ( void * ) addrbook_get_modified;
234 iface->getAccessFlag = ( void * ) addrbook_get_accessed;
235 iface->getReadFlag = ( void * ) addrbook_get_read_flag;
236 iface->getStatusCode = ( void * ) addrbook_get_status;
237 iface->getReadData = ( void * ) addrbook_read_data;
238 iface->getRootFolder = ( void * ) addrbook_get_root_folder;
239 iface->getListFolder = ( void * ) addrbook_get_list_folder;
240 iface->getListPerson = ( void * ) addrbook_get_list_person;
241 iface->getAllPersons = ( void * ) addrbook_get_all_persons;
242 iface->getAllGroups = ( void * ) addrbook_get_all_groups;
243 iface->getName = ( void * ) addrbook_get_name;
244 iface->setAccessFlag = ( void * ) addrbook_set_accessed;
245 iface->searchOrder = 0;
247 /* Add to list of interfaces in address book */
248 addrIndex->interfaceList =
249 g_list_append( addrIndex->interfaceList, iface );
250 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
252 /* Create vCard interface */
253 iface = addrindex_create_interface(
254 ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
255 iface->getModifyFlag = ( void * ) vcard_get_modified;
256 iface->getAccessFlag = ( void * ) vcard_get_accessed;
257 iface->getReadFlag = ( void * ) vcard_get_read_flag;
258 iface->getStatusCode = ( void * ) vcard_get_status;
259 iface->getReadData = ( void * ) vcard_read_data;
260 iface->getRootFolder = ( void * ) vcard_get_root_folder;
261 iface->getListFolder = ( void * ) vcard_get_list_folder;
262 iface->getListPerson = ( void * ) vcard_get_list_person;
263 iface->getAllPersons = ( void * ) vcard_get_all_persons;
264 iface->getName = ( void * ) vcard_get_name;
265 iface->setAccessFlag = ( void * ) vcard_set_accessed;
266 iface->searchOrder = 0;
267 addrIndex->interfaceList =
268 g_list_append( addrIndex->interfaceList, iface );
269 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
271 /* Create JPilot interface */
272 iface = addrindex_create_interface(
273 ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT,
276 iface->haveLibrary = jpilot_test_pilot_lib();
277 iface->useInterface = iface->haveLibrary;
278 iface->getModifyFlag = ( void * ) jpilot_get_modified;
279 iface->getAccessFlag = ( void * ) jpilot_get_accessed;
280 iface->getReadFlag = ( void * ) jpilot_get_read_flag;
281 iface->getStatusCode = ( void * ) jpilot_get_status;
282 iface->getReadData = ( void * ) jpilot_read_data;
283 iface->getRootFolder = ( void * ) jpilot_get_root_folder;
284 iface->getListFolder = ( void * ) jpilot_get_list_folder;
285 iface->getListPerson = ( void * ) jpilot_get_list_person;
286 iface->getAllPersons = ( void * ) jpilot_get_all_persons;
287 iface->getName = ( void * ) jpilot_get_name;
288 iface->setAccessFlag = ( void * ) jpilot_set_accessed;
289 iface->searchOrder = 0;
291 iface->useInterface = FALSE;
292 iface->haveLibrary = FALSE;
294 addrIndex->interfaceList =
295 g_list_append( addrIndex->interfaceList, iface );
296 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
298 /* Create LDAP interface */
299 iface = addrindex_create_interface(
300 ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
302 iface->readOnly = FALSE;
303 /* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
304 iface->haveLibrary = ldaputil_test_ldap_lib();
305 iface->useInterface = iface->haveLibrary;
306 iface->getModifyFlag = ( void * ) ldapsvr_get_modified;
307 iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
308 iface->getReadFlag = ( void * ) ldapsvr_get_read_flag;
309 iface->getStatusCode = ( void * ) ldapsvr_get_status;
310 iface->getReadData = ( void * ) ldapsvr_read_data;
311 iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
312 iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
313 iface->getListPerson = ( void * ) ldapsvr_get_list_person;
314 iface->getName = ( void * ) ldapsvr_get_name;
315 iface->setAccessFlag = ( void * ) ldapsvr_set_accessed;
316 iface->externalQuery = TRUE;
317 iface->searchOrder = 1;
319 iface->useInterface = FALSE;
320 iface->haveLibrary = FALSE;
322 addrIndex->interfaceList =
323 g_list_append( addrIndex->interfaceList, iface );
324 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
326 /* Two old legacy data sources (pre 0.7.0) */
327 iface = addrindex_create_interface(
328 ADDR_IF_COMMON, "Old Address - common",
329 TAG_IF_OLD_COMMON, NULL );
330 iface->legacyFlag = TRUE;
331 addrIndex->interfaceList =
332 g_list_append( addrIndex->interfaceList, iface );
333 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
335 iface = addrindex_create_interface(
336 ADDR_IF_COMMON, "Old Address - personal",
337 TAG_IF_OLD_PERSONAL, NULL );
338 iface->legacyFlag = TRUE;
339 addrIndex->interfaceList =
340 g_list_append( addrIndex->interfaceList, iface );
341 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
347 * \param fragment Fragment to free.
349 static void addrindex_free_fragment( AddressIfFragment *fragment ) {
353 node = fragment->children;
355 AddressIfFragment *child = node->data;
356 addrindex_free_fragment( child );
358 node = g_list_next( node );
360 g_list_free( fragment->children );
362 /* Free attributes */
363 node = fragment->attributes;
365 AddressIfAttrib *nv = node->data;
370 node = g_list_next( node );
372 g_list_free( fragment->attributes );
374 g_free( fragment->name );
375 fragment->name = NULL;
376 fragment->attributes = NULL;
377 fragment->children = NULL;
383 * Create a new data source.
384 * \param ifType Interface type to create.
385 * \return Initialized data source.
387 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
388 AddressDataSource *ds = g_new0( AddressDataSource, 1 );
390 ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
391 ADDRITEM_ID(ds) = NULL;
392 ADDRITEM_NAME(ds) = NULL;
393 ADDRITEM_PARENT(ds) = NULL;
394 ADDRITEM_SUBTYPE(ds) = 0;
396 ds->rawDataSource = NULL;
397 ds->interface = NULL;
402 * Free up data source.
403 * \param ds Data source to free.
405 void addrindex_free_datasource( AddressDataSource *ds ) {
406 AddressInterface *iface;
408 cm_return_if_fail( ds != NULL );
410 iface = ds->interface;
411 if( ds->rawDataSource != NULL ) {
412 if( iface != NULL ) {
413 if( iface->useInterface ) {
414 if( iface->type == ADDR_IF_BOOK ) {
415 AddressBookFile *abf = ds->rawDataSource;
416 addrbook_free_book( abf );
418 else if( iface->type == ADDR_IF_VCARD ) {
419 VCardFile *vcf = ds->rawDataSource;
423 else if( iface->type == ADDR_IF_JPILOT ) {
424 JPilotFile *jpf = ds->rawDataSource;
429 else if( iface->type == ADDR_IF_LDAP ) {
430 LdapServer *server = ds->rawDataSource;
431 ldapsvr_free( server );
438 AddressIfFragment *fragment = ds->rawDataSource;
439 addrindex_free_fragment( fragment );
444 ADDRITEM_TYPE(ds) = ITEMTYPE_NONE;
445 ADDRITEM_ID(ds) = NULL;
446 ADDRITEM_NAME(ds) = NULL;
447 ADDRITEM_PARENT(ds) = NULL;
448 ADDRITEM_SUBTYPE(ds) = 0;
449 ds->type = ADDR_IF_NONE;
450 ds->interface = NULL;
451 ds->rawDataSource = NULL;
457 * Free up all data sources for specified interface.
458 * \param iface Address interface to process.
460 static void addrindex_free_all_datasources( AddressInterface *iface ) {
461 GList *node = iface->listSource;
463 AddressDataSource *ds = node->data;
464 addrindex_free_datasource( ds );
466 node = g_list_next( node );
471 * Free up specified interface.
472 * \param iface Interface to process.
474 static void addrindex_free_interface( AddressInterface *iface ) {
475 /* Free up data sources */
476 addrindex_free_all_datasources( iface );
477 g_list_free( iface->listSource );
479 /* Free internal storage */
480 g_free( ADDRITEM_ID(iface) );
481 g_free( ADDRITEM_NAME(iface) );
482 g_free( iface->name );
483 g_free( iface->listTag );
484 g_free( iface->itemTag );
486 /* Clear all pointers */
487 ADDRITEM_TYPE(iface) = ITEMTYPE_NONE;
488 ADDRITEM_ID(iface) = NULL;
489 ADDRITEM_NAME(iface) = NULL;
490 ADDRITEM_PARENT(iface) = NULL;
491 ADDRITEM_SUBTYPE(iface) = 0;
492 iface->type = ADDR_IF_NONE;
494 iface->listTag = NULL;
495 iface->itemTag = NULL;
496 iface->legacyFlag = FALSE;
497 iface->useInterface = FALSE;
498 iface->haveLibrary = FALSE;
499 iface->listSource = NULL;
502 iface->searchOrder = 0;
503 iface->startSearch = NULL;
504 iface->stopSearch = NULL;
510 * Return cache ID for specified data source.
512 * \param addrIndex Address index.
513 * \param ds Data source.
514 * \return ID or NULL if not found. This should be <code>g_free()</code>
517 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
518 gchar *cacheID = NULL;
519 AddrBookBase *adbase;
522 cm_return_val_if_fail( addrIndex != NULL, NULL );
523 cm_return_val_if_fail( ds != NULL, NULL );
525 adbase = ( AddrBookBase * ) ds->rawDataSource;
527 cache = adbase->addressCache;
529 cacheID = g_strdup( cache->cacheID );
537 * Return reference to data source for specified cacheID.
538 * \param addrIndex Address index.
540 * \return Data source, or NULL if not found.
542 static AddressDataSource *addrindex_get_datasource(
543 AddressIndex *addrIndex, const gchar *cacheID )
545 cm_return_val_if_fail( addrIndex != NULL, NULL );
546 cm_return_val_if_fail( cacheID != NULL, NULL );
547 return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
551 * Return reference to address cache for specified cacheID.
552 * \param addrIndex Address index.
554 * \return Address cache, or NULL if not found.
556 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
557 AddressDataSource *ds;
558 AddrBookBase *adbase;
561 cm_return_val_if_fail( addrIndex != NULL, NULL );
562 cm_return_val_if_fail( cacheID != NULL, NULL );
565 ds = addrindex_get_datasource( addrIndex, cacheID );
567 adbase = ( AddrBookBase * ) ds->rawDataSource;
568 cache = adbase->addressCache;
574 * Add data source into hash table.
575 * \param addrIndex Address index.
576 * \param ds Data source.
578 static void addrindex_hash_add_cache(
579 AddressIndex *addrIndex, AddressDataSource *ds )
583 cacheID = addrindex_get_cache_id( addrIndex, ds );
585 g_hash_table_insert( addrIndex->hashCache, cacheID, ds );
590 * Free hash table callback function.
592 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
600 * Free hash table of address cache items.
602 static void addrindex_free_cache_hash( GHashTable *table ) {
603 g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
604 g_hash_table_destroy( table );
608 * Remove data source from internal hashtable.
609 * \param addrIndex Address index.
610 * \param ds Data source to remove.
612 static void addrindex_hash_remove_cache(
613 AddressIndex *addrIndex, AddressDataSource *ds )
617 cacheID = addrindex_get_cache_id( addrIndex, ds );
619 g_hash_table_remove( addrIndex->hashCache, cacheID );
626 * Create a new address index. This is created as a singleton object.
627 * \return Initialized address index object.
629 AddressIndex *addrindex_create_index( void ) {
632 if( _addressIndex_ == NULL ) {
633 index = g_new0( AddressIndex, 1 );
634 ADDRITEM_TYPE(index) = ITEMTYPE_INDEX;
635 ADDRITEM_ID(index) = NULL;
636 ADDRITEM_NAME(index) = g_strdup( "Address Index" );
637 ADDRITEM_PARENT(index) = NULL;
638 ADDRITEM_SUBTYPE(index) = 0;
639 index->filePath = NULL;
640 index->fileName = NULL;
641 index->retVal = MGU_SUCCESS;
642 index->needsConversion = FALSE;
643 index->wasConverted = FALSE;
644 index->conversionError = FALSE;
645 index->interfaceList = NULL;
646 index->lastType = ADDR_IF_NONE;
647 index->dirtyFlag = FALSE;
648 index->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
649 index->loadedFlag = FALSE;
650 index->searchOrder = NULL;
651 addrindex_build_if_list( index );
652 _addressIndex_ = index;
654 return _addressIndex_;
658 * Property - Specify file path to address index file.
659 * \param addrIndex Address index.
660 * \param value Path to index file.
662 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
663 cm_return_if_fail( addrIndex != NULL );
664 addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
668 * Property - Specify file name to address index file.
669 * \param addrIndex Address index.
670 * \param value File name.
672 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
673 cm_return_if_fail( addrIndex != NULL );
674 addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
678 * Return list of address interfaces.
679 * \param addrIndex Address index.
680 * \return List of address interfaces.
682 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
683 cm_return_val_if_fail( addrIndex != NULL, NULL );
684 return addrIndex->interfaceList;
688 * Perform any other initialization of address index.
690 void addrindex_initialize( void ) {
692 addrcompl_initialize();
696 * Perform any other teardown of address index.
698 void addrindex_teardown( void ) {
699 addrcompl_teardown();
704 * Free up address index.
705 * \param addrIndex Address index.
707 void addrindex_free_index( AddressIndex *addrIndex ) {
710 cm_return_if_fail( addrIndex != NULL );
713 g_list_free( addrIndex->searchOrder );
714 addrIndex->searchOrder = NULL;
716 /* Free internal storage */
717 g_free( ADDRITEM_ID(addrIndex) );
718 g_free( ADDRITEM_NAME(addrIndex) );
719 g_free( addrIndex->filePath );
720 g_free( addrIndex->fileName );
723 ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
724 ADDRITEM_ID(addrIndex) = NULL;
725 ADDRITEM_NAME(addrIndex) = NULL;
726 ADDRITEM_PARENT(addrIndex) = NULL;
727 ADDRITEM_SUBTYPE(addrIndex) = 0;
728 addrIndex->filePath = NULL;
729 addrIndex->fileName = NULL;
730 addrIndex->retVal = MGU_SUCCESS;
731 addrIndex->needsConversion = FALSE;
732 addrIndex->wasConverted = FALSE;
733 addrIndex->conversionError = FALSE;
734 addrIndex->lastType = ADDR_IF_NONE;
735 addrIndex->dirtyFlag = FALSE;
737 /* Free up interfaces */
738 node = addrIndex->interfaceList;
740 AddressInterface *iface = node->data;
741 addrindex_free_interface( iface );
742 node = g_list_next( node );
744 g_list_free( addrIndex->interfaceList );
745 addrIndex->interfaceList = NULL;
747 /* Free up hash cache */
748 addrindex_free_cache_hash( addrIndex->hashCache );
749 addrIndex->hashCache = NULL;
751 addrIndex->loadedFlag = FALSE;
755 _addressIndex_ = NULL;
759 * Print address index.
760 * \param addrIndex Address index.
761 * \parem stream Stream to print.
763 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
764 cm_return_if_fail( addrIndex != NULL );
765 fprintf( stream, "AddressIndex:\n" );
766 fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
767 fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
768 fprintf( stream, "\t status: %d\n", addrIndex->retVal );
769 fprintf( stream, "\tconverted: '%s'\n",
770 addrIndex->wasConverted ? "yes" : "no" );
771 fprintf( stream, "\tcvt error: '%s'\n",
772 addrIndex->conversionError ? "yes" : "no" );
773 fprintf( stream, "\t---\n" );
777 * Retrieve reference to address interface for specified interface type.
778 * \param addrIndex Address index.
779 * \param ifType Interface type.
780 * \return Address interface, or NULL if not found.
782 static AddressInterface *addrindex_get_interface(
783 AddressIndex *addrIndex, AddressIfType ifType )
785 AddressInterface *retVal = NULL;
788 cm_return_val_if_fail( addrIndex != NULL, NULL );
790 node = addrIndex->interfaceList;
792 AddressInterface *iface = node->data;
793 node = g_list_next( node );
794 if( iface->type == ifType ) {
803 * Add raw data source to index. The raw data object (an AddressBookFile or
804 * VCardFile object, for example) should be supplied as the raw dataSource
807 * \param addrIndex Address index.
808 * \param ifType Interface type to add.
809 * \param dataSource Actual raw data source to add.
810 * \return Data source added, or NULL if invalid interface type.
812 AddressDataSource *addrindex_index_add_datasource(
813 AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
815 AddressInterface *iface;
816 AddressDataSource *ds = NULL;
818 cm_return_val_if_fail( addrIndex != NULL, NULL );
819 cm_return_val_if_fail( dataSource != NULL, NULL );
821 iface = addrindex_get_interface( addrIndex, ifType );
823 ds = addrindex_create_datasource( ifType );
824 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
826 ds->rawDataSource = dataSource;
827 ds->interface = iface;
828 iface->listSource = g_list_append( iface->listSource, ds );
829 addrIndex->dirtyFlag = TRUE;
831 addrindex_hash_add_cache( addrIndex, ds );
837 * Remove specified data source from index.
838 * \param addrIndex Address index.
839 * \param dataSource Data source to add.
840 * \return Reference to data source if removed, or NULL if data source was not
841 * found in index. Note the this object must still be freed.
843 AddressDataSource *addrindex_index_remove_datasource(
844 AddressIndex *addrIndex, AddressDataSource *dataSource )
846 AddressDataSource *retVal = FALSE;
847 AddressInterface *iface;
849 cm_return_val_if_fail( addrIndex != NULL, NULL );
850 cm_return_val_if_fail( dataSource != NULL, NULL );
852 iface = addrindex_get_interface( addrIndex, dataSource->type );
854 iface->listSource = g_list_remove( iface->listSource, dataSource );
855 addrIndex->dirtyFlag = TRUE;
856 dataSource->interface = NULL;
858 /* Remove cache from hash table */
859 addrindex_hash_remove_cache( addrIndex, dataSource );
867 * Retrieve a reference to address interface for specified interface type and
868 * XML interface tag name.
869 * \param addrIndex Address index.
870 * \param tag XML interface tag name to match.
871 * \param ifType Interface type to match.
872 * \return Reference to address index, or NULL if not found in index.
874 static AddressInterface *addrindex_tag_get_interface(
875 AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
877 AddressInterface *retVal = NULL;
878 GList *node = addrIndex->interfaceList;
881 AddressInterface *iface = node->data;
882 node = g_list_next( node );
884 if( strcmp( iface->listTag, tag ) == 0 ) {
890 if( iface->type == ifType ) {
900 * Retrieve a reference to address interface for specified interface type and
901 * XML datasource tag name.
902 * \param addrIndex Address index.
903 * \param ifType Interface type to match.
904 * \param tag XML datasource tag name to match.
905 * \return Reference to address index, or NULL if not found in index.
907 static AddressInterface *addrindex_tag_get_datasource(
908 AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
910 AddressInterface *retVal = NULL;
911 GList *node = addrIndex->interfaceList;
914 AddressInterface *iface = node->data;
915 node = g_list_next( node );
916 if( iface->type == ifType && iface->itemTag ) {
917 if( strcmp( iface->itemTag, tag ) == 0 ) {
926 /* **********************************************************************
927 * Interface XML parsing functions.
928 * ***********************************************************************
932 * Write start of XML element to file.
934 * \param lvl Indentation level.
935 * \param name Element name.
937 static int addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
939 for( i = 0; i < lvl; i++ )
940 if (claws_fputs( " ", fp ) == EOF)
942 if (claws_fputs( "<", fp ) == EOF)
944 if (claws_fputs( name, fp ) == EOF)
950 * Write end of XML element to file.
952 * \param lvl Indentation level.
953 * \param name Element name.
955 static int addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
957 for( i = 0; i < lvl; i++ )
958 if (claws_fputs( " ", fp ) == EOF)
960 if (claws_fputs( "</", fp ) == EOF)
962 if (claws_fputs( name, fp ) == EOF)
964 if (claws_fputs( ">\n", fp ) == EOF)
970 * Write XML attribute to file.
972 * \param name Attribute name.
973 * \param value Attribute value.
975 static int addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
976 if (claws_fputs( " ", fp ) == EOF)
978 if (claws_fputs( name, fp ) == EOF)
980 if (claws_fputs( "=\"", fp ) == EOF)
982 if (xml_file_put_escape_str( fp, value ) < 0)
984 if (claws_fputs( "\"", fp ) == EOF)
989 #if !defined(USE_LDAP) || !defined(USE_JPILOT)
991 * Return DOM fragment for current XML tag from file.
992 * \param file XML file being processed.
993 * \return Fragment representing DOM fragment for configuration element.
995 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
996 AddressIfFragment *fragment;
997 AddressIfFragment *child;
1007 /* g_print( "addrindex_read_fragment\n" ); */
1009 prevLevel = file->level;
1011 /* Get current tag name */
1012 xtag = xml_get_current_tag( file );
1014 /* Create new fragment */
1015 fragment = g_new0( AddressIfFragment, 1 );
1016 fragment->name = g_strdup( xtag->tag );
1017 fragment->children = NULL;
1018 fragment->attributes = NULL;
1020 /* Read attributes */
1022 attr = xml_get_current_tag_attr( file );
1024 name = ((XMLAttr *)attr->data)->name;
1025 value = ((XMLAttr *)attr->data)->value;
1026 nv = g_new0( AddressIfAttrib, 1 );
1027 nv->name = g_strdup( name );
1028 nv->value = g_strdup( value );
1029 list = g_list_append( list, nv );
1030 attr = g_list_next( attr );
1032 fragment->attributes = list;
1034 /* Now read the children */
1036 rc = xml_parse_next_tag( file );
1041 if( file->level < prevLevel ) {
1042 /* We must be above level we start at */
1045 child = addrindex_read_fragment( file );
1046 fragment->children = g_list_append( fragment->children, child );
1053 * Write DOM fragment to file.
1054 * \param fp File to write.
1055 * \param fragment DOM fragment for configuration element.
1056 * \param lvl Indent level.
1058 static int addrindex_write_fragment(
1059 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1064 if (addrindex_write_elem_s( fp, lvl, fragment->name ) < 0)
1066 node = fragment->attributes;
1068 AddressIfAttrib *nv = node->data;
1069 if (addrindex_write_attr( fp, nv->name, nv->value ) < 0)
1071 node = g_list_next( node );
1073 if( fragment->children ) {
1074 if (claws_fputs(" >\n", fp) == EOF)
1077 /* Output children */
1078 node = fragment->children;
1080 AddressIfFragment *child = node->data;
1081 if (addrindex_write_fragment( fp, child, 1+lvl ) < 0)
1083 node = g_list_next( node );
1086 /* Output closing tag */
1087 if (addrindex_write_elem_e( fp, lvl, fragment->name ) < 0)
1091 if (claws_fputs(" />\n", fp) == EOF)
1100 * Read/parse address index file, creating a data source for a regular
1101 * intrinsic XML addressbook.
1102 * \param file Address index file.
1103 * \return Data source.
1105 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1106 AddressDataSource *ds;
1107 AddressBookFile *abf;
1110 ds = addrindex_create_datasource( ADDR_IF_BOOK );
1111 abf = addrbook_create_book();
1112 attr = xml_get_current_tag_attr( file );
1114 gchar *name = ((XMLAttr *)attr->data)->name;
1115 gchar *value = ((XMLAttr *)attr->data)->value;
1116 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1117 addrbook_set_name( abf, value );
1119 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1120 addrbook_set_file( abf, value );
1122 attr = g_list_next( attr );
1124 ds->rawDataSource = abf;
1128 static int addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1129 AddressBookFile *abf = ds->rawDataSource;
1131 if (addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK ) < 0)
1133 if (addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) ) < 0)
1135 if (addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName ) < 0)
1137 if (claws_fputs( " />\n", fp ) == EOF)
1143 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1144 AddressDataSource *ds;
1148 ds = addrindex_create_datasource( ADDR_IF_VCARD );
1149 vcf = vcard_create();
1150 attr = xml_get_current_tag_attr( file );
1152 gchar *name = ((XMLAttr *)attr->data)->name;
1153 gchar *value = ((XMLAttr *)attr->data)->value;
1154 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1155 vcard_set_name( vcf, value );
1157 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1158 vcard_set_file( vcf, value );
1160 attr = g_list_next( attr );
1162 ds->rawDataSource = vcf;
1166 static int addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1167 VCardFile *vcf = ds->rawDataSource;
1169 if (addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD ) < 0)
1171 if (addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) ) < 0)
1173 if (addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path ) < 0)
1175 if (claws_fputs( " />\n", fp ) == EOF)
1182 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1183 AddressDataSource *ds;
1187 ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1188 jpf = jpilot_create();
1189 attr = xml_get_current_tag_attr( file );
1191 gchar *name = ((XMLAttr *)attr->data)->name;
1192 gchar *value = ((XMLAttr *)attr->data)->value;
1193 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1194 jpilot_set_name( jpf, value );
1196 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1197 jpilot_set_file( jpf, value );
1199 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1200 jpilot_add_custom_label( jpf, value );
1202 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1203 jpilot_add_custom_label( jpf, value );
1205 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1206 jpilot_add_custom_label( jpf, value );
1208 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1209 jpilot_add_custom_label( jpf, value );
1211 attr = g_list_next( attr );
1213 ds->rawDataSource = jpf;
1217 static int addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1218 JPilotFile *jpf = ds->rawDataSource;
1222 GList *customLbl = jpilot_get_custom_labels( jpf );
1223 if (addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT ) < 0)
1225 if (addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) ) < 0)
1227 if (addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path ) < 0)
1233 g_snprintf( name, sizeof(name), "%s%d",
1234 ATTAG_JPILOT_CUSTOM, ind );
1235 if (addrindex_write_attr( fp, name, node->data ) < 0)
1238 node = g_list_next( node );
1240 if (claws_fputs( " />\n", fp ) == EOF)
1248 * Just read/write DOM fragments (preserve data found in file).
1250 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1251 AddressDataSource *ds;
1253 ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1254 ds->rawDataSource = addrindex_read_fragment( file );
1258 static int addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1259 AddressIfFragment *fragment = ds->rawDataSource;
1261 if (addrindex_write_fragment( fp, fragment, lvl ) < 0)
1270 * Parse LDAP criteria attribute data from XML file.
1271 * \param file Index file.
1272 * \param ctl LDAP control object to populate.
1274 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1283 if( file == NULL ) {
1288 prevLevel = file->level;
1289 xtagPrev = xml_get_current_tag( file );
1291 rc = xml_parse_next_tag( file );
1293 /* Terminate prematurely */
1294 mgu_free_dlist( list );
1298 if( file->level < prevLevel ) {
1299 /* We must be above level we start at */
1303 /* Get a tag (element) */
1304 xtag = xml_get_current_tag( file );
1305 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1306 /* LDAP criteria attribute */
1307 attr = xml_get_current_tag_attr( file );
1309 gchar *name = ((XMLAttr *)attr->data)->name;
1310 gchar *value = ((XMLAttr *)attr->data)->value;
1311 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1312 if( value && strlen( value ) > 0 ) {
1313 list = g_list_append(
1314 list, g_strdup( value ) );
1317 attr = g_list_next( attr );
1321 if( xtag != xtagPrev ) {
1322 /* Found a new tag */
1328 /* Build list of search attributes */
1329 ldapctl_criteria_list_clear( ctl );
1332 ldapctl_criteria_list_add( ctl, node->data );
1333 g_free( node->data );
1335 node = g_list_next( node );
1337 g_list_free( list );
1342 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl );
1344 * Parse LDAP control data from XML file.
1345 * \param file Index file.
1346 * \return Initialized data soruce object.
1348 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1349 AddressDataSource *ds;
1353 gchar *serverName = NULL;
1354 gchar *criteria = NULL;
1355 gboolean bDynSearch;
1356 gboolean bTLS, bSSL;
1358 gchar *password = NULL;
1360 /* g_print( "addrindex_parse_ldap\n" ); */
1361 /* Set up some defaults */
1365 iMatch = LDAPCTL_MATCH_BEGINWITH;
1367 ds = addrindex_create_datasource( ADDR_IF_LDAP );
1368 ctl = ldapctl_create();
1369 attr = xml_get_current_tag_attr( file );
1371 gchar *name = ((XMLAttr *)attr->data)->name;
1372 gchar *value = ((XMLAttr *)attr->data)->value;
1373 gint ivalue = atoi( value );
1375 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
1376 g_free( serverName );
1377 serverName = g_strdup( value );
1379 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
1380 ldapctl_set_host( ctl, value );
1382 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
1383 ldapctl_set_port( ctl, ivalue );
1385 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
1386 ldapctl_set_base_dn( ctl, value );
1388 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
1389 ldapctl_set_bind_dn( ctl, value );
1391 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
1394 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
1396 criteria = g_strdup( value );
1397 g_print("criteria %s\n", criteria);
1399 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
1400 ldapctl_set_max_entries( ctl, ivalue );
1402 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
1403 ldapctl_set_timeout( ctl, ivalue );
1405 else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
1406 ldapctl_set_max_query_age( ctl, ivalue );
1408 else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
1410 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1414 else if( strcmp( name, ATTAG_LDAP_MATCH_OPT ) == 0 ) {
1415 iMatch = LDAPCTL_MATCH_BEGINWITH;
1416 if( strcmp( value, ATVAL_LDAP_MATCH_CONTAINS ) == 0 ) {
1417 iMatch = LDAPCTL_MATCH_CONTAINS;
1420 else if( strcmp( name, ATTAG_LDAP_ENABLE_TLS ) == 0 ) {
1422 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1426 else if( strcmp( name, ATTAG_LDAP_ENABLE_SSL ) == 0 ) {
1428 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1432 attr = g_list_next( attr );
1435 if (password != NULL)
1436 passwd_store_set(PWS_CORE, "LDAP", ctl->hostName, password, TRUE);
1438 server = ldapsvr_create_noctl();
1439 ldapsvr_set_name( server, serverName );
1440 ldapsvr_set_search_flag( server, bDynSearch );
1441 ldapctl_set_matching_option( ctl, iMatch );
1442 ldapctl_set_tls( ctl, bTLS );
1443 ldapctl_set_ssl( ctl, bSSL );
1444 g_free( serverName );
1445 ldapsvr_set_control( server, ctl );
1446 ds->rawDataSource = server;
1448 addrindex_parse_ldap_attrlist( file, ctl );
1450 * If criteria have been specified and no attributes were listed, then
1451 * convert old style criteria into an attribute list. Any criteria will
1452 * be dropped when saving data.
1455 if( ! ldapctl_get_criteria_list( ctl ) ) {
1456 ldapctl_parse_ldap_search( ctl, criteria );
1460 /* ldapsvr_print_data( server, stdout ); */
1465 static int addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1466 LdapServer *server = ds->rawDataSource;
1467 LdapControl *ctl = NULL;
1472 ctl = server->control;
1474 if( ctl == NULL ) return 0;
1476 /* Output start element with attributes */
1477 if (addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP ) < 0)
1479 if (addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) ) < 0)
1481 if (addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName ) < 0)
1484 sprintf( value, "%d", ctl->port );
1485 if (addrindex_write_attr( fp, ATTAG_LDAP_PORT, value ) < 0)
1488 if (addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN ) < 0)
1490 if (addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN ) < 0)
1493 sprintf( value, "%d", ctl->maxEntries );
1494 if (addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value ) < 0)
1496 sprintf( value, "%d", ctl->timeOut );
1497 if (addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value ) < 0)
1499 sprintf( value, "%d", ctl->maxQueryAge );
1500 if (addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value ) < 0)
1503 if (addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
1504 server->searchFlag ?
1505 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1508 if (addrindex_write_attr( fp, ATTAG_LDAP_MATCH_OPT,
1509 ( ctl->matchingOption == LDAPCTL_MATCH_CONTAINS ) ?
1510 ATVAL_LDAP_MATCH_CONTAINS : ATVAL_LDAP_MATCH_BEGIN ) < 0)
1513 if (addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_TLS,
1515 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1517 if (addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_SSL,
1519 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1522 if (claws_fputs(" >\n", fp) == EOF)
1525 /* Output attributes */
1526 node = ldapctl_get_criteria_list( ctl );
1528 if (addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH ) < 0)
1530 if (addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data ) < 0)
1532 if (claws_fputs(" />\n", fp) == EOF)
1534 node = g_list_next( node );
1537 /* End of element */
1538 if (addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP ) < 0)
1546 * Just read/write DOM fragments (preserve data found in file).
1548 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1549 AddressDataSource *ds;
1551 ds = addrindex_create_datasource( ADDR_IF_LDAP );
1552 ds->rawDataSource = addrindex_read_fragment( file );
1556 static int addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1557 AddressIfFragment *fragment = ds->rawDataSource;
1559 if (addrindex_write_fragment( fp, fragment, lvl ) < 0)
1566 /* **********************************************************************
1567 * Address index I/O functions.
1568 * ***********************************************************************
1571 * Read address index file, creating appropriate data sources for each address
1574 * \param addrIndex Address index.
1575 * \param file Address index file.
1577 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
1579 AddressInterface *iface = NULL, *dsIFace = NULL;
1580 AddressDataSource *ds;
1583 addrIndex->loadedFlag = FALSE;
1585 rc = xml_parse_next_tag( file );
1586 if( rc < 0 || file->level == 0 ) return;
1588 xtag = xml_get_current_tag( file );
1590 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
1592 addrIndex->lastType = iface->type;
1593 if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
1596 dsIFace = addrindex_tag_get_datasource(
1597 addrIndex, addrIndex->lastType, xtag->tag );
1599 /* Add data source to list */
1601 if( addrIndex->lastType == ADDR_IF_BOOK ) {
1602 ds = addrindex_parse_book( file );
1603 if( ds->rawDataSource ) {
1604 addrbook_set_path( ds->rawDataSource,
1605 addrIndex->filePath );
1608 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
1609 ds = addrindex_parse_vcard( file );
1611 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
1612 ds = addrindex_parse_jpilot( file );
1614 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
1615 ds = addrindex_parse_ldap( file );
1618 ds->interface = dsIFace;
1619 addrindex_hash_add_cache( addrIndex, ds );
1620 dsIFace->listSource =
1621 g_list_append( dsIFace->listSource, ds );
1629 * Search order sorting comparison function for building search order list.
1631 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
1632 AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
1633 AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
1635 return ifaceA->searchOrder - ifaceB->searchOrder;
1639 * Build list of data sources to process.
1640 * \param addrIndex Address index object.
1642 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
1645 /* Clear existing list */
1646 g_list_free( addrIndex->searchOrder );
1647 addrIndex->searchOrder = NULL;
1649 /* Build new list */
1650 nodeIf = addrIndex->interfaceList;
1652 AddressInterface *iface = nodeIf->data;
1653 if( iface->useInterface ) {
1654 if( iface->searchOrder > 0 ) {
1655 /* Add to search order list */
1656 addrIndex->searchOrder = g_list_insert_sorted(
1657 addrIndex->searchOrder, iface,
1658 addrindex_search_order_compare );
1661 nodeIf = g_list_next( nodeIf );
1665 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1666 XMLFile *file = NULL;
1667 gchar *fileSpec = NULL;
1669 cm_return_val_if_fail( addrIndex != NULL, -1 );
1671 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1672 addrIndex->retVal = MGU_NO_FILE;
1673 file = xml_open_file( fileSpec );
1676 if( file == NULL ) {
1678 g_print( " file '%s' does not exist.\n", addrIndex->fileName );
1680 return addrIndex->retVal;
1683 addrIndex->retVal = MGU_BAD_FORMAT;
1684 if( xml_get_dtd( file ) == 0 ) {
1685 if( xml_parse_next_tag( file ) == 0 ) {
1686 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1687 addrindex_read_index( addrIndex, file );
1688 addrIndex->retVal = MGU_SUCCESS;
1692 xml_close_file( file );
1694 addrindex_build_search_order( addrIndex );
1696 return addrIndex->retVal;
1699 static int addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1700 GList *nodeIF, *nodeDS;
1702 gint lvlItem = 1 + lvlList;
1704 nodeIF = addrIndex->interfaceList;
1706 AddressInterface *iface = nodeIF->data;
1707 if( ! iface->legacyFlag ) {
1708 nodeDS = iface->listSource;
1709 if (addrindex_write_elem_s( fp, lvlList, iface->listTag ) < 0)
1711 if (claws_fputs( ">\n", fp ) == EOF)
1714 AddressDataSource *ds = nodeDS->data;
1716 if( iface->type == ADDR_IF_BOOK ) {
1717 if (addrindex_write_book( fp, ds, lvlItem ) < 0)
1720 if( iface->type == ADDR_IF_VCARD ) {
1721 if (addrindex_write_vcard( fp, ds, lvlItem ) < 0)
1724 if( iface->type == ADDR_IF_JPILOT ) {
1725 if (addrindex_write_jpilot( fp, ds, lvlItem ) < 0)
1728 if( iface->type == ADDR_IF_LDAP ) {
1729 if (addrindex_write_ldap( fp, ds, lvlItem ) < 0)
1733 nodeDS = g_list_next( nodeDS );
1735 if (addrindex_write_elem_e( fp, lvlList, iface->listTag ) < 0)
1738 nodeIF = g_list_next( nodeIF );
1744 * Write data to specified file.
1745 * Enter: addrIndex Address index object.
1746 * newFile New file name.
1747 * return: Status code, from addrIndex->retVal.
1748 * Note: File will be created in directory specified by addrIndex.
1750 static gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1753 #ifndef DEV_STANDALONE
1757 cm_return_val_if_fail( addrIndex != NULL, -1 );
1759 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1760 addrIndex->retVal = MGU_OPEN_FILE;
1761 #ifdef DEV_STANDALONE
1762 fp = claws_fopen( fileSpec, "wb" );
1765 claws_fputs( "<?xml version=\"1.0\" ?>\n", fp );
1767 pfile = prefs_write_open( fileSpec );
1771 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0)
1774 if (addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX ) < 0)
1776 if (claws_fputs( ">\n", fp ) == EOF)
1779 if (addrindex_write_index( addrIndex, fp ) < 0)
1781 if (addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX ) < 0)
1784 addrIndex->retVal = MGU_SUCCESS;
1785 #ifdef DEV_STANDALONE
1786 claws_safe_fclose( fp );
1788 if( prefs_file_close( pfile ) < 0 ) {
1789 addrIndex->retVal = MGU_ERROR_WRITE;
1795 return addrIndex->retVal;
1797 g_warning("error writing AB index");
1798 addrIndex->retVal = MGU_ERROR_WRITE;
1800 prefs_file_close_revert( pfile );
1801 return addrIndex->retVal;
1805 * Save address index data to original file.
1806 * return: Status code, from addrIndex->retVal.
1808 gint addrindex_save_data( AddressIndex *addrIndex ) {
1814 cm_return_val_if_fail( addrIndex != NULL, -1 );
1817 nodeIf = addrIndex->interfaceList;
1818 /* save LDAP interfaces */
1820 AddressInterface *iface = nodeIf->data;
1821 if( iface->type == ADDR_IF_LDAP ) {
1822 nodeDS = iface->listSource;
1824 AddressDataSource *ds = nodeDS->data;
1825 LdapServer *abf = ds->rawDataSource;
1826 if( ldapsvr_get_read_flag( abf ) ) {
1827 if( ldapsvr_get_modified( abf ) ) {
1828 ldapsvr_update_book( abf, NULL );
1829 if( abf->retVal != LDAPRC_SUCCESS ) {
1830 alertpanel( _("Address(es) update"),
1831 _("Update failed. Changes not written to Directory."),
1832 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
1835 abf->retVal = MGU_SUCCESS;
1836 ldapsvr_set_modified( abf, FALSE );
1840 nodeDS = g_list_next( nodeDS );
1844 nodeIf = g_list_next( nodeIf );
1847 addrIndex->retVal = MGU_NO_FILE;
1848 if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1849 if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1851 addrindex_write_to( addrIndex, addrIndex->fileName );
1852 if( addrIndex->retVal == MGU_SUCCESS ) {
1853 addrIndex->dirtyFlag = FALSE;
1855 return addrIndex->retVal;
1859 * Save all address book files which may have changed.
1860 * Return: Status code, set if there was a problem saving data.
1862 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1863 gint retVal = MGU_SUCCESS;
1864 GList *nodeIf, *nodeDS;
1866 nodeIf = addrIndex->interfaceList;
1868 AddressInterface *iface = nodeIf->data;
1869 if( iface->type == ADDR_IF_BOOK ) {
1870 nodeDS = iface->listSource;
1872 AddressDataSource *ds = nodeDS->data;
1873 AddressBookFile *abf = ds->rawDataSource;
1874 if( addrbook_get_dirty( abf ) ) {
1875 if( addrbook_get_read_flag( abf ) ) {
1876 addrbook_save_data( abf );
1877 if( abf->retVal != MGU_SUCCESS ) {
1878 retVal = abf->retVal;
1882 nodeDS = g_list_next( nodeDS );
1886 nodeIf = g_list_next( nodeIf );
1892 /* **********************************************************************
1893 * Address book conversion to new format.
1894 * ***********************************************************************
1897 #define ELTAG_IF_OLD_FOLDER "folder"
1898 #define ELTAG_IF_OLD_GROUP "group"
1899 #define ELTAG_IF_OLD_ITEM "item"
1900 #define ELTAG_IF_OLD_NAME "name"
1901 #define ELTAG_IF_OLD_ADDRESS "address"
1902 #define ELTAG_IF_OLD_REMARKS "remarks"
1903 #define ATTAG_IF_OLD_NAME "name"
1905 #define TEMPNODE_ROOT 0
1906 #define TEMPNODE_FOLDER 1
1907 #define TEMPNODE_GROUP 2
1908 #define TEMPNODE_ADDRESS 3
1910 typedef struct _AddressCvt_Node AddressCvtNode;
1911 struct _AddressCvt_Node {
1920 * Parse current address item.
1922 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1927 nn = g_new0( AddressCvtNode, 1 );
1928 nn->type = TEMPNODE_ADDRESS;
1931 level = file->level;
1934 xml_parse_next_tag(file);
1935 if (file->level < level) return nn;
1937 element = xml_get_element( file );
1938 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1939 nn->name = g_strdup( element );
1941 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1942 nn->address = g_strdup( element );
1944 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1945 nn->remarks = g_strdup( element );
1948 xml_parse_next_tag(file);
1953 * Create a temporary node below specified node.
1955 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1957 nn = g_new0( AddressCvtNode, 1 );
1959 nn->name = g_strdup( name );
1960 nn->remarks = g_strdup( rem );
1961 node->list = g_list_append( node->list, nn );
1966 * Process current temporary node.
1968 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1971 AddressCvtNode *newNode = NULL;
1976 prev_level = file->level;
1977 xml_parse_next_tag( file );
1978 if (file->level < prev_level) return;
1982 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1983 attr = xml_get_current_tag_attr(file);
1985 name = ((XMLAttr *)attr->data)->name;
1986 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1987 value = ((XMLAttr *)attr->data)->value;
1990 newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1991 addrindex_add_obj( file, newNode );
1994 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1995 attr = xml_get_current_tag_attr(file);
1997 name = ((XMLAttr *)attr->data)->name;
1998 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1999 value = ((XMLAttr *)attr->data)->value;
2002 newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
2003 addrindex_add_obj( file, newNode );
2005 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
2006 newNode = addrindex_parse_item( file );
2007 node->list = g_list_append( node->list, newNode );
2010 g_warning("Invalid tag");
2016 * Consume all nodes below current tag.
2018 static void addrindex_consume_tree( XMLFile *file ) {
2022 prev_level = file->level;
2023 xml_parse_next_tag( file );
2024 if (file->level < prev_level)
2027 addrindex_consume_tree( file );
2032 * Free up temporary tree.
2034 static void addrindex_free_node( AddressCvtNode *node ) {
2035 GList *list = node->list;
2038 AddressCvtNode *lNode = list->data;
2039 list = g_list_next( list );
2040 addrindex_free_node( lNode );
2042 node->type = TEMPNODE_ROOT;
2043 g_free( node->name );
2044 g_free( node->address );
2045 g_free( node->remarks );
2046 g_list_free( node->list );
2051 * Process address book for specified node.
2053 static void addrindex_process_node(
2054 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
2055 ItemGroup *parentGrp, ItemFolder *folderGrp )
2058 ItemFolder *itemFolder = NULL;
2059 ItemGroup *itemGParent = parentGrp;
2060 ItemFolder *itemGFolder = folderGrp;
2061 AddressCache *cache = abf->addressCache;
2063 if( node->type == TEMPNODE_ROOT ) {
2064 itemFolder = parent;
2066 else if( node->type == TEMPNODE_FOLDER ) {
2067 itemFolder = addritem_create_item_folder();
2068 addritem_folder_set_name( itemFolder, node->name );
2069 addrcache_id_folder( cache, itemFolder );
2070 addrcache_folder_add_folder( cache, parent, itemFolder );
2073 else if( node->type == TEMPNODE_GROUP ) {
2074 ItemGroup *itemGroup;
2077 /* Create a folder for group */
2078 fName = g_strdup_printf( "Cvt - %s", node->name );
2079 itemGFolder = addritem_create_item_folder();
2080 addritem_folder_set_name( itemGFolder, fName );
2081 addrcache_id_folder( cache, itemGFolder );
2082 addrcache_folder_add_folder( cache, parent, itemGFolder );
2085 /* Add group into folder */
2086 itemGroup = addritem_create_item_group();
2087 addritem_group_set_name( itemGroup, node->name );
2088 addrcache_id_group( cache, itemGroup );
2089 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
2090 itemGParent = itemGroup;
2092 else if( node->type == TEMPNODE_ADDRESS ) {
2093 ItemPerson *itemPerson;
2094 ItemEMail *itemEMail;
2096 /* Create person and email objects */
2097 itemPerson = addritem_create_item_person();
2098 addritem_person_set_common_name( itemPerson, node->name );
2099 addrcache_id_person( cache, itemPerson );
2100 itemEMail = addritem_create_item_email();
2101 addritem_email_set_address( itemEMail, node->address );
2102 addritem_email_set_remarks( itemEMail, node->remarks );
2103 addrcache_id_email( cache, itemEMail );
2104 addrcache_person_add_email( cache, itemPerson, itemEMail );
2106 /* Add person into appropriate folder */
2108 addrcache_folder_add_person( cache, itemGFolder, itemPerson );
2111 addrcache_folder_add_person( cache, parent, itemPerson );
2114 /* Add email address only into group */
2116 addrcache_group_add_email( cache, parentGrp, itemEMail );
2122 AddressCvtNode *lNode = list->data;
2123 list = g_list_next( list );
2124 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
2129 * Process address book to specified file number.
2131 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
2132 gboolean retVal = FALSE;
2133 AddressBookFile *abf = NULL;
2134 AddressCvtNode *rootNode = NULL;
2135 gchar *newFile = NULL;
2136 GList *fileList = NULL;
2139 /* Setup root node */
2140 rootNode = g_new0( AddressCvtNode, 1 );
2141 rootNode->type = TEMPNODE_ROOT;
2142 rootNode->name = g_strdup( "root" );
2143 rootNode->list = NULL;
2144 addrindex_add_obj( file, rootNode );
2145 /* addrindex_print_node( rootNode, stdout ); */
2147 /* Create new address book */
2148 abf = addrbook_create_book();
2149 addrbook_set_name( abf, displayName );
2150 addrbook_set_path( abf, addrIndex->filePath );
2152 /* Determine next available file number */
2153 fileList = addrbook_get_bookfile_list( abf );
2155 fileNum = 1 + abf->maxValue;
2157 g_list_free( fileList );
2160 newFile = addrbook_gen_new_file_name( fileNum );
2162 addrbook_set_file( abf, newFile );
2165 addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
2167 /* addrbook_dump_book( abf, stdout ); */
2168 addrbook_save_data( abf );
2169 addrIndex->retVal = abf->retVal;
2170 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2172 addrbook_free_book( abf );
2174 addrindex_free_node( rootNode );
2177 /* Create entries in address index */
2179 abf = addrbook_create_book();
2180 addrbook_set_name( abf, displayName );
2181 addrbook_set_path( abf, addrIndex->filePath );
2182 addrbook_set_file( abf, newFile );
2183 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2190 * Process tree converting data.
2192 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
2198 prev_level = file->level;
2199 xml_parse_next_tag( file );
2200 if (file->level < prev_level) return;
2202 xtag = xml_get_current_tag( file );
2203 /* g_print( "tag : %d : %s\n", prev_level, xtag->tag ); */
2204 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
2205 if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
2206 addrIndex->needsConversion = FALSE;
2207 addrIndex->wasConverted = TRUE;
2212 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
2213 if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
2214 addrIndex->needsConversion = FALSE;
2215 addrIndex->wasConverted = TRUE;
2220 addrindex_consume_tree( file );
2224 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
2225 XMLFile *file = NULL;
2228 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
2229 addrIndex->retVal = MGU_NO_FILE;
2230 file = xml_open_file( fileSpec );
2233 if( file == NULL ) {
2234 /* g_print( " file '%s' does not exist.\n", addrIndex->fileName ); */
2235 return addrIndex->retVal;
2238 addrIndex->retVal = MGU_BAD_FORMAT;
2239 if( xml_get_dtd( file ) == 0 ) {
2240 if( xml_parse_next_tag( file ) == 0 ) {
2241 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
2242 addrindex_convert_tree( addrIndex, file );
2246 xml_close_file( file );
2247 return addrIndex->retVal;
2251 * Create a new address book file.
2253 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
2254 gboolean retVal = FALSE;
2255 AddressBookFile *abf = NULL;
2256 gchar *newFile = NULL;
2257 GList *fileList = NULL;
2260 /* Create new address book */
2261 abf = addrbook_create_book();
2262 addrbook_set_name( abf, displayName );
2263 addrbook_set_path( abf, addrIndex->filePath );
2265 /* Determine next available file number */
2266 fileList = addrbook_get_bookfile_list( abf );
2268 fileNum = 1 + abf->maxValue;
2270 g_list_free( fileList );
2273 newFile = addrbook_gen_new_file_name( fileNum );
2275 addrbook_set_file( abf, newFile );
2278 addrbook_save_data( abf );
2279 addrIndex->retVal = abf->retVal;
2280 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2281 addrbook_free_book( abf );
2284 /* Create entries in address index */
2286 abf = addrbook_create_book();
2287 addrbook_set_name( abf, displayName );
2288 addrbook_set_path( abf, addrIndex->filePath );
2289 addrbook_set_file( abf, newFile );
2290 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2297 * Read data for address index performing a conversion if necesary.
2298 * Enter: addrIndex Address index object.
2299 * return: Status code, from addrIndex->retVal.
2300 * Note: New address book files will be created in directory specified by
2301 * addrIndex. Three files will be created, for the following:
2302 * "Common addresses"
2303 * "Personal addresses"
2304 * "Gathered addresses" - a new address book.
2306 gint addrindex_read_data( AddressIndex *addrIndex ) {
2307 cm_return_val_if_fail( addrIndex != NULL, -1 );
2309 addrIndex->conversionError = FALSE;
2310 addrindex_read_file( addrIndex );
2311 if( addrIndex->retVal == MGU_SUCCESS ) {
2312 if( addrIndex->needsConversion ) {
2313 if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS )
2314 addrIndex->conversionError = FALSE;
2316 addrIndex->conversionError = TRUE;
2318 addrIndex->dirtyFlag = TRUE;
2320 return addrIndex->retVal;
2324 * Create new address books for a new address index.
2325 * Enter: addrIndex Address index object.
2326 * return: Status code, from addrIndex->retVal.
2327 * Note: New address book files will be created in directory specified by
2328 * addrIndex. Three files will be created, for the following:
2329 * "Common addresses"
2330 * "Personal addresses"
2331 * "Gathered addresses" - a new address book.
2333 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
2336 cm_return_val_if_fail( addrIndex != NULL, -1 );
2338 flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
2340 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
2341 addrIndex->dirtyFlag = TRUE;
2343 return addrIndex->retVal;
2346 /* **********************************************************************
2347 * New interface stuff.
2348 * ***********************************************************************
2352 * Return modified flag for specified data source.
2354 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
2355 gboolean retVal = FALSE;
2356 AddressInterface *iface;
2358 if( ds == NULL ) return retVal;
2359 iface = ds->interface;
2360 if( iface == NULL ) return retVal;
2361 if( iface->getModifyFlag ) {
2362 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
2368 * Return accessed flag for specified data source.
2370 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
2371 gboolean retVal = FALSE;
2372 AddressInterface *iface;
2374 if( ds == NULL ) return retVal;
2375 iface = ds->interface;
2376 if( iface == NULL ) return retVal;
2377 if( iface->getAccessFlag ) {
2378 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
2384 * Return data read flag for specified data source.
2386 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
2387 gboolean retVal = TRUE;
2388 AddressInterface *iface;
2390 if( ds == NULL ) return retVal;
2391 iface = ds->interface;
2392 if( iface == NULL ) return retVal;
2393 if( iface->getReadFlag ) {
2394 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
2400 * Return status code for specified data source.
2402 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
2403 gint retVal = MGU_SUCCESS;
2404 AddressInterface *iface;
2406 if( ds == NULL ) return retVal;
2407 iface = ds->interface;
2408 if( iface == NULL ) return retVal;
2409 if( iface->getStatusCode ) {
2410 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
2416 * Return data read flag for specified data source.
2418 gint addrindex_ds_read_data( AddressDataSource *ds ) {
2419 gint retVal = MGU_SUCCESS;
2420 AddressInterface *iface;
2422 if( ds == NULL ) return retVal;
2423 iface = ds->interface;
2424 if( iface == NULL ) return retVal;
2425 if( iface->getReadData ) {
2427 gchar *name = ( iface->getName ) ( ds->rawDataSource );
2428 g_print( "addrindex_ds_read_data...reading:::%s:::\n", name );
2430 retVal = ( iface->getReadData ) ( ds->rawDataSource );
2436 * Return data read flag for specified data source.
2438 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
2439 ItemFolder *retVal = NULL;
2440 AddressInterface *iface;
2442 if( ds == NULL ) return retVal;
2443 iface = ds->interface;
2444 if( iface == NULL ) return retVal;
2445 if( iface->getRootFolder ) {
2446 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
2452 * Return name for specified data source.
2454 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
2455 gchar *retVal = FALSE;
2456 AddressInterface *iface;
2458 if( ds == NULL ) return retVal;
2459 iface = ds->interface;
2460 if( iface == NULL ) return retVal;
2461 if( iface->getName ) {
2462 retVal = ( iface->getName ) ( ds->rawDataSource );
2468 * Set the access flag inside the data source.
2470 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
2471 AddressInterface *iface;
2473 if( ds == NULL ) return;
2474 iface = ds->interface;
2475 if( iface == NULL ) return;
2476 if( iface->setAccessFlag ) {
2477 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
2482 * Return read only flag for specified data source.
2484 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
2485 AddressInterface *iface;
2486 if( ds == NULL ) return TRUE;
2487 iface = ds->interface;
2488 if( iface == NULL ) return TRUE;
2489 return iface->readOnly;
2493 * Return list of all persons for specified data source.
2495 static GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
2496 GList *retVal = NULL;
2497 AddressInterface *iface;
2499 if( ds == NULL ) return retVal;
2500 iface = ds->interface;
2501 if( iface == NULL ) return retVal;
2502 if( iface->getAllPersons ) {
2503 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
2509 * Return list of all groups for specified data source.
2511 static GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
2512 GList *retVal = NULL;
2513 AddressInterface *iface;
2515 if( ds == NULL ) return retVal;
2516 iface = ds->interface;
2517 if( iface == NULL ) return retVal;
2518 if( iface->getAllGroups ) {
2519 retVal = ( iface->getAllGroups ) ( ds->rawDataSource );
2524 /* **********************************************************************
2525 * Address search stuff.
2526 * ***********************************************************************
2530 * Setup or register the dynamic search that will be performed. The search
2531 * is registered with the query manager.
2533 * \param searchTerm Search term. A private copy will be made.
2534 * \param callBackEntry Callback function that should be called when
2535 * each entry is received.
2536 * \param callBackEnd Callback function that should be called when
2537 * search has finished running.
2538 * \return ID allocated to query that will be executed.
2540 gint addrindex_setup_search(
2541 const gchar *searchTerm, void *callBackEnd, void *callBackEntry )
2546 /* Set up a dynamic address query */
2547 req = qrymgr_add_request( searchTerm, callBackEnd, callBackEntry );
2548 queryID = req->queryID;
2549 qryreq_set_search_type( req, ADDRSEARCH_DYNAMIC );
2551 /* g_print( "***> query ID ::%d::\n", queryID ); */
2558 * Function prototypes (not in header file or circular reference errors are
2561 LdapQuery *ldapsvr_new_dynamic_search(
2562 LdapServer *server, QueryRequest *req );
2563 LdapQuery *ldapsvr_new_explicit_search(
2564 LdapServer *server, QueryRequest *req, ItemFolder *folder );
2565 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry );
2570 * Execute the previously registered dynamic search.
2572 * \param req Address query object to execute.
2573 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2576 static gboolean addrindex_start_dynamic( QueryRequest *req ) {
2577 AddressInterface *iface;
2578 AddressDataSource *ds;
2583 /* g_print( "addrindex_start_dynamic::%d::\n", req->queryID ); */
2584 nodeIf = _addressIndex_->searchOrder;
2586 iface = nodeIf->data;
2587 nodeIf = g_list_next( nodeIf );
2589 if( ! iface->useInterface ) {
2592 if( ! iface->externalQuery ) {
2597 nodeDS = iface->listSource;
2600 nodeDS = g_list_next( nodeDS );
2602 if( type == ADDR_IF_LDAP ) {
2606 server = ds->rawDataSource;
2607 if( ! server->searchFlag ) {
2610 if( ldapsvr_reuse_previous( server, req ) ) {
2614 /* Start a new dynamic search */
2615 qry = ldapsvr_new_dynamic_search( server, req );
2617 ldapsvr_execute_query( server, qry );
2627 * Stop the previously registered search.
2629 * \param queryID ID of search query to stop.
2631 void addrindex_stop_search( const gint queryID ){
2633 AddrQueryObject *aqo;
2636 /* g_print( "addrindex_stop_search/queryID=%d\n", queryID ); */
2637 /* If query ID does not match, search has not been setup */
2638 req = qrymgr_find_request( queryID );
2643 /* Stop all queries that were associated with request */
2644 node = req->queryList;
2648 if( aqo->queryType == ADDRQUERY_LDAP ) {
2649 LdapQuery *qry = ( LdapQuery * ) aqo;
2650 ldapqry_set_stop_flag( qry, TRUE );
2654 node = g_list_next( node );
2657 /* Delete query request */
2658 qrymgr_delete_request( queryID );
2662 * Setup or register the explicit search that will be performed. The search is
2663 * registered with the query manager.
2665 * \param ds Data source to search.
2666 * \param searchTerm Search term to locate.
2667 * \param folder Folder to receive search results; may be NULL.
2668 * \param callbackEnd Function to call when search has terminated.
2669 * \param callbackEntry Function to called for each entry processed.
2670 * \return ID allocated to query that will be executed.
2672 gint addrindex_setup_explicit_search(
2673 AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder,
2674 void *callBackEnd, void *callBackEntry )
2681 /* Name the query */
2682 name = g_strdup_printf( "Search '%s'", searchTerm );
2684 /* Set up query request */
2685 if (!strcmp(searchTerm, "*"))
2686 mySearch = g_strdup("*@");
2688 mySearch = g_strdup(searchTerm);
2690 req = qrymgr_add_request( mySearch, callBackEnd, callBackEntry );
2694 qryreq_set_search_type( req, ADDRSEARCH_EXPLICIT );
2695 queryID = req->queryID;
2697 if( ds->type == ADDR_IF_LDAP ) {
2701 server = ds->rawDataSource;
2702 ldapsvr_new_explicit_search( server, req, folder );
2706 qrymgr_delete_request( queryID );
2715 * Execute the previously registered explicit search.
2717 * \param req Address query request object to execute.
2718 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2721 static gboolean addrindex_start_explicit( QueryRequest *req ) {
2723 AddrQueryObject *aqo;
2727 /* Note: there should only be one query in the list. */
2728 aqo = req->queryList->data;
2730 if( aqo->queryType == ADDRQUERY_LDAP ) {
2734 qry = ( LdapQuery * ) aqo;
2735 server = qry->server;
2737 /* Start the search */
2739 ldapsvr_execute_query( server, qry );
2746 * Start the previously registered search.
2748 * \param queryID ID of search query to be executed.
2749 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2752 gboolean addrindex_start_search( const gint queryID ) {
2755 AddrSearchType searchType;
2758 /* g_print( "addrindex_start_search/queryID=%d\n", queryID ); */
2759 req = qrymgr_find_request( queryID );
2764 searchType = req->searchType;
2765 if( searchType == ADDRSEARCH_DYNAMIC ) {
2766 retVal = addrindex_start_dynamic( req );
2768 else if( searchType == ADDRSEARCH_EXPLICIT ) {
2769 retVal = addrindex_start_explicit( req );
2776 * Remove results (folder and data) for specified data source and folder.
2777 * \param ds Data source to process.
2778 * \param folder Results folder to remove.
2780 void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) {
2781 AddrBookBase *adbase;
2784 /* g_print( "addrindex_remove_results/start\n" ); */
2786 /* Test for folder */
2787 if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return;
2788 /* g_print( "folder name ::%s::\n", ADDRITEM_NAME(folder) ); */
2789 adbase = ( AddrBookBase * ) ds->rawDataSource;
2790 if( adbase == NULL ) return;
2792 /* Hide folder to prevent re-display */
2793 addritem_folder_set_hidden( folder, TRUE );
2795 if( ds->type == ADDR_IF_LDAP ) {
2800 qry = ( LdapQuery * ) folder->folderData;
2801 queryID = ADDRQUERY_ID(qry);
2802 /* g_print( "calling ldapquery_remove_results...queryID=%d\n", queryID ); */
2803 delFlag = ldapquery_remove_results( qry );
2805 ldapqry_free( qry );
2807 /* g_print( "calling ldapquery_remove_results...done\n" ); */
2810 g_print( "delFlag IS-TRUE\n" );
2813 g_print( "delFlag IS-FALSE\n" );
2818 /* g_print( "addrindex_remove_results/end\n" ); */
2820 /* Delete query request */
2822 qrymgr_delete_request( queryID );
2826 /* **********************************************************************
2827 * Address completion stuff.
2828 * ***********************************************************************
2831 static void addrindex_load_completion_load_persons(
2832 gint (*callBackFunc) ( const gchar *, const gchar *,
2833 const gchar *, const gchar *, GList * ),
2834 AddressDataSource *ds)
2836 GList *listP, *nodeP;
2840 /* Read address book */
2841 if( addrindex_ds_get_modify_flag( ds ) ) {
2842 addrindex_ds_read_data( ds );
2845 if( ! addrindex_ds_get_read_flag( ds ) ) {
2846 addrindex_ds_read_data( ds );
2849 /* Get all groups */
2850 listP = addrindex_ds_get_all_groups( ds );
2853 ItemGroup *group = nodeP->data;
2854 GList *emails = NULL;
2855 for (nodeM = group->listEMail; nodeM; nodeM = g_list_next(nodeM)) {
2856 ItemEMail *email = nodeM->data;
2858 emails = g_list_append(emails, email);
2860 callBackFunc( ((AddrItemObject *)group)->name, NULL,
2861 NULL, NULL, emails );
2862 nodeP = g_list_next( nodeP );
2865 /* Free up the list */
2866 g_list_free( listP );
2867 /* Get all persons */
2868 listP = addrindex_ds_get_all_persons( ds );
2871 ItemPerson *person = nodeP->data;
2872 nodeM = person->listEMail;
2874 /* Figure out name to use */
2875 sName = ADDRITEM_NAME(person);
2876 if( sName == NULL || *sName == '\0' ) {
2877 sName = person->nickName;
2880 /* Process each E-Mail address */
2882 ItemEMail *email = nodeM->data;
2884 callBackFunc( sName, email->address, person->nickName,
2885 ADDRITEM_NAME(email), NULL );
2887 nodeM = g_list_next( nodeM );
2889 nodeP = g_list_next( nodeP );
2892 /* Free up the list */
2893 g_list_free( listP );
2897 * This function is used by the address completion function to load
2898 * addresses for all non-external address book interfaces.
2900 * \param callBackFunc Function to be called when an address is
2902 * \param folderpath Addressbook's Book/folder path to restrict to (if NULL or ""
2903 * or "Any", assume the whole addressbook
2904 * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded.
2907 gboolean addrindex_load_completion(
2908 gint (*callBackFunc) ( const gchar *, const gchar *,
2909 const gchar *, const gchar *, GList * ),
2912 GList *nodeIf, *nodeDS;
2914 if( folderpath != NULL ) {
2915 AddressDataSource *book;
2918 /* split the folder path we've received, we'll try to match this path, subpath by
2919 subpath against the book/folder structure in order and restrict loading of
2920 addresses to that subpart (if matches). book/folder path must exist and
2921 folderpath must not be empty or NULL */
2923 if( ! addressbook_peek_folder_exists( folderpath, &book, &folder ) ) {
2924 g_warning("addrindex_load_completion: folder path '%s' doesn't exist", folderpath);
2928 if( folder != NULL ) {
2935 debug_print("addrindex_load_completion: folder %p '%s'\n", folder, folder->obj.name);
2937 /* Load email addresses */
2938 items = addritem_folder_get_person_list( folder );
2939 for( ; items != NULL; items = g_list_next( items ) ) {
2940 person = items->data;
2941 nodeM = person->listEMail;
2943 /* Figure out name to use */
2944 sName = ADDRITEM_NAME(person);
2945 if( sName == NULL || *sName == '\0' ) {
2946 sName = person->nickName;
2949 /* Process each E-Mail address */
2951 ItemEMail *email = nodeM->data;
2953 callBackFunc( sName, email->address, person->nickName,
2954 ADDRITEM_NAME(email), NULL );
2956 nodeM = g_list_next( nodeM );
2959 /* Free up the list */
2960 mgu_clear_list( items );
2961 g_list_free( items );
2967 if( book != NULL ) {
2969 AddressBookFile *abf = book->rawDataSource;
2971 debug_print("addrindex_load_completion: book %p '%s'\n", book, abf?abf->fileName:"(null)");
2973 addrindex_load_completion_load_persons( callBackFunc, book );
2978 g_warning("addrindex_load_completion: book/folder path is valid but got no pointer");
2985 nodeIf = addrindex_get_interface_list( _addressIndex_ );
2987 AddressInterface *iface = nodeIf->data;
2989 nodeIf = g_list_next( nodeIf );
2991 if( ! iface->useInterface || iface->externalQuery )
2994 nodeDS = iface->listSource;
2996 addrindex_load_completion_load_persons( callBackFunc, nodeDS->data );
2997 nodeDS = g_list_next( nodeDS );
3006 * This function can be used to collect information about
3007 * addressbook entries that contain a specific attribute.
3009 * \param attr Name of attribute to look for
3010 * \param callBackFunc Function to be called when a matching attribute was found
3011 * \return <i>TRUE</i>
3013 gboolean addrindex_load_person_attribute(
3015 gint (*callBackFunc) ( ItemPerson *, const gchar * ) )
3017 AddressDataSource *ds;
3018 GList *nodeIf, *nodeDS;
3019 GList *listP, *nodeP;
3022 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3025 AddressInterface *iface = nodeIf->data;
3027 nodeIf = g_list_next( nodeIf );
3029 if( ! iface->useInterface || iface->externalQuery )
3032 nodeDS = iface->listSource;
3036 /* Read address book */
3037 if( addrindex_ds_get_modify_flag( ds ) ) {
3038 addrindex_ds_read_data( ds );
3041 if( ! addrindex_ds_get_read_flag( ds ) ) {
3042 addrindex_ds_read_data( ds );
3045 /* Check addressbook name */
3046 cur_bname = addrindex_ds_get_name( ds );
3048 /* Get all persons */
3049 listP = addrindex_ds_get_all_persons( ds );
3052 ItemPerson *person = nodeP->data;
3054 /* Return all ItemPerson's if attr is NULL */
3055 if( attr == NULL ) {
3056 callBackFunc(person, cur_bname);
3059 /* Return ItemPerson's with specific attribute */
3061 nodeA = person->listAttrib;
3062 /* Process each User Attribute */
3064 UserAttribute *attrib = nodeA->data;
3066 !strcmp( attrib->name,attr ) ) {
3067 callBackFunc(person, cur_bname);
3069 nodeA = g_list_next( nodeA );
3072 nodeP = g_list_next( nodeP );
3074 /* Free up the list */
3075 g_list_free( listP );
3077 nodeDS = g_list_next( nodeDS );
3084 * This function can be used to collect information about
3085 * addressbook entries
3087 * \param callBackFunc Function to be called for each ItemPerson
3088 * \return <i>TRUE</i>
3090 gboolean addrindex_load_person_ds( gint (*callBackFunc)
3091 ( ItemPerson *, AddressDataSource * ) )
3093 AddressDataSource *ds;
3094 GList *nodeIf, *nodeDS;
3095 GList *listP, *nodeP;
3097 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3099 AddressInterface *iface = nodeIf->data;
3101 nodeIf = g_list_next( nodeIf );
3103 if( ! iface->useInterface || iface->externalQuery )
3106 nodeDS = iface->listSource;
3110 /* Read address book */
3111 if( addrindex_ds_get_modify_flag( ds ) ) {
3112 addrindex_ds_read_data( ds );
3115 if( ! addrindex_ds_get_read_flag( ds ) ) {
3116 addrindex_ds_read_data( ds );
3119 /* Get all persons */
3120 listP = addrindex_ds_get_all_persons( ds );
3123 ItemPerson *person = nodeP->data;
3125 callBackFunc(person, ds);
3126 nodeP = g_list_next( nodeP );
3128 /* Free up the list */
3129 g_list_free( listP );
3131 nodeDS = g_list_next( nodeDS );
3137 gchar *addrindex_get_picture_file(const gchar *emailaddr)
3139 AddressDataSource *ds;
3140 GList *nodeIf, *nodeDS;
3141 GList *listP, *nodeP;
3142 gboolean found = FALSE;
3143 gchar *filename = NULL;
3144 gchar *raw_addr = NULL;
3149 Xstrdup_a(raw_addr, emailaddr, return NULL);
3150 extract_address(raw_addr);
3152 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3154 AddressInterface *iface = nodeIf->data;
3156 nodeIf = g_list_next( nodeIf );
3158 if( ! iface->useInterface || iface->externalQuery )
3161 nodeDS = iface->listSource;
3162 while( nodeDS && !found) {
3165 /* Read address book */
3166 if( addrindex_ds_get_modify_flag( ds ) ) {
3167 addrindex_ds_read_data( ds );
3170 if( ! addrindex_ds_get_read_flag( ds ) ) {
3171 addrindex_ds_read_data( ds );
3174 /* Get all persons */
3175 listP = addrindex_ds_get_all_persons( ds );
3179 ItemPerson *person = nodeP->data;
3180 nodeM = person->listEMail;
3182 ItemEMail *email = nodeM->data;
3183 if (email->address && !strcasecmp(raw_addr, email->address)) {
3185 filename = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S,
3186 ADDRBOOK_DIR, G_DIR_SEPARATOR_S,
3187 person->picture, ".png", NULL );
3190 nodeM = nodeM->next;
3192 nodeP = g_list_next( nodeP );
3194 /* Free up the list */
3195 g_list_free( listP );
3197 nodeDS = g_list_next( nodeDS );
3205 GSList *addrindex_get_password_protected_ldap_servers()
3207 AddressInterface *iface;
3208 AddressDataSource *ds;
3211 GSList *list = NULL;
3215 nodeIf = _addressIndex_->searchOrder;
3217 iface = nodeIf->data;
3218 nodeIf = g_list_next(nodeIf);
3220 if (!iface->useInterface)
3222 if (!iface->externalQuery)
3224 if (iface->type != ADDR_IF_LDAP)
3227 nodeDS = iface->listSource;
3230 nodeDS = g_list_next(nodeDS);
3231 server = ds->rawDataSource;
3232 if (!server->searchFlag)
3235 ctl = server->control;
3240 if (ctl->bindDN != NULL && strlen(ctl->bindDN)) {
3241 list = g_slist_append(list, server);
3248 #endif /* USE_LDAP */