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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /* General functions for accessing address book files */
32 #include "addrcache.h"
34 #include "adbookbase.h"
36 #ifndef DEV_STANDALONE
37 #include "prefs_gtk.h"
41 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
42 #define ADDRBOOK_PREFIX "addrbook-"
43 #define ADDRBOOK_SUFFIX ".xml"
44 #define FILE_NUMDIGITS 6
46 #define ID_TIME_OFFSET 998000000
49 * Create new address book
50 * \return Address book.
52 AddressBookFile *addrbook_create_book()
54 AddressBookFile *book;
56 book = g_new0(AddressBookFile, 1);
57 book->type = ADBOOKTYPE_BOOK;
58 book->addressCache = addrcache_create();
59 book->retVal = MGU_SUCCESS;
61 book->fileName = NULL;
63 book->tempList = NULL;
64 book->tempHash = NULL;
65 book->addressCache->modified = TRUE;
71 * Specify name to be used
72 * \param book Address book.
75 void addrbook_set_name(AddressBookFile *book, const gchar *value)
77 g_return_if_fail(book != NULL);
78 addrcache_set_name(book->addressCache, value);
81 gchar *addrbook_get_name(AddressBookFile *book)
83 g_return_val_if_fail(book != NULL, NULL);
84 return addrcache_get_name(book->addressCache);
88 * Specify path to address book file.
89 * \param book Address book.
92 void addrbook_set_path(AddressBookFile *book, const gchar *value)
94 g_return_if_fail(book != NULL);
95 book->path = mgu_replace_string(book->path, value);
96 addrcache_set_dirty(book->addressCache, TRUE);
100 * Specify filename to be used
101 * \param book Address book.
102 * \param value Filename.
104 void addrbook_set_file(AddressBookFile *book, const gchar *value)
106 g_return_if_fail(book != NULL);
107 book->fileName = mgu_replace_string(book->fileName, value);
108 addrcache_set_dirty(book->addressCache, TRUE);
111 gboolean addrbook_get_modified(AddressBookFile *book)
113 g_return_val_if_fail(book != NULL, FALSE);
114 return book->addressCache->modified;
118 * Specify book as modified.
119 * \param book Address book.
120 * \param value Indicator.
122 void addrbook_set_modified(AddressBookFile *book, const gboolean value)
124 g_return_if_fail(book != NULL);
125 book->addressCache->modified = value;
128 gboolean addrbook_get_accessed(AddressBookFile *book)
130 g_return_val_if_fail(book != NULL, FALSE);
131 return book->addressCache->accessFlag;
135 * Specify address book as accessed.
136 * \param book Address book.
137 * \param value Value.
139 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
141 g_return_if_fail(book != NULL);
142 book->addressCache->accessFlag = value;
145 gboolean addrbook_get_read_flag(AddressBookFile *book)
147 g_return_val_if_fail(book != NULL, FALSE);
148 return book->addressCache->dataRead;
152 * Specify address book as read.
153 * \param book Address book.
154 * \param value Value.
156 void addrbook_set_read_flag(AddressBookFile *book, const gboolean value)
158 g_return_if_fail(book != NULL);
159 book->addressCache->dataRead = value;
162 gint addrbook_get_status(AddressBookFile *book)
164 g_return_val_if_fail(book != NULL, -1);
168 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
170 g_return_val_if_fail(book != NULL, NULL);
171 return addrcache_get_root_folder(book->addressCache);
174 GList *addrbook_get_list_folder(AddressBookFile *book)
176 g_return_val_if_fail(book != NULL, NULL);
177 return addrcache_get_list_folder(book->addressCache);
180 GList *addrbook_get_list_person(AddressBookFile *book)
182 g_return_val_if_fail(book != NULL, NULL);
183 return addrcache_get_list_person(book->addressCache);
186 gboolean addrbook_get_dirty(AddressBookFile *book)
188 g_return_val_if_fail(book != NULL, FALSE);
189 return addrcache_get_dirty(book->addressCache);
193 * Set address book as dirty (needs to be written to file).
194 * \param book Address book.
195 * \param value Dirty flag.
197 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
199 g_return_if_fail(book != NULL);
200 addrcache_set_dirty(book->addressCache, value);
204 * Empty address book contents.
205 * \param book Address book.
207 void addrbook_empty_book(AddressBookFile *book)
209 g_return_if_fail(book != NULL);
211 /* Free up internal objects */
212 addrcache_clear(book->addressCache);
213 addrcache_set_dirty(book->addressCache, FALSE);
214 g_list_free(book->tempList);
216 /* Reset to initial state */
217 book->tempList = NULL;
218 book->tempHash = NULL;
219 book->addressCache->dataRead = FALSE;
220 book->addressCache->modified = FALSE;
221 book->addressCache->accessFlag = FALSE;
222 book->retVal = MGU_SUCCESS;
227 * \param book Address book.
229 void addrbook_free_book(AddressBookFile *book)
231 g_return_if_fail(book != NULL);
234 addrcache_free(book->addressCache);
236 /* Free up internal objects */
238 g_free(book->fileName);
239 g_list_free(book->tempList);
242 book->fileName = NULL;
244 book->tempList = NULL;
245 book->tempHash = NULL;
247 book->type = ADBOOKTYPE_NONE;
248 book->addressCache = NULL;
249 book->retVal = MGU_SUCCESS;
255 * Print list of items.
256 * \param book Address book.
257 * \param stream Output stream.
259 void addrbook_print_item_list(GList *list, FILE *stream)
264 AddrItemObject *obj = node->data;
265 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON)
266 addritem_print_item_person((ItemPerson *) obj, stream);
267 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP)
268 addritem_print_item_group((ItemGroup *) obj, stream);
269 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER)
270 addritem_print_item_folder((ItemFolder *) obj, stream);
271 node = g_list_next(node);
273 fprintf(stream, "\t---\n");
277 * Print address book header.
278 * \param book Address book.
279 * \param stream Output stream.
281 void addrbook_print_book(AddressBookFile *book, FILE *stream)
283 g_return_if_fail(book != NULL);
285 fprintf(stream, "AddressBook:\n");
286 fprintf(stream, "\tpath : '%s'\n", book->path);
287 fprintf(stream, "\tfile : '%s'\n", book->fileName);
288 fprintf(stream, "\tstatus : %d\n", book->retVal );
289 addrcache_print(book->addressCache, stream);
293 * Dump entire address book traversing folders.
294 * \param book Address book.
295 * \param stream Output stream.
297 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
301 g_return_if_fail(book != NULL);
303 addrbook_print_book(book, stream);
304 folder = book->addressCache->rootFolder;
305 addritem_print_item_folder(folder, stream);
309 * Remove specified group from address book. Note that object should still
311 * Specify name to be used
312 * \param book Address book.
313 * \param group Group to remove.
315 * \return Group, or NULL if not found.
317 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
319 g_return_val_if_fail(book != NULL, NULL);
320 return addrcache_remove_group(book->addressCache, group);
324 * Remove specified person from address book. Note that object should still
326 * \param book Address book.
327 * \param person Person to remove.
328 * \return Person, or NULL if not found.
330 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
332 g_return_val_if_fail(book != NULL, NULL);
333 return addrcache_remove_person(book->addressCache, person);
337 * Remove specified email address in address book for specified person.
338 * Note that object should still be freed.
339 * \param book Address book.
340 * \param person Person.
341 * \param email EMail to remove.
342 * \return EMail object, or NULL if not found.
344 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
345 ItemPerson *person, ItemEMail *email)
347 g_return_val_if_fail(book != NULL, NULL);
348 return addrcache_person_remove_email(book->addressCache, person, email);
352 * ***********************************************************************
353 * Read/Write XML data file...
354 * ===========================
356 * 1) The address book is structured as follows:
371 * 2) This sequence of elements was chosen so that the most important
372 * elements (person and their email addresses) appear first.
374 * 3) Groups then appear. When groups are loaded, person's email
375 * addresses have already been loaded and can be found.
377 * 4) Finally folders are loaded. Any forward and backward references
378 * to folders, groups and persons in the folders are resolved after
381 * ***********************************************************************
384 /* Element tag names */
385 #define AB_ELTAG_ADDRESS "address"
386 #define AB_ELTAG_ATTRIBUTE "attribute"
387 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
388 #define AB_ELTAG_ADDRESS_LIST "address-list"
389 #define AB_ELTAG_MEMBER "member"
390 #define AB_ELTAG_MEMBER_LIST "member-list"
391 #define AB_ELTAG_ITEM "item"
392 #define AB_ELTAG_ITEM_LIST "item-list"
393 #define AB_ELTAG_ADDRESS_BOOK "address-book"
394 #define AB_ELTAG_PERSON "person"
395 #define AB_ELTAG_GROUP "group"
396 #define AB_ELTAG_FOLDER "folder"
398 /* Attribute tag names */
399 #define AB_ATTAG_TYPE "type"
400 #define AB_ATTAG_UID "uid"
401 #define AB_ATTAG_NAME "name"
402 #define AB_ATTAG_REMARKS "remarks"
403 #define AB_ATTAG_FIRST_NAME "first-name"
404 #define AB_ATTAG_LAST_NAME "last-name"
405 #define AB_ATTAG_NICK_NAME "nick-name"
406 #define AB_ATTAG_COMMON_NAME "cn"
407 #define AB_ATTAG_ALIAS "alias"
408 #define AB_ATTAG_EMAIL "email"
409 #define AB_ATTAG_EID "eid"
410 #define AB_ATTAG_PID "pid"
412 /* Attribute values */
413 #define AB_ATTAG_VAL_PERSON "person"
414 #define AB_ATTAG_VAL_GROUP "group"
415 #define AB_ATTAG_VAL_FOLDER "folder"
418 * Parse address item for person from XML file.
419 * \param book Address book.
420 * \param file XML file handle.
421 * \param person Person.
423 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
428 ItemEMail *email = NULL;
430 attr = xml_get_current_tag_attr(file);
432 name = ((XMLAttr *)attr->data)->name;
433 value = ((XMLAttr *)attr->data)->value;
435 email = addritem_create_item_email();
436 if (strcmp(name, AB_ATTAG_UID) == 0)
437 ADDRITEM_ID(email) = g_strdup(value);
438 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
439 ADDRITEM_NAME(email) = g_strdup(value);
440 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
441 email->address = g_strdup(value);
442 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
443 email->remarks = g_strdup(value);
444 attr = g_list_next(attr);
448 addrcache_person_add_email(book->addressCache, person,
452 addritem_free_item_email(email);
459 * Parse list of email address for person from XML file.
460 * \param book Address book.
461 * \param file XML file handle.
462 * \param person Person.
464 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
471 prev_level = file->level;
472 if (xml_parse_next_tag(file)) {
473 longjmp(book->jumper, 1);
475 if (file->level < prev_level) return;
476 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
477 attr = xml_get_current_tag_attr(file);
478 addrbook_parse_address(book, file, person);
479 addrbook_parse_addr_list(book, file, person);
485 * Parse attribute for person from XML file.
486 * \param book Address book.
487 * \param file XML file handle.
488 * \param person Person.
490 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
495 UserAttribute *uAttr = NULL;
497 attr = xml_get_current_tag_attr(file);
499 name = ((XMLAttr *)attr->data)->name;
500 value = ((XMLAttr *)attr->data)->value;
501 if (!uAttr) uAttr = addritem_create_attribute();
502 if (strcmp(name, AB_ATTAG_UID) == 0)
503 addritem_attrib_set_id(uAttr, value);
504 else if (strcmp(name, AB_ATTAG_NAME) == 0)
505 addritem_attrib_set_name(uAttr, value);
506 attr = g_list_next(attr);
509 element = xml_get_element(file);
510 addritem_attrib_set_value(uAttr, element);
514 addritem_person_add_attribute(person, uAttr);
517 addritem_free_attribute(uAttr);
524 * Parse list of attributes for person from XML file.
525 * \param book Address book.
526 * \param file XML file handle.
527 * \param person Person.
529 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
536 prev_level = file->level;
537 if (xml_parse_next_tag(file)) {
538 longjmp( book->jumper, 1 );
540 if (file->level < prev_level) return;
541 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
542 attr = xml_get_current_tag_attr(file);
543 addrbook_parse_attribute(file, person);
544 addrbook_parse_attr_list(book, file, person);
550 * Parse person from XML file.
551 * \param book Address book.
552 * \param file XML file handle.
554 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
558 ItemPerson *person = NULL;
560 attr = xml_get_current_tag_attr(file);
562 name = ((XMLAttr *)attr->data)->name;
563 value = ((XMLAttr *)attr->data)->value;
565 person = addritem_create_item_person();
566 if (strcmp(name, AB_ATTAG_UID) == 0)
567 ADDRITEM_ID(person) = g_strdup(value);
568 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
569 person->firstName = g_strdup(value);
570 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
571 person->lastName = g_strdup(value);
572 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
573 person->nickName = g_strdup(value);
574 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
575 ADDRITEM_NAME(person) = g_strdup(value);
576 attr = g_list_next(attr);
578 if (xml_parse_next_tag(file)) { /* Consume closing tag */
579 longjmp(book->jumper, 1);
581 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
582 addrbook_parse_addr_list(book, file, person);
584 addrcache_hash_add_person(book->addressCache, person);
587 if (xml_parse_next_tag(file)) { /* Consume closing tag */
588 longjmp(book->jumper, 1);
590 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
591 addrbook_parse_attr_list(book, file, person);
596 * Parse group member from XML file.
597 * \param book Address book.
598 * \param file XML file handle.
599 * \param group Group.
601 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
607 /* gchar *pid = NULL; */
608 ItemEMail *email = NULL;
610 attr = xml_get_current_tag_attr(file);
612 name = ((XMLAttr *)attr->data)->name;
613 value = ((XMLAttr *)attr->data)->value;
615 if (strcmp(name, AB_ATTAG_PID) == 0)
616 pid = g_strdup(value);
617 else if (strcmp(name, AB_ATTAG_EID) == 0)
618 eid = g_strdup(value);
620 if( strcmp( name, AB_ATTAG_EID ) == 0 )
621 eid = g_strdup( value );
622 attr = g_list_next(attr);
624 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
625 email = addrcache_get_email(book->addressCache, eid);
628 addrcache_group_add_email(book->addressCache, group,
632 addritem_free_item_email(email);
639 * Parse list of group members from XML file.
640 * \param book Address book.
641 * \param file XML file handle.
642 * \param group Group.
644 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
651 prev_level = file->level;
652 if (xml_parse_next_tag(file)) {
653 longjmp(book->jumper, 1);
655 if (file->level < prev_level)
657 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
658 attr = xml_get_current_tag_attr(file);
659 addrbook_parse_member(book, file, group);
660 addrbook_parse_member_list(book, file, group);
663 attr = xml_get_current_tag_attr(file);
669 * Parse group object from XML file.
670 * \param book Address book.
671 * \param file XML file handle.
673 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
677 ItemGroup *group = NULL;
679 attr = xml_get_current_tag_attr(file);
681 name = ((XMLAttr *)attr->data)->name;
682 value = ((XMLAttr *)attr->data)->value;
684 group = addritem_create_item_group();
685 if (strcmp(name, AB_ATTAG_UID) == 0)
686 ADDRITEM_ID(group) = g_strdup(value);
687 else if (strcmp(name, AB_ATTAG_NAME) == 0)
688 ADDRITEM_NAME(group) = g_strdup(value);
689 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
690 group->remarks = g_strdup(value);
691 attr = g_list_next(attr);
693 if (xml_parse_next_tag(file)) { /* Consume closing tag */
694 longjmp(book->jumper, 1);
696 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
698 addrcache_hash_add_group(book->addressCache, group);
700 addrbook_parse_member_list(book, file, group);
705 * Parse folder item from XML file.
706 * \param book Address book.
707 * \param file XML file handle.
708 * \param folder Folder.
710 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
717 attr = xml_get_current_tag_attr(file);
719 name = ((XMLAttr *)attr->data)->name;
720 value = ((XMLAttr *)attr->data)->value;
721 if (strcmp(name, AB_ATTAG_UID) == 0) {
722 uid = g_strdup(value);
724 attr = g_list_next(attr);
728 folder->listItems = g_list_append(folder->listItems, uid);
734 * Parse list of folder items from XML file.
735 * \param book Address book.
736 * \param file XML file handle.
737 * \param folder Folder.
739 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
746 prev_level = file->level;
747 if (xml_parse_next_tag(file)) {
748 longjmp(book->jumper, 1);
750 if (file->level < prev_level)
752 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
753 attr = xml_get_current_tag_attr(file);
754 addrbook_parse_folder_item(book, file, folder);
755 addrbook_parse_folder_list(book, file, folder);
758 attr = xml_get_current_tag_attr(file);
764 * Parse folder from XML file.
765 * \param book Address book.
766 * \param file XML file handle.
768 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
772 ItemFolder *folder = NULL;
774 attr = xml_get_current_tag_attr(file);
776 name = ((XMLAttr *)attr->data)->name;
777 value = ((XMLAttr *)attr->data)->value;
779 folder = addritem_create_item_folder();
780 if (strcmp(name, AB_ATTAG_UID) == 0)
781 ADDRITEM_ID(folder) = g_strdup(value);
782 else if (strcmp(name, AB_ATTAG_NAME) == 0)
783 ADDRITEM_NAME(folder) = g_strdup(value);
784 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
785 folder->remarks = g_strdup(value);
786 attr = g_list_next(attr);
788 if (xml_parse_next_tag(file)) { /* Consume closing tag */
789 longjmp(book->jumper, 1);
791 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
793 if (addrcache_hash_add_folder(book->addressCache,
795 book->tempList = g_list_append(book->tempList,
797 /* We will resolve folder later */
798 ADDRITEM_PARENT(folder) = NULL;
801 addrbook_parse_folder_list(book, file, folder);
806 * Read address book (DOM) tree from file.
807 * \param book Address book.
808 * \param file XML file handle.
809 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
812 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
818 book->retVal = MGU_BAD_FORMAT;
819 if (xml_get_dtd(file))
821 if (xml_parse_next_tag(file))
822 longjmp(book->jumper, 1);
823 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
826 attr = xml_get_current_tag_attr(file);
828 name = ((XMLAttr *)attr->data)->name;
829 value = ((XMLAttr *)attr->data)->value;
830 if (strcmp( name, AB_ATTAG_NAME) == 0)
831 addrbook_set_name( book, value );
832 attr = g_list_next( attr );
839 /* Get next item tag (person, group or folder) */
840 if (xml_parse_next_tag(file))
841 longjmp( book->jumper, 1 );
843 if (xml_compare_tag(file, AB_ELTAG_PERSON))
844 addrbook_parse_person(book, file);
845 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
846 addrbook_parse_group(book, file);
847 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
848 addrbook_parse_folder(book, file);
850 if (retVal) book->retVal = MGU_SUCCESS;
855 * Resolve folder items callback function.
856 * \param key Table key.
857 * \param value Reference to object contained in folder.
858 * \param data Reference to address book.
860 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
862 AddressBookFile *book = data;
863 AddrItemObject *obj = (AddrItemObject *) value;
864 ItemFolder *rootFolder = book->addressCache->rootFolder;
865 if (obj->parent == NULL) {
866 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
867 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
869 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
871 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
872 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
874 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
880 * Resolve folder items. Lists of UID's are replaced with pointers to
882 * \param book Address book.
884 static void addrbook_resolve_folder_items(AddressBookFile *book)
886 GList *nodeFolder = NULL;
887 GList *listRemove = NULL;
889 ItemFolder *rootFolder = book->addressCache->rootFolder;
890 nodeFolder = book->tempList;
893 ItemFolder *folder = nodeFolder->data;
895 node = folder->listItems;
897 gchar *uid = node->data;
898 AddrItemObject *aio = addrcache_get_object(book->addressCache,
901 if (aio->type == ITEMTYPE_FOLDER) {
902 ItemFolder *item = (ItemFolder *) aio;
903 folder->listFolder = g_list_append(folder->listFolder, item);
904 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
905 addrcache_hash_add_folder(book->addressCache, folder);
907 else if (aio->type == ITEMTYPE_PERSON) {
908 ItemPerson *item = (ItemPerson *) aio;
909 folder->listPerson = g_list_append(folder->listPerson, item);
910 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
912 else if (aio->type == ITEMTYPE_GROUP) {
913 ItemGroup *item = (ItemGroup *) aio;
914 folder->listGroup = g_list_append(folder->listGroup, item);
915 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
917 /* Replace data with pointer to item */
921 else { /* Not found, append to remove list. */
922 listRemove = g_list_append(listRemove, uid);
924 node = g_list_next(node);
926 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
928 /* Process remove list */
931 gchar *uid = node->data;
932 folder->listItems = g_list_remove(folder->listItems,
935 node = g_list_next(node);
937 g_list_free(listRemove);
938 nodeFolder = g_list_next(nodeFolder);
940 /* Remove folders with parents. */
942 node = rootFolder->listFolder;
944 ItemFolder *folder = (ItemFolder *) node->data;
945 if (ADDRITEM_PARENT(folder))
946 /* Remove folders with parents */
947 listRemove = g_list_append(listRemove, folder);
948 else /* Add to root folder */
949 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
951 node = g_list_next( node );
953 /* Process remove list */
956 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
958 node = g_list_next(node);
960 g_list_free(listRemove);
962 /* Move all unparented persons and groups into root folder */
963 g_hash_table_foreach(book->addressCache->itemHash,
964 addrbook_res_items_vis, book);
966 /* Free up some more */
967 nodeFolder = book->tempList;
969 ItemFolder *folder = nodeFolder->data;
970 g_list_free(folder->listItems);
971 folder->listItems = NULL;
972 nodeFolder = g_list_next(nodeFolder);
974 g_list_free(book->tempList);
975 book->tempList = NULL;
980 * \param book Address book.
981 * \return Status code.
983 gint addrbook_read_data(AddressBookFile *book)
985 XMLFile *file = NULL;
986 gchar *fileSpec = NULL;
988 g_return_val_if_fail(book != NULL, -1);
991 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
992 addrcache_get_name( book->addressCache ) );
995 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
996 book->fileName, NULL);
997 book->retVal = MGU_OPEN_FILE;
998 addrcache_clear(book->addressCache);
999 book->addressCache->modified = FALSE;
1000 book->addressCache->accessFlag = FALSE;
1001 file = xml_open_file(fileSpec);
1004 book->tempList = NULL;
1005 /* Trap for parsing errors. */
1006 if (setjmp( book->jumper)) {
1007 xml_close_file(file);
1008 return book->retVal;
1010 addrbook_read_tree(book, file);
1011 xml_close_file(file);
1012 /* Resolve folder items */
1013 addrbook_resolve_folder_items(book);
1014 book->tempList = NULL;
1015 book->addressCache->modified = FALSE;
1016 book->addressCache->dataRead = TRUE;
1017 addrcache_set_dirty(book->addressCache, FALSE);
1019 return book->retVal;
1023 * Write start element to file.
1024 * \param fp File handle.
1025 * \param lvl Indent level.
1026 * \param name Element name.
1028 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
1031 for (i = 0; i < lvl; i++)
1038 * Write end element to file.
1039 * \param fp File handle.
1040 * \param lvl Indent level.
1041 * \param name Element name.
1043 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
1046 for(i = 0; i < lvl; i++)
1054 * Write attribute name/value pair to file.
1055 * \param fp File handle.
1056 * \param name Attribute name.
1057 * \param value Attribute value.
1059 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
1064 xml_file_put_escape_str(fp, value);
1069 * Write person and associated addresses and attributes to file.
1070 * file hash table visitor function.
1071 * \param key Table key.
1072 * \param value Reference to person.
1073 * \param data File pointer.
1075 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1078 AddrItemObject *obj = (AddrItemObject *) value;
1079 FILE *fp = (FILE *) data;
1084 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1085 ItemPerson *person = (ItemPerson *) value;
1087 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
1088 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
1089 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
1090 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
1091 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
1092 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
1095 /* Output email addresses */
1096 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
1098 node = person->listEMail;
1100 ItemEMail *email = node->data;
1101 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
1102 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
1103 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
1104 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
1105 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
1107 node = g_list_next(node);
1109 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
1111 /* Output user attributes */
1112 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1114 node = person->listAttrib;
1116 UserAttribute *attrib = node->data;
1117 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
1118 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
1119 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
1121 xml_file_put_escape_str(fp, attrib->value);
1122 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
1123 node = g_list_next(node);
1125 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1126 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
1132 * Write group and associated references to addresses to file.
1133 * file hash table visitor function.
1134 * \param key Table key.
1135 * \param value Reference to group.
1136 * \param data File pointer.
1138 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1141 AddrItemObject *obj = (AddrItemObject *) value;
1142 FILE *fp = (FILE *) data;
1147 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1148 ItemGroup *group = (ItemGroup *) value;
1150 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
1151 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
1152 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
1153 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
1156 /* Output email address links */
1157 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
1159 node = group->listEMail;
1161 ItemEMail *email = node->data;
1162 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1163 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1164 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1165 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1167 node = g_list_next(node);
1169 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1170 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1176 * Write folder and associated references to addresses to file.
1177 * file hash table visitor function.
1178 * \param key Table key.
1179 * \param value Reference to folder.
1180 * \param data File pointer.
1182 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1185 AddrItemObject *obj = (AddrItemObject *) value;
1186 FILE *fp = (FILE *) data;
1191 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1192 ItemFolder *folder = (ItemFolder *) value;
1194 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1195 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1196 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1197 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1199 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1202 /* Output persons */
1203 node = folder->listPerson;
1205 ItemPerson *item = node->data;
1206 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1207 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1208 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1210 node = g_list_next(node);
1214 node = folder->listGroup;
1216 ItemGroup *item = node->data;
1217 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1218 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1219 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1221 node = g_list_next(node);
1224 /* Output folders */
1225 node = folder->listFolder;
1227 ItemFolder *item = node->data;
1228 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1229 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1230 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1232 node = g_list_next(node);
1234 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1235 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1241 * Output address book data to specified file.
1242 * \param book Address book.
1243 * \param newFile Filename of new file (in book's filepath).
1244 * \return Status code.
1246 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1250 #ifndef DEV_STANDALONE
1254 g_return_val_if_fail(book != NULL, -1);
1255 g_return_val_if_fail(newFile != NULL, -1);
1257 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1259 book->retVal = MGU_OPEN_FILE;
1260 #ifdef DEV_STANDALONE
1261 fp = g_fopen(fileSpec, "wb");
1264 fputs("<?xml version=\"1.0\" ?>\n", fp);
1266 pfile = prefs_write_open(fileSpec);
1270 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
1272 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1273 addrbook_write_attr(fp, AB_ATTAG_NAME,
1274 addrcache_get_name(book->addressCache));
1277 /* Output all persons */
1278 g_hash_table_foreach(book->addressCache->itemHash,
1279 addrbook_write_item_person_vis, fp);
1281 /* Output all groups */
1282 g_hash_table_foreach(book->addressCache->itemHash,
1283 addrbook_write_item_group_vis, fp);
1285 /* Output all folders */
1286 g_hash_table_foreach(book->addressCache->itemHash,
1287 addrbook_write_item_folder_vis, fp);
1289 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1290 book->retVal = MGU_SUCCESS;
1291 #ifdef DEV_STANDALONE
1294 if (prefs_file_close( pfile ) < 0)
1295 book->retVal = MGU_ERROR_WRITE;
1300 return book->retVal;
1304 * Output address book data to original file.
1305 * \param book Address book.
1306 * \return Status code.
1308 gint addrbook_save_data(AddressBookFile *book)
1310 g_return_val_if_fail(book != NULL, -1);
1312 book->retVal = MGU_NO_FILE;
1313 if (book->fileName == NULL || *book->fileName == '\0')
1314 return book->retVal;
1315 if (book->path == NULL || *book->path == '\0')
1316 return book->retVal;
1318 addrbook_write_to(book, book->fileName);
1319 if (book->retVal == MGU_SUCCESS)
1320 addrcache_set_dirty(book->addressCache, FALSE);
1321 return book->retVal;
1325 * **********************************************************************
1326 * Address book edit interface functions.
1327 * **********************************************************************
1331 * Move email item within list of person's email items.
1332 * \param book Address book.
1333 * \param person Person.
1334 * \param itemMove EMail item to move.
1335 * \param itemTarget EMail item to move before.
1336 * \return Moved item.
1338 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1339 ItemEMail *itemMove, ItemEMail *itemTarget)
1341 ItemEMail *email = NULL;
1343 g_return_val_if_fail(book != NULL, NULL);
1345 email = addritem_move_email_before(person, itemMove, itemTarget);
1347 addrcache_set_dirty(book->addressCache, TRUE);
1352 * Move email item within list of person's email items.
1353 * \param book Address book.
1354 * \param person Person.
1355 * \param itemMove EMail item to move.
1356 * \param itemTarget EMail item after which to move.
1357 * \return Moved item.
1359 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1360 ItemEMail *itemMove, ItemEMail *itemTarget)
1362 ItemEMail *email = NULL;
1364 g_return_val_if_fail(book != NULL, NULL);
1366 email = addritem_move_email_after(person, itemMove, itemTarget);
1368 addrcache_set_dirty(book->addressCache, TRUE);
1373 * Hash table callback function for simple deletion of hashtable entries.
1374 * \param key Table key (will be freed).
1375 * \param value Value stored in table.
1376 * \param data User data.
1377 * \return <i>TRUE</i> to indicate that entry freed.
1379 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1389 * Update address book email list for specified person. Note: The existing
1390 * email addresses are replaced with the new addresses. Any references to
1391 * old addresses in the groups are re-linked to the new addresses. All old
1392 * addresses linked to the person are removed.
1393 * \param book Address book.
1394 * \param person Person to update.
1395 * \param listEMail List of new email addresses.
1397 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1404 g_return_if_fail(book != NULL);
1405 g_return_if_fail(person != NULL);
1407 /* Get groups where person's existing email addresses are listed */
1408 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1410 GHashTable *hashEMail;
1411 GHashTable *hashEMailAlias;
1414 /* Load hash table with new address entries */
1415 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1416 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1419 ItemEMail *email = node->data;
1420 gchar *addr = g_strdup(email->address);
1421 gchar *alias = email->obj.name ;
1423 if (!g_hash_table_lookup(hashEMail, addr)) {
1424 g_hash_table_insert(hashEMail, addr, email);
1426 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1428 g_hash_table_insert(hashEMailAlias, alias, email);
1430 node = g_list_next(node);
1433 /* Re-parent new addresses to existing groups, where email address match. */
1434 nodeGrp = listGroup;
1436 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1437 GList *groupEMail = group->listEMail;
1439 GList *listRemove = NULL;
1441 /* Process each email item linked to group */
1442 nodeGrpEM = groupEMail;
1444 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1446 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1447 /* Found an email address for this person */
1448 ItemEMail *emailNew = NULL;
1449 gchar *addr = g_strdup(emailGrp->address);
1450 gchar *alias = emailGrp->obj.name;
1452 emailNew = (ItemEMail *)
1453 g_hash_table_lookup(hashEMail, addr);
1455 /* If no match by e-mail, try to match by e-mail alias */
1456 if (!emailNew && *alias != '\0') {
1457 emailNew = (ItemEMail *)
1458 g_hash_table_lookup(hashEMailAlias, alias);
1462 /* Point to this entry */
1463 nodeGrpEM->data = emailNew;
1464 else if (g_hash_table_size(hashEMail)==1)
1465 /* If the person has just one e-mail address, then
1466 change e-mail address in group list */
1467 nodeGrpEM->data = listEMail->data;
1469 /* Mark for removal */
1470 listRemove = g_list_append(listRemove, emailGrp);
1472 /* Move on to next email link */
1473 nodeGrpEM = g_list_next(nodeGrpEM);
1476 /* Process all removed links in current group */
1477 nodeGrpEM = listRemove;
1479 ItemEMail *emailGrp = nodeGrpEM->data;
1480 groupEMail = g_list_remove(groupEMail, emailGrp);
1481 nodeGrpEM = g_list_next(nodeGrpEM);
1484 g_list_free(listRemove);
1486 /* Move on to next group */
1487 nodeGrp = g_list_next(nodeGrp);
1490 /* Clear hash table */
1491 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1492 addrbook_free_simple_hash_vis, NULL);
1493 g_hash_table_destroy(hashEMail);
1495 g_hash_table_destroy(hashEMailAlias);
1496 hashEMailAlias = NULL;
1497 g_list_free(listGroup);
1500 /* Remove old addresses from person and cache */
1502 node = person->listEMail;
1504 ItemEMail *email = node->data;
1506 if (addrcache_person_remove_email(book->addressCache, person, email))
1507 addrcache_remove_email(book->addressCache, email);
1509 listDelete = g_list_append(listDelete, email);
1510 node = person->listEMail;
1512 /* Add new address entries */
1515 ItemEMail *email = node->data;
1517 if (ADDRITEM_ID(email) == NULL)
1518 /* Allocate an ID for new address */
1519 addrcache_id_email(book->addressCache, email);
1521 addrcache_person_add_email( book->addressCache, person, email );
1522 node = g_list_next( node );
1525 addrcache_set_dirty(book->addressCache, TRUE);
1527 /* Free up memory */
1528 g_list_free(listEMail);
1533 ItemEMail *email = node->data;
1535 addritem_free_item_email(email);
1536 node = g_list_next(node);
1538 g_list_free(listDelete);
1544 * Create person object and add person with specified address data to address
1545 * book. Note: A new person is created with specified list of email addresses.
1546 * All objects inserted into address book.
1548 * \param book Address book.
1549 * \param folder Parent folder where to add person, or <i>NULL</i> for
1551 * \param listEMail List of new email addresses to associate with person.
1552 * \return Person object created.
1554 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1558 ItemFolder *f = folder;
1561 g_return_val_if_fail(book != NULL, NULL);
1564 f = book->addressCache->rootFolder;
1565 person = addritem_create_item_person();
1566 addrcache_id_person(book->addressCache, person);
1567 addrcache_folder_add_person(book->addressCache, f, person);
1571 ItemEMail *email = node->data;
1572 if (ADDRITEM_ID(email) == NULL)
1573 addrcache_id_email(book->addressCache, email);
1575 addrcache_person_add_email(book->addressCache, person, email);
1576 node = g_list_next(node);
1582 * Build available email list visitor function.
1583 * \param key Table key.
1584 * \param value Value stored in table.
1585 * \param data Reference to address book.
1587 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1590 AddrItemObject *obj = (AddrItemObject *) value;
1592 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1593 AddressBookFile *book = data;
1594 ItemPerson *person = (ItemPerson *) obj;
1595 GList *node = person->listEMail;
1597 ItemEMail *email = node->data;
1598 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1600 if (!g_hash_table_lookup(book->tempHash,
1601 ADDRITEM_ID(email)))
1602 book->tempList = g_list_append(book->tempList, email);
1604 node = g_list_next(node);
1610 * Return link list of available email items that have not already been linked
1611 * to groups. Note that the list contains references to items and should be
1612 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1613 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1616 * \param book Address book.
1617 * \param group Group to process.
1618 * \return List of items, or <i>NULL</i> if none.
1620 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1625 g_return_val_if_fail(book != NULL, NULL);
1627 /* Load hash table with group email entries */
1628 table = g_hash_table_new(g_str_hash, g_str_equal);
1630 list = group->listEMail;
1632 ItemEMail *email = list->data;
1633 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1634 list = g_list_next(list);
1638 /* Build list of available email addresses which exclude those already in groups */
1639 book->tempList = NULL;
1640 book->tempHash = table;
1641 g_hash_table_foreach(book->addressCache->itemHash,
1642 addrbook_build_avail_email_vis, book);
1643 list = book->tempList;
1644 book->tempList = NULL;
1645 book->tempHash = NULL;
1647 /* Clear hash table */
1648 g_hash_table_destroy(table);
1655 * Update address book email list for specified group. Note: The existing email
1656 * addresses are replaced with the new addresses. Any references to old addresses
1657 * in the groups are re-linked to the new addresses. All old addresses linked to
1658 * the person are removed.
1660 * \param book Address book.
1661 * \param group Group to process.
1662 * \param listEMail List of email items. This should <b>*NOT*</b> be
1663 * <code>g_free()</code> when done.
1665 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1670 g_return_if_fail(book != NULL);
1671 g_return_if_fail(group != NULL);
1673 addrcache_set_dirty(book->addressCache, TRUE);
1675 /* Remember old list */
1676 oldData = group->listEMail;
1677 group->listEMail = listEMail;
1678 mgu_clear_list(oldData);
1683 * Create group object and add with specifed list of email addresses to
1684 * address book. Note: The existing email addresses are replaced with the new
1685 * addresses. Any references to old addresses in the groups are re-linked to
1686 * the new addresses. All old addresses linked to the person are removed.
1688 * \param book Address book.
1689 * \param folder Parent folder where to add group, or <i>NULL</i> for
1691 * \param listEMail List of email items. This should <b>*NOT*</b> be
1692 * <code>g_free()</code> when done.
1693 * \return Group object created.
1695 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1698 ItemGroup *group = NULL;
1699 ItemFolder *f = folder;
1701 g_return_val_if_fail(book != NULL, NULL);
1704 f = book->addressCache->rootFolder;
1705 group = addritem_create_item_group();
1706 addrcache_id_group(book->addressCache, group);
1707 addrcache_folder_add_group(book->addressCache, f, group);
1708 group->listEMail = listEMail;
1713 * Create a new folder and add to address book.
1714 * \param book Address book.
1715 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1717 * \return Folder that was created. This should <b>*NOT*</b> be
1718 * <code>g_free()</code> when done.
1720 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1722 g_return_val_if_fail(book != NULL, NULL);
1723 return addrcache_add_new_folder( book->addressCache, parent );
1727 ItemFolder *folder = NULL;
1728 ItemFolder *p = parent;
1730 g_return_val_if_fail(book != NULL, NULL);
1733 p = book->addressCache->rootFolder;
1734 folder = addritem_create_item_folder();
1735 addrcache_id_folder(book->addressCache, folder);
1736 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1737 p->listFolder = g_list_append(p->listFolder, folder);
1738 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1739 addrcache_set_dirty(book->addressCache, TRUE);
1742 addritem_free_item_folder(folder);
1750 * Update address book attribute list for specified person. Note: The existing
1751 * attributes are replaced with the new addresses. All old attributes linked
1752 * to the person are removed.
1754 * \param book Address book.
1755 * \param person Person to receive attributes.
1756 * \param listAttrib New list of attributes.
1758 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1764 g_return_if_fail(book != NULL);
1765 g_return_if_fail(person != NULL);
1767 /* Remember old list */
1768 oldData = person->listAttrib;
1770 /* Attach new address list to person. */
1773 UserAttribute *attrib = node->data;
1774 if (attrib->uid == NULL) {
1775 /* Allocate an ID */
1776 addrcache_id_attribute(book->addressCache, attrib);
1778 node = g_list_next(node);
1780 person->listAttrib = listAttrib;
1781 addrcache_set_dirty(book->addressCache, TRUE);
1783 /* Free up old data */
1784 addritem_free_list_attribute(oldData);
1789 * Add attribute data for specified person to address book. Note: Only
1790 * attributes are inserted into address book.
1791 * \param book Address book.
1792 * \param person Person to receive attributes.
1793 * \param listAttrib List of attributes.
1795 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1798 g_return_if_fail( book != NULL );
1799 g_return_if_fail( person != NULL );
1803 UserAttribute *attrib = node->data;
1804 if( attrib->uid == NULL ) {
1805 addrcache_id_attribute( book->addressCache, attrib );
1807 addritem_person_add_attribute( person, attrib );
1808 node = g_list_next( node );
1810 addrcache_set_dirty( book->addressCache, TRUE );
1814 * Return reference to address book file for specified object by traversing up
1815 * address book heirarchy.
1817 * \param aio Book item object.
1818 * \return Address book, or <i>NULL</i> if not found.
1820 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1822 AddressBookFile *book = NULL;
1825 ItemFolder *parent = NULL;
1826 ItemFolder *root = NULL;
1827 if (aio->type == ITEMTYPE_EMAIL) {
1828 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1830 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1833 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1836 root = addrcache_find_root_folder(parent);
1838 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1844 * Remove folder from address book. Children are re-parented to the parent
1846 * \param book Address book.
1847 * \param folder Folder to remove.
1848 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1851 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1855 g_return_val_if_fail(book != NULL, NULL);
1857 f = addrcache_remove_folder(book->addressCache, folder);
1862 * Remove folder from address book. Children are deleted.
1863 * \param book Address book.
1864 * \param folder Folder to remove.
1865 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1868 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1873 g_return_val_if_fail(book != NULL, NULL);
1875 f = addrcache_remove_folder_delete(book->addressCache, folder);
1879 #define WORK_BUFLEN 1024
1880 #define ADDRBOOK_DIGITS "0123456789"
1883 * Return list of existing address book files.
1884 * \param book Address book.
1885 * \return List of files (as strings).
1887 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1890 const gchar *dir_name;
1891 struct stat statbuf;
1892 gchar buf[WORK_BUFLEN];
1893 gchar numbuf[WORK_BUFLEN];
1894 gint len, lenpre, lensuf, lennum;
1895 long int val, maxval;
1896 GList *fileList = NULL;
1898 g_return_val_if_fail(book != NULL, NULL);
1900 if (book->path == NULL || *book->path == '\0') {
1901 book->retVal = MGU_NO_PATH;
1905 strcpy(buf, book->path);
1908 if (buf[len-1] != G_DIR_SEPARATOR) {
1909 buf[len] = G_DIR_SEPARATOR;
1914 adbookdir = g_strdup(buf);
1915 strcat(buf, ADDRBOOK_PREFIX);
1917 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1918 book->retVal = MGU_OPEN_DIRECTORY;
1923 lenpre = strlen(ADDRBOOK_PREFIX);
1924 lensuf = strlen(ADDRBOOK_SUFFIX);
1925 lennum = FILE_NUMDIGITS + lenpre;
1928 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1929 gchar *endptr = NULL;
1933 strcpy(buf, adbookdir);
1934 strcat( buf, dir_name );
1935 stat(buf, &statbuf);
1936 if (S_ISREG(statbuf.st_mode)) {
1939 ADDRBOOK_PREFIX, lenpre) == 0)
1942 (dir_name) + lennum,
1943 ADDRBOOK_SUFFIX, lensuf) == 0)
1946 (dir_name) + lenpre,
1948 numbuf[FILE_NUMDIGITS] = '\0';
1950 for(i = 0; i < FILE_NUMDIGITS; i++) {
1951 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1958 val = strtol(numbuf, &endptr, 10);
1959 if (endptr && val > -1) {
1960 if (val > maxval) maxval = val;
1961 fileList = g_list_append(
1963 g_strdup(dir_name));
1973 book->maxValue = maxval;
1974 book->retVal = MGU_SUCCESS;
1979 * Return file name for specified file number.
1980 * \param fileNum File number.
1981 * \return File name, or <i>NULL</i> if file number too large. Should be
1982 * <code>g_free()</code> when done.
1984 gchar *addrbook_gen_new_file_name(gint fileNum) {
1986 gchar buf[WORK_BUFLEN];
1992 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1995 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1996 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1997 return g_strdup(buf);
2001 * **********************************************************************
2002 * Address book test functions...
2003 * **********************************************************************
2007 * Attempt to parse list of email address from file.
2008 * \param book Address book.
2009 * \param file XML file handle.
2011 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
2016 prev_level = file->level;
2017 if (xml_parse_next_tag(file))
2018 longjmp(book->jumper, 1);
2019 if (file->level < prev_level)
2021 attr = xml_get_current_tag_attr(file);
2022 /* addrbook_show_attribs( attr ); */
2023 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
2024 addrbook_chkparse_addr_list(book, file);
2029 * Attempt to parse attributes for person address from file.
2030 * \param book Address book.
2031 * \param file XML file handle.
2033 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
2038 attr = xml_get_current_tag_attr(file);
2039 /* addrbook_show_attribs( attr ); */
2040 element = xml_get_element(file);
2041 /* printf( "\t\tattrib value : %s\n", element ); */
2045 * Attempt to parse list of attributes for person address from file.
2046 * \param book Address book.
2047 * \param file XML file handle.
2049 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
2054 prev_level = file->level;
2055 if (xml_parse_next_tag(file))
2056 longjmp(book->jumper, 1);
2057 if (file->level < prev_level)
2059 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
2060 addrbook_chkparse_attribute(book, file);
2061 addrbook_chkparse_attr_list(book, file);
2067 * Attempt to parse person from file.
2068 * \param book Address book.
2069 * \param file XML file handle.
2071 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
2075 attr = xml_get_current_tag_attr(file);
2076 /* addrbook_show_attribs( attr ); */
2077 if (xml_parse_next_tag(file)) /* Consume closing tag */
2078 longjmp(book->jumper, 1);
2080 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
2081 addrbook_chkparse_addr_list(book, file);
2083 if (xml_parse_next_tag(file)) /* Consume closing tag */
2084 longjmp(book->jumper, 1);
2086 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
2087 addrbook_chkparse_attr_list(book, file);
2091 * Attempt to parse list of members from file.
2092 * \param book Address book.
2093 * \param file XML file handle.
2095 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2101 prev_level = file->level;
2102 if (xml_parse_next_tag(file))
2103 longjmp(book->jumper, 1);
2105 if (file->level < prev_level)
2108 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2109 attr = xml_get_current_tag_attr(file);
2110 /* addrbook_show_attribs( attr ); */
2111 addrbook_chkparse_member_list(book, file);
2114 attr = xml_get_current_tag_attr(file);
2115 /* addrbook_show_attribs( attr ); */
2121 * Attempt to parse group from file.
2122 * \param book Address book.
2123 * \param file XML file handle.
2125 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2129 attr = xml_get_current_tag_attr(file);
2130 /* addrbook_show_attribs( attr ); */
2131 if (xml_parse_next_tag(file)) /* Consume closing tag */
2132 longjmp(book->jumper, 1);
2134 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2135 addrbook_chkparse_member_list(book, file);
2139 * Attempt to parse list of folders from file.
2140 * \param book Address book.
2141 * \param file XML file handle.
2143 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2149 prev_level = file->level;
2150 if (xml_parse_next_tag(file))
2151 longjmp(book->jumper, 1);
2153 if (file->level < prev_level)
2156 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2157 attr = xml_get_current_tag_attr(file);
2158 /* addrbook_show_attribs( attr ); */
2159 addrbook_chkparse_folder_list(book, file);
2162 attr = xml_get_current_tag_attr(file);
2163 /* addrbook_show_attribs( attr ); */
2169 * Attempt to parse a folder from file.
2170 * \param book Address book.
2171 * \param file XML file handle.
2173 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2177 attr = xml_get_current_tag_attr(file);
2178 /* addrbook_show_attribs( attr ); */
2179 if (xml_parse_next_tag(file)) /* Consume closing tag */
2180 longjmp(book->jumper, 1);
2182 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2183 addrbook_chkparse_folder_list(book, file);
2187 * Attempt to parse (DOM) tree from file.
2188 * \param book Address book.
2189 * \param file XML file handle.
2191 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2196 if (xml_get_dtd(file))
2199 if (xml_parse_next_tag(file))
2202 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2205 attr = xml_get_current_tag_attr(file);
2206 /* addrbook_show_attribs( attr ); */
2213 if (xml_parse_next_tag(file))
2214 longjmp(book->jumper, 1);
2216 /* Get next tag (person, group or folder) */
2217 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2218 addrbook_chkparse_person( book, file );
2219 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2220 addrbook_chkparse_group(book, file);
2221 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2222 addrbook_chkparse_folder(book, file);
2228 * Test address book file by parsing contents.
2229 * \param book Address book.
2230 * \param fileName Filename of XML file.
2231 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2233 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2235 XMLFile *file = NULL;
2236 gchar *fileSpec = NULL;
2238 g_return_val_if_fail(book != NULL, -1);
2240 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2241 book->retVal = MGU_OPEN_FILE;
2242 file = xml_open_file(fileSpec);
2245 book->retVal = MGU_BAD_FORMAT;
2246 if (setjmp(book->jumper)) {
2247 /* printf( "Caught Ya!!!\n" ); */
2248 xml_close_file(file);
2249 return book->retVal;
2251 if (addrbook_chkread_tree(book, file))
2252 book->retVal = MGU_SUCCESS;
2254 xml_close_file( file );
2256 return book->retVal;
2260 * Return link list of all persons in address book. Note that the list
2261 * contains references to items. Do <b>*NOT*</b> attempt to use the
2262 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2264 * \param book Address book.
2265 * \return List of persons, or NULL if none.
2267 GList *addrbook_get_all_persons(AddressBookFile *book)
2269 g_return_val_if_fail(book != NULL, NULL);
2270 return addrcache_get_all_persons(book->addressCache);
2274 * Add person and address data to address book.
2275 * \param book Address book.
2276 * \param folder Folder where to add person, or NULL for root folder.
2277 * \param name Common name.
2278 * \param address EMail address.
2279 * \param remarks Remarks.
2280 * \return Person added. Do not <b>*NOT*</b> to use the
2281 * <code>addrbook_free_xxx()</code> functions... this will destroy
2282 * the address book data.
2284 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2285 const gchar *name,const gchar *address,
2286 const gchar *remarks)
2290 g_return_val_if_fail(book != NULL, NULL);
2291 person = addrcache_add_contact(
2292 book->addressCache, folder, name, address, remarks );
2297 * Return file name for next address book file.
2298 * \param book Address book.
2299 * \return File name, or <i>NULL</i> if could not create. This should be
2300 * <code>g_free()</code> when done.
2302 gchar *addrbook_guess_next_file(AddressBookFile *book)
2304 gchar *newFile = NULL;
2305 GList *fileList = NULL;
2307 fileList = addrbook_get_bookfile_list(book);
2309 fileNum = 1 + book->maxValue;
2311 newFile = addrbook_gen_new_file_name(fileNum);
2312 g_list_free(fileList);