2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2011 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.
31 #include <glib/gi18n.h>
35 #include "addrcache.h"
37 #include "addressbook.h"
38 #include "addrindex.h"
40 #include "addrquery.h"
41 #include "addr_compl.h"
43 #include "alertpanel.h"
45 #ifndef DEV_STANDALONE
46 #include "prefs_gtk.h"
57 #include "ldapserver.h"
59 #include "ldapquery.h"
60 #include "ldapupdate.h"
68 #define TAG_ADDRESS_INDEX "addressbook"
70 #define TAG_IF_ADDRESS_BOOK "book_list"
71 #define TAG_IF_VCARD "vcard_list"
72 #define TAG_IF_JPILOT "jpilot_list"
73 #define TAG_IF_LDAP "ldap_list"
75 #define TAG_DS_ADDRESS_BOOK "book"
76 #define TAG_DS_VCARD "vcard"
77 #define TAG_DS_JPILOT "jpilot"
78 #define TAG_DS_LDAP "server"
80 /* XML Attribute names */
81 #define ATTAG_BOOK_NAME "name"
82 #define ATTAG_BOOK_FILE "file"
84 #define ATTAG_VCARD_NAME "name"
85 #define ATTAG_VCARD_FILE "file"
87 #define ATTAG_JPILOT_NAME "name"
88 #define ATTAG_JPILOT_FILE "file"
89 #define ATTAG_JPILOT_CUSTOM_1 "custom-1"
90 #define ATTAG_JPILOT_CUSTOM_2 "custom-2"
91 #define ATTAG_JPILOT_CUSTOM_3 "custom-3"
92 #define ATTAG_JPILOT_CUSTOM_4 "custom-4"
93 #define ATTAG_JPILOT_CUSTOM "custom-"
95 #define ATTAG_LDAP_NAME "name"
96 #define ATTAG_LDAP_HOST "host"
97 #define ATTAG_LDAP_PORT "port"
98 #define ATTAG_LDAP_BASE_DN "base-dn"
99 #define ATTAG_LDAP_BIND_DN "bind-dn"
100 #define ATTAG_LDAP_BIND_PASS "bind-pass"
101 #define ATTAG_LDAP_CRITERIA "criteria"
102 #define ATTAG_LDAP_MAX_ENTRY "max-entry"
103 #define ATTAG_LDAP_TIMEOUT "timeout"
104 #define ATTAG_LDAP_MAX_AGE "max-age"
105 #define ATTAG_LDAP_DYN_SEARCH "dyn-search"
106 #define ATTAG_LDAP_MATCH_OPT "match-opt"
107 #define ATTAG_LDAP_ENABLE_TLS "enable-tls"
108 #define ATTAG_LDAP_ENABLE_SSL "enable-ssl"
110 #define ELTAG_LDAP_ATTR_SRCH "attribute"
111 #define ATTAG_LDAP_ATTR_NAME "name"
113 /* Attribute values */
114 #define ATVAL_BOOLEAN_YES "yes"
115 #define ATVAL_BOOLEAN_NO "no"
116 #define ATVAL_LDAP_MATCH_BEGIN "begin-with"
117 #define ATVAL_LDAP_MATCH_CONTAINS "contains"
120 #define ATTAG_LDAP_DEFAULT "default"
122 #define DISP_NEW_COMMON _("Common addresses")
123 #define DISP_NEW_PERSONAL _("Personal addresses")
125 /* Old address book */
126 #define TAG_IF_OLD_COMMON "common_address"
127 #define TAG_IF_OLD_PERSONAL "personal_address"
129 #define DISP_OLD_COMMON _("Common address")
130 #define DISP_OLD_PERSONAL _("Personal address")
135 static AddressIndex *_addressIndex_ = NULL;
138 * Define attribute name-value pair.
140 typedef struct _AddressIfAttr AddressIfAttrib;
141 struct _AddressIfAttr {
146 static AddressDataSource *addrindex_create_datasource ( AddressIfType ifType );
148 static GList *addrindex_ds_get_all_persons ( AddressDataSource *ds );
149 static GList *addrindex_ds_get_all_groups ( AddressDataSource *ds );
150 static AddressDataSource *addrindex_get_datasource ( AddressIndex *addrIndex,
151 const gchar *cacheID );
152 static AddressInterface *addrindex_get_interface ( AddressIndex *addrIndex,
153 AddressIfType ifType );
154 static gint addrindex_write_to ( AddressIndex *addrIndex,
155 const gchar *newFile );
158 * Define DOM fragment.
160 typedef struct _AddressIfFrag AddressIfFragment;
161 struct _AddressIfFrag {
168 * Build interface with default values.
170 * \param type Interface type.
171 * \param name Interface name.
172 * \param tagIf XML tag name for interface in address index file.
173 * \param tagDS XML tag name for datasource in address index file.
174 * \return Address interface object.
176 static AddressInterface *addrindex_create_interface(
177 gint type, gchar *name, gchar *tagIf, gchar *tagDS )
179 AddressInterface *iface = g_new0( AddressInterface, 1 );
181 ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
182 ADDRITEM_ID(iface) = NULL;
183 ADDRITEM_NAME(iface) = g_strdup( name );
184 ADDRITEM_PARENT(iface) = NULL;
185 ADDRITEM_SUBTYPE(iface) = type;
187 iface->name = g_strdup( name );
188 iface->listTag = g_strdup( tagIf );
189 iface->itemTag = g_strdup( tagDS );
190 iface->legacyFlag = FALSE;
191 iface->haveLibrary = TRUE;
192 iface->useInterface = TRUE;
193 iface->readOnly = TRUE;
195 /* Set callbacks to NULL values - override for each interface */
196 iface->getAccessFlag = NULL;
197 iface->getModifyFlag = NULL;
198 iface->getReadFlag = NULL;
199 iface->getStatusCode = NULL;
200 iface->getReadData = NULL;
201 iface->getRootFolder = NULL;
202 iface->getListFolder = NULL;
203 iface->getListPerson = NULL;
204 iface->getAllPersons = NULL;
205 iface->getAllGroups = NULL;
206 iface->getName = NULL;
207 iface->listSource = NULL;
210 iface->externalQuery = FALSE;
211 iface->searchOrder = 0; /* Ignored */
212 iface->startSearch = NULL;
213 iface->stopSearch = NULL;
219 * Build table of of all address book interfaces.
220 * \param addrIndex Address index object.
222 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
223 AddressInterface *iface;
225 /* Create intrinsic XML address book interface */
226 iface = addrindex_create_interface(
227 ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK,
228 TAG_DS_ADDRESS_BOOK );
229 iface->readOnly = FALSE;
230 iface->getModifyFlag = ( void * ) addrbook_get_modified;
231 iface->getAccessFlag = ( void * ) addrbook_get_accessed;
232 iface->getReadFlag = ( void * ) addrbook_get_read_flag;
233 iface->getStatusCode = ( void * ) addrbook_get_status;
234 iface->getReadData = ( void * ) addrbook_read_data;
235 iface->getRootFolder = ( void * ) addrbook_get_root_folder;
236 iface->getListFolder = ( void * ) addrbook_get_list_folder;
237 iface->getListPerson = ( void * ) addrbook_get_list_person;
238 iface->getAllPersons = ( void * ) addrbook_get_all_persons;
239 iface->getAllGroups = ( void * ) addrbook_get_all_groups;
240 iface->getName = ( void * ) addrbook_get_name;
241 iface->setAccessFlag = ( void * ) addrbook_set_accessed;
242 iface->searchOrder = 0;
244 /* Add to list of interfaces in address book */
245 addrIndex->interfaceList =
246 g_list_append( addrIndex->interfaceList, iface );
247 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
249 /* Create vCard interface */
250 iface = addrindex_create_interface(
251 ADDR_IF_VCARD, "vCard", TAG_IF_VCARD, TAG_DS_VCARD );
252 iface->getModifyFlag = ( void * ) vcard_get_modified;
253 iface->getAccessFlag = ( void * ) vcard_get_accessed;
254 iface->getReadFlag = ( void * ) vcard_get_read_flag;
255 iface->getStatusCode = ( void * ) vcard_get_status;
256 iface->getReadData = ( void * ) vcard_read_data;
257 iface->getRootFolder = ( void * ) vcard_get_root_folder;
258 iface->getListFolder = ( void * ) vcard_get_list_folder;
259 iface->getListPerson = ( void * ) vcard_get_list_person;
260 iface->getAllPersons = ( void * ) vcard_get_all_persons;
261 iface->getName = ( void * ) vcard_get_name;
262 iface->setAccessFlag = ( void * ) vcard_set_accessed;
263 iface->searchOrder = 0;
264 addrIndex->interfaceList =
265 g_list_append( addrIndex->interfaceList, iface );
266 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
268 /* Create JPilot interface */
269 iface = addrindex_create_interface(
270 ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT,
273 iface->haveLibrary = jpilot_test_pilot_lib();
274 iface->useInterface = iface->haveLibrary;
275 iface->getModifyFlag = ( void * ) jpilot_get_modified;
276 iface->getAccessFlag = ( void * ) jpilot_get_accessed;
277 iface->getReadFlag = ( void * ) jpilot_get_read_flag;
278 iface->getStatusCode = ( void * ) jpilot_get_status;
279 iface->getReadData = ( void * ) jpilot_read_data;
280 iface->getRootFolder = ( void * ) jpilot_get_root_folder;
281 iface->getListFolder = ( void * ) jpilot_get_list_folder;
282 iface->getListPerson = ( void * ) jpilot_get_list_person;
283 iface->getAllPersons = ( void * ) jpilot_get_all_persons;
284 iface->getName = ( void * ) jpilot_get_name;
285 iface->setAccessFlag = ( void * ) jpilot_set_accessed;
286 iface->searchOrder = 0;
288 iface->useInterface = FALSE;
289 iface->haveLibrary = FALSE;
291 addrIndex->interfaceList =
292 g_list_append( addrIndex->interfaceList, iface );
293 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
295 /* Create LDAP interface */
296 iface = addrindex_create_interface(
297 ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
299 iface->readOnly = FALSE;
300 /* iface->haveLibrary = ldapsvr_test_ldap_lib(); */
301 iface->haveLibrary = ldaputil_test_ldap_lib();
302 iface->useInterface = iface->haveLibrary;
303 iface->getModifyFlag = ( void * ) ldapsvr_get_modified;
304 iface->getAccessFlag = ( void * ) ldapsvr_get_accessed;
305 iface->getReadFlag = ( void * ) ldapsvr_get_read_flag;
306 iface->getStatusCode = ( void * ) ldapsvr_get_status;
307 iface->getReadData = ( void * ) ldapsvr_read_data;
308 iface->getRootFolder = ( void * ) ldapsvr_get_root_folder;
309 iface->getListFolder = ( void * ) ldapsvr_get_list_folder;
310 iface->getListPerson = ( void * ) ldapsvr_get_list_person;
311 iface->getName = ( void * ) ldapsvr_get_name;
312 iface->setAccessFlag = ( void * ) ldapsvr_set_accessed;
313 iface->externalQuery = TRUE;
314 iface->searchOrder = 1;
316 iface->useInterface = FALSE;
317 iface->haveLibrary = FALSE;
319 addrIndex->interfaceList =
320 g_list_append( addrIndex->interfaceList, iface );
321 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
323 /* Two old legacy data sources (pre 0.7.0) */
324 iface = addrindex_create_interface(
325 ADDR_IF_COMMON, "Old Address - common",
326 TAG_IF_OLD_COMMON, NULL );
327 iface->legacyFlag = TRUE;
328 addrIndex->interfaceList =
329 g_list_append( addrIndex->interfaceList, iface );
330 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
332 iface = addrindex_create_interface(
333 ADDR_IF_COMMON, "Old Address - personal",
334 TAG_IF_OLD_PERSONAL, NULL );
335 iface->legacyFlag = TRUE;
336 addrIndex->interfaceList =
337 g_list_append( addrIndex->interfaceList, iface );
338 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
344 * \param fragment Fragment to free.
346 static void addrindex_free_fragment( AddressIfFragment *fragment ) {
350 node = fragment->children;
352 AddressIfFragment *child = node->data;
353 addrindex_free_fragment( child );
355 node = g_list_next( node );
357 g_list_free( fragment->children );
359 /* Free attributes */
360 node = fragment->attributes;
362 AddressIfAttrib *nv = node->data;
367 node = g_list_next( node );
369 g_list_free( fragment->attributes );
371 g_free( fragment->name );
372 fragment->name = NULL;
373 fragment->attributes = NULL;
374 fragment->children = NULL;
380 * Create a new data source.
381 * \param ifType Interface type to create.
382 * \return Initialized data source.
384 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
385 AddressDataSource *ds = g_new0( AddressDataSource, 1 );
387 ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
388 ADDRITEM_ID(ds) = NULL;
389 ADDRITEM_NAME(ds) = NULL;
390 ADDRITEM_PARENT(ds) = NULL;
391 ADDRITEM_SUBTYPE(ds) = 0;
393 ds->rawDataSource = NULL;
394 ds->interface = NULL;
399 * Free up data source.
400 * \param ds Data source to free.
402 void addrindex_free_datasource( AddressDataSource *ds ) {
403 AddressInterface *iface;
405 cm_return_if_fail( ds != NULL );
407 iface = ds->interface;
408 if( ds->rawDataSource != NULL ) {
409 if( iface != NULL ) {
410 if( iface->useInterface ) {
411 if( iface->type == ADDR_IF_BOOK ) {
412 AddressBookFile *abf = ds->rawDataSource;
413 addrbook_free_book( abf );
415 else if( iface->type == ADDR_IF_VCARD ) {
416 VCardFile *vcf = ds->rawDataSource;
420 else if( iface->type == ADDR_IF_JPILOT ) {
421 JPilotFile *jpf = ds->rawDataSource;
426 else if( iface->type == ADDR_IF_LDAP ) {
427 LdapServer *server = ds->rawDataSource;
428 ldapsvr_free( server );
435 AddressIfFragment *fragment = ds->rawDataSource;
436 addrindex_free_fragment( fragment );
441 ADDRITEM_TYPE(ds) = ITEMTYPE_NONE;
442 ADDRITEM_ID(ds) = NULL;
443 ADDRITEM_NAME(ds) = NULL;
444 ADDRITEM_PARENT(ds) = NULL;
445 ADDRITEM_SUBTYPE(ds) = 0;
446 ds->type = ADDR_IF_NONE;
447 ds->interface = NULL;
448 ds->rawDataSource = NULL;
454 * Free up all data sources for specified interface.
455 * \param iface Address interface to process.
457 static void addrindex_free_all_datasources( AddressInterface *iface ) {
458 GList *node = iface->listSource;
460 AddressDataSource *ds = node->data;
461 addrindex_free_datasource( ds );
463 node = g_list_next( node );
468 * Free up specified interface.
469 * \param iface Interface to process.
471 static void addrindex_free_interface( AddressInterface *iface ) {
472 /* Free up data sources */
473 addrindex_free_all_datasources( iface );
474 g_list_free( iface->listSource );
476 /* Free internal storage */
477 g_free( ADDRITEM_ID(iface) );
478 g_free( ADDRITEM_NAME(iface) );
479 g_free( iface->name );
480 g_free( iface->listTag );
481 g_free( iface->itemTag );
483 /* Clear all pointers */
484 ADDRITEM_TYPE(iface) = ITEMTYPE_NONE;
485 ADDRITEM_ID(iface) = NULL;
486 ADDRITEM_NAME(iface) = NULL;
487 ADDRITEM_PARENT(iface) = NULL;
488 ADDRITEM_SUBTYPE(iface) = 0;
489 iface->type = ADDR_IF_NONE;
491 iface->listTag = NULL;
492 iface->itemTag = NULL;
493 iface->legacyFlag = FALSE;
494 iface->useInterface = FALSE;
495 iface->haveLibrary = FALSE;
496 iface->listSource = NULL;
499 iface->searchOrder = 0;
500 iface->startSearch = NULL;
501 iface->stopSearch = NULL;
507 * Return cache ID for specified data source.
509 * \param addrIndex Address index.
510 * \param ds Data source.
511 * \return ID or NULL if not found. This should be <code>g_free()</code>
514 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
515 gchar *cacheID = NULL;
516 AddrBookBase *adbase;
519 cm_return_val_if_fail( addrIndex != NULL, NULL );
520 cm_return_val_if_fail( ds != NULL, NULL );
522 adbase = ( AddrBookBase * ) ds->rawDataSource;
524 cache = adbase->addressCache;
526 cacheID = g_strdup( cache->cacheID );
534 * Return reference to data source for specified cacheID.
535 * \param addrIndex Address index.
537 * \return Data source, or NULL if not found.
539 static AddressDataSource *addrindex_get_datasource(
540 AddressIndex *addrIndex, const gchar *cacheID )
542 cm_return_val_if_fail( addrIndex != NULL, NULL );
543 cm_return_val_if_fail( cacheID != NULL, NULL );
544 return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
548 * Return reference to address cache for specified cacheID.
549 * \param addrIndex Address index.
551 * \return Address cache, or NULL if not found.
553 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
554 AddressDataSource *ds;
555 AddrBookBase *adbase;
558 cm_return_val_if_fail( addrIndex != NULL, NULL );
559 cm_return_val_if_fail( cacheID != NULL, NULL );
562 ds = addrindex_get_datasource( addrIndex, cacheID );
564 adbase = ( AddrBookBase * ) ds->rawDataSource;
565 cache = adbase->addressCache;
571 * Add data source into hash table.
572 * \param addrIndex Address index.
573 * \param ds Data source.
575 static void addrindex_hash_add_cache(
576 AddressIndex *addrIndex, AddressDataSource *ds )
580 cacheID = addrindex_get_cache_id( addrIndex, ds );
582 g_hash_table_insert( addrIndex->hashCache, cacheID, ds );
587 * Free hash table callback function.
589 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
597 * Free hash table of address cache items.
599 static void addrindex_free_cache_hash( GHashTable *table ) {
600 g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
601 g_hash_table_destroy( table );
605 * Remove data source from internal hashtable.
606 * \param addrIndex Address index.
607 * \param ds Data source to remove.
609 static void addrindex_hash_remove_cache(
610 AddressIndex *addrIndex, AddressDataSource *ds )
614 cacheID = addrindex_get_cache_id( addrIndex, ds );
616 g_hash_table_remove( addrIndex->hashCache, cacheID );
623 * Create a new address index. This is created as a singleton object.
624 * \return Initialized address index object.
626 AddressIndex *addrindex_create_index( void ) {
629 if( _addressIndex_ == NULL ) {
630 index = g_new0( AddressIndex, 1 );
631 ADDRITEM_TYPE(index) = ITEMTYPE_INDEX;
632 ADDRITEM_ID(index) = NULL;
633 ADDRITEM_NAME(index) = g_strdup( "Address Index" );
634 ADDRITEM_PARENT(index) = NULL;
635 ADDRITEM_SUBTYPE(index) = 0;
636 index->filePath = NULL;
637 index->fileName = NULL;
638 index->retVal = MGU_SUCCESS;
639 index->needsConversion = FALSE;
640 index->wasConverted = FALSE;
641 index->conversionError = FALSE;
642 index->interfaceList = NULL;
643 index->lastType = ADDR_IF_NONE;
644 index->dirtyFlag = FALSE;
645 index->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
646 index->loadedFlag = FALSE;
647 index->searchOrder = NULL;
648 addrindex_build_if_list( index );
649 _addressIndex_ = index;
651 return _addressIndex_;
655 * Property - Specify file path to address index file.
656 * \param addrIndex Address index.
657 * \param value Path to index file.
659 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
660 cm_return_if_fail( addrIndex != NULL );
661 addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
665 * Property - Specify file name to address index file.
666 * \param addrIndex Address index.
667 * \param value File name.
669 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
670 cm_return_if_fail( addrIndex != NULL );
671 addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
675 * Return list of address interfaces.
676 * \param addrIndex Address index.
677 * \return List of address interfaces.
679 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
680 cm_return_val_if_fail( addrIndex != NULL, NULL );
681 return addrIndex->interfaceList;
685 * Perform any other initialization of address index.
687 void addrindex_initialize( void ) {
689 addrcompl_initialize();
693 * Perform any other teardown of address index.
695 void addrindex_teardown( void ) {
696 addrcompl_teardown();
701 * Free up address index.
702 * \param addrIndex Address index.
704 void addrindex_free_index( AddressIndex *addrIndex ) {
707 cm_return_if_fail( addrIndex != NULL );
710 g_list_free( addrIndex->searchOrder );
711 addrIndex->searchOrder = NULL;
713 /* Free internal storage */
714 g_free( ADDRITEM_ID(addrIndex) );
715 g_free( ADDRITEM_NAME(addrIndex) );
716 g_free( addrIndex->filePath );
717 g_free( addrIndex->fileName );
720 ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
721 ADDRITEM_ID(addrIndex) = NULL;
722 ADDRITEM_NAME(addrIndex) = NULL;
723 ADDRITEM_PARENT(addrIndex) = NULL;
724 ADDRITEM_SUBTYPE(addrIndex) = 0;
725 addrIndex->filePath = NULL;
726 addrIndex->fileName = NULL;
727 addrIndex->retVal = MGU_SUCCESS;
728 addrIndex->needsConversion = FALSE;
729 addrIndex->wasConverted = FALSE;
730 addrIndex->conversionError = FALSE;
731 addrIndex->lastType = ADDR_IF_NONE;
732 addrIndex->dirtyFlag = FALSE;
734 /* Free up interfaces */
735 node = addrIndex->interfaceList;
737 AddressInterface *iface = node->data;
738 addrindex_free_interface( iface );
739 node = g_list_next( node );
741 g_list_free( addrIndex->interfaceList );
742 addrIndex->interfaceList = NULL;
744 /* Free up hash cache */
745 addrindex_free_cache_hash( addrIndex->hashCache );
746 addrIndex->hashCache = NULL;
748 addrIndex->loadedFlag = FALSE;
752 _addressIndex_ = NULL;
756 * Print address index.
757 * \param addrIndex Address index.
758 * \parem stream Stream to print.
760 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
761 cm_return_if_fail( addrIndex != NULL );
762 fprintf( stream, "AddressIndex:\n" );
763 fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
764 fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
765 fprintf( stream, "\t status: %d\n", addrIndex->retVal );
766 fprintf( stream, "\tconverted: '%s'\n",
767 addrIndex->wasConverted ? "yes" : "no" );
768 fprintf( stream, "\tcvt error: '%s'\n",
769 addrIndex->conversionError ? "yes" : "no" );
770 fprintf( stream, "\t---\n" );
774 * Retrieve reference to address interface for specified interface type.
775 * \param addrIndex Address index.
776 * \param ifType Interface type.
777 * \return Address interface, or NULL if not found.
779 static AddressInterface *addrindex_get_interface(
780 AddressIndex *addrIndex, AddressIfType ifType )
782 AddressInterface *retVal = NULL;
785 cm_return_val_if_fail( addrIndex != NULL, NULL );
787 node = addrIndex->interfaceList;
789 AddressInterface *iface = node->data;
790 node = g_list_next( node );
791 if( iface->type == ifType ) {
800 * Add raw data source to index. The raw data object (an AddressBookFile or
801 * VCardFile object, for example) should be supplied as the raw dataSource
804 * \param addrIndex Address index.
805 * \param ifType Interface type to add.
806 * \param dataSource Actual raw data source to add.
807 * \return Data source added, or NULL if invalid interface type.
809 AddressDataSource *addrindex_index_add_datasource(
810 AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
812 AddressInterface *iface;
813 AddressDataSource *ds = NULL;
815 cm_return_val_if_fail( addrIndex != NULL, NULL );
816 cm_return_val_if_fail( dataSource != NULL, NULL );
818 iface = addrindex_get_interface( addrIndex, ifType );
820 ds = addrindex_create_datasource( ifType );
821 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
823 ds->rawDataSource = dataSource;
824 ds->interface = iface;
825 iface->listSource = g_list_append( iface->listSource, ds );
826 addrIndex->dirtyFlag = TRUE;
828 addrindex_hash_add_cache( addrIndex, ds );
834 * Remove specified data source from index.
835 * \param addrIndex Address index.
836 * \param dataSource Data source to add.
837 * \return Reference to data source if removed, or NULL if data source was not
838 * found in index. Note the this object must still be freed.
840 AddressDataSource *addrindex_index_remove_datasource(
841 AddressIndex *addrIndex, AddressDataSource *dataSource )
843 AddressDataSource *retVal = FALSE;
844 AddressInterface *iface;
846 cm_return_val_if_fail( addrIndex != NULL, NULL );
847 cm_return_val_if_fail( dataSource != NULL, NULL );
849 iface = addrindex_get_interface( addrIndex, dataSource->type );
851 iface->listSource = g_list_remove( iface->listSource, dataSource );
852 addrIndex->dirtyFlag = TRUE;
853 dataSource->interface = NULL;
855 /* Remove cache from hash table */
856 addrindex_hash_remove_cache( addrIndex, dataSource );
864 * Retrieve a reference to address interface for specified interface type and
865 * XML interface tag name.
866 * \param addrIndex Address index.
867 * \param tag XML interface tag name to match.
868 * \param ifType Interface type to match.
869 * \return Reference to address index, or NULL if not found in index.
871 static AddressInterface *addrindex_tag_get_interface(
872 AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
874 AddressInterface *retVal = NULL;
875 GList *node = addrIndex->interfaceList;
878 AddressInterface *iface = node->data;
879 node = g_list_next( node );
881 if( strcmp( iface->listTag, tag ) == 0 ) {
887 if( iface->type == ifType ) {
897 * Retrieve a reference to address interface for specified interface type and
898 * XML datasource tag name.
899 * \param addrIndex Address index.
900 * \param ifType Interface type to match.
901 * \param tag XML datasource tag name to match.
902 * \return Reference to address index, or NULL if not found in index.
904 static AddressInterface *addrindex_tag_get_datasource(
905 AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
907 AddressInterface *retVal = NULL;
908 GList *node = addrIndex->interfaceList;
911 AddressInterface *iface = node->data;
912 node = g_list_next( node );
913 if( iface->type == ifType && iface->itemTag ) {
914 if( strcmp( iface->itemTag, tag ) == 0 ) {
923 /* **********************************************************************
924 * Interface XML parsing functions.
925 * ***********************************************************************
929 * Write start of XML element to file.
931 * \param lvl Indentation level.
932 * \param name Element name.
934 static int addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) {
936 for( i = 0; i < lvl; i++ )
937 if (fputs( " ", fp ) == EOF)
939 if (fputs( "<", fp ) == EOF)
941 if (fputs( name, fp ) == EOF)
947 * Write end of XML element to file.
949 * \param lvl Indentation level.
950 * \param name Element name.
952 static int addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) {
954 for( i = 0; i < lvl; i++ )
955 if (fputs( " ", fp ) == EOF)
957 if (fputs( "</", fp ) == EOF)
959 if (fputs( name, fp ) == EOF)
961 if (fputs( ">\n", fp ) == EOF)
967 * Write XML attribute to file.
969 * \param name Attribute name.
970 * \param value Attribute value.
972 static int addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) {
973 if (fputs( " ", fp ) == EOF)
975 if (fputs( name, fp ) == EOF)
977 if (fputs( "=\"", fp ) == EOF)
979 if (xml_file_put_escape_str( fp, value ) < 0)
981 if (fputs( "\"", fp ) == EOF)
986 #if !defined(USE_LDAP) || !defined(USE_JPILOT)
988 * Return DOM fragment for current XML tag from file.
989 * \param file XML file being processed.
990 * \return Fragment representing DOM fragment for configuration element.
992 static AddressIfFragment *addrindex_read_fragment( XMLFile *file ) {
993 AddressIfFragment *fragment;
994 AddressIfFragment *child;
1004 /* g_print( "addrindex_read_fragment\n" ); */
1006 prevLevel = file->level;
1008 /* Get current tag name */
1009 xtag = xml_get_current_tag( file );
1011 /* Create new fragment */
1012 fragment = g_new0( AddressIfFragment, 1 );
1013 fragment->name = g_strdup( xtag->tag );
1014 fragment->children = NULL;
1015 fragment->attributes = NULL;
1017 /* Read attributes */
1019 attr = xml_get_current_tag_attr( file );
1021 name = ((XMLAttr *)attr->data)->name;
1022 value = ((XMLAttr *)attr->data)->value;
1023 nv = g_new0( AddressIfAttrib, 1 );
1024 nv->name = g_strdup( name );
1025 nv->value = g_strdup( value );
1026 list = g_list_append( list, nv );
1027 attr = g_list_next( attr );
1029 fragment->attributes = list;
1031 /* Now read the children */
1033 rc = xml_parse_next_tag( file );
1038 if( file->level < prevLevel ) {
1039 /* We must be above level we start at */
1042 child = addrindex_read_fragment( file );
1043 fragment->children = g_list_append( fragment->children, child );
1050 * Write DOM fragment to file.
1051 * \param fp File to write.
1052 * \param fragment DOM fragment for configuration element.
1053 * \param lvl Indent level.
1055 static int addrindex_write_fragment(
1056 FILE *fp, const AddressIfFragment *fragment, const gint lvl )
1061 if (addrindex_write_elem_s( fp, lvl, fragment->name ) < 0)
1063 node = fragment->attributes;
1065 AddressIfAttrib *nv = node->data;
1066 if (addrindex_write_attr( fp, nv->name, nv->value ) < 0)
1068 node = g_list_next( node );
1070 if( fragment->children ) {
1071 if (fputs(" >\n", fp) == EOF)
1074 /* Output children */
1075 node = fragment->children;
1077 AddressIfFragment *child = node->data;
1078 if (addrindex_write_fragment( fp, child, 1+lvl ) < 0)
1080 node = g_list_next( node );
1083 /* Output closing tag */
1084 if (addrindex_write_elem_e( fp, lvl, fragment->name ) < 0)
1088 if (fputs(" />\n", fp) == EOF)
1097 * Read/parse address index file, creating a data source for a regular
1098 * intrinsic XML addressbook.
1099 * \param file Address index file.
1100 * \return Data source.
1102 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
1103 AddressDataSource *ds;
1104 AddressBookFile *abf;
1107 ds = addrindex_create_datasource( ADDR_IF_BOOK );
1108 abf = addrbook_create_book();
1109 attr = xml_get_current_tag_attr( file );
1111 gchar *name = ((XMLAttr *)attr->data)->name;
1112 gchar *value = ((XMLAttr *)attr->data)->value;
1113 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
1114 addrbook_set_name( abf, value );
1116 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
1117 addrbook_set_file( abf, value );
1119 attr = g_list_next( attr );
1121 ds->rawDataSource = abf;
1125 static int addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
1126 AddressBookFile *abf = ds->rawDataSource;
1128 if (addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK ) < 0)
1130 if (addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) ) < 0)
1132 if (addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName ) < 0)
1134 if (fputs( " />\n", fp ) == EOF)
1140 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
1141 AddressDataSource *ds;
1145 ds = addrindex_create_datasource( ADDR_IF_VCARD );
1146 vcf = vcard_create();
1147 attr = xml_get_current_tag_attr( file );
1149 gchar *name = ((XMLAttr *)attr->data)->name;
1150 gchar *value = ((XMLAttr *)attr->data)->value;
1151 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
1152 vcard_set_name( vcf, value );
1154 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
1155 vcard_set_file( vcf, value );
1157 attr = g_list_next( attr );
1159 ds->rawDataSource = vcf;
1163 static int addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
1164 VCardFile *vcf = ds->rawDataSource;
1166 if (addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD ) < 0)
1168 if (addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) ) < 0)
1170 if (addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path ) < 0)
1172 if (fputs( " />\n", fp ) == EOF)
1179 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1180 AddressDataSource *ds;
1184 ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1185 jpf = jpilot_create();
1186 attr = xml_get_current_tag_attr( file );
1188 gchar *name = ((XMLAttr *)attr->data)->name;
1189 gchar *value = ((XMLAttr *)attr->data)->value;
1190 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
1191 jpilot_set_name( jpf, value );
1193 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
1194 jpilot_set_file( jpf, value );
1196 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
1197 jpilot_add_custom_label( jpf, value );
1199 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
1200 jpilot_add_custom_label( jpf, value );
1202 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
1203 jpilot_add_custom_label( jpf, value );
1205 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
1206 jpilot_add_custom_label( jpf, value );
1208 attr = g_list_next( attr );
1210 ds->rawDataSource = jpf;
1214 static int addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
1215 JPilotFile *jpf = ds->rawDataSource;
1219 GList *customLbl = jpilot_get_custom_labels( jpf );
1220 if (addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT ) < 0)
1222 if (addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) ) < 0)
1224 if (addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path ) < 0)
1230 g_snprintf( name, sizeof(name), "%s%d",
1231 ATTAG_JPILOT_CUSTOM, ind );
1232 if (addrindex_write_attr( fp, name, node->data ) < 0)
1235 node = g_list_next( node );
1237 if (fputs( " />\n", fp ) == EOF)
1245 * Just read/write DOM fragments (preserve data found in file).
1247 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
1248 AddressDataSource *ds;
1250 ds = addrindex_create_datasource( ADDR_IF_JPILOT );
1251 ds->rawDataSource = addrindex_read_fragment( file );
1255 static int addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
1256 AddressIfFragment *fragment = ds->rawDataSource;
1258 if (addrindex_write_fragment( fp, fragment, lvl ) < 0)
1267 * Parse LDAP criteria attribute data from XML file.
1268 * \param file Index file.
1269 * \param ctl LDAP control object to populate.
1271 static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
1280 if( file == NULL ) {
1285 prevLevel = file->level;
1286 xtagPrev = xml_get_current_tag( file );
1288 rc = xml_parse_next_tag( file );
1290 /* Terminate prematurely */
1291 mgu_free_dlist( list );
1295 if( file->level < prevLevel ) {
1296 /* We must be above level we start at */
1300 /* Get a tag (element) */
1301 xtag = xml_get_current_tag( file );
1302 if( strcmp( xtag->tag, ELTAG_LDAP_ATTR_SRCH ) == 0 ) {
1303 /* LDAP criteria attribute */
1304 attr = xml_get_current_tag_attr( file );
1306 gchar *name = ((XMLAttr *)attr->data)->name;
1307 gchar *value = ((XMLAttr *)attr->data)->value;
1308 if( strcmp( name, ATTAG_LDAP_ATTR_NAME ) == 0 ) {
1309 if( value && strlen( value ) > 0 ) {
1310 list = g_list_append(
1311 list, g_strdup( value ) );
1314 attr = g_list_next( attr );
1318 if( xtag != xtagPrev ) {
1319 /* Found a new tag */
1326 /* Build list of search attributes */
1327 ldapctl_criteria_list_clear( ctl );
1330 ldapctl_criteria_list_add( ctl, node->data );
1331 g_free( node->data );
1333 node = g_list_next( node );
1335 g_list_free( list );
1340 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl );
1342 * Parse LDAP control data from XML file.
1343 * \param file Index file.
1344 * \return Initialized data soruce object.
1346 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1347 AddressDataSource *ds;
1351 gchar *serverName = NULL;
1352 gchar *criteria = NULL;
1353 gboolean bDynSearch;
1354 gboolean bTLS, bSSL;
1357 /* g_print( "addrindex_parse_ldap\n" ); */
1358 /* Set up some defaults */
1362 iMatch = LDAPCTL_MATCH_BEGINWITH;
1364 ds = addrindex_create_datasource( ADDR_IF_LDAP );
1365 ctl = ldapctl_create();
1366 attr = xml_get_current_tag_attr( file );
1368 gchar *name = ((XMLAttr *)attr->data)->name;
1369 gchar *value = ((XMLAttr *)attr->data)->value;
1370 gint ivalue = atoi( value );
1372 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
1373 g_free( serverName );
1374 serverName = g_strdup( value );
1376 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
1377 ldapctl_set_host( ctl, value );
1379 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
1380 ldapctl_set_port( ctl, ivalue );
1382 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
1383 ldapctl_set_base_dn( ctl, value );
1385 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
1386 ldapctl_set_bind_dn( ctl, value );
1388 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
1389 ldapctl_set_bind_password( ctl, value, FALSE, FALSE );
1391 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
1393 criteria = g_strdup( value );
1394 g_print("criteria %s\n", criteria);
1396 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
1397 ldapctl_set_max_entries( ctl, ivalue );
1399 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
1400 ldapctl_set_timeout( ctl, ivalue );
1402 else if( strcmp( name, ATTAG_LDAP_MAX_AGE ) == 0 ) {
1403 ldapctl_set_max_query_age( ctl, ivalue );
1405 else if( strcmp( name, ATTAG_LDAP_DYN_SEARCH ) == 0 ) {
1407 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1411 else if( strcmp( name, ATTAG_LDAP_MATCH_OPT ) == 0 ) {
1412 iMatch = LDAPCTL_MATCH_BEGINWITH;
1413 if( strcmp( value, ATVAL_LDAP_MATCH_CONTAINS ) == 0 ) {
1414 iMatch = LDAPCTL_MATCH_CONTAINS;
1417 else if( strcmp( name, ATTAG_LDAP_ENABLE_TLS ) == 0 ) {
1419 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1423 else if( strcmp( name, ATTAG_LDAP_ENABLE_SSL ) == 0 ) {
1425 if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) {
1429 attr = g_list_next( attr );
1432 server = ldapsvr_create_noctl();
1433 ldapsvr_set_name( server, serverName );
1434 ldapsvr_set_search_flag( server, bDynSearch );
1435 ldapctl_set_matching_option( ctl, iMatch );
1436 ldapctl_set_tls( ctl, bTLS );
1437 ldapctl_set_ssl( ctl, bSSL );
1438 g_free( serverName );
1439 ldapsvr_set_control( server, ctl );
1440 ds->rawDataSource = server;
1442 addrindex_parse_ldap_attrlist( file, ctl );
1444 * If criteria have been specified and no attributes were listed, then
1445 * convert old style criteria into an attribute list. Any criteria will
1446 * be dropped when saving data.
1449 if( ! ldapctl_get_criteria_list( ctl ) ) {
1450 ldapctl_parse_ldap_search( ctl, criteria );
1454 /* ldapsvr_print_data( server, stdout ); */
1459 static int addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1460 LdapServer *server = ds->rawDataSource;
1461 LdapControl *ctl = NULL;
1466 ctl = server->control;
1468 if( ctl == NULL ) return 0;
1470 /* Output start element with attributes */
1471 if (addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP ) < 0)
1473 if (addrindex_write_attr( fp, ATTAG_LDAP_NAME, ldapsvr_get_name( server ) ) < 0)
1475 if (addrindex_write_attr( fp, ATTAG_LDAP_HOST, ctl->hostName ) < 0)
1478 sprintf( value, "%d", ctl->port );
1479 if (addrindex_write_attr( fp, ATTAG_LDAP_PORT, value ) < 0)
1482 if (addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, ctl->baseDN ) < 0)
1484 if (addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, ctl->bindDN ) < 0)
1486 if (addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, ctl->bindPass ) < 0)
1489 sprintf( value, "%d", ctl->maxEntries );
1490 if (addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value ) < 0)
1492 sprintf( value, "%d", ctl->timeOut );
1493 if (addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value ) < 0)
1495 sprintf( value, "%d", ctl->maxQueryAge );
1496 if (addrindex_write_attr( fp, ATTAG_LDAP_MAX_AGE, value ) < 0)
1499 if (addrindex_write_attr( fp, ATTAG_LDAP_DYN_SEARCH,
1500 server->searchFlag ?
1501 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1504 if (addrindex_write_attr( fp, ATTAG_LDAP_MATCH_OPT,
1505 ( ctl->matchingOption == LDAPCTL_MATCH_CONTAINS ) ?
1506 ATVAL_LDAP_MATCH_CONTAINS : ATVAL_LDAP_MATCH_BEGIN ) < 0)
1509 if (addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_TLS,
1511 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1513 if (addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_SSL,
1515 ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ) < 0)
1518 if (fputs(" >\n", fp) == EOF)
1521 /* Output attributes */
1522 node = ldapctl_get_criteria_list( ctl );
1524 if (addrindex_write_elem_s( fp, 1+lvl, ELTAG_LDAP_ATTR_SRCH ) < 0)
1526 if (addrindex_write_attr( fp, ATTAG_LDAP_ATTR_NAME, node->data ) < 0)
1528 if (fputs(" />\n", fp) == EOF)
1530 node = g_list_next( node );
1533 /* End of element */
1534 if (addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP ) < 0)
1542 * Just read/write DOM fragments (preserve data found in file).
1544 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
1545 AddressDataSource *ds;
1547 ds = addrindex_create_datasource( ADDR_IF_LDAP );
1548 ds->rawDataSource = addrindex_read_fragment( file );
1552 static int addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
1553 AddressIfFragment *fragment = ds->rawDataSource;
1555 if (addrindex_write_fragment( fp, fragment, lvl ) < 0)
1562 /* **********************************************************************
1563 * Address index I/O functions.
1564 * ***********************************************************************
1567 * Read address index file, creating appropriate data sources for each address
1570 * \param addrIndex Address index.
1571 * \param file Address index file.
1573 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
1576 AddressInterface *iface = NULL, *dsIFace = NULL;
1577 AddressDataSource *ds;
1580 addrIndex->loadedFlag = FALSE;
1582 prev_level = file->level;
1583 rc = xml_parse_next_tag( file );
1584 if( file->level == 0 ) return;
1586 xtag = xml_get_current_tag( file );
1588 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
1590 addrIndex->lastType = iface->type;
1591 if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
1594 dsIFace = addrindex_tag_get_datasource(
1595 addrIndex, addrIndex->lastType, xtag->tag );
1597 /* Add data source to list */
1599 if( addrIndex->lastType == ADDR_IF_BOOK ) {
1600 ds = addrindex_parse_book( file );
1601 if( ds->rawDataSource ) {
1602 addrbook_set_path( ds->rawDataSource,
1603 addrIndex->filePath );
1606 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
1607 ds = addrindex_parse_vcard( file );
1609 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
1610 ds = addrindex_parse_jpilot( file );
1612 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
1613 ds = addrindex_parse_ldap( file );
1616 ds->interface = dsIFace;
1617 addrindex_hash_add_cache( addrIndex, ds );
1618 dsIFace->listSource =
1619 g_list_append( dsIFace->listSource, ds );
1627 * Search order sorting comparison function for building search order list.
1629 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) {
1630 AddressInterface *ifaceA = ( AddressInterface * ) ptrA;
1631 AddressInterface *ifaceB = ( AddressInterface * ) ptrB;
1633 return ifaceA->searchOrder - ifaceB->searchOrder;
1637 * Build list of data sources to process.
1638 * \param addrIndex Address index object.
1640 static void addrindex_build_search_order( AddressIndex *addrIndex ) {
1643 /* Clear existing list */
1644 g_list_free( addrIndex->searchOrder );
1645 addrIndex->searchOrder = NULL;
1647 /* Build new list */
1648 nodeIf = addrIndex->interfaceList;
1650 AddressInterface *iface = nodeIf->data;
1651 if( iface->useInterface ) {
1652 if( iface->searchOrder > 0 ) {
1653 /* Add to search order list */
1654 addrIndex->searchOrder = g_list_insert_sorted(
1655 addrIndex->searchOrder, iface,
1656 addrindex_search_order_compare );
1659 nodeIf = g_list_next( nodeIf );
1663 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1664 XMLFile *file = NULL;
1665 gchar *fileSpec = NULL;
1667 cm_return_val_if_fail( addrIndex != NULL, -1 );
1669 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1670 addrIndex->retVal = MGU_NO_FILE;
1671 file = xml_open_file( fileSpec );
1674 if( file == NULL ) {
1676 g_print( " file '%s' does not exist.\n", addrIndex->fileName );
1678 return addrIndex->retVal;
1681 addrIndex->retVal = MGU_BAD_FORMAT;
1682 if( xml_get_dtd( file ) == 0 ) {
1683 if( xml_parse_next_tag( file ) == 0 ) {
1684 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1685 addrindex_read_index( addrIndex, file );
1686 addrIndex->retVal = MGU_SUCCESS;
1690 xml_close_file( file );
1692 addrindex_build_search_order( addrIndex );
1694 return addrIndex->retVal;
1697 static int addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1698 GList *nodeIF, *nodeDS;
1700 gint lvlItem = 1 + lvlList;
1702 nodeIF = addrIndex->interfaceList;
1704 AddressInterface *iface = nodeIF->data;
1705 if( ! iface->legacyFlag ) {
1706 nodeDS = iface->listSource;
1707 if (addrindex_write_elem_s( fp, lvlList, iface->listTag ) < 0)
1709 if (fputs( ">\n", fp ) == EOF)
1712 AddressDataSource *ds = nodeDS->data;
1714 if( iface->type == ADDR_IF_BOOK ) {
1715 if (addrindex_write_book( fp, ds, lvlItem ) < 0)
1718 if( iface->type == ADDR_IF_VCARD ) {
1719 if (addrindex_write_vcard( fp, ds, lvlItem ) < 0)
1722 if( iface->type == ADDR_IF_JPILOT ) {
1723 if (addrindex_write_jpilot( fp, ds, lvlItem ) < 0)
1726 if( iface->type == ADDR_IF_LDAP ) {
1727 if (addrindex_write_ldap( fp, ds, lvlItem ) < 0)
1731 nodeDS = g_list_next( nodeDS );
1733 if (addrindex_write_elem_e( fp, lvlList, iface->listTag ) < 0)
1736 nodeIF = g_list_next( nodeIF );
1742 * Write data to specified file.
1743 * Enter: addrIndex Address index object.
1744 * newFile New file name.
1745 * return: Status code, from addrIndex->retVal.
1746 * Note: File will be created in directory specified by addrIndex.
1748 static gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1751 #ifndef DEV_STANDALONE
1755 cm_return_val_if_fail( addrIndex != NULL, -1 );
1757 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1758 addrIndex->retVal = MGU_OPEN_FILE;
1759 #ifdef DEV_STANDALONE
1760 fp = g_fopen( fileSpec, "wb" );
1763 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1765 pfile = prefs_write_open( fileSpec );
1769 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0)
1772 if (addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX ) < 0)
1774 if (fputs( ">\n", fp ) == EOF)
1777 if (addrindex_write_index( addrIndex, fp ) < 0)
1779 if (addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX ) < 0)
1782 addrIndex->retVal = MGU_SUCCESS;
1783 #ifdef DEV_STANDALONE
1786 if( prefs_file_close( pfile ) < 0 ) {
1787 addrIndex->retVal = MGU_ERROR_WRITE;
1793 return addrIndex->retVal;
1795 g_warning("error writing AB index\n");
1796 addrIndex->retVal = MGU_ERROR_WRITE;
1798 prefs_file_close_revert( pfile );
1799 return addrIndex->retVal;
1803 * Save address index data to original file.
1804 * return: Status code, from addrIndex->retVal.
1806 gint addrindex_save_data( AddressIndex *addrIndex ) {
1812 cm_return_val_if_fail( addrIndex != NULL, -1 );
1815 nodeIf = addrIndex->interfaceList;
1816 /* save LDAP interfaces */
1818 AddressInterface *iface = nodeIf->data;
1819 if( iface->type == ADDR_IF_LDAP ) {
1820 nodeDS = iface->listSource;
1822 AddressDataSource *ds = nodeDS->data;
1823 LdapServer *abf = ds->rawDataSource;
1824 if( ldapsvr_get_read_flag( abf ) ) {
1825 if( ldapsvr_get_modified( abf ) ) {
1826 ldapsvr_update_book( abf, NULL );
1827 if( abf->retVal != LDAPRC_SUCCESS ) {
1828 alertpanel( _("Address(es) update"),
1829 _("Update failed. Changes not written to Directory."),
1830 GTK_STOCK_CLOSE, NULL, NULL );
1833 abf->retVal = MGU_SUCCESS;
1834 ldapsvr_set_modified( abf, FALSE );
1838 nodeDS = g_list_next( nodeDS );
1842 nodeIf = g_list_next( nodeIf );
1845 addrIndex->retVal = MGU_NO_FILE;
1846 if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1847 if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1849 addrindex_write_to( addrIndex, addrIndex->fileName );
1850 if( addrIndex->retVal == MGU_SUCCESS ) {
1851 addrIndex->dirtyFlag = FALSE;
1853 return addrIndex->retVal;
1857 * Save all address book files which may have changed.
1858 * Return: Status code, set if there was a problem saving data.
1860 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1861 gint retVal = MGU_SUCCESS;
1862 GList *nodeIf, *nodeDS;
1864 nodeIf = addrIndex->interfaceList;
1866 AddressInterface *iface = nodeIf->data;
1867 if( iface->type == ADDR_IF_BOOK ) {
1868 nodeDS = iface->listSource;
1870 AddressDataSource *ds = nodeDS->data;
1871 AddressBookFile *abf = ds->rawDataSource;
1872 if( addrbook_get_dirty( abf ) ) {
1873 if( addrbook_get_read_flag( abf ) ) {
1874 addrbook_save_data( abf );
1875 if( abf->retVal != MGU_SUCCESS ) {
1876 retVal = abf->retVal;
1880 nodeDS = g_list_next( nodeDS );
1884 nodeIf = g_list_next( nodeIf );
1890 /* **********************************************************************
1891 * Address book conversion to new format.
1892 * ***********************************************************************
1895 #define ELTAG_IF_OLD_FOLDER "folder"
1896 #define ELTAG_IF_OLD_GROUP "group"
1897 #define ELTAG_IF_OLD_ITEM "item"
1898 #define ELTAG_IF_OLD_NAME "name"
1899 #define ELTAG_IF_OLD_ADDRESS "address"
1900 #define ELTAG_IF_OLD_REMARKS "remarks"
1901 #define ATTAG_IF_OLD_NAME "name"
1903 #define TEMPNODE_ROOT 0
1904 #define TEMPNODE_FOLDER 1
1905 #define TEMPNODE_GROUP 2
1906 #define TEMPNODE_ADDRESS 3
1908 typedef struct _AddressCvt_Node AddressCvtNode;
1909 struct _AddressCvt_Node {
1918 * Parse current address item.
1920 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1925 nn = g_new0( AddressCvtNode, 1 );
1926 nn->type = TEMPNODE_ADDRESS;
1929 level = file->level;
1932 xml_parse_next_tag(file);
1933 if (file->level < level) return nn;
1935 element = xml_get_element( file );
1936 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1937 nn->name = g_strdup( element );
1939 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1940 nn->address = g_strdup( element );
1942 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1943 nn->remarks = g_strdup( element );
1946 xml_parse_next_tag(file);
1951 * Create a temporary node below specified node.
1953 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1955 nn = g_new0( AddressCvtNode, 1 );
1957 nn->name = g_strdup( name );
1958 nn->remarks = g_strdup( rem );
1959 node->list = g_list_append( node->list, nn );
1964 * Process current temporary node.
1966 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1969 AddressCvtNode *newNode = NULL;
1974 prev_level = file->level;
1975 xml_parse_next_tag( file );
1976 if (file->level < prev_level) return;
1980 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1981 attr = xml_get_current_tag_attr(file);
1983 name = ((XMLAttr *)attr->data)->name;
1984 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1985 value = ((XMLAttr *)attr->data)->value;
1988 newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1989 addrindex_add_obj( file, newNode );
1992 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1993 attr = xml_get_current_tag_attr(file);
1995 name = ((XMLAttr *)attr->data)->name;
1996 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1997 value = ((XMLAttr *)attr->data)->value;
2000 newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
2001 addrindex_add_obj( file, newNode );
2003 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
2004 newNode = addrindex_parse_item( file );
2005 node->list = g_list_append( node->list, newNode );
2008 /* g_print( "invalid: !!! \n" ); */
2009 attr = xml_get_current_tag_attr( file );
2015 * Consume all nodes below current tag.
2017 static void addrindex_consume_tree( XMLFile *file ) {
2024 prev_level = file->level;
2025 xml_parse_next_tag( file );
2026 if (file->level < prev_level) return;
2028 xtag = xml_get_current_tag( file );
2029 /* g_print( "tag : %s\n", xtag->tag ); */
2030 element = xml_get_element( file );
2031 attr = xml_get_current_tag_attr( file );
2032 /* show_attribs( attr ); */
2033 /* g_print( "\ttag value : %s :\n", element ); */
2034 addrindex_consume_tree( file );
2039 * Free up temporary tree.
2041 static void addrindex_free_node( AddressCvtNode *node ) {
2042 GList *list = node->list;
2045 AddressCvtNode *lNode = list->data;
2046 list = g_list_next( list );
2047 addrindex_free_node( lNode );
2049 node->type = TEMPNODE_ROOT;
2050 g_free( node->name );
2051 g_free( node->address );
2052 g_free( node->remarks );
2053 g_list_free( node->list );
2058 * Process address book for specified node.
2060 static void addrindex_process_node(
2061 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
2062 ItemGroup *parentGrp, ItemFolder *folderGrp )
2065 ItemFolder *itemFolder = NULL;
2066 ItemGroup *itemGParent = parentGrp;
2067 ItemFolder *itemGFolder = folderGrp;
2068 AddressCache *cache = abf->addressCache;
2070 if( node->type == TEMPNODE_ROOT ) {
2071 itemFolder = parent;
2073 else if( node->type == TEMPNODE_FOLDER ) {
2074 itemFolder = addritem_create_item_folder();
2075 addritem_folder_set_name( itemFolder, node->name );
2076 addrcache_id_folder( cache, itemFolder );
2077 addrcache_folder_add_folder( cache, parent, itemFolder );
2080 else if( node->type == TEMPNODE_GROUP ) {
2081 ItemGroup *itemGroup;
2084 /* Create a folder for group */
2085 fName = g_strdup_printf( "Cvt - %s", node->name );
2086 itemGFolder = addritem_create_item_folder();
2087 addritem_folder_set_name( itemGFolder, fName );
2088 addrcache_id_folder( cache, itemGFolder );
2089 addrcache_folder_add_folder( cache, parent, itemGFolder );
2092 /* Add group into folder */
2093 itemGroup = addritem_create_item_group();
2094 addritem_group_set_name( itemGroup, node->name );
2095 addrcache_id_group( cache, itemGroup );
2096 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
2097 itemGParent = itemGroup;
2099 else if( node->type == TEMPNODE_ADDRESS ) {
2100 ItemPerson *itemPerson;
2101 ItemEMail *itemEMail;
2103 /* Create person and email objects */
2104 itemPerson = addritem_create_item_person();
2105 addritem_person_set_common_name( itemPerson, node->name );
2106 addrcache_id_person( cache, itemPerson );
2107 itemEMail = addritem_create_item_email();
2108 addritem_email_set_address( itemEMail, node->address );
2109 addritem_email_set_remarks( itemEMail, node->remarks );
2110 addrcache_id_email( cache, itemEMail );
2111 addrcache_person_add_email( cache, itemPerson, itemEMail );
2113 /* Add person into appropriate folder */
2115 addrcache_folder_add_person( cache, itemGFolder, itemPerson );
2118 addrcache_folder_add_person( cache, parent, itemPerson );
2121 /* Add email address only into group */
2123 addrcache_group_add_email( cache, parentGrp, itemEMail );
2129 AddressCvtNode *lNode = list->data;
2130 list = g_list_next( list );
2131 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
2136 * Process address book to specified file number.
2138 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
2139 gboolean retVal = FALSE;
2140 AddressBookFile *abf = NULL;
2141 AddressCvtNode *rootNode = NULL;
2142 gchar *newFile = NULL;
2143 GList *fileList = NULL;
2146 /* Setup root node */
2147 rootNode = g_new0( AddressCvtNode, 1 );
2148 rootNode->type = TEMPNODE_ROOT;
2149 rootNode->name = g_strdup( "root" );
2150 rootNode->list = NULL;
2151 addrindex_add_obj( file, rootNode );
2152 /* addrindex_print_node( rootNode, stdout ); */
2154 /* Create new address book */
2155 abf = addrbook_create_book();
2156 addrbook_set_name( abf, displayName );
2157 addrbook_set_path( abf, addrIndex->filePath );
2159 /* Determine next available file number */
2160 fileList = addrbook_get_bookfile_list( abf );
2162 fileNum = 1 + abf->maxValue;
2164 g_list_free( fileList );
2167 newFile = addrbook_gen_new_file_name( fileNum );
2169 addrbook_set_file( abf, newFile );
2172 addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
2174 /* addrbook_dump_book( abf, stdout ); */
2175 addrbook_save_data( abf );
2176 addrIndex->retVal = abf->retVal;
2177 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2179 addrbook_free_book( abf );
2181 addrindex_free_node( rootNode );
2184 /* Create entries in address index */
2186 abf = addrbook_create_book();
2187 addrbook_set_name( abf, displayName );
2188 addrbook_set_path( abf, addrIndex->filePath );
2189 addrbook_set_file( abf, newFile );
2190 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2197 * Process tree converting data.
2199 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
2207 prev_level = file->level;
2208 xml_parse_next_tag( file );
2209 if (file->level < prev_level) return;
2211 xtag = xml_get_current_tag( file );
2212 /* g_print( "tag : %d : %s\n", prev_level, xtag->tag ); */
2213 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
2214 if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
2215 addrIndex->needsConversion = FALSE;
2216 addrIndex->wasConverted = TRUE;
2221 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
2222 if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
2223 addrIndex->needsConversion = FALSE;
2224 addrIndex->wasConverted = TRUE;
2229 element = xml_get_element( file );
2230 attr = xml_get_current_tag_attr( file );
2231 /* show_attribs( attr ); */
2232 /* g_print( "\ttag value : %s :\n", element ); */
2233 addrindex_consume_tree( file );
2237 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
2238 XMLFile *file = NULL;
2241 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
2242 addrIndex->retVal = MGU_NO_FILE;
2243 file = xml_open_file( fileSpec );
2246 if( file == NULL ) {
2247 /* g_print( " file '%s' does not exist.\n", addrIndex->fileName ); */
2248 return addrIndex->retVal;
2251 addrIndex->retVal = MGU_BAD_FORMAT;
2252 if( xml_get_dtd( file ) == 0 ) {
2253 if( xml_parse_next_tag( file ) == 0 ) {
2254 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
2255 addrindex_convert_tree( addrIndex, file );
2259 xml_close_file( file );
2260 return addrIndex->retVal;
2264 * Create a new address book file.
2266 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
2267 gboolean retVal = FALSE;
2268 AddressBookFile *abf = NULL;
2269 gchar *newFile = NULL;
2270 GList *fileList = NULL;
2273 /* Create new address book */
2274 abf = addrbook_create_book();
2275 addrbook_set_name( abf, displayName );
2276 addrbook_set_path( abf, addrIndex->filePath );
2278 /* Determine next available file number */
2279 fileList = addrbook_get_bookfile_list( abf );
2281 fileNum = 1 + abf->maxValue;
2283 g_list_free( fileList );
2286 newFile = addrbook_gen_new_file_name( fileNum );
2288 addrbook_set_file( abf, newFile );
2291 addrbook_save_data( abf );
2292 addrIndex->retVal = abf->retVal;
2293 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
2294 addrbook_free_book( abf );
2297 /* Create entries in address index */
2299 abf = addrbook_create_book();
2300 addrbook_set_name( abf, displayName );
2301 addrbook_set_path( abf, addrIndex->filePath );
2302 addrbook_set_file( abf, newFile );
2303 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
2310 * Read data for address index performing a conversion if necesary.
2311 * Enter: addrIndex Address index object.
2312 * return: Status code, from addrIndex->retVal.
2313 * Note: New address book files will be created in directory specified by
2314 * addrIndex. Three files will be created, for the following:
2315 * "Common addresses"
2316 * "Personal addresses"
2317 * "Gathered addresses" - a new address book.
2319 gint addrindex_read_data( AddressIndex *addrIndex ) {
2320 cm_return_val_if_fail( addrIndex != NULL, -1 );
2322 addrIndex->conversionError = FALSE;
2323 addrindex_read_file( addrIndex );
2324 if( addrIndex->retVal == MGU_SUCCESS ) {
2325 if( addrIndex->needsConversion ) {
2326 if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS )
2327 addrIndex->conversionError = FALSE;
2329 addrIndex->conversionError = TRUE;
2331 addrIndex->dirtyFlag = TRUE;
2333 return addrIndex->retVal;
2337 * Create new address books for a new address index.
2338 * Enter: addrIndex Address index object.
2339 * return: Status code, from addrIndex->retVal.
2340 * Note: New address book files will be created in directory specified by
2341 * addrIndex. Three files will be created, for the following:
2342 * "Common addresses"
2343 * "Personal addresses"
2344 * "Gathered addresses" - a new address book.
2346 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
2349 cm_return_val_if_fail( addrIndex != NULL, -1 );
2351 flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
2353 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
2354 addrIndex->dirtyFlag = TRUE;
2356 return addrIndex->retVal;
2359 /* **********************************************************************
2360 * New interface stuff.
2361 * ***********************************************************************
2365 * Return modified flag for specified data source.
2367 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
2368 gboolean retVal = FALSE;
2369 AddressInterface *iface;
2371 if( ds == NULL ) return retVal;
2372 iface = ds->interface;
2373 if( iface == NULL ) return retVal;
2374 if( iface->getModifyFlag ) {
2375 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
2381 * Return accessed flag for specified data source.
2383 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
2384 gboolean retVal = FALSE;
2385 AddressInterface *iface;
2387 if( ds == NULL ) return retVal;
2388 iface = ds->interface;
2389 if( iface == NULL ) return retVal;
2390 if( iface->getAccessFlag ) {
2391 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
2397 * Return data read flag for specified data source.
2399 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
2400 gboolean retVal = TRUE;
2401 AddressInterface *iface;
2403 if( ds == NULL ) return retVal;
2404 iface = ds->interface;
2405 if( iface == NULL ) return retVal;
2406 if( iface->getReadFlag ) {
2407 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
2413 * Return status code for specified data source.
2415 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
2416 gint retVal = MGU_SUCCESS;
2417 AddressInterface *iface;
2419 if( ds == NULL ) return retVal;
2420 iface = ds->interface;
2421 if( iface == NULL ) return retVal;
2422 if( iface->getStatusCode ) {
2423 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
2429 * Return data read flag for specified data source.
2431 gint addrindex_ds_read_data( AddressDataSource *ds ) {
2432 gint retVal = MGU_SUCCESS;
2433 AddressInterface *iface;
2435 if( ds == NULL ) return retVal;
2436 iface = ds->interface;
2437 if( iface == NULL ) return retVal;
2438 if( iface->getReadData ) {
2440 gchar *name = ( iface->getName ) ( ds->rawDataSource );
2441 g_print( "addrindex_ds_read_data...reading:::%s:::\n", name );
2443 retVal = ( iface->getReadData ) ( ds->rawDataSource );
2449 * Return data read flag for specified data source.
2451 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
2452 ItemFolder *retVal = NULL;
2453 AddressInterface *iface;
2455 if( ds == NULL ) return retVal;
2456 iface = ds->interface;
2457 if( iface == NULL ) return retVal;
2458 if( iface->getRootFolder ) {
2459 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
2465 * Return name for specified data source.
2467 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
2468 gchar *retVal = FALSE;
2469 AddressInterface *iface;
2471 if( ds == NULL ) return retVal;
2472 iface = ds->interface;
2473 if( iface == NULL ) return retVal;
2474 if( iface->getName ) {
2475 retVal = ( iface->getName ) ( ds->rawDataSource );
2481 * Set the access flag inside the data source.
2483 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
2484 AddressInterface *iface;
2486 if( ds == NULL ) return;
2487 iface = ds->interface;
2488 if( iface == NULL ) return;
2489 if( iface->setAccessFlag ) {
2490 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
2495 * Return read only flag for specified data source.
2497 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
2498 AddressInterface *iface;
2499 if( ds == NULL ) return TRUE;
2500 iface = ds->interface;
2501 if( iface == NULL ) return TRUE;
2502 return iface->readOnly;
2506 * Return list of all persons for specified data source.
2508 static GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
2509 GList *retVal = NULL;
2510 AddressInterface *iface;
2512 if( ds == NULL ) return retVal;
2513 iface = ds->interface;
2514 if( iface == NULL ) return retVal;
2515 if( iface->getAllPersons ) {
2516 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
2522 * Return list of all groups for specified data source.
2524 static GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) {
2525 GList *retVal = NULL;
2526 AddressInterface *iface;
2528 if( ds == NULL ) return retVal;
2529 iface = ds->interface;
2530 if( iface == NULL ) return retVal;
2531 if( iface->getAllGroups ) {
2532 retVal = ( iface->getAllGroups ) ( ds->rawDataSource );
2537 /* **********************************************************************
2538 * Address search stuff.
2539 * ***********************************************************************
2543 * Setup or register the dynamic search that will be performed. The search
2544 * is registered with the query manager.
2546 * \param searchTerm Search term. A private copy will be made.
2547 * \param callBackEntry Callback function that should be called when
2548 * each entry is received.
2549 * \param callBackEnd Callback function that should be called when
2550 * search has finished running.
2551 * \return ID allocated to query that will be executed.
2553 gint addrindex_setup_search(
2554 const gchar *searchTerm, void *callBackEnd, void *callBackEntry )
2559 /* Set up a dynamic address query */
2560 req = qrymgr_add_request( searchTerm, callBackEnd, callBackEntry );
2561 queryID = req->queryID;
2562 qryreq_set_search_type( req, ADDRSEARCH_DYNAMIC );
2564 /* g_print( "***> query ID ::%d::\n", queryID ); */
2571 * Function prototypes (not in header file or circular reference errors are
2574 LdapQuery *ldapsvr_new_dynamic_search(
2575 LdapServer *server, QueryRequest *req );
2576 LdapQuery *ldapsvr_new_explicit_search(
2577 LdapServer *server, QueryRequest *req, ItemFolder *folder );
2578 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry );
2583 * Execute the previously registered dynamic search.
2585 * \param req Address query object to execute.
2586 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2589 static gboolean addrindex_start_dynamic( QueryRequest *req ) {
2590 AddressInterface *iface;
2591 AddressDataSource *ds;
2596 /* g_print( "addrindex_start_dynamic::%d::\n", req->queryID ); */
2597 nodeIf = _addressIndex_->searchOrder;
2599 iface = nodeIf->data;
2600 nodeIf = g_list_next( nodeIf );
2602 if( ! iface->useInterface ) {
2605 if( ! iface->externalQuery ) {
2610 nodeDS = iface->listSource;
2613 nodeDS = g_list_next( nodeDS );
2615 if( type == ADDR_IF_LDAP ) {
2619 server = ds->rawDataSource;
2620 if( ! server->searchFlag ) {
2623 if( ldapsvr_reuse_previous( server, req ) ) {
2627 /* Start a new dynamic search */
2628 qry = ldapsvr_new_dynamic_search( server, req );
2630 ldapsvr_execute_query( server, qry );
2640 * Stop the previously registered search.
2642 * \param queryID ID of search query to stop.
2644 void addrindex_stop_search( const gint queryID ){
2646 AddrQueryObject *aqo;
2649 /* g_print( "addrindex_stop_search/queryID=%d\n", queryID ); */
2650 /* If query ID does not match, search has not been setup */
2651 req = qrymgr_find_request( queryID );
2656 /* Stop all queries that were associated with request */
2657 node = req->queryList;
2661 if( aqo->queryType == ADDRQUERY_LDAP ) {
2662 LdapQuery *qry = ( LdapQuery * ) aqo;
2663 ldapqry_set_stop_flag( qry, TRUE );
2667 node = g_list_next( node );
2670 /* Delete query request */
2671 qrymgr_delete_request( queryID );
2675 * Setup or register the explicit search that will be performed. The search is
2676 * registered with the query manager.
2678 * \param ds Data source to search.
2679 * \param searchTerm Search term to locate.
2680 * \param folder Folder to receive search results; may be NULL.
2681 * \param callbackEnd Function to call when search has terminated.
2682 * \param callbackEntry Function to called for each entry processed.
2683 * \return ID allocated to query that will be executed.
2685 gint addrindex_setup_explicit_search(
2686 AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder,
2687 void *callBackEnd, void *callBackEntry )
2694 /* Name the query */
2695 name = g_strdup_printf( "Search '%s'", searchTerm );
2697 /* Set up query request */
2698 if (!strcmp(searchTerm, "*"))
2699 mySearch = g_strdup("*@");
2701 mySearch = g_strdup(searchTerm);
2703 req = qrymgr_add_request( mySearch, callBackEnd, callBackEntry );
2707 qryreq_set_search_type( req, ADDRSEARCH_EXPLICIT );
2708 queryID = req->queryID;
2710 if( ds->type == ADDR_IF_LDAP ) {
2714 server = ds->rawDataSource;
2715 ldapsvr_new_explicit_search( server, req, folder );
2719 qrymgr_delete_request( queryID );
2728 * Execute the previously registered explicit search.
2730 * \param req Address query request object to execute.
2731 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2734 static gboolean addrindex_start_explicit( QueryRequest *req ) {
2736 AddrQueryObject *aqo;
2740 /* Note: there should only be one query in the list. */
2741 aqo = req->queryList->data;
2743 if( aqo->queryType == ADDRQUERY_LDAP ) {
2747 qry = ( LdapQuery * ) aqo;
2748 server = qry->server;
2750 /* Start the search */
2752 ldapsvr_execute_query( server, qry );
2759 * Start the previously registered search.
2761 * \param queryID ID of search query to be executed.
2762 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if
2765 gboolean addrindex_start_search( const gint queryID ) {
2768 AddrSearchType searchType;
2771 /* g_print( "addrindex_start_search/queryID=%d\n", queryID ); */
2772 req = qrymgr_find_request( queryID );
2777 searchType = req->searchType;
2778 if( searchType == ADDRSEARCH_DYNAMIC ) {
2779 retVal = addrindex_start_dynamic( req );
2781 else if( searchType == ADDRSEARCH_EXPLICIT ) {
2782 retVal = addrindex_start_explicit( req );
2789 * Remove results (folder and data) for specified data source and folder.
2790 * \param ds Data source to process.
2791 * \param folder Results folder to remove.
2793 void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) {
2794 AddrBookBase *adbase;
2795 AddressCache *cache;
2798 /* g_print( "addrindex_remove_results/start\n" ); */
2800 /* Test for folder */
2801 if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return;
2802 /* g_print( "folder name ::%s::\n", ADDRITEM_NAME(folder) ); */
2803 adbase = ( AddrBookBase * ) ds->rawDataSource;
2804 if( adbase == NULL ) return;
2805 cache = adbase->addressCache;
2807 /* Hide folder to prevent re-display */
2808 addritem_folder_set_hidden( folder, TRUE );
2810 if( ds->type == ADDR_IF_LDAP ) {
2815 qry = ( LdapQuery * ) folder->folderData;
2816 queryID = ADDRQUERY_ID(qry);
2817 /* g_print( "calling ldapquery_remove_results...queryID=%d\n", queryID ); */
2818 delFlag = ldapquery_remove_results( qry );
2820 ldapqry_free( qry );
2822 /* g_print( "calling ldapquery_remove_results...done\n" ); */
2825 g_print( "delFlag IS-TRUE\n" );
2828 g_print( "delFlag IS-FALSE\n" );
2833 /* g_print( "addrindex_remove_results/end\n" ); */
2835 /* Delete query request */
2837 qrymgr_delete_request( queryID );
2841 /* **********************************************************************
2842 * Address completion stuff.
2843 * ***********************************************************************
2846 static void addrindex_load_completion_load_persons(
2847 gint (*callBackFunc) ( const gchar *, const gchar *,
2848 const gchar *, const gchar *, GList * ),
2849 AddressDataSource *ds)
2851 GList *listP, *nodeP;
2855 /* Read address book */
2856 if( addrindex_ds_get_modify_flag( ds ) ) {
2857 addrindex_ds_read_data( ds );
2860 if( ! addrindex_ds_get_read_flag( ds ) ) {
2861 addrindex_ds_read_data( ds );
2864 /* Get all groups */
2865 listP = addrindex_ds_get_all_groups( ds );
2868 ItemGroup *group = nodeP->data;
2869 GList *emails = NULL;
2870 for (nodeM = group->listEMail; nodeM; nodeM = g_list_next(nodeM)) {
2871 ItemEMail *email = nodeM->data;
2873 emails = g_list_append(emails, email);
2875 callBackFunc( ((AddrItemObject *)group)->name, NULL,
2876 NULL, NULL, emails );
2877 nodeP = g_list_next( nodeP );
2880 /* Free up the list */
2881 g_list_free( listP );
2882 /* Get all persons */
2883 listP = addrindex_ds_get_all_persons( ds );
2886 ItemPerson *person = nodeP->data;
2887 nodeM = person->listEMail;
2889 /* Figure out name to use */
2890 sName = ADDRITEM_NAME(person);
2891 if( sName == NULL || *sName == '\0' ) {
2892 sName = person->nickName;
2895 /* Process each E-Mail address */
2897 ItemEMail *email = nodeM->data;
2899 callBackFunc( sName, email->address, person->nickName,
2900 ADDRITEM_NAME(email), NULL );
2902 nodeM = g_list_next( nodeM );
2904 nodeP = g_list_next( nodeP );
2907 /* Free up the list */
2908 g_list_free( listP );
2912 * This function is used by the address completion function to load
2913 * addresses for all non-external address book interfaces.
2915 * \param callBackFunc Function to be called when an address is
2917 * \param folderpath Addressbook's Book/folder path to restrict to (if NULL or ""
2918 * or "Any", assume the whole addressbook
2919 * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded.
2922 gboolean addrindex_load_completion(
2923 gint (*callBackFunc) ( const gchar *, const gchar *,
2924 const gchar *, const gchar *, GList * ),
2927 GList *nodeIf, *nodeDS;
2929 if( folderpath != NULL ) {
2930 AddressDataSource *book;
2933 /* split the folder path we've received, we'll try to match this path, subpath by
2934 subpath against the book/folder structure in order and restrict loading of
2935 addresses to that subpart (if matches). book/folder path must exist and
2936 folderpath must not be empty or NULL */
2938 if( ! addressbook_peek_folder_exists( folderpath, &book, &folder ) ) {
2939 g_warning("addrindex_load_completion: folder path '%s' doesn't exist\n", folderpath);
2943 if( folder != NULL ) {
2950 debug_print("addrindex_load_completion: folder %p '%s'\n", folder, folder->obj.name);
2952 /* Load email addresses */
2953 items = addritem_folder_get_person_list( folder );
2954 for( ; items != NULL; items = g_list_next( items ) ) {
2955 person = items->data;
2956 nodeM = person->listEMail;
2958 /* Figure out name to use */
2959 sName = ADDRITEM_NAME(person);
2960 if( sName == NULL || *sName == '\0' ) {
2961 sName = person->nickName;
2964 /* Process each E-Mail address */
2966 ItemEMail *email = nodeM->data;
2968 callBackFunc( sName, email->address, person->nickName,
2969 ADDRITEM_NAME(email), NULL );
2971 nodeM = g_list_next( nodeM );
2974 /* Free up the list */
2975 mgu_clear_list( items );
2976 g_list_free( items );
2982 if( book != NULL ) {
2984 AddressBookFile *abf = book->rawDataSource;
2986 debug_print("addrindex_load_completion: book %p '%s'\n", book, abf?abf->fileName:"(null)");
2988 addrindex_load_completion_load_persons( callBackFunc, book );
2993 g_warning("addrindex_load_completion: book/folder path is valid but got no pointer\n");
3000 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3002 AddressInterface *iface = nodeIf->data;
3004 nodeIf = g_list_next( nodeIf );
3006 if( ! iface->useInterface || iface->externalQuery )
3009 nodeDS = iface->listSource;
3011 addrindex_load_completion_load_persons( callBackFunc, nodeDS->data );
3012 nodeDS = g_list_next( nodeDS );
3021 * This function can be used to collect information about
3022 * addressbook entries that contain a specific attribute.
3024 * \param attr Name of attribute to look for
3025 * \param callBackFunc Function to be called when a matching attribute was found
3026 * \return <i>TRUE</i>
3028 gboolean addrindex_load_person_attribute(
3030 gint (*callBackFunc) ( ItemPerson *, const gchar * ) )
3032 AddressDataSource *ds;
3033 GList *nodeIf, *nodeDS;
3034 GList *listP, *nodeP;
3037 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3040 AddressInterface *iface = nodeIf->data;
3042 nodeIf = g_list_next( nodeIf );
3044 if( ! iface->useInterface || iface->externalQuery )
3047 nodeDS = iface->listSource;
3051 /* Read address book */
3052 if( addrindex_ds_get_modify_flag( ds ) ) {
3053 addrindex_ds_read_data( ds );
3056 if( ! addrindex_ds_get_read_flag( ds ) ) {
3057 addrindex_ds_read_data( ds );
3060 /* Check addressbook name */
3061 cur_bname = addrindex_ds_get_name( ds );
3063 /* Get all persons */
3064 listP = addrindex_ds_get_all_persons( ds );
3067 ItemPerson *person = nodeP->data;
3069 /* Return all ItemPerson's if attr is NULL */
3070 if( attr == NULL ) {
3071 callBackFunc(person, cur_bname);
3074 /* Return ItemPerson's with specific attribute */
3076 nodeA = person->listAttrib;
3077 /* Process each User Attribute */
3079 UserAttribute *attrib = nodeA->data;
3081 !strcmp( attrib->name,attr ) ) {
3082 callBackFunc(person, cur_bname);
3084 nodeA = g_list_next( nodeA );
3087 nodeP = g_list_next( nodeP );
3089 /* Free up the list */
3090 g_list_free( listP );
3092 nodeDS = g_list_next( nodeDS );
3099 * This function can be used to collect information about
3100 * addressbook entries
3102 * \param callBackFunc Function to be called for each ItemPerson
3103 * \return <i>TRUE</i>
3105 gboolean addrindex_load_person_ds( gint (*callBackFunc)
3106 ( ItemPerson *, AddressDataSource * ) )
3108 AddressDataSource *ds;
3109 GList *nodeIf, *nodeDS;
3110 GList *listP, *nodeP;
3112 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3114 AddressInterface *iface = nodeIf->data;
3116 nodeIf = g_list_next( nodeIf );
3118 if( ! iface->useInterface || iface->externalQuery )
3121 nodeDS = iface->listSource;
3125 /* Read address book */
3126 if( addrindex_ds_get_modify_flag( ds ) ) {
3127 addrindex_ds_read_data( ds );
3130 if( ! addrindex_ds_get_read_flag( ds ) ) {
3131 addrindex_ds_read_data( ds );
3134 /* Get all persons */
3135 listP = addrindex_ds_get_all_persons( ds );
3138 ItemPerson *person = nodeP->data;
3140 callBackFunc(person, ds);
3141 nodeP = g_list_next( nodeP );
3143 /* Free up the list */
3144 g_list_free( listP );
3146 nodeDS = g_list_next( nodeDS );
3152 gchar *addrindex_get_picture_file(const gchar *emailaddr)
3154 AddressDataSource *ds;
3155 GList *nodeIf, *nodeDS;
3156 GList *listP, *nodeP;
3157 gboolean found = FALSE;
3158 gchar *filename = NULL;
3159 gchar *raw_addr = NULL;
3164 Xstrdup_a(raw_addr, emailaddr, return NULL);
3165 extract_address(raw_addr);
3167 nodeIf = addrindex_get_interface_list( _addressIndex_ );
3169 AddressInterface *iface = nodeIf->data;
3171 nodeIf = g_list_next( nodeIf );
3173 if( ! iface->useInterface || iface->externalQuery )
3176 nodeDS = iface->listSource;
3177 while( nodeDS && !found) {
3180 /* Read address book */
3181 if( addrindex_ds_get_modify_flag( ds ) ) {
3182 addrindex_ds_read_data( ds );
3185 if( ! addrindex_ds_get_read_flag( ds ) ) {
3186 addrindex_ds_read_data( ds );
3189 /* Get all persons */
3190 listP = addrindex_ds_get_all_persons( ds );
3194 ItemPerson *person = nodeP->data;
3195 nodeM = person->listEMail;
3197 ItemEMail *email = nodeM->data;
3198 if (email->address && !strcasecmp(raw_addr, email->address)) {
3200 filename = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S,
3201 ADDRBOOK_DIR, G_DIR_SEPARATOR_S,
3202 person->picture, ".png", NULL );
3205 nodeM = nodeM->next;
3207 nodeP = g_list_next( nodeP );
3209 /* Free up the list */
3210 g_list_free( listP );
3212 nodeDS = g_list_next( nodeDS );