addrindex.c (60425B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 2001-2022 the Claws Mail team and Match Grun 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "defs.h" 20 21 #include <glib.h> 22 #include <glib/gi18n.h> 23 24 #include "mgutils.h" 25 #include "addritem.h" 26 #include "addrcache.h" 27 #include "addrbook.h" 28 #include "addressbook.h" 29 #include "addrindex.h" 30 #include "xml.h" 31 #include "addrquery.h" 32 #include "addr_compl.h" 33 #include "utils.h" 34 #include "alertpanel.h" 35 #include "passwordstore.h" 36 #include "file-utils.h" 37 38 #include "prefs_gtk.h" 39 #include "codeconv.h" 40 41 #define TAG_ADDRESS_INDEX "addressbook" 42 43 #define TAG_IF_ADDRESS_BOOK "book_list" 44 45 #define TAG_DS_ADDRESS_BOOK "book" 46 47 /* XML Attribute names */ 48 #define ATTAG_BOOK_NAME "name" 49 #define ATTAG_BOOK_FILE "file" 50 51 /* Attribute values */ 52 #define ATVAL_BOOLEAN_YES "yes" 53 #define ATVAL_BOOLEAN_NO "no" 54 55 56 #define DISP_NEW_COMMON _("Common addresses") 57 #define DISP_NEW_PERSONAL _("Personal addresses") 58 59 /* Old address book */ 60 #define TAG_IF_OLD_COMMON "common_address" 61 #define TAG_IF_OLD_PERSONAL "personal_address" 62 63 #define DISP_OLD_COMMON _("Common address") 64 #define DISP_OLD_PERSONAL _("Personal address") 65 66 /** 67 * Singleton object. 68 */ 69 static AddressIndex *_addressIndex_ = NULL; 70 71 /* 72 * Define attribute name-value pair. 73 */ 74 typedef struct _AddressIfAttr AddressIfAttrib; 75 struct _AddressIfAttr { 76 gchar *name; 77 gchar *value; 78 }; 79 80 static AddressDataSource *addrindex_create_datasource ( AddressIfType ifType ); 81 82 static GList *addrindex_ds_get_all_persons ( AddressDataSource *ds ); 83 static GList *addrindex_ds_get_all_groups ( AddressDataSource *ds ); 84 static AddressDataSource *addrindex_get_datasource ( AddressIndex *addrIndex, 85 const gchar *cacheID ); 86 static AddressInterface *addrindex_get_interface ( AddressIndex *addrIndex, 87 AddressIfType ifType ); 88 static gint addrindex_write_to ( AddressIndex *addrIndex, 89 const gchar *newFile ); 90 91 /* 92 * Define DOM fragment. 93 */ 94 typedef struct _AddressIfFrag AddressIfFragment; 95 struct _AddressIfFrag { 96 AddressBookType type; 97 AddressCache *addressCache; 98 gchar *name; 99 GList *children; 100 GList *attributes; 101 }; 102 103 /** 104 * Build interface with default values. 105 * 106 * \param type Interface type. 107 * \param name Interface name. 108 * \param tagIf XML tag name for interface in address index file. 109 * \param tagDS XML tag name for datasource in address index file. 110 * \return Address interface object. 111 */ 112 static AddressInterface *addrindex_create_interface( 113 gint type, gchar *name, gchar *tagIf, gchar *tagDS ) 114 { 115 AddressInterface *iface = g_new0( AddressInterface, 1 ); 116 117 ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE; 118 ADDRITEM_ID(iface) = NULL; 119 ADDRITEM_NAME(iface) = g_strdup( name ); 120 ADDRITEM_PARENT(iface) = NULL; 121 ADDRITEM_SUBTYPE(iface) = type; 122 iface->type = type; 123 iface->name = g_strdup( name ); 124 iface->listTag = g_strdup( tagIf ); 125 iface->itemTag = g_strdup( tagDS ); 126 iface->legacyFlag = FALSE; 127 iface->haveLibrary = TRUE; 128 iface->useInterface = TRUE; 129 iface->readOnly = TRUE; 130 131 /* Set callbacks to NULL values - override for each interface */ 132 iface->getAccessFlag = NULL; 133 iface->getModifyFlag = NULL; 134 iface->getReadFlag = NULL; 135 iface->getStatusCode = NULL; 136 iface->getReadData = NULL; 137 iface->getRootFolder = NULL; 138 iface->getListFolder = NULL; 139 iface->getListPerson = NULL; 140 iface->getAllPersons = NULL; 141 iface->getAllGroups = NULL; 142 iface->getName = NULL; 143 iface->listSource = NULL; 144 145 /* Search stuff */ 146 iface->externalQuery = FALSE; 147 iface->searchOrder = 0; /* Ignored */ 148 iface->startSearch = NULL; 149 iface->stopSearch = NULL; 150 151 return iface; 152 } 153 154 /** 155 * Build table of of all address book interfaces. 156 * \param addrIndex Address index object. 157 */ 158 static void addrindex_build_if_list( AddressIndex *addrIndex ) { 159 AddressInterface *iface; 160 161 /* Create intrinsic XML address book interface */ 162 iface = addrindex_create_interface( 163 ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK, 164 TAG_DS_ADDRESS_BOOK ); 165 iface->readOnly = FALSE; 166 iface->getModifyFlag = ( void * ) addrbook_get_modified; 167 iface->getAccessFlag = ( void * ) addrbook_get_accessed; 168 iface->getReadFlag = ( void * ) addrbook_get_read_flag; 169 iface->getStatusCode = ( void * ) addrbook_get_status; 170 iface->getReadData = ( void * ) addrbook_read_data; 171 iface->getRootFolder = ( void * ) addrbook_get_root_folder; 172 iface->getListFolder = ( void * ) addrbook_get_list_folder; 173 iface->getListPerson = ( void * ) addrbook_get_list_person; 174 iface->getAllPersons = ( void * ) addrbook_get_all_persons; 175 iface->getAllGroups = ( void * ) addrbook_get_all_groups; 176 iface->getName = ( void * ) addrbook_get_name; 177 iface->setAccessFlag = ( void * ) addrbook_set_accessed; 178 iface->searchOrder = 0; 179 180 /* Add to list of interfaces in address book */ 181 addrIndex->interfaceList = 182 g_list_append( addrIndex->interfaceList, iface ); 183 ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); 184 } 185 186 /** 187 * Free DOM fragment. 188 * \param fragment Fragment to free. 189 */ 190 static void addrindex_free_fragment( AddressIfFragment *fragment ) { 191 GList *node; 192 193 /* Free children */ 194 node = fragment->children; 195 while( node ) { 196 AddressIfFragment *child = node->data; 197 addrindex_free_fragment( child ); 198 node->data = NULL; 199 node = g_list_next( node ); 200 } 201 g_list_free( fragment->children ); 202 203 /* Free attributes */ 204 node = fragment->attributes; 205 while( node ) { 206 AddressIfAttrib *nv = node->data; 207 g_free( nv->name ); 208 g_free( nv->value ); 209 g_free( nv ); 210 node->data = NULL; 211 node = g_list_next( node ); 212 } 213 g_list_free( fragment->attributes ); 214 215 g_free( fragment->name ); 216 fragment->name = NULL; 217 fragment->attributes = NULL; 218 fragment->children = NULL; 219 220 g_free( fragment ); 221 } 222 223 /** 224 * Create a new data source. 225 * \param ifType Interface type to create. 226 * \return Initialized data source. 227 */ 228 AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) { 229 AddressDataSource *ds = g_new0( AddressDataSource, 1 ); 230 231 ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE; 232 ADDRITEM_ID(ds) = NULL; 233 ADDRITEM_NAME(ds) = NULL; 234 ADDRITEM_PARENT(ds) = NULL; 235 ADDRITEM_SUBTYPE(ds) = 0; 236 ds->type = ifType; 237 ds->rawDataSource = NULL; 238 ds->interface = NULL; 239 return ds; 240 } 241 242 /** 243 * Free up data source. 244 * \param ds Data source to free. 245 */ 246 void addrindex_free_datasource( AddressDataSource *ds ) { 247 AddressInterface *iface; 248 249 cm_return_if_fail( ds != NULL ); 250 251 iface = ds->interface; 252 if( ds->rawDataSource != NULL ) { 253 if( iface != NULL ) { 254 if( iface->useInterface ) { 255 if( iface->type == ADDR_IF_BOOK ) { 256 AddressBookFile *abf = ds->rawDataSource; 257 addrbook_free_book( abf ); 258 } 259 } else { 260 AddressIfFragment *fragment = ds->rawDataSource; 261 addrindex_free_fragment( fragment ); 262 } 263 } 264 } 265 266 ADDRITEM_TYPE(ds) = ITEMTYPE_NONE; 267 ADDRITEM_ID(ds) = NULL; 268 ADDRITEM_NAME(ds) = NULL; 269 ADDRITEM_PARENT(ds) = NULL; 270 ADDRITEM_SUBTYPE(ds) = 0; 271 ds->type = ADDR_IF_NONE; 272 ds->interface = NULL; 273 ds->rawDataSource = NULL; 274 275 g_free( ds ); 276 } 277 278 /** 279 * Free up all data sources for specified interface. 280 * \param iface Address interface to process. 281 */ 282 static void addrindex_free_all_datasources( AddressInterface *iface ) { 283 GList *node = iface->listSource; 284 while( node ) { 285 AddressDataSource *ds = node->data; 286 addrindex_free_datasource( ds ); 287 node->data = NULL; 288 node = g_list_next( node ); 289 } 290 } 291 292 /** 293 * Free up specified interface. 294 * \param iface Interface to process. 295 */ 296 static void addrindex_free_interface( AddressInterface *iface ) { 297 /* Free up data sources */ 298 addrindex_free_all_datasources( iface ); 299 g_list_free( iface->listSource ); 300 301 /* Free internal storage */ 302 g_free( ADDRITEM_ID(iface) ); 303 g_free( ADDRITEM_NAME(iface) ); 304 g_free( iface->name ); 305 g_free( iface->listTag ); 306 g_free( iface->itemTag ); 307 308 /* Clear all pointers */ 309 ADDRITEM_TYPE(iface) = ITEMTYPE_NONE; 310 ADDRITEM_ID(iface) = NULL; 311 ADDRITEM_NAME(iface) = NULL; 312 ADDRITEM_PARENT(iface) = NULL; 313 ADDRITEM_SUBTYPE(iface) = 0; 314 iface->type = ADDR_IF_NONE; 315 iface->name = NULL; 316 iface->listTag = NULL; 317 iface->itemTag = NULL; 318 iface->legacyFlag = FALSE; 319 iface->useInterface = FALSE; 320 iface->haveLibrary = FALSE; 321 iface->listSource = NULL; 322 323 /* Search stuff */ 324 iface->searchOrder = 0; 325 iface->startSearch = NULL; 326 iface->stopSearch = NULL; 327 328 g_free( iface ); 329 } 330 331 /** 332 * Return cache ID for specified data source. 333 * 334 * \param addrIndex Address index. 335 * \param ds Data source. 336 * \return ID or NULL if not found. This should be <code>g_free()</code> 337 * when done. 338 */ 339 gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) { 340 gchar *cacheID = NULL; 341 AddrBookBase *adbase; 342 AddressCache *cache; 343 344 cm_return_val_if_fail( addrIndex != NULL, NULL ); 345 cm_return_val_if_fail( ds != NULL, NULL ); 346 347 adbase = ( AddrBookBase * ) ds->rawDataSource; 348 if( adbase ) { 349 cache = adbase->addressCache; 350 if( cache ) { 351 cacheID = g_strdup( cache->cacheID ); 352 } 353 } 354 355 return cacheID; 356 } 357 358 /** 359 * Return reference to data source for specified cacheID. 360 * \param addrIndex Address index. 361 * \param cacheID ID. 362 * \return Data source, or NULL if not found. 363 */ 364 static AddressDataSource *addrindex_get_datasource( 365 AddressIndex *addrIndex, const gchar *cacheID ) 366 { 367 cm_return_val_if_fail( addrIndex != NULL, NULL ); 368 cm_return_val_if_fail( cacheID != NULL, NULL ); 369 return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID ); 370 } 371 372 /** 373 * Return reference to address cache for specified cacheID. 374 * \param addrIndex Address index. 375 * \param cacheID ID. 376 * \return Address cache, or NULL if not found. 377 */ 378 AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) { 379 AddressDataSource *ds; 380 AddrBookBase *adbase; 381 AddressCache *cache; 382 383 cm_return_val_if_fail( addrIndex != NULL, NULL ); 384 cm_return_val_if_fail( cacheID != NULL, NULL ); 385 386 cache = NULL; 387 ds = addrindex_get_datasource( addrIndex, cacheID ); 388 if( ds ) { 389 adbase = ( AddrBookBase * ) ds->rawDataSource; 390 cache = adbase->addressCache; 391 } 392 return cache; 393 } 394 395 /** 396 * Add data source into hash table. 397 * \param addrIndex Address index. 398 * \param ds Data source. 399 */ 400 static void addrindex_hash_add_cache( 401 AddressIndex *addrIndex, AddressDataSource *ds ) 402 { 403 gchar *cacheID; 404 405 cacheID = addrindex_get_cache_id( addrIndex, ds ); 406 if( cacheID ) { 407 g_hash_table_insert( addrIndex->hashCache, cacheID, ds ); 408 } 409 } 410 411 /* 412 * Free hash table callback function. 413 */ 414 static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) { 415 g_free( key ); 416 key = NULL; 417 value = NULL; 418 return TRUE; 419 } 420 421 /* 422 * Free hash table of address cache items. 423 */ 424 static void addrindex_free_cache_hash( GHashTable *table ) { 425 g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL ); 426 g_hash_table_destroy( table ); 427 } 428 429 /** 430 * Remove data source from internal hashtable. 431 * \param addrIndex Address index. 432 * \param ds Data source to remove. 433 */ 434 static void addrindex_hash_remove_cache( 435 AddressIndex *addrIndex, AddressDataSource *ds ) 436 { 437 gchar *cacheID; 438 439 cacheID = addrindex_get_cache_id( addrIndex, ds ); 440 if( cacheID ) { 441 g_hash_table_remove( addrIndex->hashCache, cacheID ); 442 g_free( cacheID ); 443 cacheID = NULL; 444 } 445 } 446 447 /** 448 * Create a new address index. This is created as a singleton object. 449 * \return Initialized address index object. 450 */ 451 AddressIndex *addrindex_create_index( void ) { 452 AddressIndex *index; 453 454 if( _addressIndex_ == NULL ) { 455 index = g_new0( AddressIndex, 1 ); 456 ADDRITEM_TYPE(index) = ITEMTYPE_INDEX; 457 ADDRITEM_ID(index) = NULL; 458 ADDRITEM_NAME(index) = g_strdup( "Address Index" ); 459 ADDRITEM_PARENT(index) = NULL; 460 ADDRITEM_SUBTYPE(index) = 0; 461 index->filePath = NULL; 462 index->fileName = NULL; 463 index->retVal = MGU_SUCCESS; 464 index->needsConversion = FALSE; 465 index->wasConverted = FALSE; 466 index->conversionError = FALSE; 467 index->interfaceList = NULL; 468 index->lastType = ADDR_IF_NONE; 469 index->dirtyFlag = FALSE; 470 index->hashCache = g_hash_table_new( g_str_hash, g_str_equal ); 471 index->loadedFlag = FALSE; 472 index->searchOrder = NULL; 473 addrindex_build_if_list( index ); 474 _addressIndex_ = index; 475 } 476 return _addressIndex_; 477 } 478 479 /** 480 * Property - Specify file path to address index file. 481 * \param addrIndex Address index. 482 * \param value Path to index file. 483 */ 484 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) { 485 cm_return_if_fail( addrIndex != NULL ); 486 addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value ); 487 } 488 489 /** 490 * Property - Specify file name to address index file. 491 * \param addrIndex Address index. 492 * \param value File name. 493 */ 494 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) { 495 cm_return_if_fail( addrIndex != NULL ); 496 addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value ); 497 } 498 499 /** 500 * Return list of address interfaces. 501 * \param addrIndex Address index. 502 * \return List of address interfaces. 503 */ 504 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) { 505 cm_return_val_if_fail( addrIndex != NULL, NULL ); 506 return addrIndex->interfaceList; 507 } 508 509 /** 510 * Perform any other initialization of address index. 511 */ 512 void addrindex_initialize( void ) { 513 qrymgr_initialize(); 514 addrcompl_initialize(); 515 } 516 517 /** 518 * Perform any other teardown of address index. 519 */ 520 void addrindex_teardown( void ) { 521 addrcompl_teardown(); 522 qrymgr_teardown(); 523 } 524 525 /** 526 * Free up address index. 527 * \param addrIndex Address index. 528 */ 529 void addrindex_free_index( AddressIndex *addrIndex ) { 530 GList *node; 531 532 cm_return_if_fail( addrIndex != NULL ); 533 534 /* Search stuff */ 535 g_list_free( addrIndex->searchOrder ); 536 addrIndex->searchOrder = NULL; 537 538 /* Free internal storage */ 539 g_free( ADDRITEM_ID(addrIndex) ); 540 g_free( ADDRITEM_NAME(addrIndex) ); 541 g_free( addrIndex->filePath ); 542 g_free( addrIndex->fileName ); 543 544 /* Clear pointers */ 545 ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE; 546 ADDRITEM_ID(addrIndex) = NULL; 547 ADDRITEM_NAME(addrIndex) = NULL; 548 ADDRITEM_PARENT(addrIndex) = NULL; 549 ADDRITEM_SUBTYPE(addrIndex) = 0; 550 addrIndex->filePath = NULL; 551 addrIndex->fileName = NULL; 552 addrIndex->retVal = MGU_SUCCESS; 553 addrIndex->needsConversion = FALSE; 554 addrIndex->wasConverted = FALSE; 555 addrIndex->conversionError = FALSE; 556 addrIndex->lastType = ADDR_IF_NONE; 557 addrIndex->dirtyFlag = FALSE; 558 559 /* Free up interfaces */ 560 node = addrIndex->interfaceList; 561 while( node ) { 562 AddressInterface *iface = node->data; 563 addrindex_free_interface( iface ); 564 node = g_list_next( node ); 565 } 566 g_list_free( addrIndex->interfaceList ); 567 addrIndex->interfaceList = NULL; 568 569 /* Free up hash cache */ 570 addrindex_free_cache_hash( addrIndex->hashCache ); 571 addrIndex->hashCache = NULL; 572 573 addrIndex->loadedFlag = FALSE; 574 575 g_free( addrIndex ); 576 addrIndex = NULL; 577 _addressIndex_ = NULL; 578 } 579 580 /** 581 * Print address index. 582 * \param addrIndex Address index. 583 * \parem stream Stream to print. 584 */ 585 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) { 586 cm_return_if_fail( addrIndex != NULL ); 587 fprintf( stream, "AddressIndex:\n" ); 588 fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath ); 589 fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName ); 590 fprintf( stream, "\t status: %d\n", addrIndex->retVal ); 591 fprintf( stream, "\tconverted: '%s'\n", 592 addrIndex->wasConverted ? "yes" : "no" ); 593 fprintf( stream, "\tcvt error: '%s'\n", 594 addrIndex->conversionError ? "yes" : "no" ); 595 fprintf( stream, "\t---\n" ); 596 } 597 598 /** 599 * Retrieve reference to address interface for specified interface type. 600 * \param addrIndex Address index. 601 * \param ifType Interface type. 602 * \return Address interface, or NULL if not found. 603 */ 604 static AddressInterface *addrindex_get_interface( 605 AddressIndex *addrIndex, AddressIfType ifType ) 606 { 607 AddressInterface *retVal = NULL; 608 GList *node; 609 610 cm_return_val_if_fail( addrIndex != NULL, NULL ); 611 612 node = addrIndex->interfaceList; 613 while( node ) { 614 AddressInterface *iface = node->data; 615 node = g_list_next( node ); 616 if( iface->type == ifType ) { 617 retVal = iface; 618 break; 619 } 620 } 621 return retVal; 622 } 623 624 /** 625 * Add raw data source to index. The raw data object (an AddressBookFile for example) 626 * should be supplied as the raw dataSource argument. 627 * 628 * \param addrIndex Address index. 629 * \param ifType Interface type to add. 630 * \param dataSource Actual raw data source to add. 631 * \return Data source added, or NULL if invalid interface type. 632 */ 633 AddressDataSource *addrindex_index_add_datasource( 634 AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource ) 635 { 636 AddressInterface *iface; 637 AddressDataSource *ds = NULL; 638 639 cm_return_val_if_fail( addrIndex != NULL, NULL ); 640 cm_return_val_if_fail( dataSource != NULL, NULL ); 641 642 iface = addrindex_get_interface( addrIndex, ifType ); 643 if( iface ) { 644 ds = addrindex_create_datasource( ifType ); 645 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface); 646 ds->type = ifType; 647 ds->rawDataSource = dataSource; 648 ds->interface = iface; 649 iface->listSource = g_list_append( iface->listSource, ds ); 650 addrIndex->dirtyFlag = TRUE; 651 652 addrindex_hash_add_cache( addrIndex, ds ); 653 } 654 return ds; 655 } 656 657 /** 658 * Remove specified data source from index. 659 * \param addrIndex Address index. 660 * \param dataSource Data source to add. 661 * \return Reference to data source if removed, or NULL if data source was not 662 * found in index. Note the this object must still be freed. 663 */ 664 AddressDataSource *addrindex_index_remove_datasource( 665 AddressIndex *addrIndex, AddressDataSource *dataSource ) 666 { 667 AddressDataSource *retVal = FALSE; 668 AddressInterface *iface; 669 670 cm_return_val_if_fail( addrIndex != NULL, NULL ); 671 cm_return_val_if_fail( dataSource != NULL, NULL ); 672 673 iface = addrindex_get_interface( addrIndex, dataSource->type ); 674 if( iface ) { 675 iface->listSource = g_list_remove( iface->listSource, dataSource ); 676 addrIndex->dirtyFlag = TRUE; 677 dataSource->interface = NULL; 678 679 /* Remove cache from hash table */ 680 addrindex_hash_remove_cache( addrIndex, dataSource ); 681 682 retVal = dataSource; 683 } 684 return retVal; 685 } 686 687 /** 688 * Retrieve a reference to address interface for specified interface type and 689 * XML interface tag name. 690 * \param addrIndex Address index. 691 * \param tag XML interface tag name to match. 692 * \param ifType Interface type to match. 693 * \return Reference to address index, or NULL if not found in index. 694 */ 695 static AddressInterface *addrindex_tag_get_interface( 696 AddressIndex *addrIndex, gchar *tag, AddressIfType ifType ) 697 { 698 AddressInterface *retVal = NULL; 699 GList *node = addrIndex->interfaceList; 700 701 while( node ) { 702 AddressInterface *iface = node->data; 703 node = g_list_next( node ); 704 if( tag ) { 705 if( strcmp( iface->listTag, tag ) == 0 ) { 706 retVal = iface; 707 break; 708 } 709 } 710 else { 711 if( iface->type == ifType ) { 712 retVal = iface; 713 break; 714 } 715 } 716 } 717 return retVal; 718 } 719 720 /** 721 * Retrieve a reference to address interface for specified interface type and 722 * XML datasource tag name. 723 * \param addrIndex Address index. 724 * \param ifType Interface type to match. 725 * \param tag XML datasource tag name to match. 726 * \return Reference to address index, or NULL if not found in index. 727 */ 728 static AddressInterface *addrindex_tag_get_datasource( 729 AddressIndex *addrIndex, AddressIfType ifType, gchar *tag ) 730 { 731 AddressInterface *retVal = NULL; 732 GList *node = addrIndex->interfaceList; 733 734 while( node ) { 735 AddressInterface *iface = node->data; 736 node = g_list_next( node ); 737 if( iface->type == ifType && iface->itemTag ) { 738 if( strcmp( iface->itemTag, tag ) == 0 ) { 739 retVal = iface; 740 break; 741 } 742 } 743 } 744 return retVal; 745 } 746 747 /* ********************************************************************** 748 * Interface XML parsing functions. 749 * *********************************************************************** 750 */ 751 752 /** 753 * Write start of XML element to file. 754 * \param fp File. 755 * \param lvl Indentation level. 756 * \param name Element name. 757 */ 758 static int addrindex_write_elem_s( FILE *fp, const gint lvl, const gchar *name ) { 759 gint i; 760 for( i = 0; i < lvl; i++ ) 761 if (fputs( " ", fp ) == EOF) 762 return -1; 763 if (fputs( "<", fp ) == EOF) 764 return -1; 765 if (fputs( name, fp ) == EOF) 766 return -1; 767 return 0; 768 } 769 770 /** 771 * Write end of XML element to file. 772 * \param fp File. 773 * \param lvl Indentation level. 774 * \param name Element name. 775 */ 776 static int addrindex_write_elem_e( FILE *fp, const gint lvl, const gchar *name ) { 777 gint i; 778 for( i = 0; i < lvl; i++ ) 779 if (fputs( " ", fp ) == EOF) 780 return -1; 781 if (fputs( "</", fp ) == EOF) 782 return -1; 783 if (fputs( name, fp ) == EOF) 784 return -1; 785 if (fputs( ">\n", fp ) == EOF) 786 return -1; 787 return 0; 788 } 789 790 /** 791 * Write XML attribute to file. 792 * \param fp File. 793 * \param name Attribute name. 794 * \param value Attribute value. 795 */ 796 static int addrindex_write_attr( FILE *fp, const gchar *name, const gchar *value ) { 797 if (fputs( " ", fp ) == EOF) 798 return -1; 799 if (fputs( name, fp ) == EOF) 800 return -1; 801 if (fputs( "=\"", fp ) == EOF) 802 return -1; 803 if (xml_file_put_escape_str( fp, value ) < 0) 804 return -1; 805 if (fputs( "\"", fp ) == EOF) 806 return -1; 807 return 0; 808 } 809 810 /** 811 * Read/parse address index file, creating a data source for a regular 812 * intrinsic XML addressbook. 813 * \param file Address index file. 814 * \return Data source. 815 */ 816 static AddressDataSource *addrindex_parse_book( XMLFile *file ) { 817 AddressDataSource *ds; 818 AddressBookFile *abf; 819 GList *attr; 820 821 ds = addrindex_create_datasource( ADDR_IF_BOOK ); 822 abf = addrbook_create_book(); 823 attr = xml_get_current_tag_attr( file ); 824 while( attr ) { 825 gchar *name = ((XMLAttr *)attr->data)->name; 826 gchar *value = ((XMLAttr *)attr->data)->value; 827 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) { 828 addrbook_set_name( abf, value ); 829 } 830 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) { 831 addrbook_set_file( abf, value ); 832 } 833 attr = g_list_next( attr ); 834 } 835 ds->rawDataSource = abf; 836 return ds; 837 } 838 839 static int addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) { 840 AddressBookFile *abf = ds->rawDataSource; 841 if( abf ) { 842 if (addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK ) < 0) 843 return -1; 844 if (addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) ) < 0) 845 return -1; 846 if (addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName ) < 0) 847 return -1; 848 if (fputs( " />\n", fp ) == EOF) 849 return -1; 850 } 851 return 0; 852 } 853 854 /* ********************************************************************** 855 * Address index I/O functions. 856 * *********************************************************************** 857 */ 858 /** 859 * Read address index file, creating appropriate data sources for each address 860 * index file entry. 861 * 862 * \param addrIndex Address index. 863 * \param file Address index file. 864 */ 865 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) { 866 XMLTag *xtag; 867 AddressInterface *iface = NULL, *dsIFace = NULL; 868 AddressDataSource *ds; 869 gint rc; 870 871 addrIndex->loadedFlag = FALSE; 872 for (;;) { 873 rc = xml_parse_next_tag( file ); 874 if( rc < 0 || file->level == 0 ) return; 875 876 xtag = xml_get_current_tag( file ); 877 878 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE ); 879 if( iface ) { 880 addrIndex->lastType = iface->type; 881 if( iface->legacyFlag ) addrIndex->needsConversion = TRUE; 882 } 883 else { 884 dsIFace = addrindex_tag_get_datasource( 885 addrIndex, addrIndex->lastType, xtag->tag ); 886 if( dsIFace ) { 887 /* Add data source to list */ 888 ds = NULL; 889 if( addrIndex->lastType == ADDR_IF_BOOK ) { 890 ds = addrindex_parse_book( file ); 891 if( ds->rawDataSource ) { 892 addrbook_set_path( ds->rawDataSource, 893 addrIndex->filePath ); 894 } 895 } 896 if( ds ) { 897 ds->interface = dsIFace; 898 addrindex_hash_add_cache( addrIndex, ds ); 899 dsIFace->listSource = 900 g_list_append( dsIFace->listSource, ds ); 901 } 902 } 903 } 904 } 905 } 906 907 /* 908 * Search order sorting comparison function for building search order list. 909 */ 910 static gint addrindex_search_order_compare( gconstpointer ptrA, gconstpointer ptrB ) { 911 AddressInterface *ifaceA = ( AddressInterface * ) ptrA; 912 AddressInterface *ifaceB = ( AddressInterface * ) ptrB; 913 914 return ifaceA->searchOrder - ifaceB->searchOrder; 915 } 916 917 /** 918 * Build list of data sources to process. 919 * \param addrIndex Address index object. 920 */ 921 static void addrindex_build_search_order( AddressIndex *addrIndex ) { 922 GList *nodeIf; 923 924 /* Clear existing list */ 925 g_list_free( addrIndex->searchOrder ); 926 addrIndex->searchOrder = NULL; 927 928 /* Build new list */ 929 nodeIf = addrIndex->interfaceList; 930 while( nodeIf ) { 931 AddressInterface *iface = nodeIf->data; 932 if( iface->useInterface ) { 933 if( iface->searchOrder > 0 ) { 934 /* Add to search order list */ 935 addrIndex->searchOrder = g_list_insert_sorted( 936 addrIndex->searchOrder, iface, 937 addrindex_search_order_compare ); 938 } 939 } 940 nodeIf = g_list_next( nodeIf ); 941 } 942 } 943 944 static gint addrindex_read_file( AddressIndex *addrIndex ) { 945 XMLFile *file = NULL; 946 gchar *fileSpec = NULL; 947 948 cm_return_val_if_fail( addrIndex != NULL, -1 ); 949 950 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL ); 951 addrIndex->retVal = MGU_NO_FILE; 952 file = xml_open_file( fileSpec ); 953 g_free( fileSpec ); 954 955 if( file == NULL ) { 956 /* 957 g_print( " file '%s' does not exist.\n", addrIndex->fileName ); 958 */ 959 return addrIndex->retVal; 960 } 961 962 addrIndex->retVal = MGU_BAD_FORMAT; 963 if( xml_get_dtd( file ) == 0 ) { 964 if( xml_parse_next_tag( file ) == 0 ) { 965 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) { 966 addrindex_read_index( addrIndex, file ); 967 addrIndex->retVal = MGU_SUCCESS; 968 } 969 } 970 } 971 xml_close_file( file ); 972 973 addrindex_build_search_order( addrIndex ); 974 975 return addrIndex->retVal; 976 } 977 978 static int addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) { 979 GList *nodeIF, *nodeDS; 980 gint lvlList = 1; 981 gint lvlItem = 1 + lvlList; 982 983 nodeIF = addrIndex->interfaceList; 984 while( nodeIF ) { 985 AddressInterface *iface = nodeIF->data; 986 if( ! iface->legacyFlag ) { 987 nodeDS = iface->listSource; 988 if (addrindex_write_elem_s( fp, lvlList, iface->listTag ) < 0) 989 return -1; 990 if (fputs( ">\n", fp ) == EOF) 991 return -1; 992 while( nodeDS ) { 993 AddressDataSource *ds = nodeDS->data; 994 if( ds ) { 995 if( iface->type == ADDR_IF_BOOK ) { 996 if (addrindex_write_book( fp, ds, lvlItem ) < 0) 997 return -1; 998 } 999 } 1000 nodeDS = g_list_next( nodeDS ); 1001 } 1002 if (addrindex_write_elem_e( fp, lvlList, iface->listTag ) < 0) 1003 return -1; 1004 } 1005 nodeIF = g_list_next( nodeIF ); 1006 } 1007 return 0; 1008 } 1009 1010 /* 1011 * Write data to specified file. 1012 * Enter: addrIndex Address index object. 1013 * newFile New file name. 1014 * return: Status code, from addrIndex->retVal. 1015 * Note: File will be created in directory specified by addrIndex. 1016 */ 1017 static gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) { 1018 FILE *fp; 1019 gchar *fileSpec; 1020 PrefFile *pfile; 1021 1022 cm_return_val_if_fail( addrIndex != NULL, -1 ); 1023 1024 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL ); 1025 addrIndex->retVal = MGU_OPEN_FILE; 1026 pfile = prefs_write_open( fileSpec ); 1027 g_free( fileSpec ); 1028 if( pfile ) { 1029 fp = pfile->fp; 1030 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0) 1031 goto fail; 1032 if (addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX ) < 0) 1033 goto fail; 1034 if (fputs( ">\n", fp ) == EOF) 1035 goto fail; 1036 1037 if (addrindex_write_index( addrIndex, fp ) < 0) 1038 goto fail; 1039 if (addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX ) < 0) 1040 goto fail; 1041 1042 addrIndex->retVal = MGU_SUCCESS; 1043 if (prefs_file_close(pfile) < 0) 1044 addrIndex->retVal = MGU_ERROR_WRITE; 1045 } 1046 1047 fileSpec = NULL; 1048 return addrIndex->retVal; 1049 fail: 1050 g_warning("error writing AB index"); 1051 addrIndex->retVal = MGU_ERROR_WRITE; 1052 if (pfile) 1053 prefs_file_close_revert( pfile ); 1054 return addrIndex->retVal; 1055 } 1056 1057 /* 1058 * Save address index data to original file. 1059 * return: Status code, from addrIndex->retVal. 1060 */ 1061 gint addrindex_save_data( AddressIndex *addrIndex ) { 1062 cm_return_val_if_fail( addrIndex != NULL, -1 ); 1063 1064 addrIndex->retVal = MGU_NO_FILE; 1065 if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal; 1066 if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal; 1067 1068 addrindex_write_to( addrIndex, addrIndex->fileName ); 1069 if( addrIndex->retVal == MGU_SUCCESS ) { 1070 addrIndex->dirtyFlag = FALSE; 1071 } 1072 return addrIndex->retVal; 1073 } 1074 1075 /* 1076 * Save all address book files which may have changed. 1077 * Return: Status code, set if there was a problem saving data. 1078 */ 1079 gint addrindex_save_all_books( AddressIndex *addrIndex ) { 1080 gint retVal = MGU_SUCCESS; 1081 GList *nodeIf, *nodeDS; 1082 1083 nodeIf = addrIndex->interfaceList; 1084 while( nodeIf ) { 1085 AddressInterface *iface = nodeIf->data; 1086 if( iface->type == ADDR_IF_BOOK ) { 1087 nodeDS = iface->listSource; 1088 while( nodeDS ) { 1089 AddressDataSource *ds = nodeDS->data; 1090 AddressBookFile *abf = ds->rawDataSource; 1091 if( addrbook_get_dirty( abf ) ) { 1092 if( addrbook_get_read_flag( abf ) ) { 1093 addrbook_save_data( abf ); 1094 if( abf->retVal != MGU_SUCCESS ) { 1095 retVal = abf->retVal; 1096 } 1097 } 1098 } 1099 nodeDS = g_list_next( nodeDS ); 1100 } 1101 break; 1102 } 1103 nodeIf = g_list_next( nodeIf ); 1104 } 1105 return retVal; 1106 } 1107 1108 1109 /* ********************************************************************** 1110 * Address book conversion to new format. 1111 * *********************************************************************** 1112 */ 1113 1114 #define ELTAG_IF_OLD_FOLDER "folder" 1115 #define ELTAG_IF_OLD_GROUP "group" 1116 #define ELTAG_IF_OLD_ITEM "item" 1117 #define ELTAG_IF_OLD_NAME "name" 1118 #define ELTAG_IF_OLD_ADDRESS "address" 1119 #define ELTAG_IF_OLD_REMARKS "remarks" 1120 #define ATTAG_IF_OLD_NAME "name" 1121 1122 #define TEMPNODE_ROOT 0 1123 #define TEMPNODE_FOLDER 1 1124 #define TEMPNODE_GROUP 2 1125 #define TEMPNODE_ADDRESS 3 1126 1127 typedef struct _AddressCvt_Node AddressCvtNode; 1128 struct _AddressCvt_Node { 1129 gint type; 1130 gchar *name; 1131 gchar *address; 1132 gchar *remarks; 1133 GList *list; 1134 }; 1135 1136 /* 1137 * Parse current address item. 1138 */ 1139 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) { 1140 gchar *element; 1141 guint level; 1142 AddressCvtNode *nn; 1143 1144 nn = g_new0( AddressCvtNode, 1 ); 1145 nn->type = TEMPNODE_ADDRESS; 1146 nn->list = NULL; 1147 1148 level = file->level; 1149 1150 for (;;) { 1151 xml_parse_next_tag(file); 1152 if (file->level < level) return nn; 1153 1154 element = xml_get_element( file ); 1155 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) { 1156 nn->name = g_strdup( element ); 1157 } 1158 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) { 1159 nn->address = g_strdup( element ); 1160 } 1161 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) { 1162 nn->remarks = g_strdup( element ); 1163 } 1164 g_free(element); 1165 xml_parse_next_tag(file); 1166 } 1167 } 1168 1169 /* 1170 * Create a temporary node below specified node. 1171 */ 1172 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) { 1173 AddressCvtNode *nn; 1174 nn = g_new0( AddressCvtNode, 1 ); 1175 nn->type = type; 1176 nn->name = g_strdup( name ); 1177 nn->remarks = g_strdup( rem ); 1178 node->list = g_list_append( node->list, nn ); 1179 return nn; 1180 } 1181 1182 /* 1183 * Process current temporary node. 1184 */ 1185 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) { 1186 GList *attr; 1187 guint prev_level; 1188 AddressCvtNode *newNode = NULL; 1189 gchar *name; 1190 gchar *value; 1191 1192 for (;;) { 1193 prev_level = file->level; 1194 xml_parse_next_tag( file ); 1195 if (file->level < prev_level) return; 1196 name = NULL; 1197 value = NULL; 1198 1199 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) { 1200 attr = xml_get_current_tag_attr(file); 1201 if (attr) { 1202 name = ((XMLAttr *)attr->data)->name; 1203 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) { 1204 value = ((XMLAttr *)attr->data)->value; 1205 } 1206 } 1207 newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" ); 1208 addrindex_add_obj( file, newNode ); 1209 1210 } 1211 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) { 1212 attr = xml_get_current_tag_attr(file); 1213 if (attr) { 1214 name = ((XMLAttr *)attr->data)->name; 1215 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) { 1216 value = ((XMLAttr *)attr->data)->value; 1217 } 1218 } 1219 newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" ); 1220 addrindex_add_obj( file, newNode ); 1221 } 1222 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) { 1223 newNode = addrindex_parse_item( file ); 1224 node->list = g_list_append( node->list, newNode ); 1225 } 1226 else { 1227 g_warning("invalid tag"); 1228 } 1229 } 1230 } 1231 1232 /* 1233 * Consume all nodes below current tag. 1234 */ 1235 static void addrindex_consume_tree( XMLFile *file ) { 1236 guint prev_level; 1237 1238 for (;;) { 1239 prev_level = file->level; 1240 xml_parse_next_tag( file ); 1241 if (file->level < prev_level) 1242 return; 1243 1244 addrindex_consume_tree( file ); 1245 } 1246 } 1247 1248 /* 1249 * Free up temporary tree. 1250 */ 1251 static void addrindex_free_node( AddressCvtNode *node ) { 1252 GList *list = node->list; 1253 1254 while( list ) { 1255 AddressCvtNode *lNode = list->data; 1256 list = g_list_next( list ); 1257 addrindex_free_node( lNode ); 1258 } 1259 node->type = TEMPNODE_ROOT; 1260 g_free( node->name ); 1261 g_free( node->address ); 1262 g_free( node->remarks ); 1263 g_list_free( node->list ); 1264 g_free( node ); 1265 } 1266 1267 /* 1268 * Process address book for specified node. 1269 */ 1270 static void addrindex_process_node( 1271 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent, 1272 ItemGroup *parentGrp, ItemFolder *folderGrp ) 1273 { 1274 GList *list; 1275 ItemFolder *itemFolder = NULL; 1276 ItemGroup *itemGParent = parentGrp; 1277 ItemFolder *itemGFolder = folderGrp; 1278 AddressCache *cache = abf->addressCache; 1279 1280 if( node->type == TEMPNODE_ROOT ) { 1281 itemFolder = parent; 1282 } 1283 else if( node->type == TEMPNODE_FOLDER ) { 1284 itemFolder = addritem_create_item_folder(); 1285 addritem_folder_set_name( itemFolder, node->name ); 1286 addrcache_id_folder( cache, itemFolder ); 1287 addrcache_folder_add_folder( cache, parent, itemFolder ); 1288 itemGFolder = NULL; 1289 } 1290 else if( node->type == TEMPNODE_GROUP ) { 1291 ItemGroup *itemGroup; 1292 gchar *fName; 1293 1294 /* Create a folder for group */ 1295 fName = g_strdup_printf( "Cvt - %s", node->name ); 1296 itemGFolder = addritem_create_item_folder(); 1297 addritem_folder_set_name( itemGFolder, fName ); 1298 addrcache_id_folder( cache, itemGFolder ); 1299 addrcache_folder_add_folder( cache, parent, itemGFolder ); 1300 g_free( fName ); 1301 1302 /* Add group into folder */ 1303 itemGroup = addritem_create_item_group(); 1304 addritem_group_set_name( itemGroup, node->name ); 1305 addrcache_id_group( cache, itemGroup ); 1306 addrcache_folder_add_group( cache, itemGFolder, itemGroup ); 1307 itemGParent = itemGroup; 1308 } 1309 else if( node->type == TEMPNODE_ADDRESS ) { 1310 ItemPerson *itemPerson; 1311 ItemEMail *itemEMail; 1312 1313 /* Create person and email objects */ 1314 itemPerson = addritem_create_item_person(); 1315 addritem_person_set_common_name( itemPerson, node->name ); 1316 addrcache_id_person( cache, itemPerson ); 1317 itemEMail = addritem_create_item_email(); 1318 addritem_email_set_address( itemEMail, node->address ); 1319 addritem_email_set_remarks( itemEMail, node->remarks ); 1320 addrcache_id_email( cache, itemEMail ); 1321 addrcache_person_add_email( cache, itemPerson, itemEMail ); 1322 1323 /* Add person into appropriate folder */ 1324 if( itemGFolder ) { 1325 addrcache_folder_add_person( cache, itemGFolder, itemPerson ); 1326 } 1327 else { 1328 addrcache_folder_add_person( cache, parent, itemPerson ); 1329 } 1330 1331 /* Add email address only into group */ 1332 if( parentGrp ) { 1333 addrcache_group_add_email( cache, parentGrp, itemEMail ); 1334 } 1335 } 1336 1337 list = node->list; 1338 while( list ) { 1339 AddressCvtNode *lNode = list->data; 1340 list = g_list_next( list ); 1341 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder ); 1342 } 1343 } 1344 1345 /* 1346 * Process address book to specified file number. 1347 */ 1348 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) { 1349 gboolean retVal = FALSE; 1350 AddressBookFile *abf = NULL; 1351 AddressCvtNode *rootNode = NULL; 1352 gchar *newFile = NULL; 1353 GList *fileList = NULL; 1354 gint fileNum = 0; 1355 1356 /* Setup root node */ 1357 rootNode = g_new0( AddressCvtNode, 1 ); 1358 rootNode->type = TEMPNODE_ROOT; 1359 rootNode->name = g_strdup( "root" ); 1360 rootNode->list = NULL; 1361 addrindex_add_obj( file, rootNode ); 1362 /* addrindex_print_node( rootNode, stdout ); */ 1363 1364 /* Create new address book */ 1365 abf = addrbook_create_book(); 1366 addrbook_set_name( abf, displayName ); 1367 addrbook_set_path( abf, addrIndex->filePath ); 1368 1369 /* Determine next available file number */ 1370 fileList = addrbook_get_bookfile_list( abf ); 1371 if( fileList ) { 1372 fileNum = 1 + abf->maxValue; 1373 } 1374 g_list_free( fileList ); 1375 fileList = NULL; 1376 1377 newFile = addrbook_gen_new_file_name( fileNum ); 1378 if( newFile ) { 1379 addrbook_set_file( abf, newFile ); 1380 } 1381 1382 addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL ); 1383 1384 #ifdef DEBUG_ADDRBOOK 1385 addrbook_dump_book( abf, stdout ); 1386 #endif 1387 addrbook_save_data( abf ); 1388 addrIndex->retVal = abf->retVal; 1389 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE; 1390 1391 addrbook_free_book( abf ); 1392 abf = NULL; 1393 addrindex_free_node( rootNode ); 1394 rootNode = NULL; 1395 1396 /* Create entries in address index */ 1397 if( retVal ) { 1398 abf = addrbook_create_book(); 1399 addrbook_set_name( abf, displayName ); 1400 addrbook_set_path( abf, addrIndex->filePath ); 1401 addrbook_set_file( abf, newFile ); 1402 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf ); 1403 } 1404 1405 return retVal; 1406 } 1407 1408 /* 1409 * Process tree converting data. 1410 */ 1411 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) { 1412 guint prev_level; 1413 XMLTag *xtag; 1414 1415 /* Process file */ 1416 for (;;) { 1417 prev_level = file->level; 1418 xml_parse_next_tag( file ); 1419 if (file->level < prev_level) return; 1420 1421 xtag = xml_get_current_tag( file ); 1422 /* g_print( "tag : %d : %s\n", prev_level, xtag->tag ); */ 1423 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) { 1424 if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) { 1425 addrIndex->needsConversion = FALSE; 1426 addrIndex->wasConverted = TRUE; 1427 continue; 1428 } 1429 return; 1430 } 1431 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) { 1432 if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) { 1433 addrIndex->needsConversion = FALSE; 1434 addrIndex->wasConverted = TRUE; 1435 continue; 1436 } 1437 return; 1438 } 1439 addrindex_consume_tree( file ); 1440 } 1441 } 1442 1443 static gint addrindex_convert_data( AddressIndex *addrIndex ) { 1444 XMLFile *file = NULL; 1445 gchar *fileSpec; 1446 1447 fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL ); 1448 addrIndex->retVal = MGU_NO_FILE; 1449 file = xml_open_file( fileSpec ); 1450 g_free( fileSpec ); 1451 1452 if( file == NULL ) { 1453 /* g_print( " file '%s' does not exist.\n", addrIndex->fileName ); */ 1454 return addrIndex->retVal; 1455 } 1456 1457 addrIndex->retVal = MGU_BAD_FORMAT; 1458 if( xml_get_dtd( file ) == 0 ) { 1459 if( xml_parse_next_tag( file ) == 0 ) { 1460 if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) { 1461 addrindex_convert_tree( addrIndex, file ); 1462 } 1463 } 1464 } 1465 xml_close_file( file ); 1466 return addrIndex->retVal; 1467 } 1468 1469 /* 1470 * Create a new address book file. 1471 */ 1472 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) { 1473 gboolean retVal = FALSE; 1474 AddressBookFile *abf = NULL; 1475 gchar *newFile = NULL; 1476 GList *fileList = NULL; 1477 gint fileNum = 0; 1478 1479 /* Create new address book */ 1480 abf = addrbook_create_book(); 1481 addrbook_set_name( abf, displayName ); 1482 addrbook_set_path( abf, addrIndex->filePath ); 1483 1484 /* Determine next available file number */ 1485 fileList = addrbook_get_bookfile_list( abf ); 1486 if( fileList ) { 1487 fileNum = 1 + abf->maxValue; 1488 } 1489 g_list_free( fileList ); 1490 fileList = NULL; 1491 1492 newFile = addrbook_gen_new_file_name( fileNum ); 1493 if( newFile ) { 1494 addrbook_set_file( abf, newFile ); 1495 } 1496 1497 addrbook_save_data( abf ); 1498 addrIndex->retVal = abf->retVal; 1499 if( abf->retVal == MGU_SUCCESS ) retVal = TRUE; 1500 addrbook_free_book( abf ); 1501 abf = NULL; 1502 1503 /* Create entries in address index */ 1504 if( retVal ) { 1505 abf = addrbook_create_book(); 1506 addrbook_set_name( abf, displayName ); 1507 addrbook_set_path( abf, addrIndex->filePath ); 1508 addrbook_set_file( abf, newFile ); 1509 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf ); 1510 } 1511 1512 return retVal; 1513 } 1514 1515 /* 1516 * Read data for address index performing a conversion if necesary. 1517 * Enter: addrIndex Address index object. 1518 * return: Status code, from addrIndex->retVal. 1519 * Note: New address book files will be created in directory specified by 1520 * addrIndex. Three files will be created, for the following: 1521 * "Common addresses" 1522 * "Personal addresses" 1523 * "Gathered addresses" - a new address book. 1524 */ 1525 gint addrindex_read_data( AddressIndex *addrIndex ) { 1526 cm_return_val_if_fail( addrIndex != NULL, -1 ); 1527 1528 addrIndex->conversionError = FALSE; 1529 addrindex_read_file( addrIndex ); 1530 if( addrIndex->retVal == MGU_SUCCESS ) { 1531 if( addrIndex->needsConversion ) { 1532 if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) 1533 addrIndex->conversionError = FALSE; 1534 else 1535 addrIndex->conversionError = TRUE; 1536 } 1537 addrIndex->dirtyFlag = TRUE; 1538 } 1539 return addrIndex->retVal; 1540 } 1541 1542 /* 1543 * Create new address books for a new address index. 1544 * Enter: addrIndex Address index object. 1545 * return: Status code, from addrIndex->retVal. 1546 * Note: New address book files will be created in directory specified by 1547 * addrIndex. Three files will be created, for the following: 1548 * "Common addresses" 1549 * "Personal addresses" 1550 * "Gathered addresses" - a new address book. 1551 */ 1552 gint addrindex_create_new_books( AddressIndex *addrIndex ) { 1553 gboolean flg; 1554 1555 cm_return_val_if_fail( addrIndex != NULL, -1 ); 1556 1557 flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON ); 1558 if( flg ) { 1559 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL ); 1560 addrIndex->dirtyFlag = TRUE; 1561 } 1562 return addrIndex->retVal; 1563 } 1564 1565 /* ********************************************************************** 1566 * New interface stuff. 1567 * *********************************************************************** 1568 */ 1569 1570 /* 1571 * Return modified flag for specified data source. 1572 */ 1573 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) { 1574 gboolean retVal = FALSE; 1575 AddressInterface *iface; 1576 1577 if( ds == NULL ) return retVal; 1578 iface = ds->interface; 1579 if( iface == NULL ) return retVal; 1580 if( iface->getModifyFlag ) { 1581 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource ); 1582 } 1583 return retVal; 1584 } 1585 1586 /* 1587 * Return accessed flag for specified data source. 1588 */ 1589 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) { 1590 gboolean retVal = FALSE; 1591 AddressInterface *iface; 1592 1593 if( ds == NULL ) return retVal; 1594 iface = ds->interface; 1595 if( iface == NULL ) return retVal; 1596 if( iface->getAccessFlag ) { 1597 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource ); 1598 } 1599 return retVal; 1600 } 1601 1602 /* 1603 * Return data read flag for specified data source. 1604 */ 1605 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) { 1606 gboolean retVal = TRUE; 1607 AddressInterface *iface; 1608 1609 if( ds == NULL ) return retVal; 1610 iface = ds->interface; 1611 if( iface == NULL ) return retVal; 1612 if( iface->getReadFlag ) { 1613 retVal = ( iface->getReadFlag ) ( ds->rawDataSource ); 1614 } 1615 return retVal; 1616 } 1617 1618 /* 1619 * Return status code for specified data source. 1620 */ 1621 gint addrindex_ds_get_status_code( AddressDataSource *ds ) { 1622 gint retVal = MGU_SUCCESS; 1623 AddressInterface *iface; 1624 1625 if( ds == NULL ) return retVal; 1626 iface = ds->interface; 1627 if( iface == NULL ) return retVal; 1628 if( iface->getStatusCode ) { 1629 retVal = ( iface->getStatusCode ) ( ds->rawDataSource ); 1630 } 1631 return retVal; 1632 } 1633 1634 /* 1635 * Return data read flag for specified data source. 1636 */ 1637 gint addrindex_ds_read_data( AddressDataSource *ds ) { 1638 gint retVal = MGU_SUCCESS; 1639 AddressInterface *iface; 1640 1641 if( ds == NULL ) return retVal; 1642 iface = ds->interface; 1643 if( iface == NULL ) return retVal; 1644 if( iface->getReadData ) { 1645 /* 1646 gchar *name = ( iface->getName ) ( ds->rawDataSource ); 1647 g_print( "addrindex_ds_read_data...reading:::%s:::\n", name ); 1648 */ 1649 retVal = ( iface->getReadData ) ( ds->rawDataSource ); 1650 } 1651 return retVal; 1652 } 1653 1654 /* 1655 * Return data read flag for specified data source. 1656 */ 1657 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) { 1658 ItemFolder *retVal = NULL; 1659 AddressInterface *iface; 1660 1661 if( ds == NULL ) return retVal; 1662 iface = ds->interface; 1663 if( iface == NULL ) return retVal; 1664 if( iface->getRootFolder ) { 1665 retVal = ( iface->getRootFolder ) ( ds->rawDataSource ); 1666 } 1667 return retVal; 1668 } 1669 1670 /* 1671 * Return name for specified data source. 1672 */ 1673 gchar *addrindex_ds_get_name( AddressDataSource *ds ) { 1674 gchar *retVal = FALSE; 1675 AddressInterface *iface; 1676 1677 if( ds == NULL ) return retVal; 1678 iface = ds->interface; 1679 if( iface == NULL ) return retVal; 1680 if( iface->getName ) { 1681 retVal = ( iface->getName ) ( ds->rawDataSource ); 1682 } 1683 return retVal; 1684 } 1685 1686 /* 1687 * Set the access flag inside the data source. 1688 */ 1689 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) { 1690 AddressInterface *iface; 1691 1692 if( ds == NULL ) return; 1693 iface = ds->interface; 1694 if( iface == NULL ) return; 1695 if( iface->setAccessFlag ) { 1696 ( iface->setAccessFlag ) ( ds->rawDataSource, value ); 1697 } 1698 } 1699 1700 /* 1701 * Return read only flag for specified data source. 1702 */ 1703 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) { 1704 AddressInterface *iface; 1705 if( ds == NULL ) return TRUE; 1706 iface = ds->interface; 1707 if( iface == NULL ) return TRUE; 1708 return iface->readOnly; 1709 } 1710 1711 /* 1712 * Return list of all persons for specified data source. 1713 */ 1714 static GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) { 1715 GList *retVal = NULL; 1716 AddressInterface *iface; 1717 1718 if( ds == NULL ) return retVal; 1719 iface = ds->interface; 1720 if( iface == NULL ) return retVal; 1721 if( iface->getAllPersons ) { 1722 retVal = ( iface->getAllPersons ) ( ds->rawDataSource ); 1723 } 1724 return retVal; 1725 } 1726 1727 /* 1728 * Return list of all groups for specified data source. 1729 */ 1730 static GList *addrindex_ds_get_all_groups( AddressDataSource *ds ) { 1731 GList *retVal = NULL; 1732 AddressInterface *iface; 1733 1734 if( ds == NULL ) return retVal; 1735 iface = ds->interface; 1736 if( iface == NULL ) return retVal; 1737 if( iface->getAllGroups ) { 1738 retVal = ( iface->getAllGroups ) ( ds->rawDataSource ); 1739 } 1740 return retVal; 1741 } 1742 1743 /* ********************************************************************** 1744 * Address search stuff. 1745 * *********************************************************************** 1746 */ 1747 1748 /** 1749 * Setup or register the dynamic search that will be performed. The search 1750 * is registered with the query manager. 1751 * 1752 * \param searchTerm Search term. A private copy will be made. 1753 * \param callBackEntry Callback function that should be called when 1754 * each entry is received. 1755 * \param callBackEnd Callback function that should be called when 1756 * search has finished running. 1757 * \return ID allocated to query that will be executed. 1758 */ 1759 gint addrindex_setup_search( 1760 const gchar *searchTerm, void *callBackEnd, void *callBackEntry ) 1761 { 1762 QueryRequest *req; 1763 gint queryID; 1764 1765 /* Set up a dynamic address query */ 1766 req = qrymgr_add_request( searchTerm, callBackEnd, callBackEntry ); 1767 queryID = req->queryID; 1768 qryreq_set_search_type( req, ADDRSEARCH_DYNAMIC ); 1769 1770 /* g_print( "***> query ID ::%d::\n", queryID ); */ 1771 return queryID; 1772 } 1773 1774 /** 1775 * Execute the previously registered dynamic search. 1776 * 1777 * \param req Address query object to execute. 1778 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if 1779 * failed. 1780 */ 1781 static gboolean addrindex_start_dynamic( QueryRequest *req ) { 1782 AddressInterface *iface; 1783 GList *nodeIf; 1784 GList *nodeDS; 1785 1786 nodeIf = _addressIndex_->searchOrder; 1787 while( nodeIf ) { 1788 iface = nodeIf->data; 1789 nodeIf = g_list_next( nodeIf ); 1790 1791 if( ! iface->useInterface ) { 1792 continue; 1793 } 1794 if( ! iface->externalQuery ) { 1795 continue; 1796 } 1797 1798 nodeDS = iface->listSource; 1799 while( nodeDS ) { 1800 nodeDS = g_list_next( nodeDS ); 1801 } 1802 } 1803 return TRUE; 1804 } 1805 1806 /** 1807 * Stop the previously registered search. 1808 * 1809 * \param queryID ID of search query to stop. 1810 */ 1811 void addrindex_stop_search( const gint queryID ){ 1812 QueryRequest *req; 1813 AddrQueryObject *aqo; 1814 GList *node; 1815 1816 /* g_print( "addrindex_stop_search/queryID=%d\n", queryID ); */ 1817 /* If query ID does not match, search has not been setup */ 1818 req = qrymgr_find_request( queryID ); 1819 if( req == NULL ) { 1820 return; 1821 } 1822 1823 /* Stop all queries that were associated with request */ 1824 node = req->queryList; 1825 while( node ) { 1826 aqo = node->data; 1827 node->data = NULL; 1828 node = g_list_next( node ); 1829 } 1830 1831 /* Delete query request */ 1832 qrymgr_delete_request( queryID ); 1833 } 1834 1835 /** 1836 * Setup or register the explicit search that will be performed. The search is 1837 * registered with the query manager. 1838 * 1839 * \param ds Data source to search. 1840 * \param searchTerm Search term to locate. 1841 * \param folder Folder to receive search results; may be NULL. 1842 * \param callbackEnd Function to call when search has terminated. 1843 * \param callbackEntry Function to called for each entry processed. 1844 * \return ID allocated to query that will be executed. 1845 */ 1846 gint addrindex_setup_explicit_search( 1847 AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder, 1848 void *callBackEnd, void *callBackEntry ) 1849 { 1850 QueryRequest *req; 1851 gint queryID; 1852 gchar *name; 1853 gchar *mySearch; 1854 1855 /* Name the query */ 1856 name = g_strdup_printf( "Search '%s'", searchTerm ); 1857 1858 /* Set up query request */ 1859 if (!strcmp(searchTerm, "*")) 1860 mySearch = g_strdup("*@"); 1861 else 1862 mySearch = g_strdup(searchTerm); 1863 1864 req = qrymgr_add_request( mySearch, callBackEnd, callBackEntry ); 1865 1866 g_free(mySearch); 1867 1868 qryreq_set_search_type( req, ADDRSEARCH_EXPLICIT ); 1869 queryID = req->queryID; 1870 1871 qrymgr_delete_request( queryID ); 1872 queryID = 0; 1873 g_free( name ); 1874 1875 return queryID; 1876 } 1877 1878 /** 1879 * Start the previously registered search. 1880 * 1881 * \param queryID ID of search query to be executed. 1882 * \return <i>TRUE</i> if search started successfully, or <i>FALSE</i> if 1883 * failed. 1884 */ 1885 gboolean addrindex_start_search( const gint queryID ) { 1886 gboolean retVal; 1887 QueryRequest *req; 1888 AddrSearchType searchType; 1889 1890 retVal = FALSE; 1891 /* g_print( "addrindex_start_search/queryID=%d\n", queryID ); */ 1892 req = qrymgr_find_request( queryID ); 1893 if( req == NULL ) { 1894 return retVal; 1895 } 1896 1897 searchType = req->searchType; 1898 if( searchType == ADDRSEARCH_DYNAMIC ) { 1899 retVal = addrindex_start_dynamic( req ); 1900 } 1901 else if( searchType == ADDRSEARCH_EXPLICIT ) { 1902 retVal = FALSE; 1903 } 1904 1905 return retVal; 1906 } 1907 1908 /** 1909 * Remove results (folder and data) for specified data source and folder. 1910 * \param ds Data source to process. 1911 * \param folder Results folder to remove. 1912 */ 1913 void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) { 1914 AddrBookBase *adbase; 1915 gint queryID = 0; 1916 1917 /* g_print( "addrindex_remove_results/start\n" ); */ 1918 1919 /* Test for folder */ 1920 if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return; 1921 /* g_print( "folder name ::%s::\n", ADDRITEM_NAME(folder) ); */ 1922 adbase = ( AddrBookBase * ) ds->rawDataSource; 1923 if( adbase == NULL ) return; 1924 1925 /* Hide folder to prevent re-display */ 1926 addritem_folder_set_hidden( folder, TRUE ); 1927 1928 /* Delete query request */ 1929 if( queryID > 0 ) { 1930 qrymgr_delete_request( queryID ); 1931 } 1932 } 1933 1934 /* ********************************************************************** 1935 * Address completion stuff. 1936 * *********************************************************************** 1937 */ 1938 1939 static void addrindex_load_completion_load_persons( 1940 gint (*callBackFunc) ( const gchar *, const gchar *, 1941 const gchar *, const gchar *, GList * ), 1942 AddressDataSource *ds) 1943 { 1944 GList *listP, *nodeP; 1945 GList *nodeM; 1946 gchar *sName; 1947 1948 /* Read address book */ 1949 if( addrindex_ds_get_modify_flag( ds ) ) { 1950 addrindex_ds_read_data( ds ); 1951 } 1952 1953 if( ! addrindex_ds_get_read_flag( ds ) ) { 1954 addrindex_ds_read_data( ds ); 1955 } 1956 1957 /* Get all groups */ 1958 listP = addrindex_ds_get_all_groups( ds ); 1959 nodeP = listP; 1960 while( nodeP ) { 1961 ItemGroup *group = nodeP->data; 1962 GList *emails = NULL; 1963 for (nodeM = group->listEMail; nodeM; nodeM = g_list_next(nodeM)) { 1964 ItemEMail *email = nodeM->data; 1965 if (email->address) 1966 emails = g_list_append(emails, email); 1967 } 1968 callBackFunc( ((AddrItemObject *)group)->name, NULL, 1969 NULL, NULL, emails ); 1970 nodeP = g_list_next( nodeP ); 1971 } 1972 1973 /* Free up the list */ 1974 g_list_free( listP ); 1975 /* Get all persons */ 1976 listP = addrindex_ds_get_all_persons( ds ); 1977 nodeP = listP; 1978 while( nodeP ) { 1979 ItemPerson *person = nodeP->data; 1980 nodeM = person->listEMail; 1981 1982 /* Figure out name to use */ 1983 sName = ADDRITEM_NAME(person); 1984 if( sName == NULL || *sName == '\0' ) { 1985 sName = person->nickName; 1986 } 1987 1988 /* Process each E-Mail address */ 1989 while( nodeM ) { 1990 ItemEMail *email = nodeM->data; 1991 1992 callBackFunc( sName, email->address, person->nickName, 1993 ADDRITEM_NAME(email), NULL ); 1994 1995 nodeM = g_list_next( nodeM ); 1996 } 1997 nodeP = g_list_next( nodeP ); 1998 } 1999 2000 /* Free up the list */ 2001 g_list_free( listP ); 2002 } 2003 2004 /** 2005 * This function is used by the address completion function to load 2006 * addresses for all non-external address book interfaces. 2007 * 2008 * \param callBackFunc Function to be called when an address is 2009 * to be loaded. 2010 * \param folderpath Addressbook's Book/folder path to restrict to (if NULL or "" 2011 * or "Any", assume the whole addressbook 2012 * \return <i>TRUE</i> if data loaded, <i>FALSE</i> if address index not loaded. 2013 */ 2014 2015 gboolean addrindex_load_completion( 2016 gint (*callBackFunc) ( const gchar *, const gchar *, 2017 const gchar *, const gchar *, GList * ), 2018 gchar *folderpath ) 2019 { 2020 GList *nodeIf, *nodeDS; 2021 2022 if( folderpath != NULL ) { 2023 AddressDataSource *book; 2024 ItemFolder* folder; 2025 2026 /* split the folder path we've received, we'll try to match this path, subpath by 2027 subpath against the book/folder structure in order and restrict loading of 2028 addresses to that subpart (if matches). book/folder path must exist and 2029 folderpath must not be empty or NULL */ 2030 2031 if( ! addressbook_peek_folder_exists( folderpath, &book, &folder ) ) { 2032 g_warning("addrindex_load_completion: folder path '%s' doesn't exist", folderpath); 2033 return FALSE; 2034 } 2035 2036 if( folder != NULL ) { 2037 2038 GList *items; 2039 GList *nodeM; 2040 gchar *sName; 2041 ItemPerson *person; 2042 2043 debug_print("addrindex_load_completion: folder %p '%s'\n", folder, folder->obj.name); 2044 2045 /* Load email addresses */ 2046 items = addritem_folder_get_person_list( folder ); 2047 for( ; items != NULL; items = g_list_next( items ) ) { 2048 person = items->data; 2049 nodeM = person->listEMail; 2050 2051 /* Figure out name to use */ 2052 sName = ADDRITEM_NAME(person); 2053 if( sName == NULL || *sName == '\0' ) { 2054 sName = person->nickName; 2055 } 2056 2057 /* Process each E-Mail address */ 2058 while( nodeM ) { 2059 ItemEMail *email = nodeM->data; 2060 2061 callBackFunc( sName, email->address, person->nickName, 2062 ADDRITEM_NAME(email), NULL ); 2063 2064 nodeM = g_list_next( nodeM ); 2065 } 2066 } 2067 /* Free up the list (but not the data inside the 2068 * individual list items) */ 2069 g_list_free( items ); 2070 2071 return TRUE; 2072 2073 } else { 2074 2075 if( book != NULL ) { 2076 2077 AddressBookFile *abf = book->rawDataSource; 2078 2079 debug_print("addrindex_load_completion: book %p '%s'\n", book, abf?abf->fileName:"(null)"); 2080 2081 addrindex_load_completion_load_persons( callBackFunc, book ); 2082 2083 return TRUE; 2084 2085 } else { 2086 g_warning("addrindex_load_completion: book/folder path is valid but got no pointer"); 2087 } 2088 } 2089 return FALSE; 2090 2091 } else { 2092 2093 nodeIf = addrindex_get_interface_list( _addressIndex_ ); 2094 while( nodeIf ) { 2095 AddressInterface *iface = nodeIf->data; 2096 2097 nodeIf = g_list_next( nodeIf ); 2098 2099 if( ! iface->useInterface || iface->externalQuery ) 2100 continue; 2101 2102 nodeDS = iface->listSource; 2103 while( nodeDS ) { 2104 addrindex_load_completion_load_persons( callBackFunc, nodeDS->data ); 2105 nodeDS = g_list_next( nodeDS ); 2106 } 2107 } 2108 } 2109 2110 return TRUE; 2111 } 2112 2113 /** 2114 * This function can be used to collect information about 2115 * addressbook entries that contain a specific attribute. 2116 * 2117 * \param attr Name of attribute to look for 2118 * \param callBackFunc Function to be called when a matching attribute was found 2119 * \return <i>TRUE</i> 2120 */ 2121 gboolean addrindex_load_person_attribute( 2122 const gchar *attr, 2123 gint (*callBackFunc) ( ItemPerson *, const gchar * ) ) 2124 { 2125 AddressDataSource *ds; 2126 GList *nodeIf, *nodeDS; 2127 GList *listP, *nodeP; 2128 GList *nodeA; 2129 2130 nodeIf = addrindex_get_interface_list( _addressIndex_ ); 2131 while( nodeIf ) { 2132 gchar *cur_bname; 2133 AddressInterface *iface = nodeIf->data; 2134 2135 nodeIf = g_list_next( nodeIf ); 2136 2137 if( ! iface->useInterface || iface->externalQuery ) 2138 continue; 2139 2140 nodeDS = iface->listSource; 2141 while( nodeDS ) { 2142 ds = nodeDS->data; 2143 2144 /* Read address book */ 2145 if( addrindex_ds_get_modify_flag( ds ) ) { 2146 addrindex_ds_read_data( ds ); 2147 } 2148 2149 if( ! addrindex_ds_get_read_flag( ds ) ) { 2150 addrindex_ds_read_data( ds ); 2151 } 2152 2153 /* Check addressbook name */ 2154 cur_bname = addrindex_ds_get_name( ds ); 2155 2156 /* Get all persons */ 2157 listP = addrindex_ds_get_all_persons( ds ); 2158 nodeP = listP; 2159 while( nodeP ) { 2160 ItemPerson *person = nodeP->data; 2161 2162 /* Return all ItemPerson's if attr is NULL */ 2163 if( attr == NULL ) { 2164 callBackFunc(person, cur_bname); 2165 } 2166 2167 /* Return ItemPerson's with specific attribute */ 2168 else { 2169 nodeA = person->listAttrib; 2170 /* Process each User Attribute */ 2171 while( nodeA ) { 2172 UserAttribute *attrib = nodeA->data; 2173 if( attrib->name && 2174 !strcmp( attrib->name,attr ) ) { 2175 callBackFunc(person, cur_bname); 2176 } 2177 nodeA = g_list_next( nodeA ); 2178 } 2179 } 2180 nodeP = g_list_next( nodeP ); 2181 } 2182 /* Free up the list */ 2183 g_list_free( listP ); 2184 2185 nodeDS = g_list_next( nodeDS ); 2186 } 2187 } 2188 return TRUE; 2189 } 2190 2191 /** 2192 * This function can be used to collect information about 2193 * addressbook entries 2194 * 2195 * \param callBackFunc Function to be called for each ItemPerson 2196 * \return <i>TRUE</i> 2197 */ 2198 gboolean addrindex_load_person_ds( gint (*callBackFunc) 2199 ( ItemPerson *, AddressDataSource * ) ) 2200 { 2201 AddressDataSource *ds; 2202 GList *nodeIf, *nodeDS; 2203 GList *listP, *nodeP; 2204 2205 nodeIf = addrindex_get_interface_list( _addressIndex_ ); 2206 while( nodeIf ) { 2207 AddressInterface *iface = nodeIf->data; 2208 2209 nodeIf = g_list_next( nodeIf ); 2210 2211 if( ! iface->useInterface || iface->externalQuery ) 2212 continue; 2213 2214 nodeDS = iface->listSource; 2215 while( nodeDS ) { 2216 ds = nodeDS->data; 2217 2218 /* Read address book */ 2219 if( addrindex_ds_get_modify_flag( ds ) ) { 2220 addrindex_ds_read_data( ds ); 2221 } 2222 2223 if( ! addrindex_ds_get_read_flag( ds ) ) { 2224 addrindex_ds_read_data( ds ); 2225 } 2226 2227 /* Get all persons */ 2228 listP = addrindex_ds_get_all_persons( ds ); 2229 nodeP = listP; 2230 while( nodeP ) { 2231 ItemPerson *person = nodeP->data; 2232 2233 callBackFunc(person, ds); 2234 nodeP = g_list_next( nodeP ); 2235 } 2236 /* Free up the list */ 2237 g_list_free( listP ); 2238 2239 nodeDS = g_list_next( nodeDS ); 2240 } 2241 } 2242 return TRUE; 2243 } 2244 2245 gchar *addrindex_get_picture_file(const gchar *emailaddr) 2246 { 2247 AddressDataSource *ds; 2248 GList *nodeIf, *nodeDS; 2249 GList *listP, *nodeP; 2250 gboolean found = FALSE; 2251 gchar *filename = NULL; 2252 gchar *raw_addr = NULL; 2253 2254 if (!emailaddr) 2255 return NULL; 2256 2257 Xstrdup_a(raw_addr, emailaddr, return NULL); 2258 extract_address(raw_addr); 2259 2260 nodeIf = addrindex_get_interface_list( _addressIndex_ ); 2261 while( nodeIf ) { 2262 AddressInterface *iface = nodeIf->data; 2263 2264 nodeIf = g_list_next( nodeIf ); 2265 2266 if( ! iface->useInterface || iface->externalQuery ) 2267 continue; 2268 2269 nodeDS = iface->listSource; 2270 while( nodeDS && !found) { 2271 ds = nodeDS->data; 2272 2273 /* Read address book */ 2274 if( addrindex_ds_get_modify_flag( ds ) ) { 2275 addrindex_ds_read_data( ds ); 2276 } 2277 2278 if( ! addrindex_ds_get_read_flag( ds ) ) { 2279 addrindex_ds_read_data( ds ); 2280 } 2281 2282 /* Get all persons */ 2283 listP = addrindex_ds_get_all_persons( ds ); 2284 nodeP = listP; 2285 while( nodeP && !found) { 2286 GList *nodeM; 2287 ItemPerson *person = nodeP->data; 2288 nodeM = person->listEMail; 2289 while(nodeM) { 2290 ItemEMail *email = nodeM->data; 2291 if (email->address && !strcasecmp(raw_addr, email->address)) { 2292 found = TRUE; 2293 filename = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, 2294 ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 2295 person->picture, ".png", NULL ); 2296 break; 2297 } 2298 nodeM = nodeM->next; 2299 } 2300 nodeP = g_list_next( nodeP ); 2301 } 2302 /* Free up the list */ 2303 g_list_free( listP ); 2304 2305 nodeDS = g_list_next( nodeDS ); 2306 } 2307 } 2308 2309 return filename; 2310 }