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,
515 /* gchar *pid = NULL; */
516 ItemEMail *email = NULL;
518 attr = xml_get_current_tag_attr(file);
520 name = ((XMLAttr *)attr->data)->name;
521 value = ((XMLAttr *)attr->data)->value;
523 if (strcmp(name, AB_ATTAG_PID) == 0)
524 pid = g_strdup(value);
525 else if (strcmp(name, AB_ATTAG_EID) == 0)
526 eid = g_strdup(value);
528 if( strcmp( name, AB_ATTAG_EID ) == 0 )
529 eid = g_strdup( value );
530 attr = g_list_next(attr);
532 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
533 email = addrcache_get_email(book->addressCache, eid);
536 addrcache_group_add_email(book->addressCache, group,
540 addritem_free_item_email(email);
546 /* Parse group member list */
547 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
554 prev_level = file->level;
555 if (xml_parse_next_tag(file)) {
556 longjmp(book->jumper, 1);
558 if (file->level < prev_level)
560 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
561 attr = xml_get_current_tag_attr(file);
562 addrbook_parse_member(book, file, group);
563 addrbook_parse_member_list(book, file, group);
566 attr = xml_get_current_tag_attr(file);
572 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
576 ItemGroup *group = NULL;
578 attr = xml_get_current_tag_attr(file);
580 name = ((XMLAttr *)attr->data)->name;
581 value = ((XMLAttr *)attr->data)->value;
583 group = addritem_create_item_group();
584 if (strcmp(name, AB_ATTAG_UID) == 0)
585 ADDRITEM_ID(group) = g_strdup(value);
586 else if (strcmp(name, AB_ATTAG_NAME) == 0)
587 ADDRITEM_NAME(group) = g_strdup(value);
588 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
589 group->remarks = g_strdup(value);
590 attr = g_list_next(attr);
592 if (xml_parse_next_tag(file)) { /* Consume closing tag */
593 longjmp(book->jumper, 1);
595 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
597 addrcache_hash_add_group(book->addressCache, group);
599 addrbook_parse_member_list(book, file, group);
603 /* Parse folder item */
604 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
611 attr = xml_get_current_tag_attr(file);
613 name = ((XMLAttr *)attr->data)->name;
614 value = ((XMLAttr *)attr->data)->value;
615 if (strcmp(name, AB_ATTAG_UID) == 0) {
616 uid = g_strdup(value);
618 attr = g_list_next(attr);
622 folder->listItems = g_list_append(folder->listItems, uid);
627 /* Parse folder item list */
628 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
635 prev_level = file->level;
636 if (xml_parse_next_tag(file)) {
637 longjmp(book->jumper, 1);
639 if (file->level < prev_level)
641 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
642 attr = xml_get_current_tag_attr(file);
643 addrbook_parse_folder_item(book, file, folder);
644 addrbook_parse_folder_list(book, file, folder);
647 attr = xml_get_current_tag_attr(file);
653 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
657 ItemFolder *folder = NULL;
659 attr = xml_get_current_tag_attr(file);
661 name = ((XMLAttr *)attr->data)->name;
662 value = ((XMLAttr *)attr->data)->value;
664 folder = addritem_create_item_folder();
665 if (strcmp(name, AB_ATTAG_UID) == 0)
666 ADDRITEM_ID(folder) = g_strdup(value);
667 else if (strcmp(name, AB_ATTAG_NAME) == 0)
668 ADDRITEM_NAME(folder) = g_strdup(value);
669 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
670 folder->remarks = g_strdup(value);
671 attr = g_list_next(attr);
673 if (xml_parse_next_tag(file)) { /* Consume closing tag */
674 longjmp(book->jumper, 1);
676 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
678 if (addrcache_hash_add_folder(book->addressCache,
680 book->tempList = g_list_append(book->tempList,
682 /* We will resolve folder later */
683 ADDRITEM_PARENT(folder) = NULL;
686 addrbook_parse_folder_list(book, file, folder);
690 /* Parse address book.
691 Return: TRUE if data read successfully, FALSE if error reading data */
692 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
698 book->retVal = MGU_BAD_FORMAT;
699 if (xml_get_dtd(file))
701 if (xml_parse_next_tag(file))
702 longjmp(book->jumper, 1);
703 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
706 attr = xml_get_current_tag_attr(file);
708 name = ((XMLAttr *)attr->data)->name;
709 value = ((XMLAttr *)attr->data)->value;
710 if (strcmp( name, AB_ATTAG_NAME) == 0)
711 addrbook_set_name( book, value );
712 attr = g_list_next( attr );
719 /* Get next item tag (person, group or folder) */
720 if (xml_parse_next_tag(file))
721 longjmp( book->jumper, 1 );
723 if (xml_compare_tag(file, AB_ELTAG_PERSON))
724 addrbook_parse_person(book, file);
725 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
726 addrbook_parse_group(book, file);
727 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
728 addrbook_parse_folder(book, file);
730 if (retVal) book->retVal = MGU_SUCCESS;
734 /* Resolve folder items visitor function */
735 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
737 AddressBookFile *book = data;
738 AddrItemObject *obj = (AddrItemObject *) value;
739 ItemFolder *rootFolder = book->addressCache->rootFolder;
740 if (obj->parent == NULL) {
741 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
742 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
744 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
746 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
747 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
749 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
754 /* Resolve folder items. Lists of UID's are replaced with pointers to
756 static void addrbook_resolve_folder_items(AddressBookFile *book)
758 GList *nodeFolder = NULL;
759 GList *listRemove = NULL;
761 ItemFolder *rootFolder = book->addressCache->rootFolder;
762 nodeFolder = book->tempList;
765 ItemFolder *folder = nodeFolder->data;
767 node = folder->listItems;
769 gchar *uid = node->data;
770 AddrItemObject *aio = addrcache_get_object(book->addressCache,
773 if (aio->type == ITEMTYPE_FOLDER) {
774 ItemFolder *item = (ItemFolder *) aio;
775 folder->listFolder = g_list_append(folder->listFolder, item);
776 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
777 addrcache_hash_add_folder(book->addressCache, folder);
779 else if (aio->type == ITEMTYPE_PERSON) {
780 ItemPerson *item = (ItemPerson *) aio;
781 folder->listPerson = g_list_append(folder->listPerson, item);
782 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
784 else if (aio->type == ITEMTYPE_GROUP) {
785 ItemGroup *item = (ItemGroup *) aio;
786 folder->listGroup = g_list_append(folder->listGroup, item);
787 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
789 /* Replace data with pointer to item */
793 else { /* Not found, append to remove list. */
794 listRemove = g_list_append(listRemove, uid);
796 node = g_list_next(node);
798 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
800 /* Process remove list */
803 gchar *uid = node->data;
804 folder->listItems = g_list_remove(folder->listItems,
807 node = g_list_next(node);
809 g_list_free(listRemove);
810 nodeFolder = g_list_next(nodeFolder);
812 /* Remove folders with parents. */
814 node = rootFolder->listFolder;
816 ItemFolder *folder = (ItemFolder *) node->data;
817 if (ADDRITEM_PARENT(folder))
818 /* Remove folders with parents */
819 listRemove = g_list_append(listRemove, folder);
820 else /* Add to root folder */
821 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
823 node = g_list_next( node );
825 /* Process remove list */
828 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
830 node = g_list_next(node);
832 g_list_free(listRemove);
834 /* Move all unparented persons and groups into root folder */
835 g_hash_table_foreach(book->addressCache->itemHash,
836 addrbook_res_items_vis, book);
838 /* Free up some more */
839 nodeFolder = book->tempList;
841 ItemFolder *folder = nodeFolder->data;
842 g_list_free(folder->listItems);
843 folder->listItems = NULL;
844 nodeFolder = g_list_next(nodeFolder);
846 g_list_free(book->tempList);
847 book->tempList = NULL;
850 /* Read address book file */
851 gint addrbook_read_data(AddressBookFile *book)
853 XMLFile *file = NULL;
854 gchar *fileSpec = NULL;
856 g_return_val_if_fail(book != NULL, -1);
859 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
860 addrcache_get_name( book->addressCache ) );
863 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
864 book->fileName, NULL);
865 book->retVal = MGU_OPEN_FILE;
866 addrcache_clear(book->addressCache);
867 book->addressCache->modified = FALSE;
868 book->addressCache->accessFlag = FALSE;
869 file = xml_open_file(fileSpec);
872 book->tempList = NULL;
873 /* Trap for parsing errors. */
874 if (setjmp( book->jumper)) {
875 xml_close_file(file);
878 addrbook_read_tree(book, file);
879 xml_close_file(file);
880 /* Resolve folder items */
881 addrbook_resolve_folder_items(book);
882 book->tempList = NULL;
883 book->addressCache->modified = FALSE;
884 book->addressCache->dataRead = TRUE;
885 addrcache_set_dirty(book->addressCache, FALSE);
887 /* Build address completion index */
888 addrcache_build_index( book->addressCache );
893 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
896 for (i = 0; i < lvl; i++)
902 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
905 for(i = 0; i < lvl; i++)
912 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
917 xml_file_put_escape_str(fp, value);
921 /* Write file hash table visitor function */
922 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
925 AddrItemObject *obj = (AddrItemObject *) value;
926 FILE *fp = (FILE *) data;
931 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
932 ItemPerson *person = (ItemPerson *) value;
934 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
935 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
936 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
937 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
938 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
939 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
942 /* Output email addresses */
943 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
945 node = person->listEMail;
947 ItemEMail *email = node->data;
948 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
949 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
950 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
951 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
952 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
954 node = g_list_next(node);
956 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
958 /* Output user attributes */
959 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
961 node = person->listAttrib;
963 UserAttribute *attrib = node->data;
964 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
965 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
966 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
968 xml_file_put_escape_str(fp, attrib->value);
969 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
970 node = g_list_next(node);
972 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
973 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
978 /* Write file hash table visitor function */
979 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
982 AddrItemObject *obj = (AddrItemObject *) value;
983 FILE *fp = (FILE *) data;
988 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
989 ItemGroup *group = (ItemGroup *) value;
991 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
992 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
993 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
994 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
997 /* Output email address links */
998 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
1000 node = group->listEMail;
1002 ItemEMail *email = node->data;
1003 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1004 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1005 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1006 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1008 node = g_list_next(node);
1010 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1011 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1016 /* Write file hash table visitor function */
1017 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1020 AddrItemObject *obj = (AddrItemObject *) value;
1021 FILE *fp = (FILE *) data;
1026 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1027 ItemFolder *folder = (ItemFolder *) value;
1029 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1030 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1031 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1032 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1034 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1037 /* Output persons */
1038 node = folder->listPerson;
1040 ItemPerson *item = node->data;
1041 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1042 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1043 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1045 node = g_list_next(node);
1049 node = folder->listGroup;
1051 ItemGroup *item = node->data;
1052 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1053 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1054 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1056 node = g_list_next(node);
1059 /* Output folders */
1060 node = folder->listFolder;
1062 ItemFolder *item = node->data;
1063 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1064 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1065 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1067 node = g_list_next(node);
1069 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1070 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1075 /* Output address book data to specified file.
1076 return: Status code */
1077 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1081 #ifndef DEV_STANDALONE
1085 g_return_val_if_fail(book != NULL, -1);
1086 g_return_val_if_fail(newFile != NULL, -1);
1088 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1090 book->retVal = MGU_OPEN_FILE;
1091 #ifdef DEV_STANDALONE
1092 fp = fopen(fileSpec, "wb");
1095 fputs("<?xml version=\"1.0\" ?>\n", fp);
1097 pfile = prefs_write_open(fileSpec);
1101 fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1102 conv_get_current_charset_str());
1104 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1105 addrbook_write_attr(fp, AB_ATTAG_NAME,
1106 addrcache_get_name(book->addressCache));
1109 /* Output all persons */
1110 g_hash_table_foreach(book->addressCache->itemHash,
1111 addrbook_write_item_person_vis, fp);
1113 /* Output all groups */
1114 g_hash_table_foreach(book->addressCache->itemHash,
1115 addrbook_write_item_group_vis, fp);
1117 /* Output all folders */
1118 g_hash_table_foreach(book->addressCache->itemHash,
1119 addrbook_write_item_folder_vis, fp);
1121 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1122 book->retVal = MGU_SUCCESS;
1123 #ifdef DEV_STANDALONE
1126 if (prefs_file_close( pfile ) < 0)
1127 book->retVal = MGU_ERROR_WRITE;
1132 return book->retVal;
1135 /* Output address book data to original file.
1136 return: Status code */
1137 gint addrbook_save_data(AddressBookFile *book)
1139 g_return_val_if_fail(book != NULL, -1);
1141 book->retVal = MGU_NO_FILE;
1142 if (book->fileName == NULL || *book->fileName == '\0')
1143 return book->retVal;
1144 if (book->path == NULL || *book->path == '\0')
1145 return book->retVal;
1147 addrbook_write_to(book, book->fileName);
1148 if (book->retVal == MGU_SUCCESS)
1149 addrcache_set_dirty(book->addressCache, FALSE);
1150 return book->retVal;
1153 /* **********************************************************************
1154 Address book edit interface functions...
1155 ***********************************************************************
1156 Move person's email item.
1157 param: book Address book.
1159 itemMove Item to move.
1160 itemTarget Target item before which to move item */
1161 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1162 ItemEMail *itemMove, ItemEMail *itemTarget)
1164 ItemEMail *email = NULL;
1166 g_return_val_if_fail(book != NULL, NULL);
1168 email = addritem_move_email_before(person, itemMove, itemTarget);
1170 addrcache_set_dirty(book->addressCache, TRUE);
1174 /* Move person's email item.
1175 param: book Address book.
1177 itemMove Item to move.
1178 itemTarget Target item after which to move item */
1179 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1180 ItemEMail *itemMove, ItemEMail *itemTarget)
1182 ItemEMail *email = NULL;
1184 g_return_val_if_fail(book != NULL, NULL);
1186 email = addritem_move_email_after(person, itemMove, itemTarget);
1188 addrcache_set_dirty(book->addressCache, TRUE);
1192 /* Hash table visitor function for deletion of hashtable entries */
1193 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1202 /* Update address book email list for specified person.
1203 Enter: book Address book.
1204 person Person to update.
1205 listEMail List of new email addresses.
1206 Note: The existing email addresses are replaced with the new addresses. Any references
1207 to old addresses in the groups are re-linked to the new addresses. All old addresses
1208 linked to the person are removed */
1209 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1216 g_return_if_fail(book != NULL);
1217 g_return_if_fail(person != NULL);
1219 /* Get groups where person's existing email addresses are listed */
1220 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1222 GHashTable *hashEMail;
1223 GHashTable *hashEMailAlias;
1226 /* Load hash table with new address entries */
1227 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1228 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1231 ItemEMail *email = node->data;
1232 gchar *addr = g_strdup(email->address);
1233 gchar *alias = email->obj.name ;
1235 if (!g_hash_table_lookup(hashEMail, addr)) {
1236 g_hash_table_insert(hashEMail, addr, email);
1238 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1240 g_hash_table_insert(hashEMailAlias, alias, email);
1242 node = g_list_next(node);
1245 /* Re-parent new addresses to existing groups, where email address match. */
1246 nodeGrp = listGroup;
1248 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1249 GList *groupEMail = group->listEMail;
1251 GList *listRemove = NULL;
1253 /* Process each email item linked to group */
1254 nodeGrpEM = groupEMail;
1256 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1258 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1259 /* Found an email address for this person */
1260 ItemEMail *emailNew = NULL;
1261 gchar *addr = g_strdup(emailGrp->address);
1262 gchar *alias = emailGrp->obj.name;
1264 emailNew = (ItemEMail *)
1265 g_hash_table_lookup(hashEMail, addr);
1267 /* If no match by e-mail, try to match by e-mail alias */
1268 if (!emailNew && *alias != '\0') {
1269 emailNew = (ItemEMail *)
1270 g_hash_table_lookup(hashEMailAlias, alias);
1274 /* Point to this entry */
1275 nodeGrpEM->data = emailNew;
1276 else if (g_hash_table_size(hashEMail)==1)
1277 /* If the person has just one e-mail address, then
1278 change e-mail address in group list */
1279 nodeGrpEM->data = listEMail->data;
1281 /* Mark for removal */
1282 listRemove = g_list_append(listRemove, emailGrp);
1284 /* Move on to next email link */
1285 nodeGrpEM = g_list_next(nodeGrpEM);
1288 /* Process all removed links in current group */
1289 nodeGrpEM = listRemove;
1291 ItemEMail *emailGrp = nodeGrpEM->data;
1292 groupEMail = g_list_remove(groupEMail, emailGrp);
1293 nodeGrpEM = g_list_next(nodeGrpEM);
1296 g_list_free(listRemove);
1298 /* Move on to next group */
1299 nodeGrp = g_list_next(nodeGrp);
1302 /* Clear hash table */
1303 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1304 addrbook_free_simple_hash_vis, NULL);
1305 g_hash_table_destroy(hashEMail);
1307 g_hash_table_destroy(hashEMailAlias);
1308 hashEMailAlias = NULL;
1309 g_list_free(listGroup);
1312 /* Remove old addresses from person and cache */
1314 node = person->listEMail;
1316 ItemEMail *email = node->data;
1318 if (addrcache_person_remove_email(book->addressCache, person, email))
1319 addrcache_remove_email(book->addressCache, email);
1321 listDelete = g_list_append(listDelete, email);
1322 node = person->listEMail;
1324 /* Add new address entries */
1327 ItemEMail *email = node->data;
1329 if (ADDRITEM_ID(email) == NULL)
1330 /* Allocate an ID for new address */
1331 addrcache_id_email(book->addressCache, email);
1333 addrcache_person_add_email( book->addressCache, person, email );
1334 node = g_list_next( node );
1337 addrcache_set_dirty(book->addressCache, TRUE);
1339 /* Free up memory */
1340 g_list_free(listEMail);
1345 ItemEMail *email = node->data;
1347 addritem_free_item_email(email);
1348 node = g_list_next(node);
1350 g_list_free(listDelete);
1355 /* Add person and address data to address book.
1356 Enter: book Address book.
1357 folder Folder where to add person, or NULL for root folder.
1358 listEMail New list of email addresses.
1359 Return: Person added.
1360 Note: A new person is created with specified list of email addresses. All objects inserted
1361 into address book */
1362 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1366 ItemFolder *f = folder;
1369 g_return_val_if_fail(book != NULL, NULL);
1372 f = book->addressCache->rootFolder;
1373 person = addritem_create_item_person();
1374 addrcache_id_person(book->addressCache, person);
1375 addrcache_folder_add_person(book->addressCache, f, person);
1379 ItemEMail *email = node->data;
1380 if (ADDRITEM_ID(email) == NULL)
1381 addrcache_id_email(book->addressCache, email);
1383 addrcache_person_add_email(book->addressCache, person, email);
1384 node = g_list_next(node);
1389 /* Build available email list visitor function */
1390 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1393 AddrItemObject *obj = (AddrItemObject *) value;
1395 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1396 AddressBookFile *book = data;
1397 ItemPerson *person = (ItemPerson *) obj;
1398 GList *node = person->listEMail;
1400 ItemEMail *email = node->data;
1401 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1403 if (!g_hash_table_lookup(book->tempHash,
1404 ADDRITEM_ID(email)))
1405 book->tempList = g_list_append(book->tempList, email);
1407 node = g_list_next(node);
1412 /* Return link list of available email items (which have not already been linked to
1413 groups). Note that the list contains references to items and should be g_free()
1414 when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1415 destroy the addressbook data!
1416 Return: List of items, or NULL if none */
1417 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1422 g_return_val_if_fail(book != NULL, NULL);
1424 /* Load hash table with group email entries */
1425 table = g_hash_table_new(g_str_hash, g_str_equal);
1427 list = group->listEMail;
1429 ItemEMail *email = list->data;
1430 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1431 list = g_list_next(list);
1435 /* Build list of available email addresses which exclude those already in groups */
1436 book->tempList = NULL;
1437 book->tempHash = table;
1438 g_hash_table_foreach(book->addressCache->itemHash,
1439 addrbook_build_avail_email_vis, book);
1440 list = book->tempList;
1441 book->tempList = NULL;
1442 book->tempHash = NULL;
1444 /* Clear hash table */
1445 g_hash_table_destroy(table);
1451 /* Update address book email list for specified group.
1452 Enter: book Address book.
1453 group group to update.
1454 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1455 Note: The existing email addresses are replaced with the new addresses. Any references
1456 to old addresses in the groups are re-linked to the new addresses. All old addresses
1457 linked to the person are removed */
1458 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1463 g_return_if_fail(book != NULL);
1464 g_return_if_fail(group != NULL);
1466 addrcache_set_dirty(book->addressCache, TRUE);
1468 /* Remember old list */
1469 oldData = group->listEMail;
1470 group->listEMail = listEMail;
1471 mgu_clear_list(oldData);
1475 /* Add group and email list to address book.
1476 Enter: book Address book.
1477 folder Parent folder, or NULL for root folder.
1478 listEMail New list of email addresses. This should *NOT* be g_free() when done.
1479 Return: Group object.
1480 Note: The existing email addresses are replaced with the new addresses. Any references
1481 to old addresses in the groups are re-linked to the new addresses. All old addresses
1482 linked to the person are removed */
1483 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1486 ItemGroup *group = NULL;
1487 ItemFolder *f = folder;
1489 g_return_val_if_fail(book != NULL, NULL);
1492 f = book->addressCache->rootFolder;
1493 group = addritem_create_item_group();
1494 addrcache_id_group(book->addressCache, group);
1495 addrcache_folder_add_group(book->addressCache, f, group);
1496 group->listEMail = listEMail;
1500 /* Add new folder to address book.
1501 Enter: book Address book.
1502 parent Parent folder.
1503 Return: Folder that was added. This should *NOT* be g_free() when done */
1504 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1506 ItemFolder *folder = NULL;
1507 ItemFolder *p = parent;
1509 g_return_val_if_fail(book != NULL, NULL);
1512 p = book->addressCache->rootFolder;
1513 folder = addritem_create_item_folder();
1514 addrcache_id_folder(book->addressCache, folder);
1515 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1516 p->listFolder = g_list_append(p->listFolder, folder);
1517 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1518 addrcache_set_dirty(book->addressCache, TRUE);
1521 addritem_free_item_folder(folder);
1527 /* Update address book attribute list for specified person.
1528 Enter: book Address book.
1529 person Person to update.
1530 listAttrib New list of attributes.
1531 Note: The existing email addresses are replaced with the new addresses. All old attributes
1532 linked to the person are removed */
1533 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1539 g_return_if_fail(book != NULL);
1540 g_return_if_fail(person != NULL);
1542 /* Remember old list */
1543 oldData = person->listAttrib;
1545 /* Attach new address list to person. */
1548 UserAttribute *attrib = node->data;
1549 if (attrib->uid == NULL) {
1550 /* Allocate an ID */
1551 addrcache_id_attribute(book->addressCache, attrib);
1553 node = g_list_next(node);
1555 person->listAttrib = listAttrib;
1556 addrcache_set_dirty(book->addressCache, TRUE);
1558 /* Free up old data */
1559 addritem_free_list_attribute(oldData);
1564 * Add attribute data for person to address book.
1565 * Enter: book Address book.
1566 * person New person object.
1567 * listAttrib New list of attributes.
1568 * Note: Only attributes are inserted into address book.
1570 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1573 g_return_if_fail( book != NULL );
1574 g_return_if_fail( person != NULL );
1578 UserAttribute *attrib = node->data;
1579 if( attrib->uid == NULL ) {
1580 addrcache_id_attribute( book->addressCache, attrib );
1582 addritem_person_add_attribute( person, attrib );
1583 node = g_list_next( node );
1585 addrcache_set_dirty( book->addressCache, TRUE );
1588 /* Return address book file for specified object.
1589 Enter: aio Book item object.
1590 Return: Address book, or NULL if not found */
1591 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1593 AddressBookFile *book = NULL;
1596 ItemFolder *parent = NULL;
1597 ItemFolder *root = NULL;
1598 if (aio->type == ITEMTYPE_EMAIL) {
1599 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1601 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1604 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1607 root = addrcache_find_root_folder(parent);
1609 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1614 /* Remove folder from address book. Children are re-parented to parent folder.
1615 param: folder Folder to remove.
1616 return: Folder, or NULL if not found. Note that object should still be freed */
1617 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1621 g_return_val_if_fail(book != NULL, NULL);
1623 f = addrcache_remove_folder(book->addressCache, folder);
1627 /* Remove folder from address book. Children are deleted.
1628 param: folder Folder to remove.
1629 return: Folder, or NULL if not found. Note that object should still be freed */
1630 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1635 g_return_val_if_fail(book != NULL, NULL);
1637 f = addrcache_remove_folder_delete(book->addressCache, folder);
1641 #define WORK_BUFLEN 1024
1642 #define ADDRBOOK_DIGITS "0123456789"
1644 /* Return list of existing address book files.
1645 Enter: book Address book file.
1646 Return: File list */
1647 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1650 struct dirent *entry;
1651 struct stat statbuf;
1652 gchar buf[WORK_BUFLEN];
1653 gchar numbuf[WORK_BUFLEN];
1654 gint len, lenpre, lensuf, lennum;
1655 long int val, maxval;
1656 GList *fileList = NULL;
1658 g_return_val_if_fail(book != NULL, NULL);
1660 if (book->path == NULL || *book->path == '\0') {
1661 book->retVal = MGU_NO_PATH;
1665 strcpy(buf, book->path);
1668 if (buf[len-1] != G_DIR_SEPARATOR) {
1669 buf[len] = G_DIR_SEPARATOR;
1674 adbookdir = g_strdup(buf);
1675 strcat(buf, ADDRBOOK_PREFIX);
1677 if ((dp = opendir(adbookdir)) == NULL) {
1678 book->retVal = MGU_OPEN_DIRECTORY;
1683 lenpre = strlen(ADDRBOOK_PREFIX);
1684 lensuf = strlen(ADDRBOOK_SUFFIX);
1685 lennum = FILE_NUMDIGITS + lenpre;
1688 while ((entry = readdir(dp)) != NULL) {
1689 gchar *endptr = NULL;
1693 strcpy(buf, adbookdir);
1694 strcat(buf, entry->d_name);
1695 stat(buf, &statbuf);
1696 if (S_IFREG & statbuf.st_mode) {
1697 if (strncmp(entry->d_name, ADDRBOOK_PREFIX, lenpre) == 0) {
1698 if (strncmp((entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf) == 0) {
1699 strncpy(numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS);
1700 numbuf[FILE_NUMDIGITS] = '\0';
1702 for(i = 0; i < FILE_NUMDIGITS; i++) {
1703 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1710 val = strtol(numbuf, &endptr, 10);
1711 if (endptr && val > -1) {
1712 if (val > maxval) maxval = val;
1713 fileList = g_list_append(fileList, g_strdup(entry->d_name));
1723 book->maxValue = maxval;
1724 book->retVal = MGU_SUCCESS;
1728 /* Return file name for specified file number.
1729 Enter: fileNum File number.
1730 Return: File name, or NULL if file number too large. Should be g_free() when done */
1731 gchar *addrbook_gen_new_file_name(gint fileNum) {
1733 gchar buf[WORK_BUFLEN];
1739 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1742 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1743 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1744 return g_strdup(buf);
1747 /* **********************************************************************
1748 Address book test functions...
1749 **********************************************************************
1753 * Test email address list.
1755 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1760 prev_level = file->level;
1761 if (xml_parse_next_tag(file))
1762 longjmp(book->jumper, 1);
1763 if (file->level < prev_level)
1765 attr = xml_get_current_tag_attr(file);
1766 /* addrbook_show_attribs( attr ); */
1767 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1768 addrbook_chkparse_addr_list(book, file);
1772 /* Test user attributes for person */
1773 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1778 attr = xml_get_current_tag_attr(file);
1779 /* addrbook_show_attribs( attr ); */
1780 element = xml_get_element(file);
1781 /* printf( "\t\tattrib value : %s\n", element ); */
1784 /* Test attribute list */
1785 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1790 prev_level = file->level;
1791 if (xml_parse_next_tag(file))
1792 longjmp(book->jumper, 1);
1793 if (file->level < prev_level)
1795 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1796 addrbook_chkparse_attribute(book, file);
1797 addrbook_chkparse_attr_list(book, file);
1803 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1807 attr = xml_get_current_tag_attr(file);
1808 /* addrbook_show_attribs( attr ); */
1809 if (xml_parse_next_tag(file)) /* Consume closing tag */
1810 longjmp(book->jumper, 1);
1812 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1813 addrbook_chkparse_addr_list(book, file);
1815 if (xml_parse_next_tag(file)) /* Consume closing tag */
1816 longjmp(book->jumper, 1);
1818 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1819 addrbook_chkparse_attr_list(book, file);
1822 /* Test group member list */
1823 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
1829 prev_level = file->level;
1830 if (xml_parse_next_tag(file))
1831 longjmp(book->jumper, 1);
1833 if (file->level < prev_level)
1836 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
1837 attr = xml_get_current_tag_attr(file);
1838 /* addrbook_show_attribs( attr ); */
1839 addrbook_chkparse_member_list(book, file);
1842 attr = xml_get_current_tag_attr(file);
1843 /* addrbook_show_attribs( attr ); */
1849 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
1853 attr = xml_get_current_tag_attr(file);
1854 /* addrbook_show_attribs( attr ); */
1855 if (xml_parse_next_tag(file)) /* Consume closing tag */
1856 longjmp(book->jumper, 1);
1858 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
1859 addrbook_chkparse_member_list(book, file);
1862 /* Test folder item list */
1863 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
1869 prev_level = file->level;
1870 if (xml_parse_next_tag(file))
1871 longjmp(book->jumper, 1);
1873 if (file->level < prev_level)
1876 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
1877 attr = xml_get_current_tag_attr(file);
1878 /* addrbook_show_attribs( attr ); */
1879 addrbook_chkparse_folder_list(book, file);
1882 attr = xml_get_current_tag_attr(file);
1883 /* addrbook_show_attribs( attr ); */
1889 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
1893 attr = xml_get_current_tag_attr(file);
1894 /* addrbook_show_attribs( attr ); */
1895 if (xml_parse_next_tag(file)) /* Consume closing tag */
1896 longjmp(book->jumper, 1);
1898 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
1899 addrbook_chkparse_folder_list(book, file);
1902 /* Test address book */
1903 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
1908 if (xml_get_dtd(file))
1911 if (xml_parse_next_tag(file))
1914 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
1917 attr = xml_get_current_tag_attr(file);
1918 /* addrbook_show_attribs( attr ); */
1925 if (xml_parse_next_tag(file))
1926 longjmp(book->jumper, 1);
1928 /* Get next tag (person, group or folder) */
1929 if (xml_compare_tag(file, AB_ELTAG_PERSON))
1930 addrbook_chkparse_person( book, file );
1931 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
1932 addrbook_chkparse_group(book, file);
1933 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
1934 addrbook_chkparse_folder(book, file);
1939 /* Test address book file by parsing contents.
1940 Enter: book Address book file to check.
1941 fileName File name to check.
1942 Return: MGU_SUCCESS if file appears to be valid format */
1943 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
1945 XMLFile *file = NULL;
1946 gchar *fileSpec = NULL;
1948 g_return_val_if_fail(book != NULL, -1);
1950 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
1951 book->retVal = MGU_OPEN_FILE;
1952 file = xml_open_file(fileSpec);
1955 book->retVal = MGU_BAD_FORMAT;
1956 if (setjmp(book->jumper)) {
1957 /* printf( "Caught Ya!!!\n" ); */
1958 xml_close_file(file);
1959 return book->retVal;
1961 if (addrbook_chkread_tree(book, file))
1962 book->retVal = MGU_SUCCESS;
1964 xml_close_file( file );
1966 return book->retVal;
1969 /* Return link list of all persons in address book. Note that the list contains
1970 references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1971 this will destroy the addressbook data!
1972 Return: List of items, or NULL if none */
1973 GList *addrbook_get_all_persons(AddressBookFile *book)
1975 g_return_val_if_fail(book != NULL, NULL);
1976 return addrcache_get_all_persons(book->addressCache);
1980 * Add person and address data to address book.
1981 * \param book Address book.
1982 * \param folder Folder where to add person, or NULL for root folder.
1983 * \param name Common name.
1984 * \param address EMail address.
1985 * \param remarks Remarks.
1986 * \return Person added. Do not <b>*NOT*</b> to use the
1987 * <code>addrbook_free_xxx()</code> functions... this will destroy
1988 * the address book data.
1990 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
1991 const gchar *name,const gchar *address,
1992 const gchar *remarks)
1996 g_return_val_if_fail(book != NULL, NULL);
1997 person = addrcache_add_contact(
1998 book->addressCache, folder, name, address, remarks );
1999 addrcache_invalidate( book->addressCache );
2004 * Return file name for next address book file.
2005 * \param book Address book.
2006 * \return File name, or <i>NULL</i> if could not create. This should be
2007 * <code>g_free()</code> when done.
2009 gchar *addrbook_guess_next_file(AddressBookFile *book)
2011 gchar *newFile = NULL;
2012 GList *fileList = NULL;
2014 fileList = addrbook_get_bookfile_list(book);
2016 fileNum = 1 + book->maxValue;
2018 newFile = addrbook_gen_new_file_name(fileNum);
2019 g_list_free(fileList);
2025 * Invalidate the address book data. This will cause index to be rebuilt.
2026 * \param book Address book.
2028 void addrbook_invalidate( AddressBookFile *book ) {
2029 g_return_if_fail( book != NULL );
2030 addrcache_invalidate( book->addressCache );