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\n", book->retVal );
239 addrcache_print(book->addressCache, stream);
242 /* Dump entire address book traversing folders */
243 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
247 g_return_if_fail(book != NULL);
249 addrbook_print_book(book, stream);
250 folder = book->addressCache->rootFolder;
251 addritem_print_item_folder(folder, stream);
254 /* Remove group from address book.
255 param: group Group to remove.
256 return: Group, or NULL if not found.
257 Note that object should still be freed */
258 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
260 g_return_val_if_fail(book != NULL, NULL);
261 return addrcache_remove_group(book->addressCache, group);
264 /* Remove specified person from address book.
265 param: person Person to remove.
266 return: Person, or NULL if not found.
267 Note that object should still be freed */
268 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
270 g_return_val_if_fail(book != NULL, NULL);
271 return addrcache_remove_person(book->addressCache, person);
274 /* Remove email address in address book for specified person.
275 param: person Person.
276 email EMail to remove.
277 return: EMail object, or NULL if not found.
278 Note that object should still be freed */
279 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
280 ItemPerson *person, ItemEMail *email)
282 g_return_val_if_fail(book != NULL, NULL);
283 return addrcache_person_remove_email(book->addressCache, person, email);
286 /* **********************************************************************
287 * Read/Write XML data file...
288 * ===========================
290 * 1) The address book is structured as follows:
305 * 2) This sequence of elements was chosen so that the most important
306 * elements (person and their email addresses) appear first.
308 * 3) Groups then appear. When groups are loaded, person's email
309 * addresses have already been loaded and can be found.
311 * 4) Finally folders are loaded. Any forward and backward references
312 * to folders, groups and persons in the folders are resolved after
315 * ***********************************************************************
318 /* Element tag names */
319 #define AB_ELTAG_ADDRESS "address"
320 #define AB_ELTAG_ATTRIBUTE "attribute"
321 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
322 #define AB_ELTAG_ADDRESS_LIST "address-list"
323 #define AB_ELTAG_MEMBER "member"
324 #define AB_ELTAG_MEMBER_LIST "member-list"
325 #define AB_ELTAG_ITEM "item"
326 #define AB_ELTAG_ITEM_LIST "item-list"
327 #define AB_ELTAG_ADDRESS_BOOK "address-book"
328 #define AB_ELTAG_PERSON "person"
329 #define AB_ELTAG_GROUP "group"
330 #define AB_ELTAG_FOLDER "folder"
332 /* Attribute tag names */
333 #define AB_ATTAG_TYPE "type"
334 #define AB_ATTAG_UID "uid"
335 #define AB_ATTAG_NAME "name"
336 #define AB_ATTAG_REMARKS "remarks"
337 #define AB_ATTAG_FIRST_NAME "first-name"
338 #define AB_ATTAG_LAST_NAME "last-name"
339 #define AB_ATTAG_NICK_NAME "nick-name"
340 #define AB_ATTAG_COMMON_NAME "cn"
341 #define AB_ATTAG_ALIAS "alias"
342 #define AB_ATTAG_EMAIL "email"
343 #define AB_ATTAG_EID "eid"
344 #define AB_ATTAG_PID "pid"
346 /* Attribute values */
347 #define AB_ATTAG_VAL_PERSON "person"
348 #define AB_ATTAG_VAL_GROUP "group"
349 #define AB_ATTAG_VAL_FOLDER "folder"
351 /* Parse address item for person */
352 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
357 ItemEMail *email = NULL;
359 attr = xml_get_current_tag_attr(file);
361 name = ((XMLAttr *)attr->data)->name;
362 value = ((XMLAttr *)attr->data)->value;
364 email = addritem_create_item_email();
365 if (strcmp(name, AB_ATTAG_UID) == 0)
366 ADDRITEM_ID(email) = g_strdup(value);
367 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
368 ADDRITEM_NAME(email) = g_strdup(value);
369 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
370 email->address = g_strdup(value);
371 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
372 email->remarks = g_strdup(value);
373 attr = g_list_next(attr);
377 addrcache_person_add_email(book->addressCache, person,
381 addritem_free_item_email(email);
387 /* Parse email address list */
388 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
395 prev_level = file->level;
396 if (xml_parse_next_tag(file)) {
397 longjmp(book->jumper, 1);
399 if (file->level < prev_level) return;
400 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
401 attr = xml_get_current_tag_attr(file);
402 addrbook_parse_address(book, file, person);
403 addrbook_parse_addr_list(book, file, person);
408 /* Parse attibute for person */
409 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
414 UserAttribute *uAttr = NULL;
416 attr = xml_get_current_tag_attr(file);
418 name = ((XMLAttr *)attr->data)->name;
419 value = ((XMLAttr *)attr->data)->value;
420 if (!uAttr) uAttr = addritem_create_attribute();
421 if (strcmp(name, AB_ATTAG_UID) == 0)
422 addritem_attrib_set_id(uAttr, value);
423 else if (strcmp(name, AB_ATTAG_NAME) == 0)
424 addritem_attrib_set_name(uAttr, value);
425 attr = g_list_next(attr);
428 element = xml_get_element(file);
429 addritem_attrib_set_value(uAttr, element);
433 addritem_person_add_attribute(person, uAttr);
436 addritem_free_attribute(uAttr);
442 /* Parse attribute list */
443 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
450 prev_level = file->level;
451 if (xml_parse_next_tag(file)) {
452 longjmp( book->jumper, 1 );
454 if (file->level < prev_level) return;
455 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
456 attr = xml_get_current_tag_attr(file);
457 addrbook_parse_attribute(file, person);
458 addrbook_parse_attr_list(book, file, person);
464 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
468 ItemPerson *person = NULL;
470 attr = xml_get_current_tag_attr(file);
472 name = ((XMLAttr *)attr->data)->name;
473 value = ((XMLAttr *)attr->data)->value;
475 person = addritem_create_item_person();
476 if (strcmp(name, AB_ATTAG_UID) == 0)
477 ADDRITEM_ID(person) = g_strdup(value);
478 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
479 person->firstName = g_strdup(value);
480 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
481 person->lastName = g_strdup(value);
482 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
483 person->nickName = g_strdup(value);
484 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
485 ADDRITEM_NAME(person) = g_strdup(value);
486 attr = g_list_next(attr);
488 if (xml_parse_next_tag(file)) { /* Consume closing tag */
489 longjmp(book->jumper, 1);
491 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
492 addrbook_parse_addr_list(book, file, person);
494 addrcache_hash_add_person(book->addressCache, person);
497 if (xml_parse_next_tag(file)) { /* Consume closing tag */
498 longjmp(book->jumper, 1);
500 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
501 addrbook_parse_attr_list(book, file, person);
505 /* Parse group member */
506 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
511 gchar *pid = NULL, *eid = NULL;
512 ItemEMail *email = NULL;
514 attr = xml_get_current_tag_attr(file);
516 name = ((XMLAttr *)attr->data)->name;
517 value = ((XMLAttr *)attr->data)->value;
518 if (strcmp(name, AB_ATTAG_PID) == 0)
519 pid = g_strdup(value);
520 else if (strcmp(name, AB_ATTAG_EID) == 0)
521 eid = g_strdup(value);
522 attr = g_list_next(attr);
524 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
525 email = addrcache_get_email(book->addressCache, eid);
528 addrcache_group_add_email(book->addressCache, group,
532 addritem_free_item_email(email);
538 /* Parse group member list */
539 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
546 prev_level = file->level;
547 if (xml_parse_next_tag(file)) {
548 longjmp(book->jumper, 1);
550 if (file->level < prev_level)
552 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
553 attr = xml_get_current_tag_attr(file);
554 addrbook_parse_member(book, file, group);
555 addrbook_parse_member_list(book, file, group);
558 attr = xml_get_current_tag_attr(file);
564 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
568 ItemGroup *group = NULL;
570 attr = xml_get_current_tag_attr(file);
572 name = ((XMLAttr *)attr->data)->name;
573 value = ((XMLAttr *)attr->data)->value;
575 group = addritem_create_item_group();
576 if (strcmp(name, AB_ATTAG_UID) == 0)
577 ADDRITEM_ID(group) = g_strdup(value);
578 else if (strcmp(name, AB_ATTAG_NAME) == 0)
579 ADDRITEM_NAME(group) = g_strdup(value);
580 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
581 group->remarks = g_strdup(value);
582 attr = g_list_next(attr);
584 if (xml_parse_next_tag(file)) { /* Consume closing tag */
585 longjmp(book->jumper, 1);
587 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
589 addrcache_hash_add_group(book->addressCache, group);
591 addrbook_parse_member_list(book, file, group);
595 /* Parse folder item */
596 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
603 attr = xml_get_current_tag_attr(file);
605 name = ((XMLAttr *)attr->data)->name;
606 value = ((XMLAttr *)attr->data)->value;
607 if (strcmp(name, AB_ATTAG_UID) == 0) {
608 uid = g_strdup(value);
610 attr = g_list_next(attr);
614 folder->listItems = g_list_append(folder->listItems, uid);
619 /* Parse folder item list */
620 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
627 prev_level = file->level;
628 if (xml_parse_next_tag(file)) {
629 longjmp(book->jumper, 1);
631 if (file->level < prev_level)
633 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
634 attr = xml_get_current_tag_attr(file);
635 addrbook_parse_folder_item(book, file, folder);
636 addrbook_parse_folder_list(book, file, folder);
639 attr = xml_get_current_tag_attr(file);
645 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
649 ItemFolder *folder = NULL;
651 attr = xml_get_current_tag_attr(file);
653 name = ((XMLAttr *)attr->data)->name;
654 value = ((XMLAttr *)attr->data)->value;
656 folder = addritem_create_item_folder();
657 if (strcmp(name, AB_ATTAG_UID) == 0)
658 ADDRITEM_ID(folder) = g_strdup(value);
659 else if (strcmp(name, AB_ATTAG_NAME) == 0)
660 ADDRITEM_NAME(folder) = g_strdup(value);
661 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
662 folder->remarks = g_strdup(value);
663 attr = g_list_next(attr);
665 if (xml_parse_next_tag(file)) { /* Consume closing tag */
666 longjmp(book->jumper, 1);
668 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
670 if (addrcache_hash_add_folder(book->addressCache,
672 book->tempList = g_list_append(book->tempList,
674 /* We will resolve folder later */
675 ADDRITEM_PARENT(folder) = NULL;
678 addrbook_parse_folder_list(book, file, folder);
682 /* Parse address book.
683 Return: TRUE if data read successfully, FALSE if error reading data */
684 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
690 book->retVal = MGU_BAD_FORMAT;
691 if (xml_get_dtd(file))
693 if (xml_parse_next_tag(file))
694 longjmp(book->jumper, 1);
695 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
698 attr = xml_get_current_tag_attr(file);
700 name = ((XMLAttr *)attr->data)->name;
701 value = ((XMLAttr *)attr->data)->value;
702 if (strcmp( name, AB_ATTAG_NAME) == 0)
703 addrbook_set_name( book, value );
704 attr = g_list_next( attr );
711 /* Get next item tag (person, group or folder) */
712 if (xml_parse_next_tag(file))
713 longjmp( book->jumper, 1 );
715 if (xml_compare_tag(file, AB_ELTAG_PERSON))
716 addrbook_parse_person(book, file);
717 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
718 addrbook_parse_group(book, file);
719 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
720 addrbook_parse_folder(book, file);
722 if (retVal) book->retVal = MGU_SUCCESS;
726 /* Resolve folder items visitor function */
727 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
729 AddressBookFile *book = data;
730 AddrItemObject *obj = (AddrItemObject *) value;
731 ItemFolder *rootFolder = book->addressCache->rootFolder;
732 if (obj->parent == NULL) {
733 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
734 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
736 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
738 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
739 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
741 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
746 /* Resolve folder items. Lists of UID's are replaced with pointers to
748 static void addrbook_resolve_folder_items(AddressBookFile *book)
750 GList *nodeFolder = NULL;
751 GList *listRemove = NULL;
753 ItemFolder *rootFolder = book->addressCache->rootFolder;
754 nodeFolder = book->tempList;
757 ItemFolder *folder = nodeFolder->data;
759 node = folder->listItems;
761 gchar *uid = node->data;
762 AddrItemObject *aio = addrcache_get_object(book->addressCache,
765 if (aio->type == ITEMTYPE_FOLDER) {
766 ItemFolder *item = (ItemFolder *) aio;
767 folder->listFolder = g_list_append(folder->listFolder, item);
768 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
769 addrcache_hash_add_folder(book->addressCache, folder);
771 else if (aio->type == ITEMTYPE_PERSON) {
772 ItemPerson *item = (ItemPerson *) aio;
773 folder->listPerson = g_list_append(folder->listPerson, item);
774 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
776 else if (aio->type == ITEMTYPE_GROUP) {
777 ItemGroup *item = (ItemGroup *) aio;
778 folder->listGroup = g_list_append(folder->listGroup, item);
779 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
781 /* Replace data with pointer to item */
785 else { /* Not found, append to remove list. */
786 listRemove = g_list_append(listRemove, uid);
788 node = g_list_next(node);
790 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
792 /* Process remove list */
795 gchar *uid = node->data;
796 folder->listItems = g_list_remove(folder->listItems,
799 node = g_list_next(node);
801 g_list_free(listRemove);
802 nodeFolder = g_list_next(nodeFolder);
804 /* Remove folders with parents. */
806 node = rootFolder->listFolder;
808 ItemFolder *folder = (ItemFolder *) node->data;
809 if (ADDRITEM_PARENT(folder))
810 /* Remove folders with parents */
811 listRemove = g_list_append(listRemove, folder);
812 else /* Add to root folder */
813 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
815 node = g_list_next( node );
817 /* Process remove list */
820 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
822 node = g_list_next(node);
824 g_list_free(listRemove);
826 /* Move all unparented persons and groups into root folder */
827 g_hash_table_foreach(book->addressCache->itemHash,
828 addrbook_res_items_vis, book);
830 /* Free up some more */
831 nodeFolder = book->tempList;
833 ItemFolder *folder = nodeFolder->data;
834 g_list_free(folder->listItems);
835 folder->listItems = NULL;
836 nodeFolder = g_list_next(nodeFolder);
838 g_list_free(book->tempList);
839 book->tempList = NULL;
842 /* Read address book file */
843 gint addrbook_read_data(AddressBookFile *book)
845 XMLFile *file = NULL;
846 gchar *fileSpec = NULL;
848 g_return_val_if_fail(book != NULL, -1);
851 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
852 addrcache_get_name( book->addressCache ) );
855 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
856 book->fileName, NULL);
857 book->retVal = MGU_OPEN_FILE;
858 addrcache_clear(book->addressCache);
859 book->addressCache->modified = FALSE;
860 book->addressCache->accessFlag = FALSE;
861 file = xml_open_file(fileSpec);
864 book->tempList = NULL;
865 /* Trap for parsing errors. */
866 if (setjmp( book->jumper)) {
867 xml_close_file(file);
870 addrbook_read_tree(book, file);
871 xml_close_file(file);
872 /* Resolve folder items */
873 addrbook_resolve_folder_items(book);
874 book->tempList = NULL;
875 book->addressCache->modified = FALSE;
876 book->addressCache->dataRead = TRUE;
877 addrcache_set_dirty(book->addressCache, FALSE);
882 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
885 for (i = 0; i < lvl; i++)
891 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
894 for(i = 0; i < lvl; i++)
901 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
906 xml_file_put_escape_str(fp, value);
910 /* Write file hash table visitor function */
911 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
914 AddrItemObject *obj = (AddrItemObject *) value;
915 FILE *fp = (FILE *) data;
920 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
921 ItemPerson *person = (ItemPerson *) value;
923 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
924 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
925 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
926 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
927 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
928 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
931 /* Output email addresses */
932 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
934 node = person->listEMail;
936 ItemEMail *email = node->data;
937 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
938 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
939 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
940 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
941 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
943 node = g_list_next(node);
945 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
947 /* Output user attributes */
948 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
950 node = person->listAttrib;
952 UserAttribute *attrib = node->data;
953 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
954 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
955 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
957 xml_file_put_escape_str(fp, attrib->value);
958 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
959 node = g_list_next(node);
961 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
962 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
967 /* Write file hash table visitor function */
968 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
971 AddrItemObject *obj = (AddrItemObject *) value;
972 FILE *fp = (FILE *) data;
977 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
978 ItemGroup *group = (ItemGroup *) value;
980 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
981 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
982 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
983 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
986 /* Output email address links */
987 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
989 node = group->listEMail;
991 ItemEMail *email = node->data;
992 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
993 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
994 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
995 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
997 node = g_list_next(node);
999 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1000 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1005 /* Write file hash table visitor function */
1006 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1009 AddrItemObject *obj = (AddrItemObject *) value;
1010 FILE *fp = (FILE *) data;
1015 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1016 ItemFolder *folder = (ItemFolder *) value;
1018 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1019 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1020 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1021 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1023 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1026 /* Output persons */
1027 node = folder->listPerson;
1029 ItemPerson *item = node->data;
1030 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1031 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1032 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1034 node = g_list_next(node);
1038 node = folder->listGroup;
1040 ItemGroup *item = node->data;
1041 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1042 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1043 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1045 node = g_list_next(node);
1048 /* Output folders */
1049 node = folder->listFolder;
1051 ItemFolder *item = node->data;
1052 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1053 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1054 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1056 node = g_list_next(node);
1058 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1059 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1064 /* Output address book data to specified file.
1065 return: Status code */
1066 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1070 #ifndef DEV_STANDALONE
1074 g_return_val_if_fail(book != NULL, -1);
1075 g_return_val_if_fail(newFile != NULL, -1);
1077 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1079 book->retVal = MGU_OPEN_FILE;
1080 #ifdef DEV_STANDALONE
1081 fp = fopen(fileSpec, "wb");
1084 fputs("<?xml version=\"1.0\" ?>\n", fp);
1086 pfile = prefs_write_open(fileSpec);
1090 fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1091 conv_get_current_charset_str());
1093 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1094 addrbook_write_attr(fp, AB_ATTAG_NAME,
1095 addrcache_get_name(book->addressCache));
1098 /* Output all persons */
1099 g_hash_table_foreach(book->addressCache->itemHash,
1100 addrbook_write_item_person_vis, fp);
1102 /* Output all groups */
1103 g_hash_table_foreach(book->addressCache->itemHash,
1104 addrbook_write_item_group_vis, fp);
1106 /* Output all folders */
1107 g_hash_table_foreach(book->addressCache->itemHash,
1108 addrbook_write_item_folder_vis, fp);
1110 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1111 book->retVal = MGU_SUCCESS;
1112 #ifdef DEV_STANDALONE
1115 if (prefs_file_close( pfile ) < 0)
1116 book->retVal = MGU_ERROR_WRITE;
1121 return book->retVal;
1124 /* Output address book data to original file.
1125 return: Status code */
1126 gint addrbook_save_data(AddressBookFile *book)
1128 g_return_val_if_fail(book != NULL, -1);
1130 book->retVal = MGU_NO_FILE;
1131 if (book->fileName == NULL || *book->fileName == '\0')
1132 return book->retVal;
1133 if (book->path == NULL || *book->path == '\0')
1134 return book->retVal;
1136 addrbook_write_to(book, book->fileName);
1137 if (book->retVal == MGU_SUCCESS)
1138 addrcache_set_dirty(book->addressCache, FALSE);
1139 return book->retVal;
1142 /* **********************************************************************
1143 Address book edit interface functions...
1144 ***********************************************************************
1145 Move person's email item.
1146 param: book Address book.
1148 itemMove Item to move.
1149 itemTarget Target item before which to move item */
1150 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1151 ItemEMail *itemMove, ItemEMail *itemTarget)
1153 ItemEMail *email = NULL;
1155 g_return_val_if_fail(book != NULL, NULL);
1157 email = addritem_move_email_before(person, itemMove, itemTarget);
1159 addrcache_set_dirty(book->addressCache, TRUE);
1163 /* Move person's email item.
1164 param: book Address book.
1166 itemMove Item to move.
1167 itemTarget Target item after which to move item */
1168 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1169 ItemEMail *itemMove, ItemEMail *itemTarget)
1171 ItemEMail *email = NULL;
1173 g_return_val_if_fail(book != NULL, NULL);
1175 email = addritem_move_email_after(person, itemMove, itemTarget);
1177 addrcache_set_dirty(book->addressCache, TRUE);
1181 /* Hash table visitor function for deletion of hashtable entries */
1182 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1191 /* Update address book email list for specified person.
1192 Enter: book Address book.
1193 person Person to update.
1194 listEMail List of new email addresses.
1195 Note: The existing email addresses are replaced with the new addresses. Any references
1196 to old addresses in the groups are re-linked to the new addresses. All old addresses
1197 linked to the person are removed */
1198 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1205 g_return_if_fail(book != NULL);
1206 g_return_if_fail(person != NULL);
1208 /* Get groups where person's existing email addresses are listed */
1209 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1211 GHashTable *hashEMail;
1212 GHashTable *hashEMailAlias;
1215 /* Load hash table with new address entries */
1216 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1217 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1220 ItemEMail *email = node->data;
1221 gchar *addr = g_strdup(email->address);
1222 gchar *alias = email->obj.name ;
1224 if (!g_hash_table_lookup(hashEMail, addr)) {
1225 g_hash_table_insert(hashEMail, addr, email);
1227 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1229 g_hash_table_insert(hashEMailAlias, alias, email);
1231 node = g_list_next(node);
1234 /* Re-parent new addresses to existing groups, where email address match. */
1235 nodeGrp = listGroup;
1237 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1238 GList *groupEMail = group->listEMail;
1240 GList *listRemove = NULL;
1242 /* Process each email item linked to group */
1243 nodeGrpEM = groupEMail;
1245 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1247 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1248 /* Found an email address for this person */
1249 ItemEMail *emailNew = NULL;
1250 gchar *addr = g_strdup(emailGrp->address);
1251 gchar *alias = emailGrp->obj.name;
1253 emailNew = (ItemEMail *)
1254 g_hash_table_lookup(hashEMail, addr);
1256 /* If no match by e-mail, try to match by e-mail alias */
1257 if (!emailNew && *alias != '\0') {
1258 emailNew = (ItemEMail *)
1259 g_hash_table_lookup(hashEMailAlias, alias);
1263 /* Point to this entry */
1264 nodeGrpEM->data = emailNew;
1265 else if (g_hash_table_size(hashEMail)==1)
1266 /* If the person has just one e-mail address, then
1267 change e-mail address in group list */
1268 nodeGrpEM->data = listEMail->data;
1270 /* Mark for removal */
1271 listRemove = g_list_append(listRemove, emailGrp);
1273 /* Move on to next email link */
1274 nodeGrpEM = g_list_next(nodeGrpEM);
1277 /* Process all removed links in current group */
1278 nodeGrpEM = listRemove;
1280 ItemEMail *emailGrp = nodeGrpEM->data;
1281 groupEMail = g_list_remove(groupEMail, emailGrp);
1282 nodeGrpEM = g_list_next(nodeGrpEM);
1285 g_list_free(listRemove);
1287 /* Move on to next group */
1288 nodeGrp = g_list_next(nodeGrp);
1291 /* Clear hash table */
1292 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1293 addrbook_free_simple_hash_vis, NULL);
1294 g_hash_table_destroy(hashEMail);
1296 g_hash_table_destroy(hashEMailAlias);
1297 hashEMailAlias = NULL;
1298 g_list_free(listGroup);
1301 /* Remove old addresses from person and cache */
1303 node = person->listEMail;
1305 ItemEMail *email = node->data;
1307 if (addrcache_person_remove_email(book->addressCache, person, email))
1308 addrcache_remove_email(book->addressCache, email);
1310 listDelete = g_list_append(listDelete, email);
1311 node = person->listEMail;
1313 /* Add new address entries */
1316 ItemEMail *email = node->data;
1318 if (ADDRITEM_ID(email) == NULL)
1319 /* Allocate an ID for new address */
1320 addrcache_id_email(book->addressCache, email);
1322 addrcache_person_add_email( book->addressCache, person, email );
1323 node = g_list_next( node );
1326 addrcache_set_dirty(book->addressCache, TRUE);
1328 /* Free up memory */
1329 g_list_free(listEMail);
1334 ItemEMail *email = node->data;
1336 addritem_free_item_email(email);
1337 node = g_list_next(node);
1339 g_list_free(listDelete);
1344 /* Add person and address data to address book.
1345 Enter: book Address book.
1346 folder Folder where to add person, or NULL for root folder.
1347 listEMail New list of email addresses.
1348 Return: Person added.
1349 Note: A new person is created with specified list of email addresses. All objects inserted
1350 into address book */
1351 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1355 ItemFolder *f = folder;
1358 g_return_val_if_fail(book != NULL, NULL);
1361 f = book->addressCache->rootFolder;
1362 person = addritem_create_item_person();
1363 addrcache_id_person(book->addressCache, person);
1364 addrcache_folder_add_person(book->addressCache, f, person);
1368 ItemEMail *email = node->data;
1369 if (ADDRITEM_ID(email) == NULL)
1370 addrcache_id_email(book->addressCache, email);
1372 addrcache_person_add_email(book->addressCache, person, email);
1373 node = g_list_next(node);
1378 /* Build available email list visitor function */
1379 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1382 AddrItemObject *obj = (AddrItemObject *) value;
1384 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1385 AddressBookFile *book = data;
1386 ItemPerson *person = (ItemPerson *) obj;
1387 GList *node = person->listEMail;
1389 ItemEMail *email = node->data;
1390 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1392 if (!g_hash_table_lookup(book->tempHash,
1393 ADDRITEM_ID(email)))
1394 book->tempList = g_list_append(book->tempList, email);
1396 node = g_list_next(node);
1401 /* Return link list of available email items (which have not already been linked to
1402 groups). Note that the list contains references to items and should be g_free()
1403 when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1404 destroy the addressbook data!
1405 Return: List of items, or NULL if none */
1406 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1411 g_return_val_if_fail(book != NULL, NULL);
1413 /* Load hash table with group email entries */
1414 table = g_hash_table_new(g_str_hash, g_str_equal);
1416 list = group->listEMail;
1418 ItemEMail *email = list->data;
1419 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1420 list = g_list_next(list);
1424 /* Build list of available email addresses which exclude those already in groups */
1425 book->tempList = NULL;
1426 book->tempHash = table;
1427 g_hash_table_foreach(book->addressCache->itemHash,
1428 addrbook_build_avail_email_vis, book);
1429 list = book->tempList;
1430 book->tempList = NULL;
1431 book->tempHash = NULL;
1433 /* Clear hash table */
1434 g_hash_table_destroy(table);
1440 /* Update address book email list for specified group.
1441 Enter: book Address book.
1442 group group to update.
1443 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1444 Note: The existing email addresses are replaced with the new addresses. Any references
1445 to old addresses in the groups are re-linked to the new addresses. All old addresses
1446 linked to the person are removed */
1447 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1452 g_return_if_fail(book != NULL);
1453 g_return_if_fail(group != NULL);
1455 addrcache_set_dirty(book->addressCache, TRUE);
1457 /* Remember old list */
1458 oldData = group->listEMail;
1459 group->listEMail = listEMail;
1460 mgu_clear_list(oldData);
1464 /* Add group and email list to address book.
1465 Enter: book Address book.
1466 folder Parent folder, or NULL for root folder.
1467 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1468 Return: Group object.
1469 Note: The existing email addresses are replaced with the new addresses. Any references
1470 to old addresses in the groups are re-linked to the new addresses. All old addresses
1471 linked to the person are removed */
1472 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1475 ItemGroup *group = NULL;
1476 ItemFolder *f = folder;
1478 g_return_val_if_fail(book != NULL, NULL);
1481 f = book->addressCache->rootFolder;
1482 group = addritem_create_item_group();
1483 addrcache_id_group(book->addressCache, group);
1484 addrcache_folder_add_group(book->addressCache, f, group);
1485 group->listEMail = listEMail;
1489 /* Add new folder to address book.
1490 Enter: book Address book.
1491 parent Parent folder.
1492 Return: Folder that was added. This should *NOT* be g_free() when done */
1493 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1495 ItemFolder *folder = NULL;
1496 ItemFolder *p = parent;
1498 g_return_val_if_fail(book != NULL, NULL);
1501 p = book->addressCache->rootFolder;
1502 folder = addritem_create_item_folder();
1503 addrcache_id_folder(book->addressCache, folder);
1504 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1505 p->listFolder = g_list_append(p->listFolder, folder);
1506 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1507 addrcache_set_dirty(book->addressCache, TRUE);
1510 addritem_free_item_folder(folder);
1516 /* Update address book attribute list for specified person.
1517 Enter: book Address book.
1518 person Person to update.
1519 listAttrib New list of attributes.
1520 Note: The existing email addresses are replaced with the new addresses. All old attributes
1521 linked to the person are removed */
1522 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1528 g_return_if_fail(book != NULL);
1529 g_return_if_fail(person != NULL);
1531 /* Remember old list */
1532 oldData = person->listAttrib;
1534 /* Attach new address list to person. */
1537 UserAttribute *attrib = node->data;
1538 if (attrib->uid == NULL) {
1539 /* Allocate an ID */
1540 addrcache_id_attribute(book->addressCache, attrib);
1542 node = g_list_next(node);
1544 person->listAttrib = listAttrib;
1545 addrcache_set_dirty(book->addressCache, TRUE);
1547 /* Free up old data */
1548 addritem_free_list_attribute(oldData);
1553 * Add attribute data for person to address book.
1554 * Enter: book Address book.
1555 * person New person object.
1556 * listAttrib New list of attributes.
1557 * Note: Only attributes are inserted into address book.
1559 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1562 g_return_if_fail( book != NULL );
1563 g_return_if_fail( person != NULL );
1567 UserAttribute *attrib = node->data;
1568 if( attrib->uid == NULL ) {
1569 addrcache_id_attribute( book->addressCache, attrib );
1571 addritem_person_add_attribute( person, attrib );
1572 node = g_list_next( node );
1574 addrcache_set_dirty( book->addressCache, TRUE );
1577 /* Return address book file for specified object.
1578 Enter: aio Book item object.
1579 Return: Address book, or NULL if not found */
1580 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1582 AddressBookFile *book = NULL;
1585 ItemFolder *parent = NULL;
1586 ItemFolder *root = NULL;
1587 if (aio->type == ITEMTYPE_EMAIL) {
1588 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1590 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1593 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1596 root = addrcache_find_root_folder(parent);
1598 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1603 /* Remove folder from address book. Children are re-parented to parent folder.
1604 param: folder Folder to remove.
1605 return: Folder, or NULL if not found. Note that object should still be freed */
1606 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1610 g_return_val_if_fail(book != NULL, NULL);
1612 f = addrcache_remove_folder(book->addressCache, folder);
1616 /* Remove folder from address book. Children are deleted.
1617 param: folder Folder to remove.
1618 return: Folder, or NULL if not found. Note that object should still be freed */
1619 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1624 g_return_val_if_fail(book != NULL, NULL);
1626 f = addrcache_remove_folder_delete(book->addressCache, folder);
1630 #define WORK_BUFLEN 1024
1631 #define ADDRBOOK_DIGITS "0123456789"
1633 /* Return list of existing address book files.
1634 Enter: book Address book file.
1635 Return: File list */
1636 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1639 struct dirent *entry;
1640 struct stat statbuf;
1641 gchar buf[WORK_BUFLEN];
1642 gchar numbuf[WORK_BUFLEN];
1643 gint len, lenpre, lensuf, lennum;
1644 long int val, maxval;
1645 GList *fileList = NULL;
1647 g_return_val_if_fail(book != NULL, NULL);
1649 if (book->path == NULL || *book->path == '\0') {
1650 book->retVal = MGU_NO_PATH;
1654 strcpy(buf, book->path);
1657 if (buf[len-1] != G_DIR_SEPARATOR) {
1658 buf[len] = G_DIR_SEPARATOR;
1663 adbookdir = g_strdup(buf);
1664 strcat(buf, ADDRBOOK_PREFIX);
1666 if ((dp = opendir(adbookdir)) == NULL) {
1667 book->retVal = MGU_OPEN_DIRECTORY;
1672 lenpre = strlen(ADDRBOOK_PREFIX);
1673 lensuf = strlen(ADDRBOOK_SUFFIX);
1674 lennum = FILE_NUMDIGITS + lenpre;
1677 while ((entry = readdir(dp)) != NULL) {
1678 gchar *endptr = NULL;
1682 strcpy(buf, adbookdir);
1683 strcat(buf, entry->d_name);
1684 stat(buf, &statbuf);
1685 if (S_IFREG & statbuf.st_mode) {
1686 if (strncmp(entry->d_name, ADDRBOOK_PREFIX, lenpre) == 0) {
1687 if (strncmp((entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf) == 0) {
1688 strncpy(numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS);
1689 numbuf[FILE_NUMDIGITS] = '\0';
1691 for(i = 0; i < FILE_NUMDIGITS; i++) {
1692 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1699 val = strtol(numbuf, &endptr, 10);
1700 if (endptr && val > -1) {
1701 if (val > maxval) maxval = val;
1702 fileList = g_list_append(fileList, g_strdup(entry->d_name));
1712 book->maxValue = maxval;
1713 book->retVal = MGU_SUCCESS;
1717 /* Return file name for specified file number.
1718 Enter: fileNum File number.
1719 Return: File name, or NULL if file number too large. Should be g_free() when done */
1720 gchar *addrbook_gen_new_file_name(gint fileNum) {
1722 gchar buf[WORK_BUFLEN];
1728 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1731 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1732 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1733 return g_strdup(buf);
1736 /* **********************************************************************
1737 Address book test functions...
1738 **********************************************************************
1742 * Test email address list.
1744 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1749 prev_level = file->level;
1750 if (xml_parse_next_tag(file))
1751 longjmp(book->jumper, 1);
1752 if (file->level < prev_level)
1754 attr = xml_get_current_tag_attr(file);
1755 /* addrbook_show_attribs( attr ); */
1756 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1757 addrbook_chkparse_addr_list(book, file);
1761 /* Test user attributes for person */
1762 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1767 attr = xml_get_current_tag_attr(file);
1768 /* addrbook_show_attribs( attr ); */
1769 element = xml_get_element(file);
1770 /* printf( "\t\tattrib value : %s\n", element ); */
1773 /* Test attribute list */
1774 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1779 prev_level = file->level;
1780 if (xml_parse_next_tag(file))
1781 longjmp(book->jumper, 1);
1782 if (file->level < prev_level)
1784 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1785 addrbook_chkparse_attribute(book, file);
1786 addrbook_chkparse_attr_list(book, file);
1792 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1796 attr = xml_get_current_tag_attr(file);
1797 /* addrbook_show_attribs( attr ); */
1798 if (xml_parse_next_tag(file)) /* Consume closing tag */
1799 longjmp(book->jumper, 1);
1801 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1802 addrbook_chkparse_addr_list(book, file);
1804 if (xml_parse_next_tag(file)) /* Consume closing tag */
1805 longjmp(book->jumper, 1);
1807 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1808 addrbook_chkparse_attr_list(book, file);
1811 /* Test group member list */
1812 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
1818 prev_level = file->level;
1819 if (xml_parse_next_tag(file))
1820 longjmp(book->jumper, 1);
1822 if (file->level < prev_level)
1825 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
1826 attr = xml_get_current_tag_attr(file);
1827 /* addrbook_show_attribs( attr ); */
1828 addrbook_chkparse_member_list(book, file);
1831 attr = xml_get_current_tag_attr(file);
1832 /* addrbook_show_attribs( attr ); */
1838 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
1842 attr = xml_get_current_tag_attr(file);
1843 /* addrbook_show_attribs( attr ); */
1844 if (xml_parse_next_tag(file)) /* Consume closing tag */
1845 longjmp(book->jumper, 1);
1847 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
1848 addrbook_chkparse_member_list(book, file);
1851 /* Test folder item list */
1852 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
1858 prev_level = file->level;
1859 if (xml_parse_next_tag(file))
1860 longjmp(book->jumper, 1);
1862 if (file->level < prev_level)
1865 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
1866 attr = xml_get_current_tag_attr(file);
1867 /* addrbook_show_attribs( attr ); */
1868 addrbook_chkparse_folder_list(book, file);
1871 attr = xml_get_current_tag_attr(file);
1872 /* addrbook_show_attribs( attr ); */
1878 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
1882 attr = xml_get_current_tag_attr(file);
1883 /* addrbook_show_attribs( attr ); */
1884 if (xml_parse_next_tag(file)) /* Consume closing tag */
1885 longjmp(book->jumper, 1);
1887 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
1888 addrbook_chkparse_folder_list(book, file);
1891 /* Test address book */
1892 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
1897 if (xml_get_dtd(file))
1900 if (xml_parse_next_tag(file))
1903 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
1906 attr = xml_get_current_tag_attr(file);
1907 /* addrbook_show_attribs( attr ); */
1914 if (xml_parse_next_tag(file))
1915 longjmp(book->jumper, 1);
1917 /* Get next tag (person, group or folder) */
1918 if (xml_compare_tag(file, AB_ELTAG_PERSON))
1919 addrbook_chkparse_person( book, file );
1920 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
1921 addrbook_chkparse_group(book, file);
1922 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
1923 addrbook_chkparse_folder(book, file);
1928 /* Test address book file by parsing contents.
1929 Enter: book Address book file to check.
1930 fileName File name to check.
1931 Return: MGU_SUCCESS if file appears to be valid format */
1932 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
1934 XMLFile *file = NULL;
1935 gchar *fileSpec = NULL;
1937 g_return_val_if_fail(book != NULL, -1);
1939 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
1940 book->retVal = MGU_OPEN_FILE;
1941 file = xml_open_file(fileSpec);
1944 book->retVal = MGU_BAD_FORMAT;
1945 if (setjmp(book->jumper)) {
1946 /* printf( "Caught Ya!!!\n" ); */
1947 xml_close_file(file);
1948 return book->retVal;
1950 if (addrbook_chkread_tree(book, file))
1951 book->retVal = MGU_SUCCESS;
1953 xml_close_file( file );
1955 return book->retVal;
1958 /* Return link list of all persons in address book. Note that the list contains
1959 references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1960 this will destroy the addressbook data!
1961 Return: List of items, or NULL if none */
1962 GList *addrbook_get_all_persons(AddressBookFile *book)
1964 g_return_val_if_fail(book != NULL, NULL);
1965 return addrcache_get_all_persons(book->addressCache);
1968 /* Add person and address data to address book.
1969 Enter: book Address book.
1970 folder Folder where to add person, or NULL for root folder.
1972 address EMail address.
1974 Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1975 this will destroy the address book data */
1976 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
1977 const gchar *name,const gchar *address,
1978 const gchar *remarks)
1980 g_return_val_if_fail(book != NULL, NULL);
1981 return addrcache_add_contact(book->addressCache, folder, name, address,
1985 /* Return file name for next address book file.
1986 Enter: book Address book.
1987 Return: File name, or NULL if could not create. This should be g_free()
1989 gchar *addrbook_guess_next_file(AddressBookFile *book)
1991 gchar *newFile = NULL;
1992 GList *fileList = NULL;
1994 fileList = addrbook_get_bookfile_list(book);
1996 fileNum = 1 + book->maxValue;
1998 newFile = addrbook_gen_new_file_name(fileNum);
1999 g_list_free(fileList);