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;
65 /* We want to use an address completion index */
66 addrcache_use_index( book->addressCache, TRUE );
71 /* Specify name to be used */
72 void addrbook_set_name(AddressBookFile *book, const gchar *value)
74 g_return_if_fail(book != NULL);
75 addrcache_set_name(book->addressCache, value);
78 gchar *addrbook_get_name(AddressBookFile *book)
80 g_return_val_if_fail(book != NULL, NULL);
81 return addrcache_get_name(book->addressCache);
84 void addrbook_set_path(AddressBookFile *book, const gchar *value)
86 g_return_if_fail(book != NULL);
87 book->path = mgu_replace_string(book->path, value);
88 addrcache_set_dirty(book->addressCache, TRUE);
91 void addrbook_set_file(AddressBookFile *book, const gchar *value)
93 g_return_if_fail(book != NULL);
94 book->fileName = mgu_replace_string(book->fileName, value);
95 addrcache_set_dirty(book->addressCache, TRUE);
98 gboolean addrbook_get_modified(AddressBookFile *book)
100 g_return_val_if_fail(book != NULL, FALSE);
101 return book->addressCache->modified;
104 void addrbook_set_modified(AddressBookFile *book, const gboolean value)
106 g_return_if_fail(book != NULL);
107 book->addressCache->modified = value;
110 gboolean addrbook_get_accessed(AddressBookFile *book)
112 g_return_val_if_fail(book != NULL, FALSE);
113 return book->addressCache->accessFlag;
116 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
118 g_return_if_fail(book != NULL);
119 book->addressCache->accessFlag = value;
122 gboolean addrbook_get_read_flag(AddressBookFile *book)
124 g_return_val_if_fail(book != NULL, FALSE);
125 return book->addressCache->dataRead;
128 void addrbook_set_read_flag(AddressBookFile *book, const gboolean value)
130 g_return_if_fail(book != NULL);
131 book->addressCache->dataRead = value;
134 gint addrbook_get_status(AddressBookFile *book)
136 g_return_val_if_fail(book != NULL, -1);
140 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
142 g_return_val_if_fail(book != NULL, NULL);
143 return addrcache_get_root_folder(book->addressCache);
146 GList *addrbook_get_list_folder(AddressBookFile *book)
148 g_return_val_if_fail(book != NULL, NULL);
149 return addrcache_get_list_folder(book->addressCache);
152 GList *addrbook_get_list_person(AddressBookFile *book)
154 g_return_val_if_fail(book != NULL, NULL);
155 return addrcache_get_list_person(book->addressCache);
158 gboolean addrbook_get_dirty(AddressBookFile *book)
160 g_return_val_if_fail(book != NULL, FALSE);
161 return addrcache_get_dirty(book->addressCache);
164 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
166 g_return_if_fail(book != NULL);
167 addrcache_set_dirty(book->addressCache, value);
170 /* Empty address book */
171 void addrbook_empty_book(AddressBookFile *book)
173 g_return_if_fail(book != NULL);
175 /* Free up internal objects */
176 addrcache_clear(book->addressCache);
177 addrcache_set_dirty(book->addressCache, FALSE);
178 g_list_free(book->tempList);
180 /* Reset to initial state */
181 book->tempList = NULL;
182 book->tempHash = NULL;
183 book->addressCache->dataRead = FALSE;
184 book->addressCache->modified = FALSE;
185 book->addressCache->accessFlag = FALSE;
186 book->retVal = MGU_SUCCESS;
189 /* Free address book */
190 void addrbook_free_book(AddressBookFile *book)
192 g_return_if_fail(book != NULL);
195 addrcache_free(book->addressCache);
197 /* Free up internal objects */
199 g_free(book->fileName);
200 g_list_free(book->tempList);
203 book->fileName = NULL;
205 book->tempList = NULL;
206 book->tempHash = NULL;
208 book->type = ADBOOKTYPE_NONE;
209 book->addressCache = NULL;
210 book->retVal = MGU_SUCCESS;
215 /* Print list of items */
216 void addrbook_print_item_list(GList *list, FILE *stream)
221 AddrItemObject *obj = node->data;
222 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON)
223 addritem_print_item_person((ItemPerson *) obj, stream);
224 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP)
225 addritem_print_item_group((ItemGroup *) obj, stream);
226 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER)
227 addritem_print_item_folder((ItemFolder *) obj, stream);
228 node = g_list_next(node);
230 fprintf(stream, "\t---\n");
233 /* Print address book */
234 void addrbook_print_book(AddressBookFile *book, FILE *stream)
236 g_return_if_fail(book != NULL);
238 fprintf(stream, "AddressBook:\n");
239 fprintf(stream, "\tpath : '%s'\n", book->path);
240 fprintf(stream, "\tfile : '%s'\n", book->fileName);
241 fprintf(stream, "\tstatus : %d\n", book->retVal );
242 addrcache_print(book->addressCache, stream);
245 /* Dump entire address book traversing folders */
246 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
250 g_return_if_fail(book != NULL);
252 addrbook_print_book(book, stream);
253 folder = book->addressCache->rootFolder;
254 addritem_print_item_folder(folder, stream);
257 /* Remove group from address book.
258 param: group Group to remove.
259 return: Group, or NULL if not found.
260 Note that object should still be freed */
261 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
263 g_return_val_if_fail(book != NULL, NULL);
264 return addrcache_remove_group(book->addressCache, group);
267 /* Remove specified person from address book.
268 param: person Person to remove.
269 return: Person, or NULL if not found.
270 Note that object should still be freed */
271 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
273 g_return_val_if_fail(book != NULL, NULL);
274 return addrcache_remove_person(book->addressCache, person);
277 /* Remove email address in address book for specified person.
278 param: person Person.
279 email EMail to remove.
280 return: EMail object, or NULL if not found.
281 Note that object should still be freed */
282 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
283 ItemPerson *person, ItemEMail *email)
285 g_return_val_if_fail(book != NULL, NULL);
286 return addrcache_person_remove_email(book->addressCache, person, email);
289 /* **********************************************************************
290 * Read/Write XML data file...
291 * ===========================
293 * 1) The address book is structured as follows:
308 * 2) This sequence of elements was chosen so that the most important
309 * elements (person and their email addresses) appear first.
311 * 3) Groups then appear. When groups are loaded, person's email
312 * addresses have already been loaded and can be found.
314 * 4) Finally folders are loaded. Any forward and backward references
315 * to folders, groups and persons in the folders are resolved after
318 * ***********************************************************************
321 /* Element tag names */
322 #define AB_ELTAG_ADDRESS "address"
323 #define AB_ELTAG_ATTRIBUTE "attribute"
324 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
325 #define AB_ELTAG_ADDRESS_LIST "address-list"
326 #define AB_ELTAG_MEMBER "member"
327 #define AB_ELTAG_MEMBER_LIST "member-list"
328 #define AB_ELTAG_ITEM "item"
329 #define AB_ELTAG_ITEM_LIST "item-list"
330 #define AB_ELTAG_ADDRESS_BOOK "address-book"
331 #define AB_ELTAG_PERSON "person"
332 #define AB_ELTAG_GROUP "group"
333 #define AB_ELTAG_FOLDER "folder"
335 /* Attribute tag names */
336 #define AB_ATTAG_TYPE "type"
337 #define AB_ATTAG_UID "uid"
338 #define AB_ATTAG_NAME "name"
339 #define AB_ATTAG_REMARKS "remarks"
340 #define AB_ATTAG_FIRST_NAME "first-name"
341 #define AB_ATTAG_LAST_NAME "last-name"
342 #define AB_ATTAG_NICK_NAME "nick-name"
343 #define AB_ATTAG_COMMON_NAME "cn"
344 #define AB_ATTAG_ALIAS "alias"
345 #define AB_ATTAG_EMAIL "email"
346 #define AB_ATTAG_EID "eid"
347 #define AB_ATTAG_PID "pid"
349 /* Attribute values */
350 #define AB_ATTAG_VAL_PERSON "person"
351 #define AB_ATTAG_VAL_GROUP "group"
352 #define AB_ATTAG_VAL_FOLDER "folder"
354 /* Parse address item for person */
355 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
360 ItemEMail *email = NULL;
362 attr = xml_get_current_tag_attr(file);
364 name = ((XMLAttr *)attr->data)->name;
365 value = ((XMLAttr *)attr->data)->value;
367 email = addritem_create_item_email();
368 if (strcmp(name, AB_ATTAG_UID) == 0)
369 ADDRITEM_ID(email) = g_strdup(value);
370 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
371 ADDRITEM_NAME(email) = g_strdup(value);
372 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
373 email->address = g_strdup(value);
374 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
375 email->remarks = g_strdup(value);
376 attr = g_list_next(attr);
380 addrcache_person_add_email(book->addressCache, person,
384 addritem_free_item_email(email);
390 /* Parse email address list */
391 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
398 prev_level = file->level;
399 if (xml_parse_next_tag(file)) {
400 longjmp(book->jumper, 1);
402 if (file->level < prev_level) return;
403 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
404 attr = xml_get_current_tag_attr(file);
405 addrbook_parse_address(book, file, person);
406 addrbook_parse_addr_list(book, file, person);
411 /* Parse attibute for person */
412 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
417 UserAttribute *uAttr = NULL;
419 attr = xml_get_current_tag_attr(file);
421 name = ((XMLAttr *)attr->data)->name;
422 value = ((XMLAttr *)attr->data)->value;
423 if (!uAttr) uAttr = addritem_create_attribute();
424 if (strcmp(name, AB_ATTAG_UID) == 0)
425 addritem_attrib_set_id(uAttr, value);
426 else if (strcmp(name, AB_ATTAG_NAME) == 0)
427 addritem_attrib_set_name(uAttr, value);
428 attr = g_list_next(attr);
431 element = xml_get_element(file);
432 addritem_attrib_set_value(uAttr, element);
436 addritem_person_add_attribute(person, uAttr);
439 addritem_free_attribute(uAttr);
445 /* Parse attribute list */
446 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
453 prev_level = file->level;
454 if (xml_parse_next_tag(file)) {
455 longjmp( book->jumper, 1 );
457 if (file->level < prev_level) return;
458 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
459 attr = xml_get_current_tag_attr(file);
460 addrbook_parse_attribute(file, person);
461 addrbook_parse_attr_list(book, file, person);
467 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
471 ItemPerson *person = NULL;
473 attr = xml_get_current_tag_attr(file);
475 name = ((XMLAttr *)attr->data)->name;
476 value = ((XMLAttr *)attr->data)->value;
478 person = addritem_create_item_person();
479 if (strcmp(name, AB_ATTAG_UID) == 0)
480 ADDRITEM_ID(person) = g_strdup(value);
481 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
482 person->firstName = g_strdup(value);
483 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
484 person->lastName = g_strdup(value);
485 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
486 person->nickName = g_strdup(value);
487 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
488 ADDRITEM_NAME(person) = g_strdup(value);
489 attr = g_list_next(attr);
491 if (xml_parse_next_tag(file)) { /* Consume closing tag */
492 longjmp(book->jumper, 1);
494 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
495 addrbook_parse_addr_list(book, file, person);
497 addrcache_hash_add_person(book->addressCache, person);
500 if (xml_parse_next_tag(file)) { /* Consume closing tag */
501 longjmp(book->jumper, 1);
503 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
504 addrbook_parse_attr_list(book, file, person);
508 /* Parse group member */
509 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
514 gchar *pid = NULL, *eid = NULL;
515 ItemEMail *email = NULL;
517 attr = xml_get_current_tag_attr(file);
519 name = ((XMLAttr *)attr->data)->name;
520 value = ((XMLAttr *)attr->data)->value;
521 if (strcmp(name, AB_ATTAG_PID) == 0)
522 pid = g_strdup(value);
523 else if (strcmp(name, AB_ATTAG_EID) == 0)
524 eid = g_strdup(value);
525 attr = g_list_next(attr);
527 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
528 email = addrcache_get_email(book->addressCache, eid);
531 addrcache_group_add_email(book->addressCache, group,
535 addritem_free_item_email(email);
541 /* Parse group member list */
542 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
549 prev_level = file->level;
550 if (xml_parse_next_tag(file)) {
551 longjmp(book->jumper, 1);
553 if (file->level < prev_level)
555 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
556 attr = xml_get_current_tag_attr(file);
557 addrbook_parse_member(book, file, group);
558 addrbook_parse_member_list(book, file, group);
561 attr = xml_get_current_tag_attr(file);
567 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
571 ItemGroup *group = NULL;
573 attr = xml_get_current_tag_attr(file);
575 name = ((XMLAttr *)attr->data)->name;
576 value = ((XMLAttr *)attr->data)->value;
578 group = addritem_create_item_group();
579 if (strcmp(name, AB_ATTAG_UID) == 0)
580 ADDRITEM_ID(group) = g_strdup(value);
581 else if (strcmp(name, AB_ATTAG_NAME) == 0)
582 ADDRITEM_NAME(group) = g_strdup(value);
583 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
584 group->remarks = g_strdup(value);
585 attr = g_list_next(attr);
587 if (xml_parse_next_tag(file)) { /* Consume closing tag */
588 longjmp(book->jumper, 1);
590 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
592 addrcache_hash_add_group(book->addressCache, group);
594 addrbook_parse_member_list(book, file, group);
598 /* Parse folder item */
599 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
606 attr = xml_get_current_tag_attr(file);
608 name = ((XMLAttr *)attr->data)->name;
609 value = ((XMLAttr *)attr->data)->value;
610 if (strcmp(name, AB_ATTAG_UID) == 0) {
611 uid = g_strdup(value);
613 attr = g_list_next(attr);
617 folder->listItems = g_list_append(folder->listItems, uid);
622 /* Parse folder item list */
623 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
630 prev_level = file->level;
631 if (xml_parse_next_tag(file)) {
632 longjmp(book->jumper, 1);
634 if (file->level < prev_level)
636 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
637 attr = xml_get_current_tag_attr(file);
638 addrbook_parse_folder_item(book, file, folder);
639 addrbook_parse_folder_list(book, file, folder);
642 attr = xml_get_current_tag_attr(file);
648 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
652 ItemFolder *folder = NULL;
654 attr = xml_get_current_tag_attr(file);
656 name = ((XMLAttr *)attr->data)->name;
657 value = ((XMLAttr *)attr->data)->value;
659 folder = addritem_create_item_folder();
660 if (strcmp(name, AB_ATTAG_UID) == 0)
661 ADDRITEM_ID(folder) = g_strdup(value);
662 else if (strcmp(name, AB_ATTAG_NAME) == 0)
663 ADDRITEM_NAME(folder) = g_strdup(value);
664 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
665 folder->remarks = g_strdup(value);
666 attr = g_list_next(attr);
668 if (xml_parse_next_tag(file)) { /* Consume closing tag */
669 longjmp(book->jumper, 1);
671 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
673 if (addrcache_hash_add_folder(book->addressCache,
675 book->tempList = g_list_append(book->tempList,
677 /* We will resolve folder later */
678 ADDRITEM_PARENT(folder) = NULL;
681 addrbook_parse_folder_list(book, file, folder);
685 /* Parse address book.
686 Return: TRUE if data read successfully, FALSE if error reading data */
687 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
693 book->retVal = MGU_BAD_FORMAT;
694 if (xml_get_dtd(file))
696 if (xml_parse_next_tag(file))
697 longjmp(book->jumper, 1);
698 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
701 attr = xml_get_current_tag_attr(file);
703 name = ((XMLAttr *)attr->data)->name;
704 value = ((XMLAttr *)attr->data)->value;
705 if (strcmp( name, AB_ATTAG_NAME) == 0)
706 addrbook_set_name( book, value );
707 attr = g_list_next( attr );
714 /* Get next item tag (person, group or folder) */
715 if (xml_parse_next_tag(file))
716 longjmp( book->jumper, 1 );
718 if (xml_compare_tag(file, AB_ELTAG_PERSON))
719 addrbook_parse_person(book, file);
720 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
721 addrbook_parse_group(book, file);
722 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
723 addrbook_parse_folder(book, file);
725 if (retVal) book->retVal = MGU_SUCCESS;
729 /* Resolve folder items visitor function */
730 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
732 AddressBookFile *book = data;
733 AddrItemObject *obj = (AddrItemObject *) value;
734 ItemFolder *rootFolder = book->addressCache->rootFolder;
735 if (obj->parent == NULL) {
736 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
737 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
739 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
741 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
742 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
744 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
749 /* Resolve folder items. Lists of UID's are replaced with pointers to
751 static void addrbook_resolve_folder_items(AddressBookFile *book)
753 GList *nodeFolder = NULL;
754 GList *listRemove = NULL;
756 ItemFolder *rootFolder = book->addressCache->rootFolder;
757 nodeFolder = book->tempList;
760 ItemFolder *folder = nodeFolder->data;
762 node = folder->listItems;
764 gchar *uid = node->data;
765 AddrItemObject *aio = addrcache_get_object(book->addressCache,
768 if (aio->type == ITEMTYPE_FOLDER) {
769 ItemFolder *item = (ItemFolder *) aio;
770 folder->listFolder = g_list_append(folder->listFolder, item);
771 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
772 addrcache_hash_add_folder(book->addressCache, folder);
774 else if (aio->type == ITEMTYPE_PERSON) {
775 ItemPerson *item = (ItemPerson *) aio;
776 folder->listPerson = g_list_append(folder->listPerson, item);
777 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
779 else if (aio->type == ITEMTYPE_GROUP) {
780 ItemGroup *item = (ItemGroup *) aio;
781 folder->listGroup = g_list_append(folder->listGroup, item);
782 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
784 /* Replace data with pointer to item */
788 else { /* Not found, append to remove list. */
789 listRemove = g_list_append(listRemove, uid);
791 node = g_list_next(node);
793 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
795 /* Process remove list */
798 gchar *uid = node->data;
799 folder->listItems = g_list_remove(folder->listItems,
802 node = g_list_next(node);
804 g_list_free(listRemove);
805 nodeFolder = g_list_next(nodeFolder);
807 /* Remove folders with parents. */
809 node = rootFolder->listFolder;
811 ItemFolder *folder = (ItemFolder *) node->data;
812 if (ADDRITEM_PARENT(folder))
813 /* Remove folders with parents */
814 listRemove = g_list_append(listRemove, folder);
815 else /* Add to root folder */
816 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
818 node = g_list_next( node );
820 /* Process remove list */
823 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
825 node = g_list_next(node);
827 g_list_free(listRemove);
829 /* Move all unparented persons and groups into root folder */
830 g_hash_table_foreach(book->addressCache->itemHash,
831 addrbook_res_items_vis, book);
833 /* Free up some more */
834 nodeFolder = book->tempList;
836 ItemFolder *folder = nodeFolder->data;
837 g_list_free(folder->listItems);
838 folder->listItems = NULL;
839 nodeFolder = g_list_next(nodeFolder);
841 g_list_free(book->tempList);
842 book->tempList = NULL;
845 /* Read address book file */
846 gint addrbook_read_data(AddressBookFile *book)
848 XMLFile *file = NULL;
849 gchar *fileSpec = NULL;
851 g_return_val_if_fail(book != NULL, -1);
854 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
855 addrcache_get_name( book->addressCache ) );
858 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
859 book->fileName, NULL);
860 book->retVal = MGU_OPEN_FILE;
861 addrcache_clear(book->addressCache);
862 book->addressCache->modified = FALSE;
863 book->addressCache->accessFlag = FALSE;
864 file = xml_open_file(fileSpec);
867 book->tempList = NULL;
868 /* Trap for parsing errors. */
869 if (setjmp( book->jumper)) {
870 xml_close_file(file);
873 addrbook_read_tree(book, file);
874 xml_close_file(file);
875 /* Resolve folder items */
876 addrbook_resolve_folder_items(book);
877 book->tempList = NULL;
878 book->addressCache->modified = FALSE;
879 book->addressCache->dataRead = TRUE;
880 addrcache_set_dirty(book->addressCache, FALSE);
882 /* Build address completion index */
883 addrcache_build_index( book->addressCache );
888 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
891 for (i = 0; i < lvl; i++)
897 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
900 for(i = 0; i < lvl; i++)
907 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
912 xml_file_put_escape_str(fp, value);
916 /* Write file hash table visitor function */
917 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
920 AddrItemObject *obj = (AddrItemObject *) value;
921 FILE *fp = (FILE *) data;
926 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
927 ItemPerson *person = (ItemPerson *) value;
929 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
930 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
931 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
932 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
933 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
934 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
937 /* Output email addresses */
938 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
940 node = person->listEMail;
942 ItemEMail *email = node->data;
943 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
944 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
945 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
946 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
947 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
949 node = g_list_next(node);
951 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
953 /* Output user attributes */
954 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
956 node = person->listAttrib;
958 UserAttribute *attrib = node->data;
959 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
960 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
961 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
963 xml_file_put_escape_str(fp, attrib->value);
964 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
965 node = g_list_next(node);
967 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
968 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
973 /* Write file hash table visitor function */
974 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
977 AddrItemObject *obj = (AddrItemObject *) value;
978 FILE *fp = (FILE *) data;
983 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
984 ItemGroup *group = (ItemGroup *) value;
986 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
987 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
988 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
989 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
992 /* Output email address links */
993 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
995 node = group->listEMail;
997 ItemEMail *email = node->data;
998 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
999 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1000 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1001 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1003 node = g_list_next(node);
1005 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1006 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1011 /* Write file hash table visitor function */
1012 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1015 AddrItemObject *obj = (AddrItemObject *) value;
1016 FILE *fp = (FILE *) data;
1021 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1022 ItemFolder *folder = (ItemFolder *) value;
1024 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1025 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1026 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1027 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1029 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1032 /* Output persons */
1033 node = folder->listPerson;
1035 ItemPerson *item = node->data;
1036 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1037 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1038 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1040 node = g_list_next(node);
1044 node = folder->listGroup;
1046 ItemGroup *item = node->data;
1047 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1048 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1049 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1051 node = g_list_next(node);
1054 /* Output folders */
1055 node = folder->listFolder;
1057 ItemFolder *item = node->data;
1058 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1059 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1060 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1062 node = g_list_next(node);
1064 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1065 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1070 /* Output address book data to specified file.
1071 return: Status code */
1072 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1076 #ifndef DEV_STANDALONE
1080 g_return_val_if_fail(book != NULL, -1);
1081 g_return_val_if_fail(newFile != NULL, -1);
1083 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1085 book->retVal = MGU_OPEN_FILE;
1086 #ifdef DEV_STANDALONE
1087 fp = fopen(fileSpec, "wb");
1090 fputs("<?xml version=\"1.0\" ?>\n", fp);
1092 pfile = prefs_write_open(fileSpec);
1096 fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1097 conv_get_current_charset_str());
1099 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1100 addrbook_write_attr(fp, AB_ATTAG_NAME,
1101 addrcache_get_name(book->addressCache));
1104 /* Output all persons */
1105 g_hash_table_foreach(book->addressCache->itemHash,
1106 addrbook_write_item_person_vis, fp);
1108 /* Output all groups */
1109 g_hash_table_foreach(book->addressCache->itemHash,
1110 addrbook_write_item_group_vis, fp);
1112 /* Output all folders */
1113 g_hash_table_foreach(book->addressCache->itemHash,
1114 addrbook_write_item_folder_vis, fp);
1116 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1117 book->retVal = MGU_SUCCESS;
1118 #ifdef DEV_STANDALONE
1121 if (prefs_file_close( pfile ) < 0)
1122 book->retVal = MGU_ERROR_WRITE;
1127 return book->retVal;
1130 /* Output address book data to original file.
1131 return: Status code */
1132 gint addrbook_save_data(AddressBookFile *book)
1134 g_return_val_if_fail(book != NULL, -1);
1136 book->retVal = MGU_NO_FILE;
1137 if (book->fileName == NULL || *book->fileName == '\0')
1138 return book->retVal;
1139 if (book->path == NULL || *book->path == '\0')
1140 return book->retVal;
1142 addrbook_write_to(book, book->fileName);
1143 if (book->retVal == MGU_SUCCESS)
1144 addrcache_set_dirty(book->addressCache, FALSE);
1145 return book->retVal;
1148 /* **********************************************************************
1149 Address book edit interface functions...
1150 ***********************************************************************
1151 Move person's email item.
1152 param: book Address book.
1154 itemMove Item to move.
1155 itemTarget Target item before which to move item */
1156 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1157 ItemEMail *itemMove, ItemEMail *itemTarget)
1159 ItemEMail *email = NULL;
1161 g_return_val_if_fail(book != NULL, NULL);
1163 email = addritem_move_email_before(person, itemMove, itemTarget);
1165 addrcache_set_dirty(book->addressCache, TRUE);
1169 /* Move person's email item.
1170 param: book Address book.
1172 itemMove Item to move.
1173 itemTarget Target item after which to move item */
1174 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1175 ItemEMail *itemMove, ItemEMail *itemTarget)
1177 ItemEMail *email = NULL;
1179 g_return_val_if_fail(book != NULL, NULL);
1181 email = addritem_move_email_after(person, itemMove, itemTarget);
1183 addrcache_set_dirty(book->addressCache, TRUE);
1187 /* Hash table visitor function for deletion of hashtable entries */
1188 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1197 /* Update address book email list for specified person.
1198 Enter: book Address book.
1199 person Person to update.
1200 listEMail List of new email addresses.
1201 Note: The existing email addresses are replaced with the new addresses. Any references
1202 to old addresses in the groups are re-linked to the new addresses. All old addresses
1203 linked to the person are removed */
1204 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1211 g_return_if_fail(book != NULL);
1212 g_return_if_fail(person != NULL);
1214 /* Get groups where person's existing email addresses are listed */
1215 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1217 GHashTable *hashEMail;
1218 GHashTable *hashEMailAlias;
1221 /* Load hash table with new address entries */
1222 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1223 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1226 ItemEMail *email = node->data;
1227 gchar *addr = g_strdup(email->address);
1228 gchar *alias = email->obj.name ;
1230 if (!g_hash_table_lookup(hashEMail, addr)) {
1231 g_hash_table_insert(hashEMail, addr, email);
1233 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1235 g_hash_table_insert(hashEMailAlias, alias, email);
1237 node = g_list_next(node);
1240 /* Re-parent new addresses to existing groups, where email address match. */
1241 nodeGrp = listGroup;
1243 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1244 GList *groupEMail = group->listEMail;
1246 GList *listRemove = NULL;
1248 /* Process each email item linked to group */
1249 nodeGrpEM = groupEMail;
1251 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1253 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1254 /* Found an email address for this person */
1255 ItemEMail *emailNew = NULL;
1256 gchar *addr = g_strdup(emailGrp->address);
1257 gchar *alias = emailGrp->obj.name;
1259 emailNew = (ItemEMail *)
1260 g_hash_table_lookup(hashEMail, addr);
1262 /* If no match by e-mail, try to match by e-mail alias */
1263 if (!emailNew && *alias != '\0') {
1264 emailNew = (ItemEMail *)
1265 g_hash_table_lookup(hashEMailAlias, alias);
1269 /* Point to this entry */
1270 nodeGrpEM->data = emailNew;
1271 else if (g_hash_table_size(hashEMail)==1)
1272 /* If the person has just one e-mail address, then
1273 change e-mail address in group list */
1274 nodeGrpEM->data = listEMail->data;
1276 /* Mark for removal */
1277 listRemove = g_list_append(listRemove, emailGrp);
1279 /* Move on to next email link */
1280 nodeGrpEM = g_list_next(nodeGrpEM);
1283 /* Process all removed links in current group */
1284 nodeGrpEM = listRemove;
1286 ItemEMail *emailGrp = nodeGrpEM->data;
1287 groupEMail = g_list_remove(groupEMail, emailGrp);
1288 nodeGrpEM = g_list_next(nodeGrpEM);
1291 g_list_free(listRemove);
1293 /* Move on to next group */
1294 nodeGrp = g_list_next(nodeGrp);
1297 /* Clear hash table */
1298 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1299 addrbook_free_simple_hash_vis, NULL);
1300 g_hash_table_destroy(hashEMail);
1302 g_hash_table_destroy(hashEMailAlias);
1303 hashEMailAlias = NULL;
1304 g_list_free(listGroup);
1307 /* Remove old addresses from person and cache */
1309 node = person->listEMail;
1311 ItemEMail *email = node->data;
1313 if (addrcache_person_remove_email(book->addressCache, person, email))
1314 addrcache_remove_email(book->addressCache, email);
1316 listDelete = g_list_append(listDelete, email);
1317 node = person->listEMail;
1319 /* Add new address entries */
1322 ItemEMail *email = node->data;
1324 if (ADDRITEM_ID(email) == NULL)
1325 /* Allocate an ID for new address */
1326 addrcache_id_email(book->addressCache, email);
1328 addrcache_person_add_email( book->addressCache, person, email );
1329 node = g_list_next( node );
1332 addrcache_set_dirty(book->addressCache, TRUE);
1334 /* Free up memory */
1335 g_list_free(listEMail);
1340 ItemEMail *email = node->data;
1342 addritem_free_item_email(email);
1343 node = g_list_next(node);
1345 g_list_free(listDelete);
1350 /* Add person and address data to address book.
1351 Enter: book Address book.
1352 folder Folder where to add person, or NULL for root folder.
1353 listEMail New list of email addresses.
1354 Return: Person added.
1355 Note: A new person is created with specified list of email addresses. All objects inserted
1356 into address book */
1357 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1361 ItemFolder *f = folder;
1364 g_return_val_if_fail(book != NULL, NULL);
1367 f = book->addressCache->rootFolder;
1368 person = addritem_create_item_person();
1369 addrcache_id_person(book->addressCache, person);
1370 addrcache_folder_add_person(book->addressCache, f, person);
1374 ItemEMail *email = node->data;
1375 if (ADDRITEM_ID(email) == NULL)
1376 addrcache_id_email(book->addressCache, email);
1378 addrcache_person_add_email(book->addressCache, person, email);
1379 node = g_list_next(node);
1384 /* Build available email list visitor function */
1385 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1388 AddrItemObject *obj = (AddrItemObject *) value;
1390 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1391 AddressBookFile *book = data;
1392 ItemPerson *person = (ItemPerson *) obj;
1393 GList *node = person->listEMail;
1395 ItemEMail *email = node->data;
1396 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1398 if (!g_hash_table_lookup(book->tempHash,
1399 ADDRITEM_ID(email)))
1400 book->tempList = g_list_append(book->tempList, email);
1402 node = g_list_next(node);
1407 /* Return link list of available email items (which have not already been linked to
1408 groups). Note that the list contains references to items and should be g_free()
1409 when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1410 destroy the addressbook data!
1411 Return: List of items, or NULL if none */
1412 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1417 g_return_val_if_fail(book != NULL, NULL);
1419 /* Load hash table with group email entries */
1420 table = g_hash_table_new(g_str_hash, g_str_equal);
1422 list = group->listEMail;
1424 ItemEMail *email = list->data;
1425 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1426 list = g_list_next(list);
1430 /* Build list of available email addresses which exclude those already in groups */
1431 book->tempList = NULL;
1432 book->tempHash = table;
1433 g_hash_table_foreach(book->addressCache->itemHash,
1434 addrbook_build_avail_email_vis, book);
1435 list = book->tempList;
1436 book->tempList = NULL;
1437 book->tempHash = NULL;
1439 /* Clear hash table */
1440 g_hash_table_destroy(table);
1446 /* Update address book email list for specified group.
1447 Enter: book Address book.
1448 group group to update.
1449 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1450 Note: The existing email addresses are replaced with the new addresses. Any references
1451 to old addresses in the groups are re-linked to the new addresses. All old addresses
1452 linked to the person are removed */
1453 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1458 g_return_if_fail(book != NULL);
1459 g_return_if_fail(group != NULL);
1461 addrcache_set_dirty(book->addressCache, TRUE);
1463 /* Remember old list */
1464 oldData = group->listEMail;
1465 group->listEMail = listEMail;
1466 mgu_clear_list(oldData);
1470 /* Add group and email list to address book.
1471 Enter: book Address book.
1472 folder Parent folder, or NULL for root folder.
1473 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1474 Return: Group object.
1475 Note: The existing email addresses are replaced with the new addresses. Any references
1476 to old addresses in the groups are re-linked to the new addresses. All old addresses
1477 linked to the person are removed */
1478 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1481 ItemGroup *group = NULL;
1482 ItemFolder *f = folder;
1484 g_return_val_if_fail(book != NULL, NULL);
1487 f = book->addressCache->rootFolder;
1488 group = addritem_create_item_group();
1489 addrcache_id_group(book->addressCache, group);
1490 addrcache_folder_add_group(book->addressCache, f, group);
1491 group->listEMail = listEMail;
1495 /* Add new folder to address book.
1496 Enter: book Address book.
1497 parent Parent folder.
1498 Return: Folder that was added. This should *NOT* be g_free() when done */
1499 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1501 ItemFolder *folder = NULL;
1502 ItemFolder *p = parent;
1504 g_return_val_if_fail(book != NULL, NULL);
1507 p = book->addressCache->rootFolder;
1508 folder = addritem_create_item_folder();
1509 addrcache_id_folder(book->addressCache, folder);
1510 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1511 p->listFolder = g_list_append(p->listFolder, folder);
1512 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1513 addrcache_set_dirty(book->addressCache, TRUE);
1516 addritem_free_item_folder(folder);
1522 /* Update address book attribute list for specified person.
1523 Enter: book Address book.
1524 person Person to update.
1525 listAttrib New list of attributes.
1526 Note: The existing email addresses are replaced with the new addresses. All old attributes
1527 linked to the person are removed */
1528 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1534 g_return_if_fail(book != NULL);
1535 g_return_if_fail(person != NULL);
1537 /* Remember old list */
1538 oldData = person->listAttrib;
1540 /* Attach new address list to person. */
1543 UserAttribute *attrib = node->data;
1544 if (attrib->uid == NULL) {
1545 /* Allocate an ID */
1546 addrcache_id_attribute(book->addressCache, attrib);
1548 node = g_list_next(node);
1550 person->listAttrib = listAttrib;
1551 addrcache_set_dirty(book->addressCache, TRUE);
1553 /* Free up old data */
1554 addritem_free_list_attribute(oldData);
1559 * Add attribute data for person to address book.
1560 * Enter: book Address book.
1561 * person New person object.
1562 * listAttrib New list of attributes.
1563 * Note: Only attributes are inserted into address book.
1565 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1568 g_return_if_fail( book != NULL );
1569 g_return_if_fail( person != NULL );
1573 UserAttribute *attrib = node->data;
1574 if( attrib->uid == NULL ) {
1575 addrcache_id_attribute( book->addressCache, attrib );
1577 addritem_person_add_attribute( person, attrib );
1578 node = g_list_next( node );
1580 addrcache_set_dirty( book->addressCache, TRUE );
1583 /* Return address book file for specified object.
1584 Enter: aio Book item object.
1585 Return: Address book, or NULL if not found */
1586 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1588 AddressBookFile *book = NULL;
1591 ItemFolder *parent = NULL;
1592 ItemFolder *root = NULL;
1593 if (aio->type == ITEMTYPE_EMAIL) {
1594 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1596 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1599 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1602 root = addrcache_find_root_folder(parent);
1604 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1609 /* Remove folder from address book. Children are re-parented to parent folder.
1610 param: folder Folder to remove.
1611 return: Folder, or NULL if not found. Note that object should still be freed */
1612 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1616 g_return_val_if_fail(book != NULL, NULL);
1618 f = addrcache_remove_folder(book->addressCache, folder);
1622 /* Remove folder from address book. Children are deleted.
1623 param: folder Folder to remove.
1624 return: Folder, or NULL if not found. Note that object should still be freed */
1625 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1630 g_return_val_if_fail(book != NULL, NULL);
1632 f = addrcache_remove_folder_delete(book->addressCache, folder);
1636 #define WORK_BUFLEN 1024
1637 #define ADDRBOOK_DIGITS "0123456789"
1639 /* Return list of existing address book files.
1640 Enter: book Address book file.
1641 Return: File list */
1642 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1645 struct dirent *entry;
1646 struct stat statbuf;
1647 gchar buf[WORK_BUFLEN];
1648 gchar numbuf[WORK_BUFLEN];
1649 gint len, lenpre, lensuf, lennum;
1650 long int val, maxval;
1651 GList *fileList = NULL;
1653 g_return_val_if_fail(book != NULL, NULL);
1655 if (book->path == NULL || *book->path == '\0') {
1656 book->retVal = MGU_NO_PATH;
1660 strcpy(buf, book->path);
1663 if (buf[len-1] != G_DIR_SEPARATOR) {
1664 buf[len] = G_DIR_SEPARATOR;
1669 adbookdir = g_strdup(buf);
1670 strcat(buf, ADDRBOOK_PREFIX);
1672 if ((dp = opendir(adbookdir)) == NULL) {
1673 book->retVal = MGU_OPEN_DIRECTORY;
1678 lenpre = strlen(ADDRBOOK_PREFIX);
1679 lensuf = strlen(ADDRBOOK_SUFFIX);
1680 lennum = FILE_NUMDIGITS + lenpre;
1683 while ((entry = readdir(dp)) != NULL) {
1684 gchar *endptr = NULL;
1688 strcpy(buf, adbookdir);
1689 strcat(buf, entry->d_name);
1690 stat(buf, &statbuf);
1691 if (S_IFREG & statbuf.st_mode) {
1692 if (strncmp(entry->d_name, ADDRBOOK_PREFIX, lenpre) == 0) {
1693 if (strncmp((entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf) == 0) {
1694 strncpy(numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS);
1695 numbuf[FILE_NUMDIGITS] = '\0';
1697 for(i = 0; i < FILE_NUMDIGITS; i++) {
1698 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1705 val = strtol(numbuf, &endptr, 10);
1706 if (endptr && val > -1) {
1707 if (val > maxval) maxval = val;
1708 fileList = g_list_append(fileList, g_strdup(entry->d_name));
1718 book->maxValue = maxval;
1719 book->retVal = MGU_SUCCESS;
1723 /* Return file name for specified file number.
1724 Enter: fileNum File number.
1725 Return: File name, or NULL if file number too large. Should be g_free() when done */
1726 gchar *addrbook_gen_new_file_name(gint fileNum) {
1728 gchar buf[WORK_BUFLEN];
1734 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1737 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1738 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1739 return g_strdup(buf);
1742 /* **********************************************************************
1743 Address book test functions...
1744 **********************************************************************
1748 * Test email address list.
1750 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1755 prev_level = file->level;
1756 if (xml_parse_next_tag(file))
1757 longjmp(book->jumper, 1);
1758 if (file->level < prev_level)
1760 attr = xml_get_current_tag_attr(file);
1761 /* addrbook_show_attribs( attr ); */
1762 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1763 addrbook_chkparse_addr_list(book, file);
1767 /* Test user attributes for person */
1768 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1773 attr = xml_get_current_tag_attr(file);
1774 /* addrbook_show_attribs( attr ); */
1775 element = xml_get_element(file);
1776 /* printf( "\t\tattrib value : %s\n", element ); */
1779 /* Test attribute list */
1780 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1785 prev_level = file->level;
1786 if (xml_parse_next_tag(file))
1787 longjmp(book->jumper, 1);
1788 if (file->level < prev_level)
1790 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1791 addrbook_chkparse_attribute(book, file);
1792 addrbook_chkparse_attr_list(book, file);
1798 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1802 attr = xml_get_current_tag_attr(file);
1803 /* addrbook_show_attribs( attr ); */
1804 if (xml_parse_next_tag(file)) /* Consume closing tag */
1805 longjmp(book->jumper, 1);
1807 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1808 addrbook_chkparse_addr_list(book, file);
1810 if (xml_parse_next_tag(file)) /* Consume closing tag */
1811 longjmp(book->jumper, 1);
1813 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1814 addrbook_chkparse_attr_list(book, file);
1817 /* Test group member list */
1818 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
1824 prev_level = file->level;
1825 if (xml_parse_next_tag(file))
1826 longjmp(book->jumper, 1);
1828 if (file->level < prev_level)
1831 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
1832 attr = xml_get_current_tag_attr(file);
1833 /* addrbook_show_attribs( attr ); */
1834 addrbook_chkparse_member_list(book, file);
1837 attr = xml_get_current_tag_attr(file);
1838 /* addrbook_show_attribs( attr ); */
1844 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
1848 attr = xml_get_current_tag_attr(file);
1849 /* addrbook_show_attribs( attr ); */
1850 if (xml_parse_next_tag(file)) /* Consume closing tag */
1851 longjmp(book->jumper, 1);
1853 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
1854 addrbook_chkparse_member_list(book, file);
1857 /* Test folder item list */
1858 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
1864 prev_level = file->level;
1865 if (xml_parse_next_tag(file))
1866 longjmp(book->jumper, 1);
1868 if (file->level < prev_level)
1871 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
1872 attr = xml_get_current_tag_attr(file);
1873 /* addrbook_show_attribs( attr ); */
1874 addrbook_chkparse_folder_list(book, file);
1877 attr = xml_get_current_tag_attr(file);
1878 /* addrbook_show_attribs( attr ); */
1884 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
1888 attr = xml_get_current_tag_attr(file);
1889 /* addrbook_show_attribs( attr ); */
1890 if (xml_parse_next_tag(file)) /* Consume closing tag */
1891 longjmp(book->jumper, 1);
1893 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
1894 addrbook_chkparse_folder_list(book, file);
1897 /* Test address book */
1898 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
1903 if (xml_get_dtd(file))
1906 if (xml_parse_next_tag(file))
1909 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
1912 attr = xml_get_current_tag_attr(file);
1913 /* addrbook_show_attribs( attr ); */
1920 if (xml_parse_next_tag(file))
1921 longjmp(book->jumper, 1);
1923 /* Get next tag (person, group or folder) */
1924 if (xml_compare_tag(file, AB_ELTAG_PERSON))
1925 addrbook_chkparse_person( book, file );
1926 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
1927 addrbook_chkparse_group(book, file);
1928 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
1929 addrbook_chkparse_folder(book, file);
1934 /* Test address book file by parsing contents.
1935 Enter: book Address book file to check.
1936 fileName File name to check.
1937 Return: MGU_SUCCESS if file appears to be valid format */
1938 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
1940 XMLFile *file = NULL;
1941 gchar *fileSpec = NULL;
1943 g_return_val_if_fail(book != NULL, -1);
1945 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
1946 book->retVal = MGU_OPEN_FILE;
1947 file = xml_open_file(fileSpec);
1950 book->retVal = MGU_BAD_FORMAT;
1951 if (setjmp(book->jumper)) {
1952 /* printf( "Caught Ya!!!\n" ); */
1953 xml_close_file(file);
1954 return book->retVal;
1956 if (addrbook_chkread_tree(book, file))
1957 book->retVal = MGU_SUCCESS;
1959 xml_close_file( file );
1961 return book->retVal;
1964 /* Return link list of all persons in address book. Note that the list contains
1965 references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1966 this will destroy the addressbook data!
1967 Return: List of items, or NULL if none */
1968 GList *addrbook_get_all_persons(AddressBookFile *book)
1970 g_return_val_if_fail(book != NULL, NULL);
1971 return addrcache_get_all_persons(book->addressCache);
1975 * Add person and address data to address book.
1976 * \param book Address book.
1977 * \param folder Folder where to add person, or NULL for root folder.
1978 * \param name Common name.
1979 * \param address EMail address.
1980 * \param remarks Remarks.
1981 * \return Person added. Do not <b>*NOT*</b> to use the
1982 * <code>addrbook_free_xxx()</code> functions... this will destroy
1983 * the address book data.
1985 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
1986 const gchar *name,const gchar *address,
1987 const gchar *remarks)
1991 g_return_val_if_fail(book != NULL, NULL);
1992 person = addrcache_add_contact(
1993 book->addressCache, folder, name, address, remarks );
1994 addrcache_invalidate( book->addressCache );
1999 * Return file name for next address book file.
2000 * \param book Address book.
2001 * \return File name, or <i>NULL</i> if could not create. This should be
2002 * <code>g_free()</code> when done.
2004 gchar *addrbook_guess_next_file(AddressBookFile *book)
2006 gchar *newFile = NULL;
2007 GList *fileList = NULL;
2009 fileList = addrbook_get_bookfile_list(book);
2011 fileNum = 1 + book->maxValue;
2013 newFile = addrbook_gen_new_file_name(fileNum);
2014 g_list_free(fileList);
2020 * Invalidate the address book data. This will cause index to be rebuilt.
2021 * \param book Address book.
2023 void addrbook_invalidate( AddressBookFile *book ) {
2024 g_return_if_fail( book != NULL );
2025 addrcache_invalidate( book->addressCache );