addrbook.c (60213B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 2001-2022 Match Grun and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /* General functions for accessing address book files */ 20 21 #include <glib.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <sys/stat.h> 25 #include <math.h> 26 #include <setjmp.h> 27 28 #include "utils.h" 29 #include "xml.h" 30 #include "mgutils.h" 31 #include "addritem.h" 32 #include "addrcache.h" 33 #include "addrbook.h" 34 #include "adbookbase.h" 35 #include "file-utils.h" 36 37 #include "prefs_gtk.h" 38 #include "codeconv.h" 39 40 #define ADDRBOOK_MAX_SEARCH_COUNT 1000 41 #define ADDRBOOK_PREFIX "addrbook-" 42 #define ADDRBOOK_SUFFIX ".xml" 43 #define FILE_NUMDIGITS 6 44 45 #define ID_TIME_OFFSET 998000000 46 47 #ifdef DEBUG_ADDRBOOK 48 static void addrbook_print_book ( AddressBookFile *book, FILE *stream ); 49 #endif 50 51 /** 52 * Create new address book 53 * \return Address book. 54 */ 55 AddressBookFile *addrbook_create_book() 56 { 57 AddressBookFile *book; 58 59 book = g_new0(AddressBookFile, 1); 60 book->type = ADBOOKTYPE_BOOK; 61 book->addressCache = addrcache_create(); 62 book->retVal = MGU_SUCCESS; 63 book->path = NULL; 64 book->fileName = NULL; 65 book->maxValue = 0; 66 book->tempList = NULL; 67 book->tempHash = NULL; 68 book->addressCache->modified = TRUE; 69 70 return book; 71 } 72 73 /** 74 * Specify name to be used 75 * \param book Address book. 76 * \param value Name. 77 */ 78 void addrbook_set_name(AddressBookFile *book, const gchar *value) 79 { 80 cm_return_if_fail(book != NULL); 81 addrcache_set_name(book->addressCache, value); 82 } 83 84 gchar *addrbook_get_name(AddressBookFile *book) 85 { 86 cm_return_val_if_fail(book != NULL, NULL); 87 return addrcache_get_name(book->addressCache); 88 } 89 90 /** 91 * Specify path to address book file. 92 * \param book Address book. 93 * \param value Path. 94 */ 95 void addrbook_set_path(AddressBookFile *book, const gchar *value) 96 { 97 cm_return_if_fail(book != NULL); 98 book->path = mgu_replace_string(book->path, value); 99 addrcache_set_dirty(book->addressCache, TRUE); 100 } 101 102 /** 103 * Specify filename to be used 104 * \param book Address book. 105 * \param value Filename. 106 */ 107 void addrbook_set_file(AddressBookFile *book, const gchar *value) 108 { 109 cm_return_if_fail(book != NULL); 110 book->fileName = mgu_replace_string(book->fileName, value); 111 addrcache_set_dirty(book->addressCache, TRUE); 112 } 113 114 gboolean addrbook_get_modified(AddressBookFile *book) 115 { 116 cm_return_val_if_fail(book != NULL, FALSE); 117 return book->addressCache->modified; 118 } 119 120 gboolean addrbook_get_accessed(AddressBookFile *book) 121 { 122 cm_return_val_if_fail(book != NULL, FALSE); 123 return book->addressCache->accessFlag; 124 } 125 126 /** 127 * Specify address book as accessed. 128 * \param book Address book. 129 * \param value Value. 130 */ 131 void addrbook_set_accessed(AddressBookFile *book, const gboolean value) 132 { 133 cm_return_if_fail(book != NULL); 134 book->addressCache->accessFlag = value; 135 } 136 137 gboolean addrbook_get_read_flag(AddressBookFile *book) 138 { 139 cm_return_val_if_fail(book != NULL, FALSE); 140 return book->addressCache->dataRead; 141 } 142 143 gint addrbook_get_status(AddressBookFile *book) 144 { 145 cm_return_val_if_fail(book != NULL, -1); 146 return book->retVal; 147 } 148 149 ItemFolder *addrbook_get_root_folder(AddressBookFile *book) 150 { 151 cm_return_val_if_fail(book != NULL, NULL); 152 return addrcache_get_root_folder(book->addressCache); 153 } 154 155 GList *addrbook_get_list_folder(AddressBookFile *book) 156 { 157 cm_return_val_if_fail(book != NULL, NULL); 158 return addrcache_get_list_folder(book->addressCache); 159 } 160 161 GList *addrbook_get_list_person(AddressBookFile *book) 162 { 163 cm_return_val_if_fail(book != NULL, NULL); 164 return addrcache_get_list_person(book->addressCache); 165 } 166 167 gboolean addrbook_get_dirty(AddressBookFile *book) 168 { 169 cm_return_val_if_fail(book != NULL, FALSE); 170 return addrcache_get_dirty(book->addressCache); 171 } 172 173 /** 174 * Set address book as dirty (needs to be written to file). 175 * \param book Address book. 176 * \param value Dirty flag. 177 */ 178 void addrbook_set_dirty(AddressBookFile *book, const gboolean value) 179 { 180 cm_return_if_fail(book != NULL); 181 addrcache_set_dirty(book->addressCache, value); 182 } 183 184 /** 185 * Free address book. 186 * \param book Address book. 187 */ 188 void addrbook_free_book(AddressBookFile *book) 189 { 190 cm_return_if_fail(book != NULL); 191 192 /* Clear cache */ 193 addrcache_free(book->addressCache); 194 195 /* Free up internal objects */ 196 g_free(book->path); 197 g_free(book->fileName); 198 g_list_free(book->tempList); 199 200 book->path = NULL; 201 book->fileName = NULL; 202 book->maxValue = 0; 203 book->tempList = NULL; 204 book->tempHash = NULL; 205 206 book->type = ADBOOKTYPE_NONE; 207 book->addressCache = NULL; 208 book->retVal = MGU_SUCCESS; 209 210 g_free(book); 211 } 212 213 #ifdef DEBUG_ADDRBOOK 214 /** 215 * Print address book header. 216 * \param book Address book. 217 * \param stream Output stream. 218 */ 219 static void addrbook_print_book(AddressBookFile *book, FILE *stream) 220 { 221 cm_return_if_fail(book != NULL); 222 223 fprintf(stream, "AddressBook:\n"); 224 fprintf(stream, "\tpath : '%s'\n", book->path); 225 fprintf(stream, "\tfile : '%s'\n", book->fileName); 226 fprintf(stream, "\tstatus : %d\n", book->retVal ); 227 addrcache_print(book->addressCache, stream); 228 } 229 230 /** 231 * Dump entire address book traversing folders. 232 * \param book Address book. 233 * \param stream Output stream. 234 */ 235 void addrbook_dump_book(AddressBookFile *book, FILE *stream) 236 { 237 ItemFolder *folder; 238 239 cm_return_if_fail(book != NULL); 240 241 addrbook_print_book(book, stream); 242 folder = book->addressCache->rootFolder; 243 addritem_print_item_folder(folder, stream); 244 } 245 #endif 246 247 /** 248 * Remove specified group from address book. Note that object should still 249 * be freed. 250 * Specify name to be used 251 * \param book Address book. 252 * \param group Group to remove. 253 * \param value Name. 254 * \return Group, or NULL if not found. 255 */ 256 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group) 257 { 258 cm_return_val_if_fail(book != NULL, NULL); 259 return addrcache_remove_group(book->addressCache, group); 260 } 261 262 /** 263 * Remove specified person from address book. Note that object should still 264 * be freed. 265 * \param book Address book. 266 * \param person Person to remove. 267 * \return Person, or NULL if not found. 268 */ 269 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person) 270 { 271 cm_return_val_if_fail(book != NULL, NULL); 272 return addrcache_remove_person(book->addressCache, person); 273 } 274 275 /** 276 * Remove specified email address in address book for specified person. 277 * Note that object should still be freed. 278 * \param book Address book. 279 * \param person Person. 280 * \param email EMail to remove. 281 * \return EMail object, or NULL if not found. 282 */ 283 ItemEMail *addrbook_person_remove_email(AddressBookFile *book, 284 ItemPerson *person, ItemEMail *email) 285 { 286 cm_return_val_if_fail(book != NULL, NULL); 287 return addrcache_person_remove_email(book->addressCache, person, email); 288 } 289 290 /* 291 * *********************************************************************** 292 * Read/Write XML data file... 293 * =========================== 294 * Notes: 295 * 1) The address book is structured as follows: 296 * 297 * address-book 298 * person 299 * address-list 300 * address 301 * attribute-list 302 * attribute 303 * group 304 * member-list 305 * member 306 * folder 307 * item-list 308 * item 309 * 310 * 2) This sequence of elements was chosen so that the most important 311 * elements (person and their email addresses) appear first. 312 * 313 * 3) Groups then appear. When groups are loaded, person's email 314 * addresses have already been loaded and can be found. 315 * 316 * 4) Finally folders are loaded. Any forward and backward references 317 * to folders, groups and persons in the folders are resolved after 318 * loading. 319 * 320 * *********************************************************************** 321 */ 322 323 /* Element tag names */ 324 #define AB_ELTAG_ADDRESS "address" 325 #define AB_ELTAG_ATTRIBUTE "attribute" 326 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list" 327 #define AB_ELTAG_ADDRESS_LIST "address-list" 328 #define AB_ELTAG_MEMBER "member" 329 #define AB_ELTAG_MEMBER_LIST "member-list" 330 #define AB_ELTAG_ITEM "item" 331 #define AB_ELTAG_ITEM_LIST "item-list" 332 #define AB_ELTAG_ADDRESS_BOOK "address-book" 333 #define AB_ELTAG_PERSON "person" 334 #define AB_ELTAG_GROUP "group" 335 #define AB_ELTAG_FOLDER "folder" 336 337 /* Attribute tag names */ 338 #define AB_ATTAG_TYPE "type" 339 #define AB_ATTAG_UID "uid" 340 #define AB_ATTAG_NAME "name" 341 #define AB_ATTAG_REMARKS "remarks" 342 #define AB_ATTAG_FIRST_NAME "first-name" 343 #define AB_ATTAG_LAST_NAME "last-name" 344 #define AB_ATTAG_NICK_NAME "nick-name" 345 #define AB_ATTAG_COMMON_NAME "cn" 346 #define AB_ATTAG_ALIAS "alias" 347 #define AB_ATTAG_EMAIL "email" 348 #define AB_ATTAG_EID "eid" 349 #define AB_ATTAG_PID "pid" 350 351 /* Attribute values */ 352 #define AB_ATTAG_VAL_PERSON "person" 353 #define AB_ATTAG_VAL_GROUP "group" 354 #define AB_ATTAG_VAL_FOLDER "folder" 355 356 /** 357 * Parse address item for person from XML file. 358 * \param book Address book. 359 * \param file XML file handle. 360 * \param person Person. 361 */ 362 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file, 363 ItemPerson *person) 364 { 365 GList *attr; 366 gchar *name, *value; 367 ItemEMail *email = NULL; 368 369 attr = xml_get_current_tag_attr(file); 370 while (attr) { 371 name = ((XMLAttr *)attr->data)->name; 372 value = ((XMLAttr *)attr->data)->value; 373 if (!email) 374 email = addritem_create_item_email(); 375 if (strcmp(name, AB_ATTAG_UID) == 0) 376 ADDRITEM_ID(email) = g_strdup(value); 377 else if (strcmp(name, AB_ATTAG_ALIAS) == 0) 378 ADDRITEM_NAME(email) = g_strdup(value); 379 else if (strcmp(name, AB_ATTAG_EMAIL) == 0) 380 email->address = g_strdup(value); 381 else if (strcmp(name, AB_ATTAG_REMARKS) == 0) 382 email->remarks = g_strdup(value); 383 attr = g_list_next(attr); 384 } 385 if (email) { 386 if (person) { 387 addrcache_person_add_email(book->addressCache, person, 388 email); 389 } 390 else { 391 addritem_free_item_email(email); 392 email = NULL; 393 } 394 } 395 } 396 397 /** 398 * Parse list of email address for person from XML file. 399 * \param book Address book. 400 * \param file XML file handle. 401 * \param person Person. 402 */ 403 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file, 404 ItemPerson *person) 405 { 406 guint prev_level; 407 408 for (;;) { 409 prev_level = file->level; 410 if (xml_parse_next_tag(file)) { 411 longjmp(book->jumper, 1); 412 } 413 if (file->level < prev_level) return; 414 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) { 415 addrbook_parse_address(book, file, person); 416 addrbook_parse_addr_list(book, file, person); 417 } 418 } 419 } 420 421 /** 422 * Parse attribute for person from XML file. 423 * \param book Address book. 424 * \param file XML file handle. 425 * \param person Person. 426 */ 427 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person) 428 { 429 GList *attr; 430 gchar *name, *value; 431 gchar *element; 432 UserAttribute *uAttr = NULL; 433 434 attr = xml_get_current_tag_attr(file); 435 while (attr) { 436 name = ((XMLAttr *)attr->data)->name; 437 value = ((XMLAttr *)attr->data)->value; 438 if (!uAttr) uAttr = addritem_create_attribute(); 439 if (strcmp(name, AB_ATTAG_UID) == 0) 440 addritem_attrib_set_id(uAttr, value); 441 else if (strcmp(name, AB_ATTAG_NAME) == 0) 442 addritem_attrib_set_name(uAttr, value); 443 attr = g_list_next(attr); 444 } 445 446 element = xml_get_element(file); 447 addritem_attrib_set_value(uAttr, element); 448 g_free(element); 449 450 if (uAttr) { 451 if (person) { 452 addritem_person_add_attribute(person, uAttr); 453 } 454 else { 455 addritem_free_attribute(uAttr); 456 uAttr = NULL; 457 } 458 } 459 } 460 461 /** 462 * Parse list of attributes for person from XML file. 463 * \param book Address book. 464 * \param file XML file handle. 465 * \param person Person. 466 */ 467 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file, 468 ItemPerson *person) 469 { 470 guint prev_level; 471 472 for (;;) { 473 prev_level = file->level; 474 if (xml_parse_next_tag(file)) { 475 longjmp( book->jumper, 1 ); 476 } 477 if (file->level < prev_level) return; 478 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) { 479 addrbook_parse_attribute(file, person); 480 addrbook_parse_attr_list(book, file, person); 481 } 482 } 483 } 484 485 /** 486 * Parse person from XML file. 487 * \param book Address book. 488 * \param file XML file handle. 489 */ 490 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file) 491 { 492 GList *attr; 493 gchar *name, *value; 494 ItemPerson *person = NULL; 495 496 attr = xml_get_current_tag_attr(file); 497 while (attr) { 498 name = ((XMLAttr *)attr->data)->name; 499 value = ((XMLAttr *)attr->data)->value; 500 if (!person) 501 person = addritem_create_item_person(); 502 if (strcmp(name, AB_ATTAG_UID) == 0) { 503 ADDRITEM_ID(person) = g_strdup(value); 504 person->picture = g_strdup(value); 505 } 506 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0) 507 person->firstName = g_strdup(value); 508 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0) 509 person->lastName = g_strdup(value); 510 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0) 511 person->nickName = g_strdup(value); 512 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0) 513 ADDRITEM_NAME(person) = g_strdup(value); 514 attr = g_list_next(attr); 515 } 516 if (xml_parse_next_tag(file)) { /* Consume closing tag */ 517 longjmp(book->jumper, 1); 518 } 519 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) { 520 addrbook_parse_addr_list(book, file, person); 521 if (person) { 522 addrcache_hash_add_person(book->addressCache, person); 523 } 524 } 525 if (xml_parse_next_tag(file)) { /* Consume closing tag */ 526 longjmp(book->jumper, 1); 527 } 528 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) { 529 addrbook_parse_attr_list(book, file, person); 530 } 531 } 532 533 /** 534 * Parse group member from XML file. 535 * \param book Address book. 536 * \param file XML file handle. 537 * \param group Group. 538 */ 539 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file, 540 ItemGroup *group) 541 { 542 GList *attr; 543 gchar *name, *value; 544 gchar *eid = NULL; 545 /* gchar *pid = NULL; */ 546 ItemEMail *email = NULL; 547 548 attr = xml_get_current_tag_attr(file); 549 while (attr) { 550 name = ((XMLAttr *)attr->data)->name; 551 value = ((XMLAttr *)attr->data)->value; 552 if( strcmp( name, AB_ATTAG_EID ) == 0 ) 553 eid = g_strdup( value ); 554 attr = g_list_next(attr); 555 } 556 /* email = addrcache_get_email( book->addressCache, pid, eid ); */ 557 email = addrcache_get_email(book->addressCache, eid); 558 g_free(eid); 559 if (email) { 560 if (group) { 561 addrcache_group_add_email(book->addressCache, group, 562 email); 563 } 564 else { 565 addritem_free_item_email(email); 566 email = NULL; 567 } 568 } 569 } 570 571 /** 572 * Parse list of group members from XML file. 573 * \param book Address book. 574 * \param file XML file handle. 575 * \param group Group. 576 */ 577 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file, 578 ItemGroup *group) 579 { 580 guint prev_level; 581 582 for (;;) { 583 prev_level = file->level; 584 if (xml_parse_next_tag(file)) { 585 longjmp(book->jumper, 1); 586 } 587 if (file->level < prev_level) 588 return; 589 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) { 590 addrbook_parse_member(book, file, group); 591 addrbook_parse_member_list(book, file, group); 592 } 593 } 594 } 595 596 /** 597 * Parse group object from XML file. 598 * \param book Address book. 599 * \param file XML file handle. 600 */ 601 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file) 602 { 603 GList *attr; 604 gchar *name, *value; 605 ItemGroup *group = NULL; 606 607 attr = xml_get_current_tag_attr(file); 608 while (attr) { 609 name = ((XMLAttr *)attr->data)->name; 610 value = ((XMLAttr *)attr->data)->value; 611 if (!group) 612 group = addritem_create_item_group(); 613 if (strcmp(name, AB_ATTAG_UID) == 0) 614 ADDRITEM_ID(group) = g_strdup(value); 615 else if (strcmp(name, AB_ATTAG_NAME) == 0) 616 ADDRITEM_NAME(group) = g_strdup(value); 617 else if (strcmp(name, AB_ATTAG_REMARKS) == 0) 618 group->remarks = g_strdup(value); 619 attr = g_list_next(attr); 620 } 621 if (xml_parse_next_tag(file)) { /* Consume closing tag */ 622 longjmp(book->jumper, 1); 623 } 624 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) { 625 if (group) { 626 addrcache_hash_add_group(book->addressCache, group); 627 } 628 addrbook_parse_member_list(book, file, group); 629 } else { 630 if (group) 631 addritem_free_item_group(group); 632 } 633 } 634 635 /** 636 * Parse folder item from XML file. 637 * \param book Address book. 638 * \param file XML file handle. 639 * \param folder Folder. 640 */ 641 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file, 642 ItemFolder *folder) 643 { 644 GList *attr; 645 gchar *name, *value; 646 gchar *uid = NULL; 647 648 attr = xml_get_current_tag_attr(file); 649 while (attr) { 650 name = ((XMLAttr *)attr->data)->name; 651 value = ((XMLAttr *)attr->data)->value; 652 if (strcmp(name, AB_ATTAG_UID) == 0) { 653 uid = g_strdup(value); 654 } 655 attr = g_list_next(attr); 656 } 657 if (folder) { 658 if (uid) { 659 folder->listItems = g_list_append(folder->listItems, uid); 660 } 661 } 662 } 663 664 /** 665 * Parse list of folder items from XML file. 666 * \param book Address book. 667 * \param file XML file handle. 668 * \param folder Folder. 669 */ 670 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file, 671 ItemFolder *folder) 672 { 673 guint prev_level; 674 675 for (;;) { 676 prev_level = file->level; 677 if (xml_parse_next_tag(file)) { 678 longjmp(book->jumper, 1); 679 } 680 if (file->level < prev_level) 681 return; 682 if (xml_compare_tag(file, AB_ELTAG_ITEM)) { 683 addrbook_parse_folder_item(book, file, folder); 684 addrbook_parse_folder_list(book, file, folder); 685 } 686 } 687 } 688 689 /** 690 * Parse folder from XML file. 691 * \param book Address book. 692 * \param file XML file handle. 693 */ 694 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file) 695 { 696 GList *attr; 697 gchar *name, *value; 698 ItemFolder *folder = NULL; 699 700 attr = xml_get_current_tag_attr(file); 701 while (attr) { 702 name = ((XMLAttr *)attr->data)->name; 703 value = ((XMLAttr *)attr->data)->value; 704 if (!folder) 705 folder = addritem_create_item_folder(); 706 if (strcmp(name, AB_ATTAG_UID) == 0) 707 ADDRITEM_ID(folder) = g_strdup(value); 708 else if (strcmp(name, AB_ATTAG_NAME) == 0) 709 ADDRITEM_NAME(folder) = g_strdup(value); 710 else if (strcmp(name, AB_ATTAG_REMARKS) == 0) 711 folder->remarks = g_strdup(value); 712 attr = g_list_next(attr); 713 } 714 if (xml_parse_next_tag(file)) { /* Consume closing tag */ 715 longjmp(book->jumper, 1); 716 } 717 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) { 718 if (folder) { 719 if (addrcache_hash_add_folder(book->addressCache, 720 folder)) { 721 book->tempList = g_list_append(book->tempList, 722 folder); 723 /* We will resolve folder later */ 724 ADDRITEM_PARENT(folder) = NULL; 725 } 726 } 727 addrbook_parse_folder_list(book, file, folder); 728 } else { 729 if (folder) 730 addritem_free_item_folder(folder); 731 } 732 } 733 734 /** 735 * Read address book (DOM) tree from file. 736 * \param book Address book. 737 * \param file XML file handle. 738 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error 739 * reading data. 740 */ 741 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file) 742 { 743 gboolean retVal; 744 GList *attr; 745 gchar *name, *value; 746 747 book->retVal = MGU_BAD_FORMAT; 748 if (xml_get_dtd(file)) 749 return FALSE; 750 if (xml_parse_next_tag(file)) 751 longjmp(book->jumper, 1); 752 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK)) 753 return FALSE; 754 755 attr = xml_get_current_tag_attr(file); 756 while (attr) { 757 name = ((XMLAttr *)attr->data)->name; 758 value = ((XMLAttr *)attr->data)->value; 759 if (strcmp( name, AB_ATTAG_NAME) == 0) 760 addrbook_set_name( book, value ); 761 attr = g_list_next( attr ); 762 } 763 764 retVal = TRUE; 765 for (;;) { 766 if (!file->level) 767 break; 768 /* Get next item tag (person, group or folder) */ 769 if (xml_parse_next_tag(file)) 770 longjmp( book->jumper, 1 ); 771 772 if (xml_compare_tag(file, AB_ELTAG_PERSON)) 773 addrbook_parse_person(book, file); 774 else if (xml_compare_tag(file, AB_ELTAG_GROUP)) 775 addrbook_parse_group(book, file); 776 else if (xml_compare_tag(file, AB_ELTAG_FOLDER)) 777 addrbook_parse_folder(book, file); 778 } 779 if (retVal) book->retVal = MGU_SUCCESS; 780 return retVal; 781 } 782 783 /** 784 * Resolve folder items callback function. 785 * \param key Table key. 786 * \param value Reference to object contained in folder. 787 * \param data Reference to address book. 788 */ 789 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data) 790 { 791 AddressBookFile *book = data; 792 AddrItemObject *obj = (AddrItemObject *) value; 793 ItemFolder *rootFolder = book->addressCache->rootFolder; 794 if (obj->parent == NULL) { 795 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) { 796 rootFolder->listPerson = g_list_append(rootFolder->listPerson, 797 obj); 798 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder); 799 } 800 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) { 801 rootFolder->listGroup = g_list_append(rootFolder->listGroup, 802 obj); 803 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder); 804 } 805 } 806 } 807 808 /** 809 * Resolve folder items. Lists of UID's are replaced with pointers to 810 * data items. 811 * \param book Address book. 812 */ 813 static void addrbook_resolve_folder_items(AddressBookFile *book) 814 { 815 GList *nodeFolder = NULL; 816 GList *listRemove = NULL; 817 GList *node = NULL; 818 ItemFolder *rootFolder = book->addressCache->rootFolder; 819 nodeFolder = book->tempList; 820 821 while (nodeFolder) { 822 ItemFolder *folder = nodeFolder->data; 823 listRemove = NULL; 824 node = folder->listItems; 825 while (node) { 826 gchar *uid = node->data; 827 AddrItemObject *aio = addrcache_get_object(book->addressCache, 828 uid); 829 if (aio) { 830 if (aio->type == ITEMTYPE_FOLDER) { 831 ItemFolder *item = (ItemFolder *) aio; 832 folder->listFolder = g_list_append(folder->listFolder, item); 833 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); 834 addrcache_hash_add_folder(book->addressCache, folder); 835 } 836 else if (aio->type == ITEMTYPE_PERSON) { 837 ItemPerson *item = (ItemPerson *) aio; 838 folder->listPerson = g_list_append(folder->listPerson, item); 839 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); 840 } 841 else if (aio->type == ITEMTYPE_GROUP) { 842 ItemGroup *item = (ItemGroup *) aio; 843 folder->listGroup = g_list_append(folder->listGroup, item); 844 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); 845 } 846 /* Replace data with pointer to item */ 847 g_free(uid); 848 node->data = aio; 849 } 850 else { /* Not found, append to remove list. */ 851 listRemove = g_list_append(listRemove, uid); 852 } 853 node = g_list_next(node); 854 } 855 rootFolder->listFolder = g_list_append(rootFolder->listFolder, 856 folder); 857 /* Process remove list */ 858 node = listRemove; 859 while (node) { 860 gchar *uid = node->data; 861 folder->listItems = g_list_remove(folder->listItems, 862 uid); 863 g_free(uid); 864 node = g_list_next(node); 865 } 866 g_list_free(listRemove); 867 nodeFolder = g_list_next(nodeFolder); 868 } 869 /* Remove folders with parents. */ 870 listRemove = NULL; 871 node = rootFolder->listFolder; 872 while (node) { 873 ItemFolder *folder = (ItemFolder *) node->data; 874 if (ADDRITEM_PARENT(folder)) 875 /* Remove folders with parents */ 876 listRemove = g_list_append(listRemove, folder); 877 else /* Add to root folder */ 878 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder); 879 880 node = g_list_next( node ); 881 } 882 /* Process remove list */ 883 node = listRemove; 884 while (node) { 885 rootFolder->listFolder = g_list_remove(rootFolder->listFolder, 886 node->data); 887 node = g_list_next(node); 888 } 889 g_list_free(listRemove); 890 891 /* Move all unparented persons and groups into root folder */ 892 g_hash_table_foreach(book->addressCache->itemHash, 893 addrbook_res_items_vis, book); 894 895 /* Free up some more */ 896 nodeFolder = book->tempList; 897 while (nodeFolder) { 898 ItemFolder *folder = nodeFolder->data; 899 g_list_free(folder->listItems); 900 folder->listItems = NULL; 901 nodeFolder = g_list_next(nodeFolder); 902 } 903 g_list_free(book->tempList); 904 book->tempList = NULL; 905 } 906 907 /** 908 * Read address book. 909 * \param book Address book. 910 * \return Status code. 911 */ 912 gint addrbook_read_data(AddressBookFile *book) 913 { 914 XMLFile *file = NULL; 915 gchar *fileSpec = NULL; 916 917 cm_return_val_if_fail(book != NULL, -1); 918 919 /* 920 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName, 921 addrcache_get_name( book->addressCache ) ); 922 */ 923 924 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, 925 book->fileName, NULL); 926 book->retVal = MGU_OPEN_FILE; 927 addrcache_clear(book->addressCache); 928 book->addressCache->modified = FALSE; 929 book->addressCache->accessFlag = FALSE; 930 file = xml_open_file(fileSpec); 931 g_free(fileSpec); 932 if (file) { 933 book->tempList = NULL; 934 /* Trap for parsing errors. */ 935 if (setjmp( book->jumper)) { 936 xml_close_file(file); 937 return book->retVal; 938 } 939 addrbook_read_tree(book, file); 940 xml_close_file(file); 941 /* Resolve folder items */ 942 addrbook_resolve_folder_items(book); 943 book->tempList = NULL; 944 book->addressCache->modified = FALSE; 945 book->addressCache->dataRead = TRUE; 946 addrcache_set_dirty(book->addressCache, FALSE); 947 } 948 return book->retVal; 949 } 950 951 /** 952 * Write start element to file. 953 * \param fp File handle. 954 * \param lvl Indent level. 955 * \param name Element name. 956 */ 957 static int addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name) 958 { 959 gint i; 960 for (i = 0; i < lvl; i++) 961 if (fputs(" ", fp) == EOF) 962 return -1; 963 if (fputs("<", fp) == EOF) 964 return -1; 965 if (fputs(name, fp) == EOF) 966 return -1; 967 968 return 0; 969 } 970 971 /** 972 * Write end element to file. 973 * \param fp File handle. 974 * \param lvl Indent level. 975 * \param name Element name. 976 */ 977 static int addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name) 978 { 979 gint i; 980 for(i = 0; i < lvl; i++) 981 if (fputs(" ", fp) == EOF) 982 return -1; 983 if (fputs("</", fp) == EOF) 984 return -1; 985 if (fputs(name, fp) == EOF) 986 return -1; 987 if (fputs(">\n", fp) == EOF) 988 return -1; 989 990 return 0; 991 } 992 993 /** 994 * Write attribute name/value pair to file. 995 * \param fp File handle. 996 * \param name Attribute name. 997 * \param value Attribute value. 998 */ 999 static int addrbook_write_attr(FILE *fp, gchar *name, gchar *value) 1000 { 1001 if (fputs(" ", fp) == EOF) 1002 return -1; 1003 if (fputs(name, fp) == EOF) 1004 return -1; 1005 if (fputs("=\"", fp) == EOF) 1006 return -1; 1007 if (xml_file_put_escape_str(fp, value) < 0) 1008 return -1; 1009 if (fputs("\"", fp) == EOF) 1010 return -1; 1011 1012 return 0; 1013 } 1014 1015 typedef struct _HashLoopData { 1016 FILE *fp; 1017 gboolean error; 1018 } HashLoopData; 1019 1020 /** 1021 * Write person and associated addresses and attributes to file. 1022 * file hash table visitor function. 1023 * \param key Table key. 1024 * \param value Reference to person. 1025 * \param data File pointer. 1026 */ 1027 static void addrbook_write_item_person_vis(gpointer key, gpointer value, 1028 gpointer d) 1029 { 1030 AddrItemObject *obj = (AddrItemObject *) value; 1031 HashLoopData *data = (HashLoopData *)d; 1032 FILE *fp = data->fp; 1033 GList *node; 1034 1035 if (!obj) 1036 return; 1037 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) { 1038 ItemPerson *person = (ItemPerson *) value; 1039 if (person) { 1040 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON) < 0) 1041 data->error = TRUE; 1042 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person)) < 0) 1043 data->error = TRUE; 1044 if (addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName) < 0) 1045 data->error = TRUE; 1046 if (addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName) < 0) 1047 data->error = TRUE; 1048 if (addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName) < 0) 1049 data->error = TRUE; 1050 if (addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person)) < 0) 1051 data->error = TRUE; 1052 if (fputs(" >\n", fp) == EOF) 1053 data->error = TRUE; 1054 1055 /* Output email addresses */ 1056 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0) 1057 data->error = TRUE; 1058 if (fputs(">\n", fp) == EOF) 1059 data->error = TRUE; 1060 node = person->listEMail; 1061 while (node) { 1062 ItemEMail *email = node->data; 1063 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS) < 0) 1064 data->error = TRUE; 1065 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email)) < 0) 1066 data->error = TRUE; 1067 if (addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email)) < 0) 1068 data->error = TRUE; 1069 if (addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address) < 0) 1070 data->error = TRUE; 1071 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks) < 0) 1072 data->error = TRUE; 1073 if (fputs(" />\n", fp) == EOF) 1074 data->error = TRUE; 1075 node = g_list_next(node); 1076 } 1077 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0) 1078 data->error = TRUE; 1079 1080 /* Output user attributes */ 1081 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0) 1082 data->error = TRUE; 1083 if (fputs(">\n", fp) == EOF) 1084 data->error = TRUE; 1085 node = person->listAttrib; 1086 while (node) { 1087 UserAttribute *attrib = node->data; 1088 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE) < 0) 1089 data->error = TRUE; 1090 if (addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid) < 0) 1091 data->error = TRUE; 1092 if (addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name) < 0) 1093 data->error = TRUE; 1094 if (fputs(" >", fp) == EOF) 1095 data->error = TRUE; 1096 if (xml_file_put_escape_str(fp, attrib->value) < 0) 1097 data->error = TRUE; 1098 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE) < 0) 1099 data->error = TRUE; 1100 node = g_list_next(node); 1101 } 1102 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0) 1103 data->error = TRUE; 1104 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON) < 0) 1105 data->error = TRUE; 1106 } 1107 } 1108 } 1109 1110 /** 1111 * Write group and associated references to addresses to file. 1112 * file hash table visitor function. 1113 * \param key Table key. 1114 * \param value Reference to group. 1115 * \param data File pointer. 1116 */ 1117 static void addrbook_write_item_group_vis(gpointer key, gpointer value, 1118 gpointer d) 1119 { 1120 AddrItemObject *obj = (AddrItemObject *) value; 1121 HashLoopData *data = (HashLoopData *)d; 1122 FILE *fp = data->fp; 1123 1124 GList *node; 1125 1126 if (!obj) 1127 return; 1128 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) { 1129 ItemGroup *group = (ItemGroup *) value; 1130 if (group) { 1131 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP) < 0) 1132 data->error = TRUE; 1133 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group)) < 0) 1134 data->error = TRUE; 1135 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group)) < 0) 1136 data->error = TRUE; 1137 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks) < 0) 1138 data->error = TRUE; 1139 if (fputs(" >\n", fp) == EOF) 1140 data->error = TRUE; 1141 1142 /* Output email address links */ 1143 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST) < 0) 1144 data->error = TRUE; 1145 if (fputs(">\n", fp) == EOF) 1146 data->error = TRUE; 1147 node = group->listEMail; 1148 while (node) { 1149 ItemEMail *email = node->data; 1150 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email); 1151 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER) < 0) 1152 data->error = TRUE; 1153 if (addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person)) < 0) 1154 data->error = TRUE; 1155 if (addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email)) < 0) 1156 data->error = TRUE; 1157 if (fputs(" />\n", fp) == EOF) 1158 data->error = TRUE; 1159 node = g_list_next(node); 1160 } 1161 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST) < 0) 1162 data->error = TRUE; 1163 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP) < 0) 1164 data->error = TRUE; 1165 } 1166 } 1167 } 1168 1169 /** 1170 * Write folder and associated references to addresses to file. 1171 * file hash table visitor function. 1172 * \param key Table key. 1173 * \param value Reference to folder. 1174 * \param data File pointer. 1175 */ 1176 static void addrbook_write_item_folder_vis(gpointer key, gpointer value, 1177 gpointer d) 1178 { 1179 AddrItemObject *obj = (AddrItemObject *) value; 1180 HashLoopData *data = (HashLoopData *)d; 1181 FILE *fp = data->fp; 1182 GList *node; 1183 1184 if (!obj) 1185 return; 1186 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) { 1187 ItemFolder *folder = (ItemFolder *) value; 1188 if (folder) { 1189 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER) < 0) 1190 data->error = TRUE; 1191 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder)) < 0) 1192 data->error = TRUE; 1193 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder)) < 0) 1194 data->error = TRUE; 1195 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks) < 0) 1196 data->error = TRUE; 1197 if (fputs(" >\n", fp) == EOF) 1198 data->error = TRUE; 1199 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST) < 0) 1200 data->error = TRUE; 1201 if (fputs(">\n", fp) == EOF) 1202 data->error = TRUE; 1203 1204 /* Output persons */ 1205 node = folder->listPerson; 1206 while (node) { 1207 ItemPerson *item = node->data; 1208 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0) 1209 data->error = TRUE; 1210 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON) < 0) 1211 data->error = TRUE; 1212 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0) 1213 data->error = TRUE; 1214 if (fputs(" />\n", fp) == EOF) 1215 data->error = TRUE; 1216 node = g_list_next(node); 1217 } 1218 1219 /* Output groups */ 1220 node = folder->listGroup; 1221 while (node) { 1222 ItemGroup *item = node->data; 1223 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0) 1224 data->error = TRUE; 1225 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP) < 0) 1226 data->error = TRUE; 1227 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0) 1228 data->error = TRUE; 1229 if (fputs(" />\n", fp) == EOF) 1230 data->error = TRUE; 1231 node = g_list_next(node); 1232 } 1233 1234 /* Output folders */ 1235 node = folder->listFolder; 1236 while (node) { 1237 ItemFolder *item = node->data; 1238 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0) 1239 data->error = TRUE; 1240 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER) < 0) 1241 data->error = TRUE; 1242 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0) 1243 data->error = TRUE; 1244 if (fputs(" />\n", fp) == EOF) 1245 data->error = TRUE; 1246 node = g_list_next(node); 1247 } 1248 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST) < 0) 1249 data->error = TRUE; 1250 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER) < 0) 1251 data->error = TRUE; 1252 } 1253 } 1254 } 1255 1256 /** 1257 * Output address book data to specified file. 1258 * \param book Address book. 1259 * \param newFile Filename of new file (in book's filepath). 1260 * \return Status code. 1261 */ 1262 static gint addrbook_write_to(AddressBookFile *book, gchar *newFile) 1263 { 1264 FILE *fp; 1265 gchar *fileSpec; 1266 HashLoopData data; 1267 PrefFile *pfile; 1268 1269 cm_return_val_if_fail(book != NULL, -1); 1270 cm_return_val_if_fail(newFile != NULL, -1); 1271 1272 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL); 1273 1274 book->retVal = MGU_OPEN_FILE; 1275 pfile = prefs_write_open(fileSpec); 1276 g_free(fileSpec); 1277 if (pfile) { 1278 fp = pfile->fp; 1279 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0) 1280 goto fail; 1281 if (addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0) 1282 goto fail; 1283 if (addrbook_write_attr(fp, AB_ATTAG_NAME, 1284 addrcache_get_name(book->addressCache)) < 0) 1285 goto fail; 1286 if (fputs(" >\n", fp) == EOF) 1287 goto fail; 1288 1289 /* Output all persons */ 1290 data.fp = fp; 1291 data.error = FALSE; 1292 1293 g_hash_table_foreach(book->addressCache->itemHash, 1294 addrbook_write_item_person_vis, &data); 1295 if (data.error) 1296 goto fail; 1297 1298 /* Output all groups */ 1299 g_hash_table_foreach(book->addressCache->itemHash, 1300 addrbook_write_item_group_vis, &data); 1301 1302 if (data.error) 1303 goto fail; 1304 1305 /* Output all folders */ 1306 g_hash_table_foreach(book->addressCache->itemHash, 1307 addrbook_write_item_folder_vis, &data); 1308 1309 if (data.error) 1310 goto fail; 1311 1312 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0) 1313 goto fail; 1314 1315 book->retVal = MGU_SUCCESS; 1316 if (prefs_file_close( pfile ) < 0) 1317 book->retVal = MGU_ERROR_WRITE; 1318 } 1319 1320 fileSpec = NULL; 1321 return book->retVal; 1322 fail: 1323 g_warning("error writing AB"); 1324 book->retVal = MGU_ERROR_WRITE; 1325 if (pfile) 1326 prefs_file_close_revert( pfile ); 1327 return book->retVal; 1328 } 1329 1330 /** 1331 * Output address book data to original file. 1332 * \param book Address book. 1333 * \return Status code. 1334 */ 1335 gint addrbook_save_data(AddressBookFile *book) 1336 { 1337 cm_return_val_if_fail(book != NULL, -1); 1338 1339 book->retVal = MGU_NO_FILE; 1340 if (book->fileName == NULL || *book->fileName == '\0') 1341 return book->retVal; 1342 if (book->path == NULL || *book->path == '\0') 1343 return book->retVal; 1344 1345 addrbook_write_to(book, book->fileName); 1346 if (book->retVal == MGU_SUCCESS) 1347 addrcache_set_dirty(book->addressCache, FALSE); 1348 return book->retVal; 1349 } 1350 1351 /* 1352 * ********************************************************************** 1353 * Address book edit interface functions. 1354 * ********************************************************************** 1355 */ 1356 1357 /** 1358 * Hash table callback function for simple deletion of hashtable entries. 1359 * \param key Table key (will be freed). 1360 * \param value Value stored in table. 1361 * \param data User data. 1362 * \return <i>TRUE</i> to indicate that entry freed. 1363 */ 1364 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value, 1365 gpointer *data) 1366 { 1367 g_free(key); 1368 key = NULL; 1369 value = NULL; 1370 return TRUE; 1371 } 1372 1373 /** 1374 * Update address book email list for specified person. Note: The existing 1375 * email addresses are replaced with the new addresses. Any references to 1376 * old addresses in the groups are re-linked to the new addresses. All old 1377 * addresses linked to the person are removed. 1378 * \param book Address book. 1379 * \param person Person to update. 1380 * \param listEMail List of new email addresses. 1381 */ 1382 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person, 1383 GList *listEMail) 1384 { 1385 GList *node; 1386 GList *listDelete; 1387 GList *listGroup; 1388 1389 cm_return_if_fail(book != NULL); 1390 cm_return_if_fail(person != NULL); 1391 1392 /* Get groups where person's existing email addresses are listed */ 1393 listGroup = addrcache_get_group_for_person(book->addressCache, person); 1394 if (listGroup) { 1395 GHashTable *hashEMail; 1396 GHashTable *hashEMailAlias; 1397 GList *nodeGrp; 1398 1399 /* Load hash table with new address entries */ 1400 hashEMail = g_hash_table_new(g_str_hash, g_str_equal); 1401 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal); 1402 node = listEMail; 1403 while (node) { 1404 ItemEMail *email = node->data; 1405 gchar *alias = email->obj.name ; 1406 gchar *addr = g_utf8_strdown(email->address, -1); 1407 if (!g_hash_table_lookup(hashEMail, addr)) { 1408 g_hash_table_insert(hashEMail, addr, email); 1409 } 1410 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias, 1411 alias)) 1412 g_hash_table_insert(hashEMailAlias, alias, email); 1413 1414 node = g_list_next(node); 1415 } 1416 1417 /* Re-parent new addresses to existing groups, where email address match. */ 1418 nodeGrp = listGroup; 1419 while (nodeGrp) { 1420 ItemGroup *group = (ItemGroup *) nodeGrp->data; 1421 GList *groupEMail = group->listEMail; 1422 GList *nodeGrpEM; 1423 GList *listRemove = NULL; 1424 1425 /* Process each email item linked to group */ 1426 nodeGrpEM = groupEMail; 1427 while (nodeGrpEM) { 1428 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data; 1429 1430 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) { 1431 /* Found an email address for this person */ 1432 ItemEMail *emailNew = NULL; 1433 gchar *alias = emailGrp->obj.name; 1434 gchar *addr = g_utf8_strdown(emailGrp->address, -1); 1435 emailNew = (ItemEMail *) 1436 g_hash_table_lookup(hashEMail, addr); 1437 g_free( addr ); 1438 /* If no match by e-mail, try to match by e-mail alias */ 1439 if (!emailNew && *alias != '\0') { 1440 emailNew = (ItemEMail *) 1441 g_hash_table_lookup(hashEMailAlias, alias); 1442 } 1443 1444 if (emailNew) 1445 /* Point to this entry */ 1446 nodeGrpEM->data = emailNew; 1447 else if (g_hash_table_size(hashEMail)==1) 1448 /* If the person has just one e-mail address, then 1449 change e-mail address in group list */ 1450 nodeGrpEM->data = listEMail->data; 1451 else 1452 /* Mark for removal */ 1453 listRemove = g_list_append(listRemove, emailGrp); 1454 } 1455 /* Move on to next email link */ 1456 nodeGrpEM = g_list_next(nodeGrpEM); 1457 } 1458 1459 /* Process all removed links in current group */ 1460 nodeGrpEM = listRemove; 1461 while (nodeGrpEM) { 1462 ItemEMail *emailGrp = nodeGrpEM->data; 1463 groupEMail = g_list_remove(groupEMail, emailGrp); 1464 nodeGrpEM = g_list_next(nodeGrpEM); 1465 } 1466 1467 g_list_free(listRemove); 1468 1469 /* Move on to next group */ 1470 nodeGrp = g_list_next(nodeGrp); 1471 1472 } 1473 /* Clear hash table */ 1474 g_hash_table_foreach_remove(hashEMail, (GHRFunc) 1475 addrbook_free_simple_hash_vis, NULL); 1476 g_hash_table_destroy(hashEMail); 1477 hashEMail = NULL; 1478 g_hash_table_destroy(hashEMailAlias); 1479 hashEMailAlias = NULL; 1480 g_list_free(listGroup); 1481 listGroup = NULL; 1482 } 1483 /* Remove old addresses from person and cache */ 1484 listDelete = NULL; 1485 node = person->listEMail; 1486 while (node) { 1487 ItemEMail *email = node->data; 1488 1489 if (addrcache_person_remove_email(book->addressCache, person, email)) 1490 addrcache_remove_email(book->addressCache, email); 1491 1492 listDelete = g_list_append(listDelete, email); 1493 node = person->listEMail; 1494 } 1495 /* Add new address entries */ 1496 node = listEMail; 1497 while (node) { 1498 ItemEMail *email = node->data; 1499 1500 if (ADDRITEM_ID(email) == NULL) 1501 /* Allocate an ID for new address */ 1502 addrcache_id_email(book->addressCache, email); 1503 1504 addrcache_person_add_email( book->addressCache, person, email ); 1505 node = g_list_next( node ); 1506 } 1507 1508 addrcache_set_dirty(book->addressCache, TRUE); 1509 1510 /* Free up memory */ 1511 g_list_free(listEMail); 1512 listEMail = NULL; 1513 1514 node = listDelete; 1515 while (node) { 1516 ItemEMail *email = node->data; 1517 1518 addritem_free_item_email(email); 1519 node = g_list_next(node); 1520 } 1521 g_list_free(listDelete); 1522 listDelete = NULL; 1523 1524 } 1525 1526 /** 1527 * Create person object and add person with specified address data to address 1528 * book. Note: A new person is created with specified list of email addresses. 1529 * All objects inserted into address book. 1530 * 1531 * \param book Address book. 1532 * \param folder Parent folder where to add person, or <i>NULL</i> for 1533 * root folder. 1534 * \param listEMail List of new email addresses to associate with person. 1535 * \return Person object created. 1536 */ 1537 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder, 1538 GList *listEMail) 1539 { 1540 ItemPerson *person; 1541 ItemFolder *f = folder; 1542 GList *node; 1543 1544 cm_return_val_if_fail(book != NULL, NULL); 1545 1546 if (!f) 1547 f = book->addressCache->rootFolder; 1548 person = addritem_create_item_person(); 1549 addrcache_id_person(book->addressCache, person); 1550 addrcache_folder_add_person(book->addressCache, f, person); 1551 1552 node = listEMail; 1553 while (node) { 1554 ItemEMail *email = node->data; 1555 if (ADDRITEM_ID(email) == NULL) 1556 addrcache_id_email(book->addressCache, email); 1557 1558 addrcache_person_add_email(book->addressCache, person, email); 1559 node = g_list_next(node); 1560 } 1561 return person; 1562 } 1563 1564 /** 1565 * Build available email list visitor function. 1566 * \param key Table key. 1567 * \param value Value stored in table. 1568 * \param data Reference to address book. 1569 */ 1570 static void addrbook_build_avail_email_vis(gpointer key, gpointer value, 1571 gpointer data) 1572 { 1573 AddrItemObject *obj = (AddrItemObject *) value; 1574 1575 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) { 1576 AddressBookFile *book = data; 1577 ItemPerson *person = (ItemPerson *) obj; 1578 GList *node = person->listEMail; 1579 while (node) { 1580 ItemEMail *email = node->data; 1581 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */ 1582 1583 if (!g_hash_table_lookup(book->tempHash, 1584 ADDRITEM_ID(email))) 1585 book->tempList = g_list_append(book->tempList, email); 1586 1587 node = g_list_next(node); 1588 } 1589 } 1590 } 1591 1592 /** 1593 * Return link list of available email items that have not already been linked 1594 * to groups. Note that the list contains references to items and should be 1595 * <code>g_list_free()</code> when done. Do <b>*NOT*</b> attempt to used the 1596 * <code>addrbook_free_xxx()<code> functions... this will destroy the 1597 * addressbook data! 1598 * 1599 * \param book Address book. 1600 * \param group Group to process. 1601 * \return List of items, or <i>NULL</i> if none. 1602 */ 1603 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group) 1604 { 1605 GList *list = NULL; 1606 GHashTable *table; 1607 1608 cm_return_val_if_fail(book != NULL, NULL); 1609 1610 /* Load hash table with group email entries */ 1611 table = g_hash_table_new(g_str_hash, g_str_equal); 1612 if (group) { 1613 list = group->listEMail; 1614 while (list) { 1615 ItemEMail *email = list->data; 1616 g_hash_table_insert(table, ADDRITEM_ID(email), email); 1617 list = g_list_next(list); 1618 } 1619 } 1620 1621 /* Build list of available email addresses which exclude those already in groups */ 1622 book->tempList = NULL; 1623 book->tempHash = table; 1624 g_hash_table_foreach(book->addressCache->itemHash, 1625 addrbook_build_avail_email_vis, book); 1626 list = book->tempList; 1627 book->tempList = NULL; 1628 book->tempHash = NULL; 1629 1630 /* Clear hash table */ 1631 g_hash_table_destroy(table); 1632 table = NULL; 1633 1634 return list; 1635 } 1636 1637 /** 1638 * Update address book email list for specified group. Note: The existing email 1639 * addresses are replaced with the new addresses. Any references to old addresses 1640 * in the groups are re-linked to the new addresses. All old addresses linked to 1641 * the person are removed. 1642 * 1643 * \param book Address book. 1644 * \param group Group to process. 1645 * \param listEMail List of email items. This should <b>*NOT*</b> be 1646 * <code>g_free()</code> when done. 1647 */ 1648 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group, 1649 GList *listEMail) 1650 { 1651 GList *oldData; 1652 1653 cm_return_if_fail(book != NULL); 1654 cm_return_if_fail(group != NULL); 1655 1656 addrcache_set_dirty(book->addressCache, TRUE); 1657 1658 /* Remember old list */ 1659 oldData = group->listEMail; 1660 group->listEMail = listEMail; 1661 g_list_free(oldData); 1662 } 1663 1664 /** 1665 * Create group object and add with specifed list of email addresses to 1666 * address book. Note: The existing email addresses are replaced with the new 1667 * addresses. Any references to old addresses in the groups are re-linked to 1668 * the new addresses. All old addresses linked to the person are removed. 1669 * 1670 * \param book Address book. 1671 * \param folder Parent folder where to add group, or <i>NULL</i> for 1672 * root folder. 1673 * \param listEMail List of email items. This should <b>*NOT*</b> be 1674 * <code>g_free()</code> when done. 1675 * \return Group object created. 1676 */ 1677 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder, 1678 GList *listEMail) 1679 { 1680 ItemGroup *group = NULL; 1681 ItemFolder *f = folder; 1682 1683 cm_return_val_if_fail(book != NULL, NULL); 1684 1685 if (!f) 1686 f = book->addressCache->rootFolder; 1687 group = addritem_create_item_group(); 1688 addrcache_id_group(book->addressCache, group); 1689 addrcache_folder_add_group(book->addressCache, f, group); 1690 group->listEMail = listEMail; 1691 return group; 1692 } 1693 1694 /** 1695 * Create a new folder and add to address book. 1696 * \param book Address book. 1697 * \param folder Parent folder where to add folder, or <i>NULL</i> for 1698 * root folder. 1699 * \return Folder that was created. This should <b>*NOT*</b> be 1700 * <code>g_free()</code> when done. 1701 */ 1702 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent) 1703 { 1704 cm_return_val_if_fail(book != NULL, NULL); 1705 return addrcache_add_new_folder( book->addressCache, parent ); 1706 } 1707 1708 /** 1709 * Update address book attribute list for specified person. Note: The existing 1710 * attributes are replaced with the new addresses. All old attributes linked 1711 * to the person are removed. 1712 * 1713 * \param book Address book. 1714 * \param person Person to receive attributes. 1715 * \param listAttrib New list of attributes. 1716 */ 1717 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person, 1718 GList *listAttrib) 1719 { 1720 GList *node; 1721 GList *oldData; 1722 1723 cm_return_if_fail(book != NULL); 1724 cm_return_if_fail(person != NULL); 1725 1726 /* Remember old list */ 1727 oldData = person->listAttrib; 1728 1729 /* Attach new address list to person. */ 1730 node = listAttrib; 1731 while (node) { 1732 UserAttribute *attrib = node->data; 1733 if (attrib->uid == NULL) { 1734 /* Allocate an ID */ 1735 addrcache_id_attribute(book->addressCache, attrib); 1736 } 1737 node = g_list_next(node); 1738 } 1739 person->listAttrib = listAttrib; 1740 addrcache_set_dirty(book->addressCache, TRUE); 1741 1742 /* Free up old data */ 1743 addritem_free_list_attribute(oldData); 1744 oldData = NULL; 1745 } 1746 1747 /** 1748 * Add attribute data for specified person to address book. Note: Only 1749 * attributes are inserted into address book. 1750 * \param book Address book. 1751 * \param person Person to receive attributes. 1752 * \param listAttrib List of attributes. 1753 */ 1754 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) { 1755 GList *node; 1756 1757 cm_return_if_fail( book != NULL ); 1758 cm_return_if_fail( person != NULL ); 1759 1760 node = listAttrib; 1761 while( node ) { 1762 UserAttribute *attrib = node->data; 1763 if( attrib->uid == NULL ) { 1764 addrcache_id_attribute( book->addressCache, attrib ); 1765 } 1766 addritem_person_add_attribute( person, attrib ); 1767 node = g_list_next( node ); 1768 } 1769 addrcache_set_dirty( book->addressCache, TRUE ); 1770 } 1771 1772 #define WORK_BUFLEN 1024 1773 #define ADDRBOOK_DIGITS "0123456789" 1774 1775 /** 1776 * Return list of existing address book files. 1777 * \param book Address book. 1778 * \return List of files (as strings). 1779 */ 1780 GList *addrbook_get_bookfile_list(AddressBookFile *book) { 1781 gchar *adbookdir; 1782 GDir *dir; 1783 const gchar *dir_name; 1784 GStatBuf statbuf; 1785 gchar buf[WORK_BUFLEN + 1]; 1786 gchar numbuf[WORK_BUFLEN]; 1787 gint len, lenpre, lensuf, lennum; 1788 long int val, maxval; 1789 GList *fileList = NULL; 1790 1791 cm_return_val_if_fail(book != NULL, NULL); 1792 1793 if (book->path == NULL || *book->path == '\0') { 1794 book->retVal = MGU_NO_PATH; 1795 return NULL; 1796 } 1797 1798 strlcpy(buf, book->path, sizeof(buf)); 1799 if (buf[strlen(buf)] != '/') 1800 strlcat(buf, "/", sizeof(buf)); 1801 1802 adbookdir = strdup(buf); 1803 strlcat(buf, ADDRBOOK_PREFIX, sizeof(buf)); 1804 1805 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) { 1806 book->retVal = MGU_OPEN_DIRECTORY; 1807 g_free(adbookdir); 1808 return NULL; 1809 } 1810 1811 lenpre = strlen(ADDRBOOK_PREFIX); 1812 lensuf = strlen(ADDRBOOK_SUFFIX); 1813 lennum = FILE_NUMDIGITS + lenpre; 1814 maxval = -1; 1815 1816 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) { 1817 gchar *endptr = NULL; 1818 gint i, r; 1819 gboolean flg; 1820 1821 strncpy(buf, adbookdir, WORK_BUFLEN); 1822 strncat(buf, dir_name, WORK_BUFLEN - strlen(buf)); 1823 r = g_stat(buf, &statbuf); 1824 if (r == 0 && S_ISREG(statbuf.st_mode)) { 1825 if (strncmp( 1826 dir_name, 1827 ADDRBOOK_PREFIX, lenpre) == 0) 1828 { 1829 if (strncmp( 1830 (dir_name) + lennum, 1831 ADDRBOOK_SUFFIX, lensuf) == 0) 1832 { 1833 strncpy(numbuf, 1834 (dir_name) + lenpre, 1835 FILE_NUMDIGITS); 1836 numbuf[FILE_NUMDIGITS] = '\0'; 1837 flg = TRUE; 1838 for(i = 0; i < FILE_NUMDIGITS; i++) { 1839 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) { 1840 flg = FALSE; 1841 break; 1842 } 1843 } 1844 if (flg) { 1845 /* Get value */ 1846 val = strtol(numbuf, &endptr, 10); 1847 if (endptr && val > -1) { 1848 if (val > maxval) maxval = val; 1849 fileList = g_list_append( 1850 fileList, 1851 g_strdup(dir_name)); 1852 } 1853 } 1854 } 1855 } 1856 } 1857 } 1858 g_dir_close( dir ); 1859 g_free(adbookdir); 1860 1861 book->maxValue = maxval; 1862 book->retVal = MGU_SUCCESS; 1863 return fileList; 1864 } 1865 1866 /** 1867 * Return file name for specified file number. 1868 * \param fileNum File number. 1869 * \return File name, or <i>NULL</i> if file number too large. Should be 1870 * <code>g_free()</code> when done. 1871 */ 1872 gchar *addrbook_gen_new_file_name(gint fileNum) { 1873 gchar fmt[30]; 1874 gchar buf[WORK_BUFLEN]; 1875 gint n = fileNum; 1876 long int nmax; 1877 1878 if (n < 1) 1879 n = 1; 1880 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS); 1881 if (fileNum > nmax) 1882 return NULL; 1883 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS); 1884 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX); 1885 return g_strdup(buf); 1886 } 1887 1888 /* 1889 * ********************************************************************** 1890 * Address book test functions... 1891 * ********************************************************************** 1892 */ 1893 1894 /** 1895 * Attempt to parse list of email address from file. 1896 * \param book Address book. 1897 * \param file XML file handle. 1898 */ 1899 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ) 1900 { 1901 guint prev_level; 1902 /* GList *attr; */ 1903 1904 for (;;) { 1905 prev_level = file->level; 1906 if (xml_parse_next_tag(file)) 1907 longjmp(book->jumper, 1); 1908 if (file->level < prev_level) 1909 return; 1910 /* attr = xml_get_current_tag_attr(file); */ 1911 /* addrbook_show_attribs( attr ); */ 1912 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) 1913 addrbook_chkparse_addr_list(book, file); 1914 } 1915 } 1916 1917 /** 1918 * Attempt to parse attributes for person address from file. 1919 * \param book Address book. 1920 * \param file XML file handle. 1921 */ 1922 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file) 1923 { 1924 /* GList *attr; */ 1925 /* gchar *element; */ 1926 1927 /* attr = xml_get_current_tag_attr(file); */ 1928 /* addrbook_show_attribs( attr ); */ 1929 /* element = xml_get_element(file); */ 1930 /* g_print( "\t\tattrib value : %s\n", element ); */ 1931 } 1932 1933 /** 1934 * Attempt to parse list of attributes for person address from file. 1935 * \param book Address book. 1936 * \param file XML file handle. 1937 */ 1938 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file) 1939 { 1940 guint prev_level; 1941 1942 for (;;) { 1943 prev_level = file->level; 1944 if (xml_parse_next_tag(file)) 1945 longjmp(book->jumper, 1); 1946 if (file->level < prev_level) 1947 return; 1948 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) { 1949 addrbook_chkparse_attribute(book, file); 1950 addrbook_chkparse_attr_list(book, file); 1951 } 1952 } 1953 } 1954 1955 /** 1956 * Attempt to parse person from file. 1957 * \param book Address book. 1958 * \param file XML file handle. 1959 */ 1960 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file) 1961 { 1962 /* GList *attr; */ 1963 1964 /* attr = xml_get_current_tag_attr(file); */ 1965 /* addrbook_show_attribs( attr ); */ 1966 if (xml_parse_next_tag(file)) /* Consume closing tag */ 1967 longjmp(book->jumper, 1); 1968 1969 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) 1970 addrbook_chkparse_addr_list(book, file); 1971 1972 if (xml_parse_next_tag(file)) /* Consume closing tag */ 1973 longjmp(book->jumper, 1); 1974 1975 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) 1976 addrbook_chkparse_attr_list(book, file); 1977 } 1978 1979 /** 1980 * Attempt to parse list of members from file. 1981 * \param book Address book. 1982 * \param file XML file handle. 1983 */ 1984 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file) 1985 { 1986 /* GList *attr; */ 1987 guint prev_level; 1988 1989 for (;;) { 1990 prev_level = file->level; 1991 if (xml_parse_next_tag(file)) 1992 longjmp(book->jumper, 1); 1993 1994 if (file->level < prev_level) 1995 return; 1996 1997 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) { 1998 /* attr = xml_get_current_tag_attr(file); */ 1999 /* addrbook_show_attribs( attr ); */ 2000 addrbook_chkparse_member_list(book, file); 2001 } 2002 else { 2003 /* attr = xml_get_current_tag_attr(file); */ 2004 /* addrbook_show_attribs( attr ); */ 2005 } 2006 } 2007 } 2008 2009 /** 2010 * Attempt to parse group from file. 2011 * \param book Address book. 2012 * \param file XML file handle. 2013 */ 2014 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file) 2015 { 2016 /* GList *attr; */ 2017 2018 /* attr = xml_get_current_tag_attr(file); */ 2019 /* addrbook_show_attribs( attr ); */ 2020 if (xml_parse_next_tag(file)) /* Consume closing tag */ 2021 longjmp(book->jumper, 1); 2022 2023 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) 2024 addrbook_chkparse_member_list(book, file); 2025 } 2026 2027 /** 2028 * Attempt to parse list of folders from file. 2029 * \param book Address book. 2030 * \param file XML file handle. 2031 */ 2032 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file) 2033 { 2034 /* GList *attr; */ 2035 guint prev_level; 2036 2037 for (;;) { 2038 prev_level = file->level; 2039 if (xml_parse_next_tag(file)) 2040 longjmp(book->jumper, 1); 2041 2042 if (file->level < prev_level) 2043 return; 2044 2045 if (xml_compare_tag(file, AB_ELTAG_ITEM)) { 2046 /* attr = xml_get_current_tag_attr(file); */ 2047 /* addrbook_show_attribs( attr ); */ 2048 addrbook_chkparse_folder_list(book, file); 2049 } 2050 else { 2051 /* attr = xml_get_current_tag_attr(file); */ 2052 /* addrbook_show_attribs( attr ); */ 2053 } 2054 } 2055 } 2056 2057 /** 2058 * Attempt to parse a folder from file. 2059 * \param book Address book. 2060 * \param file XML file handle. 2061 */ 2062 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file) 2063 { 2064 /* GList *attr; */ 2065 2066 /* attr = xml_get_current_tag_attr(file); */ 2067 /* addrbook_show_attribs( attr ); */ 2068 if (xml_parse_next_tag(file)) /* Consume closing tag */ 2069 longjmp(book->jumper, 1); 2070 2071 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) 2072 addrbook_chkparse_folder_list(book, file); 2073 } 2074 2075 /** 2076 * Attempt to parse (DOM) tree from file. 2077 * \param book Address book. 2078 * \param file XML file handle. 2079 */ 2080 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file) 2081 { 2082 /* GList *attr; */ 2083 gboolean retVal; 2084 2085 if (xml_get_dtd(file)) 2086 return FALSE; 2087 2088 if (xml_parse_next_tag(file)) 2089 return FALSE; 2090 2091 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK)) 2092 return FALSE; 2093 2094 /* attr = xml_get_current_tag_attr(file); */ 2095 /* addrbook_show_attribs( attr ); */ 2096 2097 retVal = TRUE; 2098 for (;;) { 2099 if (!file->level) 2100 break; 2101 /* Get item tag */ 2102 if (xml_parse_next_tag(file)) 2103 longjmp(book->jumper, 1); 2104 2105 /* Get next tag (person, group or folder) */ 2106 if (xml_compare_tag(file, AB_ELTAG_PERSON)) 2107 addrbook_chkparse_person( book, file ); 2108 else if (xml_compare_tag(file, AB_ELTAG_GROUP)) 2109 addrbook_chkparse_group(book, file); 2110 else if (xml_compare_tag(file, AB_ELTAG_FOLDER)) 2111 addrbook_chkparse_folder(book, file); 2112 } 2113 return retVal; 2114 } 2115 2116 /** 2117 * Test address book file by parsing contents. 2118 * \param book Address book. 2119 * \param fileName Filename of XML file. 2120 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format. 2121 */ 2122 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName) 2123 { 2124 XMLFile *file = NULL; 2125 gchar *fileSpec = NULL; 2126 2127 cm_return_val_if_fail(book != NULL, -1); 2128 2129 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL); 2130 book->retVal = MGU_OPEN_FILE; 2131 file = xml_open_file(fileSpec); 2132 g_free(fileSpec); 2133 if (file) { 2134 book->retVal = MGU_BAD_FORMAT; 2135 if (setjmp(book->jumper)) { 2136 /* g_print( "Caught Ya!!!\n" ); */ 2137 xml_close_file(file); 2138 return book->retVal; 2139 } 2140 if (addrbook_chkread_tree(book, file)) 2141 book->retVal = MGU_SUCCESS; 2142 2143 xml_close_file( file ); 2144 } 2145 return book->retVal; 2146 } 2147 2148 /** 2149 * Return link list of all persons in address book. Note that the list 2150 * contains references to items. Do <b>*NOT*</b> attempt to use the 2151 * <code>addrbook_free_xxx()</code> functions... this will destroy the 2152 * addressbook data! 2153 * \param book Address book. 2154 * \return List of persons, or NULL if none. 2155 */ 2156 GList *addrbook_get_all_persons(AddressBookFile *book) 2157 { 2158 cm_return_val_if_fail(book != NULL, NULL); 2159 return addrcache_get_all_persons(book->addressCache); 2160 } 2161 2162 GList *addrbook_get_all_groups(AddressBookFile *book) 2163 { 2164 cm_return_val_if_fail(book != NULL, NULL); 2165 return addrcache_get_all_groups(book->addressCache); 2166 } 2167 2168 /** 2169 * Add person and address data to address book. 2170 * \param book Address book. 2171 * \param folder Folder where to add person, or NULL for root folder. 2172 * \param name Common name. 2173 * \param address EMail address. 2174 * \param remarks Remarks. 2175 * \return Person added. Do not <b>*NOT*</b> to use the 2176 * <code>addrbook_free_xxx()</code> functions... this will destroy 2177 * the address book data. 2178 */ 2179 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder, 2180 const gchar *name,const gchar *address, 2181 const gchar *remarks) 2182 { 2183 ItemPerson *person; 2184 2185 cm_return_val_if_fail(book != NULL, NULL); 2186 person = addrcache_add_contact( 2187 book->addressCache, folder, name, address, remarks ); 2188 return person; 2189 } 2190 2191 /** 2192 * Return file name for next address book file. 2193 * \param book Address book. 2194 * \return File name, or <i>NULL</i> if could not create. This should be 2195 * <code>g_free()</code> when done. 2196 */ 2197 gchar *addrbook_guess_next_file(AddressBookFile *book) 2198 { 2199 gchar *newFile = NULL; 2200 GList *fileList = NULL; 2201 gint fileNum = 1; 2202 fileList = addrbook_get_bookfile_list(book); 2203 if (fileList) 2204 fileNum = 1 + book->maxValue; 2205 2206 newFile = addrbook_gen_new_file_name(fileNum); 2207 g_list_free(fileList); 2208 fileList = NULL; 2209 return newFile; 2210 } 2211 2212 void addrbook_delete_book_file(AddressBookFile *book) 2213 { 2214 gchar *book_path; 2215 2216 if (!book->path || !book->fileName) 2217 return; 2218 2219 book_path = g_strconcat(book->path, G_DIR_SEPARATOR_S, 2220 book->fileName, NULL); 2221 unlink(book_path); 2222 g_free(book_path); 2223 } 2224