2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2002 Match Grun and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 /* General functions for accessing address book files */
33 #include "addrcache.h"
35 #include "adbookbase.h"
37 #ifndef DEV_STANDALONE
38 #include "prefs_gtk.h"
42 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
43 #define ADDRBOOK_PREFIX "addrbook-"
44 #define ADDRBOOK_SUFFIX ".xml"
45 #define FILE_NUMDIGITS 6
47 #define ID_TIME_OFFSET 998000000
49 /* Create new address book */
50 AddressBookFile *addrbook_create_book()
52 AddressBookFile *book;
54 book = g_new0(AddressBookFile, 1);
55 book->type = ADBOOKTYPE_BOOK;
56 book->addressCache = addrcache_create();
57 book->retVal = MGU_SUCCESS;
59 book->fileName = NULL;
61 book->tempList = NULL;
62 book->tempHash = NULL;
63 book->addressCache->modified = TRUE;
67 /* Specify name to be used */
68 void addrbook_set_name(AddressBookFile *book, const gchar *value)
70 g_return_if_fail(book != NULL);
71 addrcache_set_name(book->addressCache, value);
74 gchar *addrbook_get_name(AddressBookFile *book)
76 g_return_val_if_fail(book != NULL, NULL);
77 return addrcache_get_name(book->addressCache);
80 void addrbook_set_path(AddressBookFile *book, const gchar *value)
82 g_return_if_fail(book != NULL);
83 book->path = mgu_replace_string(book->path, value);
84 addrcache_set_dirty(book->addressCache, TRUE);
87 void addrbook_set_file(AddressBookFile *book, const gchar *value)
89 g_return_if_fail(book != NULL);
90 book->fileName = mgu_replace_string(book->fileName, value);
91 addrcache_set_dirty(book->addressCache, TRUE);
94 gboolean addrbook_get_modified(AddressBookFile *book)
96 g_return_val_if_fail(book != NULL, FALSE);
97 return book->addressCache->modified;
100 void addrbook_set_modified(AddressBookFile *book, const gboolean value)
102 g_return_if_fail(book != NULL);
103 book->addressCache->modified = value;
106 gboolean addrbook_get_accessed(AddressBookFile *book)
108 g_return_val_if_fail(book != NULL, FALSE);
109 return book->addressCache->accessFlag;
112 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
114 g_return_if_fail(book != NULL);
115 book->addressCache->accessFlag = value;
118 gboolean addrbook_get_read_flag(AddressBookFile *book)
120 g_return_val_if_fail(book != NULL, FALSE);
121 return book->addressCache->dataRead;
124 void addrbook_set_read_flag(AddressBookFile *book, const gboolean value)
126 g_return_if_fail(book != NULL);
127 book->addressCache->dataRead = value;
130 gint addrbook_get_status(AddressBookFile *book)
132 g_return_val_if_fail(book != NULL, -1);
136 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
138 g_return_val_if_fail(book != NULL, NULL);
139 return addrcache_get_root_folder(book->addressCache);
142 GList *addrbook_get_list_folder(AddressBookFile *book)
144 g_return_val_if_fail(book != NULL, NULL);
145 return addrcache_get_list_folder(book->addressCache);
148 GList *addrbook_get_list_person(AddressBookFile *book)
150 g_return_val_if_fail(book != NULL, NULL);
151 return addrcache_get_list_person(book->addressCache);
154 gboolean addrbook_get_dirty(AddressBookFile *book)
156 g_return_val_if_fail(book != NULL, FALSE);
157 return addrcache_get_dirty(book->addressCache);
160 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
162 g_return_if_fail(book != NULL);
163 addrcache_set_dirty(book->addressCache, value);
166 /* Empty address book */
167 void addrbook_empty_book(AddressBookFile *book)
169 g_return_if_fail(book != NULL);
171 /* Free up internal objects */
172 addrcache_clear(book->addressCache);
173 addrcache_set_dirty(book->addressCache, FALSE);
174 g_list_free(book->tempList);
176 /* Reset to initial state */
177 book->tempList = NULL;
178 book->tempHash = NULL;
179 book->addressCache->dataRead = FALSE;
180 book->addressCache->modified = FALSE;
181 book->addressCache->accessFlag = FALSE;
182 book->retVal = MGU_SUCCESS;
185 /* Free address book */
186 void addrbook_free_book(AddressBookFile *book)
188 g_return_if_fail(book != NULL);
191 addrcache_clear(book->addressCache);
192 addrcache_free(book->addressCache);
194 /* Free up internal objects */
196 g_free(book->fileName);
197 g_list_free(book->tempList);
200 book->fileName = NULL;
202 book->tempList = NULL;
203 book->tempHash = NULL;
205 book->type = ADBOOKTYPE_NONE;
206 book->addressCache = NULL;
207 book->retVal = MGU_SUCCESS;
212 /* Print list of items */
213 void addrbook_print_item_list(GList *list, FILE *stream)
218 AddrItemObject *obj = node->data;
219 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON)
220 addritem_print_item_person((ItemPerson *) obj, stream);
221 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP)
222 addritem_print_item_group((ItemGroup *) obj, stream);
223 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER)
224 addritem_print_item_folder((ItemFolder *) obj, stream);
225 node = g_list_next(node);
227 fprintf(stream, "\t---\n");
230 /* Print address book */
231 void addrbook_print_book(AddressBookFile *book, FILE *stream)
233 g_return_if_fail(book != NULL);
235 fprintf(stream, "AddressBook:\n");
236 fprintf(stream, "\tpath : '%s'\n", book->path);
237 fprintf(stream, "\tfile : '%s'\n", book->fileName);
238 fprintf(stream, "\tstatus : %d : '%s'\n", book->retVal,
239 mgu_error2string(book->retVal));
240 addrcache_print(book->addressCache, stream);
243 /* Dump entire address book traversing folders */
244 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
248 g_return_if_fail(book != NULL);
250 addrbook_print_book(book, stream);
251 folder = book->addressCache->rootFolder;
252 addritem_print_item_folder(folder, stream);
255 /* Remove group from address book.
256 param: group Group to remove.
257 return: Group, or NULL if not found.
258 Note that object should still be freed */
259 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
261 g_return_val_if_fail(book != NULL, NULL);
262 return addrcache_remove_group(book->addressCache, group);
265 /* Remove specified person from address book.
266 param: person Person to remove.
267 return: Person, or NULL if not found.
268 Note that object should still be freed */
269 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
271 g_return_val_if_fail(book != NULL, NULL);
272 return addrcache_remove_person(book->addressCache, person);
275 /* Remove email address in address book for specified person.
276 param: person Person.
277 email EMail to remove.
278 return: EMail object, or NULL if not found.
279 Note that object should still be freed */
280 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
281 ItemPerson *person, ItemEMail *email)
283 g_return_val_if_fail(book != NULL, NULL);
284 return addrcache_person_remove_email(book->addressCache, person, email);
287 /* **********************************************************************
288 * Read/Write XML data file...
289 * ===========================
291 * 1) The address book is structured as follows:
306 * 2) This sequence of elements was chosen so that the most important
307 * elements (person and their email addresses) appear first.
309 * 3) Groups then appear. When groups are loaded, person's email
310 * addresses have already been loaded and can be found.
312 * 4) Finally folders are loaded. Any forward and backward references
313 * to folders, groups and persons in the folders are resolved after
316 * ***********************************************************************
319 /* Element tag names */
320 #define AB_ELTAG_ADDRESS "address"
321 #define AB_ELTAG_ATTRIBUTE "attribute"
322 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
323 #define AB_ELTAG_ADDRESS_LIST "address-list"
324 #define AB_ELTAG_MEMBER "member"
325 #define AB_ELTAG_MEMBER_LIST "member-list"
326 #define AB_ELTAG_ITEM "item"
327 #define AB_ELTAG_ITEM_LIST "item-list"
328 #define AB_ELTAG_ADDRESS_BOOK "address-book"
329 #define AB_ELTAG_PERSON "person"
330 #define AB_ELTAG_GROUP "group"
331 #define AB_ELTAG_FOLDER "folder"
333 /* Attribute tag names */
334 #define AB_ATTAG_TYPE "type"
335 #define AB_ATTAG_UID "uid"
336 #define AB_ATTAG_NAME "name"
337 #define AB_ATTAG_REMARKS "remarks"
338 #define AB_ATTAG_FIRST_NAME "first-name"
339 #define AB_ATTAG_LAST_NAME "last-name"
340 #define AB_ATTAG_NICK_NAME "nick-name"
341 #define AB_ATTAG_COMMON_NAME "cn"
342 #define AB_ATTAG_ALIAS "alias"
343 #define AB_ATTAG_EMAIL "email"
344 #define AB_ATTAG_EID "eid"
345 #define AB_ATTAG_PID "pid"
347 /* Attribute values */
348 #define AB_ATTAG_VAL_PERSON "person"
349 #define AB_ATTAG_VAL_GROUP "group"
350 #define AB_ATTAG_VAL_FOLDER "folder"
352 /* Parse address item for person */
353 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
358 ItemEMail *email = NULL;
360 attr = xml_get_current_tag_attr(file);
362 name = ((XMLAttr *)attr->data)->name;
363 value = ((XMLAttr *)attr->data)->value;
365 email = addritem_create_item_email();
366 if (strcmp(name, AB_ATTAG_UID) == 0)
367 ADDRITEM_ID(email) = g_strdup(value);
368 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
369 ADDRITEM_NAME(email) = g_strdup(value);
370 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
371 email->address = g_strdup(value);
372 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
373 email->remarks = g_strdup(value);
374 attr = g_list_next(attr);
378 addrcache_person_add_email(book->addressCache, person,
382 addritem_free_item_email(email);
388 /* Parse email address list */
389 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
396 prev_level = file->level;
397 if (xml_parse_next_tag(file)) {
398 longjmp(book->jumper, 1);
400 if (file->level < prev_level) return;
401 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
402 attr = xml_get_current_tag_attr(file);
403 addrbook_parse_address(book, file, person);
404 addrbook_parse_addr_list(book, file, person);
409 /* Parse attibute for person */
410 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
415 UserAttribute *uAttr = NULL;
417 attr = xml_get_current_tag_attr(file);
419 name = ((XMLAttr *)attr->data)->name;
420 value = ((XMLAttr *)attr->data)->value;
421 if (!uAttr) uAttr = addritem_create_attribute();
422 if (strcmp(name, AB_ATTAG_UID) == 0)
423 addritem_attrib_set_id(uAttr, value);
424 else if (strcmp(name, AB_ATTAG_NAME) == 0)
425 addritem_attrib_set_name(uAttr, value);
426 attr = g_list_next(attr);
429 element = xml_get_element(file);
430 addritem_attrib_set_value(uAttr, element);
434 addritem_person_add_attribute(person, uAttr);
437 addritem_free_attribute(uAttr);
443 /* Parse attribute list */
444 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
451 prev_level = file->level;
452 if (xml_parse_next_tag(file)) {
453 longjmp( book->jumper, 1 );
455 if (file->level < prev_level) return;
456 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
457 attr = xml_get_current_tag_attr(file);
458 addrbook_parse_attribute(file, person);
459 addrbook_parse_attr_list(book, file, person);
465 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
469 ItemPerson *person = NULL;
471 attr = xml_get_current_tag_attr(file);
473 name = ((XMLAttr *)attr->data)->name;
474 value = ((XMLAttr *)attr->data)->value;
476 person = addritem_create_item_person();
477 if (strcmp(name, AB_ATTAG_UID) == 0)
478 ADDRITEM_ID(person) = g_strdup(value);
479 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
480 person->firstName = g_strdup(value);
481 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
482 person->lastName = g_strdup(value);
483 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
484 person->nickName = g_strdup(value);
485 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
486 ADDRITEM_NAME(person) = g_strdup(value);
487 attr = g_list_next(attr);
489 if (xml_parse_next_tag(file)) { /* Consume closing tag */
490 longjmp(book->jumper, 1);
492 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
493 addrbook_parse_addr_list(book, file, person);
495 addrcache_hash_add_person(book->addressCache, person);
498 if (xml_parse_next_tag(file)) { /* Consume closing tag */
499 longjmp(book->jumper, 1);
501 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
502 addrbook_parse_attr_list(book, file, person);
506 /* Parse group member */
507 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
512 gchar *pid = NULL, *eid = NULL;
513 ItemEMail *email = NULL;
515 attr = xml_get_current_tag_attr(file);
517 name = ((XMLAttr *)attr->data)->name;
518 value = ((XMLAttr *)attr->data)->value;
519 if (strcmp(name, AB_ATTAG_PID) == 0)
520 pid = g_strdup(value);
521 else if (strcmp(name, AB_ATTAG_EID) == 0)
522 eid = g_strdup(value);
523 attr = g_list_next(attr);
525 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
526 email = addrcache_get_email(book->addressCache, eid);
529 addrcache_group_add_email(book->addressCache, group,
533 addritem_free_item_email(email);
539 /* Parse group member list */
540 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
547 prev_level = file->level;
548 if (xml_parse_next_tag(file)) {
549 longjmp(book->jumper, 1);
551 if (file->level < prev_level)
553 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
554 attr = xml_get_current_tag_attr(file);
555 addrbook_parse_member(book, file, group);
556 addrbook_parse_member_list(book, file, group);
559 attr = xml_get_current_tag_attr(file);
565 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
569 ItemGroup *group = NULL;
571 attr = xml_get_current_tag_attr(file);
573 name = ((XMLAttr *)attr->data)->name;
574 value = ((XMLAttr *)attr->data)->value;
576 group = addritem_create_item_group();
577 if (strcmp(name, AB_ATTAG_UID) == 0)
578 ADDRITEM_ID(group) = g_strdup(value);
579 else if (strcmp(name, AB_ATTAG_NAME) == 0)
580 ADDRITEM_NAME(group) = g_strdup(value);
581 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
582 group->remarks = g_strdup(value);
583 attr = g_list_next(attr);
585 if (xml_parse_next_tag(file)) { /* Consume closing tag */
586 longjmp(book->jumper, 1);
588 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
590 addrcache_hash_add_group(book->addressCache, group);
592 addrbook_parse_member_list(book, file, group);
596 /* Parse folder item */
597 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
604 attr = xml_get_current_tag_attr(file);
606 name = ((XMLAttr *)attr->data)->name;
607 value = ((XMLAttr *)attr->data)->value;
608 if (strcmp(name, AB_ATTAG_UID) == 0) {
609 uid = g_strdup(value);
611 attr = g_list_next(attr);
615 folder->listItems = g_list_append(folder->listItems, uid);
620 /* Parse folder item list */
621 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
628 prev_level = file->level;
629 if (xml_parse_next_tag(file)) {
630 longjmp(book->jumper, 1);
632 if (file->level < prev_level)
634 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
635 attr = xml_get_current_tag_attr(file);
636 addrbook_parse_folder_item(book, file, folder);
637 addrbook_parse_folder_list(book, file, folder);
640 attr = xml_get_current_tag_attr(file);
646 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
650 ItemFolder *folder = NULL;
652 attr = xml_get_current_tag_attr(file);
654 name = ((XMLAttr *)attr->data)->name;
655 value = ((XMLAttr *)attr->data)->value;
657 folder = addritem_create_item_folder();
658 if (strcmp(name, AB_ATTAG_UID) == 0)
659 ADDRITEM_ID(folder) = g_strdup(value);
660 else if (strcmp(name, AB_ATTAG_NAME) == 0)
661 ADDRITEM_NAME(folder) = g_strdup(value);
662 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
663 folder->remarks = g_strdup(value);
664 attr = g_list_next(attr);
666 if (xml_parse_next_tag(file)) { /* Consume closing tag */
667 longjmp(book->jumper, 1);
669 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
671 if (addrcache_hash_add_folder(book->addressCache,
673 book->tempList = g_list_append(book->tempList,
675 /* We will resolve folder later */
676 ADDRITEM_PARENT(folder) = NULL;
679 addrbook_parse_folder_list(book, file, folder);
683 /* Parse address book.
684 Return: TRUE if data read successfully, FALSE if error reading data */
685 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
691 book->retVal = MGU_BAD_FORMAT;
692 if (xml_get_dtd(file))
694 if (xml_parse_next_tag(file))
695 longjmp(book->jumper, 1);
696 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
699 attr = xml_get_current_tag_attr(file);
701 name = ((XMLAttr *)attr->data)->name;
702 value = ((XMLAttr *)attr->data)->value;
703 if (strcmp( name, AB_ATTAG_NAME) == 0)
704 addrbook_set_name( book, value );
705 attr = g_list_next( attr );
712 /* Get next item tag (person, group or folder) */
713 if (xml_parse_next_tag(file))
714 longjmp( book->jumper, 1 );
716 if (xml_compare_tag(file, AB_ELTAG_PERSON))
717 addrbook_parse_person(book, file);
718 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
719 addrbook_parse_group(book, file);
720 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
721 addrbook_parse_folder(book, file);
723 if (retVal) book->retVal = MGU_SUCCESS;
727 /* Resolve folder items visitor function */
728 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
730 AddressBookFile *book = data;
731 AddrItemObject *obj = (AddrItemObject *) value;
732 ItemFolder *rootFolder = book->addressCache->rootFolder;
733 if (obj->parent == NULL) {
734 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
735 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
737 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
739 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
740 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
742 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
747 /* Resolve folder items. Lists of UID's are replaced with pointers to
749 static void addrbook_resolve_folder_items(AddressBookFile *book)
751 GList *nodeFolder = NULL;
752 GList *listRemove = NULL;
754 ItemFolder *rootFolder = book->addressCache->rootFolder;
755 nodeFolder = book->tempList;
758 ItemFolder *folder = nodeFolder->data;
760 node = folder->listItems;
762 gchar *uid = node->data;
763 AddrItemObject *aio = addrcache_get_object(book->addressCache,
766 if (aio->type == ITEMTYPE_FOLDER) {
767 ItemFolder *item = (ItemFolder *) aio;
768 folder->listFolder = g_list_append(folder->listFolder, item);
769 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
770 addrcache_hash_add_folder(book->addressCache, folder);
772 else if (aio->type == ITEMTYPE_PERSON) {
773 ItemPerson *item = (ItemPerson *) aio;
774 folder->listPerson = g_list_append(folder->listPerson, item);
775 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
777 else if (aio->type == ITEMTYPE_GROUP) {
778 ItemGroup *item = (ItemGroup *) aio;
779 folder->listGroup = g_list_append(folder->listGroup, item);
780 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
782 /* Replace data with pointer to item */
786 else { /* Not found, append to remove list. */
787 listRemove = g_list_append(listRemove, uid);
789 node = g_list_next(node);
791 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
793 /* Process remove list */
796 gchar *uid = node->data;
797 folder->listItems = g_list_remove(folder->listItems,
800 node = g_list_next(node);
802 g_list_free(listRemove);
803 nodeFolder = g_list_next(nodeFolder);
805 /* Remove folders with parents. */
807 node = rootFolder->listFolder;
809 ItemFolder *folder = (ItemFolder *) node->data;
810 if (ADDRITEM_PARENT(folder))
811 /* Remove folders with parents */
812 listRemove = g_list_append(listRemove, folder);
813 else /* Add to root folder */
814 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
816 node = g_list_next( node );
818 /* Process remove list */
821 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
823 node = g_list_next(node);
825 g_list_free(listRemove);
827 /* Move all unparented persons and groups into root folder */
828 g_hash_table_foreach(book->addressCache->itemHash,
829 addrbook_res_items_vis, book);
831 /* Free up some more */
832 nodeFolder = book->tempList;
834 ItemFolder *folder = nodeFolder->data;
835 g_list_free(folder->listItems);
836 folder->listItems = NULL;
837 nodeFolder = g_list_next(nodeFolder);
839 g_list_free(book->tempList);
840 book->tempList = NULL;
843 /* Read address book file */
844 gint addrbook_read_data(AddressBookFile *book)
846 XMLFile *file = NULL;
847 gchar *fileSpec = NULL;
849 g_return_val_if_fail(book != NULL, -1);
852 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
853 addrcache_get_name( book->addressCache ) );
856 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
857 book->fileName, NULL);
858 book->retVal = MGU_OPEN_FILE;
859 addrcache_clear(book->addressCache);
860 book->addressCache->modified = FALSE;
861 book->addressCache->accessFlag = FALSE;
862 file = xml_open_file(fileSpec);
865 book->tempList = NULL;
866 /* Trap for parsing errors. */
867 if (setjmp( book->jumper)) {
868 xml_close_file(file);
871 addrbook_read_tree(book, file);
872 xml_close_file(file);
873 /* Resolve folder items */
874 addrbook_resolve_folder_items(book);
875 book->tempList = NULL;
876 book->addressCache->modified = FALSE;
877 book->addressCache->dataRead = TRUE;
878 addrcache_set_dirty(book->addressCache, FALSE);
883 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
886 for (i = 0; i < lvl; i++)
892 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
895 for(i = 0; i < lvl; i++)
902 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
907 xml_file_put_escape_str(fp, value);
911 /* Write file hash table visitor function */
912 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
915 AddrItemObject *obj = (AddrItemObject *) value;
916 FILE *fp = (FILE *) data;
921 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
922 ItemPerson *person = (ItemPerson *) value;
924 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
925 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
926 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
927 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
928 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
929 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
932 /* Output email addresses */
933 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
935 node = person->listEMail;
937 ItemEMail *email = node->data;
938 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
939 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
940 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
941 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
942 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
944 node = g_list_next(node);
946 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
948 /* Output user attributes */
949 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
951 node = person->listAttrib;
953 UserAttribute *attrib = node->data;
954 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
955 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
956 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
958 xml_file_put_escape_str(fp, attrib->value);
959 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
960 node = g_list_next(node);
962 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
963 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
968 /* Write file hash table visitor function */
969 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
972 AddrItemObject *obj = (AddrItemObject *) value;
973 FILE *fp = (FILE *) data;
978 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
979 ItemGroup *group = (ItemGroup *) value;
981 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
982 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
983 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
984 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
987 /* Output email address links */
988 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
990 node = group->listEMail;
992 ItemEMail *email = node->data;
993 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
994 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
995 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
996 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
998 node = g_list_next(node);
1000 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1001 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1006 /* Write file hash table visitor function */
1007 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1010 AddrItemObject *obj = (AddrItemObject *) value;
1011 FILE *fp = (FILE *) data;
1016 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1017 ItemFolder *folder = (ItemFolder *) value;
1019 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1020 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1021 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1022 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1024 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1027 /* Output persons */
1028 node = folder->listPerson;
1030 ItemPerson *item = node->data;
1031 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1032 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1033 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1035 node = g_list_next(node);
1039 node = folder->listGroup;
1041 ItemGroup *item = node->data;
1042 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1043 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1044 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1046 node = g_list_next(node);
1049 /* Output folders */
1050 node = folder->listFolder;
1052 ItemFolder *item = node->data;
1053 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1054 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1055 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1057 node = g_list_next(node);
1059 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1060 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1065 /* Output address book data to specified file.
1066 return: Status code */
1067 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1071 #ifndef DEV_STANDALONE
1075 g_return_val_if_fail(book != NULL, -1);
1076 g_return_val_if_fail(newFile != NULL, -1);
1078 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1080 book->retVal = MGU_OPEN_FILE;
1081 #ifdef DEV_STANDALONE
1082 fp = fopen(fileSpec, "wb");
1085 fputs("<?xml version=\"1.0\" ?>\n", fp);
1087 pfile = prefs_write_open(fileSpec);
1091 fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1092 conv_get_current_charset_str());
1094 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1095 addrbook_write_attr(fp, AB_ATTAG_NAME,
1096 addrcache_get_name(book->addressCache));
1099 /* Output all persons */
1100 g_hash_table_foreach(book->addressCache->itemHash,
1101 addrbook_write_item_person_vis, fp);
1103 /* Output all groups */
1104 g_hash_table_foreach(book->addressCache->itemHash,
1105 addrbook_write_item_group_vis, fp);
1107 /* Output all folders */
1108 g_hash_table_foreach(book->addressCache->itemHash,
1109 addrbook_write_item_folder_vis, fp);
1111 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1112 book->retVal = MGU_SUCCESS;
1113 #ifdef DEV_STANDALONE
1116 if (prefs_file_close( pfile ) < 0)
1117 book->retVal = MGU_ERROR_WRITE;
1122 return book->retVal;
1125 /* Output address book data to original file.
1126 return: Status code */
1127 gint addrbook_save_data(AddressBookFile *book)
1129 g_return_val_if_fail(book != NULL, -1);
1131 book->retVal = MGU_NO_FILE;
1132 if (book->fileName == NULL || *book->fileName == '\0')
1133 return book->retVal;
1134 if (book->path == NULL || *book->path == '\0')
1135 return book->retVal;
1137 addrbook_write_to(book, book->fileName);
1138 if (book->retVal == MGU_SUCCESS)
1139 addrcache_set_dirty(book->addressCache, FALSE);
1140 return book->retVal;
1143 /* **********************************************************************
1144 Address book edit interface functions...
1145 ***********************************************************************
1146 Move person's email item.
1147 param: book Address book.
1149 itemMove Item to move.
1150 itemTarget Target item before which to move item */
1151 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1152 ItemEMail *itemMove, ItemEMail *itemTarget)
1154 ItemEMail *email = NULL;
1156 g_return_val_if_fail(book != NULL, NULL);
1158 email = addritem_move_email_before(person, itemMove, itemTarget);
1160 addrcache_set_dirty(book->addressCache, TRUE);
1164 /* Move person's email item.
1165 param: book Address book.
1167 itemMove Item to move.
1168 itemTarget Target item after which to move item */
1169 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1170 ItemEMail *itemMove, ItemEMail *itemTarget)
1172 ItemEMail *email = NULL;
1174 g_return_val_if_fail(book != NULL, NULL);
1176 email = addritem_move_email_after(person, itemMove, itemTarget);
1178 addrcache_set_dirty(book->addressCache, TRUE);
1182 /* Hash table visitor function for deletion of hashtable entries */
1183 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1192 /* Update address book email list for specified person.
1193 Enter: book Address book.
1194 person Person to update.
1195 listEMail List of new email addresses.
1196 Note: The existing email addresses are replaced with the new addresses. Any references
1197 to old addresses in the groups are re-linked to the new addresses. All old addresses
1198 linked to the person are removed */
1199 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1206 g_return_if_fail(book != NULL);
1207 g_return_if_fail(person != NULL);
1209 /* Get groups where person's existing email addresses are listed */
1210 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1212 GHashTable *hashEMail;
1213 GHashTable *hashEMailAlias;
1216 /* Load hash table with new address entries */
1217 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1218 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1221 ItemEMail *email = node->data;
1222 gchar *addr = g_strdup(email->address);
1223 gchar *alias = email->obj.name ;
1225 if (!g_hash_table_lookup(hashEMail, addr)) {
1226 g_hash_table_insert(hashEMail, addr, email);
1228 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1230 g_hash_table_insert(hashEMailAlias, alias, email);
1232 node = g_list_next(node);
1235 /* Re-parent new addresses to existing groups, where email address match. */
1236 nodeGrp = listGroup;
1238 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1239 GList *groupEMail = group->listEMail;
1241 GList *listRemove = NULL;
1243 /* Process each email item linked to group */
1244 nodeGrpEM = groupEMail;
1246 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1248 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1249 /* Found an email address for this person */
1250 ItemEMail *emailNew = NULL;
1251 gchar *addr = g_strdup(emailGrp->address);
1252 gchar *alias = emailGrp->obj.name;
1254 emailNew = (ItemEMail *)
1255 g_hash_table_lookup(hashEMail, addr);
1257 /* If no match by e-mail, try to match by e-mail alias */
1258 if (!emailNew && *alias != '\0') {
1259 emailNew = (ItemEMail *)
1260 g_hash_table_lookup(hashEMailAlias, alias);
1264 /* Point to this entry */
1265 nodeGrpEM->data = emailNew;
1266 else if (g_hash_table_size(hashEMail)==1)
1267 /* If the person has just one e-mail address, then
1268 change e-mail address in group list */
1269 nodeGrpEM->data = listEMail->data;
1271 /* Mark for removal */
1272 listRemove = g_list_append(listRemove, emailGrp);
1274 /* Move on to next email link */
1275 nodeGrpEM = g_list_next(nodeGrpEM);
1278 /* Process all removed links in current group */
1279 nodeGrpEM = listRemove;
1281 ItemEMail *emailGrp = nodeGrpEM->data;
1282 groupEMail = g_list_remove(groupEMail, emailGrp);
1283 nodeGrpEM = g_list_next(nodeGrpEM);
1286 g_list_free(listRemove);
1288 /* Move on to next group */
1289 nodeGrp = g_list_next(nodeGrp);
1292 /* Clear hash table */
1293 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1294 addrbook_free_simple_hash_vis, NULL);
1295 g_hash_table_destroy(hashEMail);
1297 g_hash_table_destroy(hashEMailAlias);
1298 hashEMailAlias = NULL;
1299 g_list_free(listGroup);
1302 /* Remove old addresses from person and cache */
1304 node = person->listEMail;
1306 ItemEMail *email = node->data;
1308 if (addrcache_person_remove_email(book->addressCache, person, email))
1309 addrcache_remove_email(book->addressCache, email);
1311 listDelete = g_list_append(listDelete, email);
1312 node = person->listEMail;
1314 /* Add new address entries */
1317 ItemEMail *email = node->data;
1319 if (ADDRITEM_ID(email) == NULL)
1320 /* Allocate an ID for new address */
1321 addrcache_id_email(book->addressCache, email);
1323 addrcache_person_add_email( book->addressCache, person, email );
1324 node = g_list_next( node );
1327 addrcache_set_dirty(book->addressCache, TRUE);
1329 /* Free up memory */
1330 g_list_free(listEMail);
1335 ItemEMail *email = node->data;
1337 addritem_free_item_email(email);
1338 node = g_list_next(node);
1340 g_list_free(listDelete);
1345 /* Add person and address data to address book.
1346 Enter: book Address book.
1347 folder Folder where to add person, or NULL for root folder.
1348 listEMail New list of email addresses.
1349 Return: Person added.
1350 Note: A new person is created with specified list of email addresses. All objects inserted
1351 into address book */
1352 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1356 ItemFolder *f = folder;
1359 g_return_val_if_fail(book != NULL, NULL);
1362 f = book->addressCache->rootFolder;
1363 person = addritem_create_item_person();
1364 addrcache_id_person(book->addressCache, person);
1365 addrcache_folder_add_person(book->addressCache, f, person);
1369 ItemEMail *email = node->data;
1370 if (ADDRITEM_ID(email) == NULL)
1371 addrcache_id_email(book->addressCache, email);
1373 addrcache_person_add_email(book->addressCache, person, email);
1374 node = g_list_next(node);
1379 /* Build available email list visitor function */
1380 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1383 AddrItemObject *obj = (AddrItemObject *) value;
1385 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1386 AddressBookFile *book = data;
1387 ItemPerson *person = (ItemPerson *) obj;
1388 GList *node = person->listEMail;
1390 ItemEMail *email = node->data;
1391 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1393 if (!g_hash_table_lookup(book->tempHash,
1394 ADDRITEM_ID(email)))
1395 book->tempList = g_list_append(book->tempList, email);
1397 node = g_list_next(node);
1402 /* Return link list of available email items (which have not already been linked to
1403 groups). Note that the list contains references to items and should be g_free()
1404 when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1405 destroy the addressbook data!
1406 Return: List of items, or NULL if none */
1407 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1412 g_return_val_if_fail(book != NULL, NULL);
1414 /* Load hash table with group email entries */
1415 table = g_hash_table_new(g_str_hash, g_str_equal);
1417 list = group->listEMail;
1419 ItemEMail *email = list->data;
1420 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1421 list = g_list_next(list);
1425 /* Build list of available email addresses which exclude those already in groups */
1426 book->tempList = NULL;
1427 book->tempHash = table;
1428 g_hash_table_foreach(book->addressCache->itemHash,
1429 addrbook_build_avail_email_vis, book);
1430 list = book->tempList;
1431 book->tempList = NULL;
1432 book->tempHash = NULL;
1434 /* Clear hash table */
1435 g_hash_table_destroy(table);
1441 /* Update address book email list for specified group.
1442 Enter: book Address book.
1443 group group to update.
1444 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1445 Note: The existing email addresses are replaced with the new addresses. Any references
1446 to old addresses in the groups are re-linked to the new addresses. All old addresses
1447 linked to the person are removed */
1448 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1453 g_return_if_fail(book != NULL);
1454 g_return_if_fail(group != NULL);
1456 addrcache_set_dirty(book->addressCache, TRUE);
1458 /* Remember old list */
1459 oldData = group->listEMail;
1460 group->listEMail = listEMail;
1461 mgu_clear_list(oldData);
1465 /* Add group and email list to address book.
1466 Enter: book Address book.
1467 folder Parent folder, or NULL for root folder.
1468 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1469 Return: Group object.
1470 Note: The existing email addresses are replaced with the new addresses. Any references
1471 to old addresses in the groups are re-linked to the new addresses. All old addresses
1472 linked to the person are removed */
1473 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1476 ItemGroup *group = NULL;
1477 ItemFolder *f = folder;
1479 g_return_val_if_fail(book != NULL, NULL);
1482 f = book->addressCache->rootFolder;
1483 group = addritem_create_item_group();
1484 addrcache_id_group(book->addressCache, group);
1485 addrcache_folder_add_group(book->addressCache, f, group);
1486 group->listEMail = listEMail;
1490 /* Add new folder to address book.
1491 Enter: book Address book.
1492 parent Parent folder.
1493 Return: Folder that was added. This should *NOT* be g_free() when done */
1494 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1496 ItemFolder *folder = NULL;
1497 ItemFolder *p = parent;
1499 g_return_val_if_fail(book != NULL, NULL);
1502 p = book->addressCache->rootFolder;
1503 folder = addritem_create_item_folder();
1504 addrcache_id_folder(book->addressCache, folder);
1505 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1506 p->listFolder = g_list_append(p->listFolder, folder);
1507 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1508 addrcache_set_dirty(book->addressCache, TRUE);
1511 addritem_free_item_folder(folder);
1517 /* Update address book attribute list for specified person.
1518 Enter: book Address book.
1519 person Person to update.
1520 listAttrib New list of attributes.
1521 Note: The existing email addresses are replaced with the new addresses. All old attributes
1522 linked to the person are removed */
1523 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1529 g_return_if_fail(book != NULL);
1530 g_return_if_fail(person != NULL);
1532 /* Remember old list */
1533 oldData = person->listAttrib;
1535 /* Attach new address list to person. */
1538 UserAttribute *attrib = node->data;
1539 if (attrib->uid == NULL) {
1540 /* Allocate an ID */
1541 addrcache_id_attribute(book->addressCache, attrib);
1543 node = g_list_next(node);
1545 person->listAttrib = listAttrib;
1546 addrcache_set_dirty(book->addressCache, TRUE);
1548 /* Free up old data */
1549 addritem_free_list_attribute(oldData);
1554 * Add attribute data for person to address book.
1555 * Enter: book Address book.
1556 * person New person object.
1557 * listAttrib New list of attributes.
1558 * Note: Only attributes are inserted into address book.
1560 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1563 g_return_if_fail( book != NULL );
1564 g_return_if_fail( person != NULL );
1568 UserAttribute *attrib = node->data;
1569 if( attrib->uid == NULL ) {
1570 addrcache_id_attribute( book->addressCache, attrib );
1572 addritem_person_add_attribute( person, attrib );
1573 node = g_list_next( node );
1575 addrcache_set_dirty( book->addressCache, TRUE );
1578 /* Return address book file for specified object.
1579 Enter: aio Book item object.
1580 Return: Address book, or NULL if not found */
1581 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1583 AddressBookFile *book = NULL;
1586 ItemFolder *parent = NULL;
1587 ItemFolder *root = NULL;
1588 if (aio->type == ITEMTYPE_EMAIL) {
1589 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1591 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1594 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1597 root = addrcache_find_root_folder(parent);
1599 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1604 /* Remove folder from address book. Children are re-parented to parent folder.
1605 param: folder Folder to remove.
1606 return: Folder, or NULL if not found. Note that object should still be freed */
1607 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1611 g_return_val_if_fail(book != NULL, NULL);
1613 f = addrcache_remove_folder(book->addressCache, folder);
1617 /* Remove folder from address book. Children are deleted.
1618 param: folder Folder to remove.
1619 return: Folder, or NULL if not found. Note that object should still be freed */
1620 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1625 g_return_val_if_fail(book != NULL, NULL);
1627 f = addrcache_remove_folder_delete(book->addressCache, folder);
1631 #define WORK_BUFLEN 1024
1632 #define ADDRBOOK_DIGITS "0123456789"
1634 /* Return list of existing address book files.
1635 Enter: book Address book file.
1636 Return: File list */
1637 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1640 struct dirent *entry;
1641 struct stat statbuf;
1642 gchar buf[WORK_BUFLEN];
1643 gchar numbuf[WORK_BUFLEN];
1644 gint len, lenpre, lensuf, lennum;
1645 long int val, maxval;
1646 GList *fileList = NULL;
1648 g_return_val_if_fail(book != NULL, NULL);
1650 if (book->path == NULL || *book->path == '\0') {
1651 book->retVal = MGU_NO_PATH;
1655 strcpy(buf, book->path);
1658 if (buf[len-1] != G_DIR_SEPARATOR) {
1659 buf[len] = G_DIR_SEPARATOR;
1664 adbookdir = g_strdup(buf);
1665 strcat(buf, ADDRBOOK_PREFIX);
1667 if ((dp = opendir(adbookdir)) == NULL) {
1668 book->retVal = MGU_OPEN_DIRECTORY;
1673 lenpre = strlen(ADDRBOOK_PREFIX);
1674 lensuf = strlen(ADDRBOOK_SUFFIX);
1675 lennum = FILE_NUMDIGITS + lenpre;
1678 while ((entry = readdir(dp)) != NULL) {
1679 gchar *endptr = NULL;
1683 strcpy(buf, adbookdir);
1684 strcat(buf, entry->d_name);
1685 stat(buf, &statbuf);
1686 if (S_IFREG & statbuf.st_mode) {
1687 if (strncmp(entry->d_name, ADDRBOOK_PREFIX, lenpre) == 0) {
1688 if (strncmp((entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf) == 0) {
1689 strncpy(numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS);
1690 numbuf[FILE_NUMDIGITS] = '\0';
1692 for(i = 0; i < FILE_NUMDIGITS; i++) {
1693 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1700 val = strtol(numbuf, &endptr, 10);
1701 if (endptr && val > -1) {
1702 if (val > maxval) maxval = val;
1703 fileList = g_list_append(fileList, g_strdup(entry->d_name));
1713 book->maxValue = maxval;
1714 book->retVal = MGU_SUCCESS;
1718 /* Return file name for specified file number.
1719 Enter: fileNum File number.
1720 Return: File name, or NULL if file number too large. Should be g_free() when done */
1721 gchar *addrbook_gen_new_file_name(gint fileNum) {
1723 gchar buf[WORK_BUFLEN];
1729 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1732 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1733 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1734 return g_strdup(buf);
1737 /* **********************************************************************
1738 Address book test functions...
1739 **********************************************************************
1743 * Test email address list.
1745 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1750 prev_level = file->level;
1751 if (xml_parse_next_tag(file))
1752 longjmp(book->jumper, 1);
1753 if (file->level < prev_level)
1755 attr = xml_get_current_tag_attr(file);
1756 /* addrbook_show_attribs( attr ); */
1757 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1758 addrbook_chkparse_addr_list(book, file);
1762 /* Test user attributes for person */
1763 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1768 attr = xml_get_current_tag_attr(file);
1769 /* addrbook_show_attribs( attr ); */
1770 element = xml_get_element(file);
1771 /* printf( "\t\tattrib value : %s\n", element ); */
1774 /* Test attribute list */
1775 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1780 prev_level = file->level;
1781 if (xml_parse_next_tag(file))
1782 longjmp(book->jumper, 1);
1783 if (file->level < prev_level)
1785 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1786 addrbook_chkparse_attribute(book, file);
1787 addrbook_chkparse_attr_list(book, file);
1793 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1797 attr = xml_get_current_tag_attr(file);
1798 /* addrbook_show_attribs( attr ); */
1799 if (xml_parse_next_tag(file)) /* Consume closing tag */
1800 longjmp(book->jumper, 1);
1802 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1803 addrbook_chkparse_addr_list(book, file);
1805 if (xml_parse_next_tag(file)) /* Consume closing tag */
1806 longjmp(book->jumper, 1);
1808 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1809 addrbook_chkparse_attr_list(book, file);
1812 /* Test group member list */
1813 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
1819 prev_level = file->level;
1820 if (xml_parse_next_tag(file))
1821 longjmp(book->jumper, 1);
1823 if (file->level < prev_level)
1826 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
1827 attr = xml_get_current_tag_attr(file);
1828 /* addrbook_show_attribs( attr ); */
1829 addrbook_chkparse_member_list(book, file);
1832 attr = xml_get_current_tag_attr(file);
1833 /* addrbook_show_attribs( attr ); */
1839 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
1843 attr = xml_get_current_tag_attr(file);
1844 /* addrbook_show_attribs( attr ); */
1845 if (xml_parse_next_tag(file)) /* Consume closing tag */
1846 longjmp(book->jumper, 1);
1848 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
1849 addrbook_chkparse_member_list(book, file);
1852 /* Test folder item list */
1853 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
1859 prev_level = file->level;
1860 if (xml_parse_next_tag(file))
1861 longjmp(book->jumper, 1);
1863 if (file->level < prev_level)
1866 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
1867 attr = xml_get_current_tag_attr(file);
1868 /* addrbook_show_attribs( attr ); */
1869 addrbook_chkparse_folder_list(book, file);
1872 attr = xml_get_current_tag_attr(file);
1873 /* addrbook_show_attribs( attr ); */
1879 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
1883 attr = xml_get_current_tag_attr(file);
1884 /* addrbook_show_attribs( attr ); */
1885 if (xml_parse_next_tag(file)) /* Consume closing tag */
1886 longjmp(book->jumper, 1);
1888 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
1889 addrbook_chkparse_folder_list(book, file);
1892 /* Test address book */
1893 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
1898 if (xml_get_dtd(file))
1901 if (xml_parse_next_tag(file))
1904 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
1907 attr = xml_get_current_tag_attr(file);
1908 /* addrbook_show_attribs( attr ); */
1915 if (xml_parse_next_tag(file))
1916 longjmp(book->jumper, 1);
1918 /* Get next tag (person, group or folder) */
1919 if (xml_compare_tag(file, AB_ELTAG_PERSON))
1920 addrbook_chkparse_person( book, file );
1921 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
1922 addrbook_chkparse_group(book, file);
1923 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
1924 addrbook_chkparse_folder(book, file);
1929 /* Test address book file by parsing contents.
1930 Enter: book Address book file to check.
1931 fileName File name to check.
1932 Return: MGU_SUCCESS if file appears to be valid format */
1933 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
1935 XMLFile *file = NULL;
1936 gchar *fileSpec = NULL;
1938 g_return_val_if_fail(book != NULL, -1);
1940 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
1941 book->retVal = MGU_OPEN_FILE;
1942 file = xml_open_file(fileSpec);
1945 book->retVal = MGU_BAD_FORMAT;
1946 if (setjmp(book->jumper)) {
1947 /* printf( "Caught Ya!!!\n" ); */
1948 xml_close_file(file);
1949 return book->retVal;
1951 if (addrbook_chkread_tree(book, file))
1952 book->retVal = MGU_SUCCESS;
1954 xml_close_file( file );
1956 return book->retVal;
1959 /* Return link list of all persons in address book. Note that the list contains
1960 references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1961 this will destroy the addressbook data!
1962 Return: List of items, or NULL if none */
1963 GList *addrbook_get_all_persons(AddressBookFile *book)
1965 g_return_val_if_fail(book != NULL, NULL);
1966 return addrcache_get_all_persons(book->addressCache);
1969 /* Add person and address data to address book.
1970 Enter: book Address book.
1971 folder Folder where to add person, or NULL for root folder.
1973 address EMail address.
1975 Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1976 this will destroy the address book data */
1977 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
1978 const gchar *name,const gchar *address,
1979 const gchar *remarks)
1981 g_return_val_if_fail(book != NULL, NULL);
1982 return addrcache_add_contact(book->addressCache, folder, name, address,
1986 /* Return file name for next address book file.
1987 Enter: book Address book.
1988 Return: File name, or NULL if could not create. This should be g_free()
1990 gchar *addrbook_guess_next_file(AddressBookFile *book)
1992 gchar *newFile = NULL;
1993 GList *fileList = NULL;
1995 fileList = addrbook_get_bookfile_list(book);
1997 fileNum = 1 + book->maxValue;
1999 newFile = addrbook_gen_new_file_name(fileNum);
2000 g_list_free(fileList);