2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2006 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);
515 addritem_person_add_attribute(person, uAttr);
518 addritem_free_attribute(uAttr);
525 * Parse list of attributes for person from XML file.
526 * \param book Address book.
527 * \param file XML file handle.
528 * \param person Person.
530 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
537 prev_level = file->level;
538 if (xml_parse_next_tag(file)) {
539 longjmp( book->jumper, 1 );
541 if (file->level < prev_level) return;
542 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
543 attr = xml_get_current_tag_attr(file);
544 addrbook_parse_attribute(file, person);
545 addrbook_parse_attr_list(book, file, person);
551 * Parse person from XML file.
552 * \param book Address book.
553 * \param file XML file handle.
555 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
559 ItemPerson *person = NULL;
561 attr = xml_get_current_tag_attr(file);
563 name = ((XMLAttr *)attr->data)->name;
564 value = ((XMLAttr *)attr->data)->value;
566 person = addritem_create_item_person();
567 if (strcmp(name, AB_ATTAG_UID) == 0)
568 ADDRITEM_ID(person) = g_strdup(value);
569 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
570 person->firstName = g_strdup(value);
571 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
572 person->lastName = g_strdup(value);
573 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
574 person->nickName = g_strdup(value);
575 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
576 ADDRITEM_NAME(person) = g_strdup(value);
577 attr = g_list_next(attr);
579 if (xml_parse_next_tag(file)) { /* Consume closing tag */
580 longjmp(book->jumper, 1);
582 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
583 addrbook_parse_addr_list(book, file, person);
585 addrcache_hash_add_person(book->addressCache, person);
588 if (xml_parse_next_tag(file)) { /* Consume closing tag */
589 longjmp(book->jumper, 1);
591 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
592 addrbook_parse_attr_list(book, file, person);
597 * Parse group member from XML file.
598 * \param book Address book.
599 * \param file XML file handle.
600 * \param group Group.
602 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
608 /* gchar *pid = NULL; */
609 ItemEMail *email = NULL;
611 attr = xml_get_current_tag_attr(file);
613 name = ((XMLAttr *)attr->data)->name;
614 value = ((XMLAttr *)attr->data)->value;
616 if (strcmp(name, AB_ATTAG_PID) == 0)
617 pid = g_strdup(value);
618 else if (strcmp(name, AB_ATTAG_EID) == 0)
619 eid = g_strdup(value);
621 if( strcmp( name, AB_ATTAG_EID ) == 0 )
622 eid = g_strdup( value );
623 attr = g_list_next(attr);
625 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
626 email = addrcache_get_email(book->addressCache, eid);
629 addrcache_group_add_email(book->addressCache, group,
633 addritem_free_item_email(email);
640 * Parse list of group members from XML file.
641 * \param book Address book.
642 * \param file XML file handle.
643 * \param group Group.
645 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
652 prev_level = file->level;
653 if (xml_parse_next_tag(file)) {
654 longjmp(book->jumper, 1);
656 if (file->level < prev_level)
658 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
659 attr = xml_get_current_tag_attr(file);
660 addrbook_parse_member(book, file, group);
661 addrbook_parse_member_list(book, file, group);
664 attr = xml_get_current_tag_attr(file);
670 * Parse group object from XML file.
671 * \param book Address book.
672 * \param file XML file handle.
674 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
678 ItemGroup *group = NULL;
680 attr = xml_get_current_tag_attr(file);
682 name = ((XMLAttr *)attr->data)->name;
683 value = ((XMLAttr *)attr->data)->value;
685 group = addritem_create_item_group();
686 if (strcmp(name, AB_ATTAG_UID) == 0)
687 ADDRITEM_ID(group) = g_strdup(value);
688 else if (strcmp(name, AB_ATTAG_NAME) == 0)
689 ADDRITEM_NAME(group) = g_strdup(value);
690 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
691 group->remarks = g_strdup(value);
692 attr = g_list_next(attr);
694 if (xml_parse_next_tag(file)) { /* Consume closing tag */
695 longjmp(book->jumper, 1);
697 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
699 addrcache_hash_add_group(book->addressCache, group);
701 addrbook_parse_member_list(book, file, group);
706 * Parse folder item from XML file.
707 * \param book Address book.
708 * \param file XML file handle.
709 * \param folder Folder.
711 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
718 attr = xml_get_current_tag_attr(file);
720 name = ((XMLAttr *)attr->data)->name;
721 value = ((XMLAttr *)attr->data)->value;
722 if (strcmp(name, AB_ATTAG_UID) == 0) {
723 uid = g_strdup(value);
725 attr = g_list_next(attr);
729 folder->listItems = g_list_append(folder->listItems, uid);
735 * Parse list of folder items from XML file.
736 * \param book Address book.
737 * \param file XML file handle.
738 * \param folder Folder.
740 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
747 prev_level = file->level;
748 if (xml_parse_next_tag(file)) {
749 longjmp(book->jumper, 1);
751 if (file->level < prev_level)
753 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
754 attr = xml_get_current_tag_attr(file);
755 addrbook_parse_folder_item(book, file, folder);
756 addrbook_parse_folder_list(book, file, folder);
759 attr = xml_get_current_tag_attr(file);
765 * Parse folder from XML file.
766 * \param book Address book.
767 * \param file XML file handle.
769 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
773 ItemFolder *folder = NULL;
775 attr = xml_get_current_tag_attr(file);
777 name = ((XMLAttr *)attr->data)->name;
778 value = ((XMLAttr *)attr->data)->value;
780 folder = addritem_create_item_folder();
781 if (strcmp(name, AB_ATTAG_UID) == 0)
782 ADDRITEM_ID(folder) = g_strdup(value);
783 else if (strcmp(name, AB_ATTAG_NAME) == 0)
784 ADDRITEM_NAME(folder) = g_strdup(value);
785 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
786 folder->remarks = g_strdup(value);
787 attr = g_list_next(attr);
789 if (xml_parse_next_tag(file)) { /* Consume closing tag */
790 longjmp(book->jumper, 1);
792 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
794 if (addrcache_hash_add_folder(book->addressCache,
796 book->tempList = g_list_append(book->tempList,
798 /* We will resolve folder later */
799 ADDRITEM_PARENT(folder) = NULL;
802 addrbook_parse_folder_list(book, file, folder);
807 * Read address book (DOM) tree from file.
808 * \param book Address book.
809 * \param file XML file handle.
810 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
813 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
819 book->retVal = MGU_BAD_FORMAT;
820 if (xml_get_dtd(file))
822 if (xml_parse_next_tag(file))
823 longjmp(book->jumper, 1);
824 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
827 attr = xml_get_current_tag_attr(file);
829 name = ((XMLAttr *)attr->data)->name;
830 value = ((XMLAttr *)attr->data)->value;
831 if (strcmp( name, AB_ATTAG_NAME) == 0)
832 addrbook_set_name( book, value );
833 attr = g_list_next( attr );
840 /* Get next item tag (person, group or folder) */
841 if (xml_parse_next_tag(file))
842 longjmp( book->jumper, 1 );
844 if (xml_compare_tag(file, AB_ELTAG_PERSON))
845 addrbook_parse_person(book, file);
846 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
847 addrbook_parse_group(book, file);
848 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
849 addrbook_parse_folder(book, file);
851 if (retVal) book->retVal = MGU_SUCCESS;
856 * Resolve folder items callback function.
857 * \param key Table key.
858 * \param value Reference to object contained in folder.
859 * \param data Reference to address book.
861 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
863 AddressBookFile *book = data;
864 AddrItemObject *obj = (AddrItemObject *) value;
865 ItemFolder *rootFolder = book->addressCache->rootFolder;
866 if (obj->parent == NULL) {
867 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
868 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
870 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
872 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
873 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
875 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
881 * Resolve folder items. Lists of UID's are replaced with pointers to
883 * \param book Address book.
885 static void addrbook_resolve_folder_items(AddressBookFile *book)
887 GList *nodeFolder = NULL;
888 GList *listRemove = NULL;
890 ItemFolder *rootFolder = book->addressCache->rootFolder;
891 nodeFolder = book->tempList;
894 ItemFolder *folder = nodeFolder->data;
896 node = folder->listItems;
898 gchar *uid = node->data;
899 AddrItemObject *aio = addrcache_get_object(book->addressCache,
902 if (aio->type == ITEMTYPE_FOLDER) {
903 ItemFolder *item = (ItemFolder *) aio;
904 folder->listFolder = g_list_append(folder->listFolder, item);
905 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
906 addrcache_hash_add_folder(book->addressCache, folder);
908 else if (aio->type == ITEMTYPE_PERSON) {
909 ItemPerson *item = (ItemPerson *) aio;
910 folder->listPerson = g_list_append(folder->listPerson, item);
911 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
913 else if (aio->type == ITEMTYPE_GROUP) {
914 ItemGroup *item = (ItemGroup *) aio;
915 folder->listGroup = g_list_append(folder->listGroup, item);
916 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
918 /* Replace data with pointer to item */
922 else { /* Not found, append to remove list. */
923 listRemove = g_list_append(listRemove, uid);
925 node = g_list_next(node);
927 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
929 /* Process remove list */
932 gchar *uid = node->data;
933 folder->listItems = g_list_remove(folder->listItems,
936 node = g_list_next(node);
938 g_list_free(listRemove);
939 nodeFolder = g_list_next(nodeFolder);
941 /* Remove folders with parents. */
943 node = rootFolder->listFolder;
945 ItemFolder *folder = (ItemFolder *) node->data;
946 if (ADDRITEM_PARENT(folder))
947 /* Remove folders with parents */
948 listRemove = g_list_append(listRemove, folder);
949 else /* Add to root folder */
950 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
952 node = g_list_next( node );
954 /* Process remove list */
957 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
959 node = g_list_next(node);
961 g_list_free(listRemove);
963 /* Move all unparented persons and groups into root folder */
964 g_hash_table_foreach(book->addressCache->itemHash,
965 addrbook_res_items_vis, book);
967 /* Free up some more */
968 nodeFolder = book->tempList;
970 ItemFolder *folder = nodeFolder->data;
971 g_list_free(folder->listItems);
972 folder->listItems = NULL;
973 nodeFolder = g_list_next(nodeFolder);
975 g_list_free(book->tempList);
976 book->tempList = NULL;
981 * \param book Address book.
982 * \return Status code.
984 gint addrbook_read_data(AddressBookFile *book)
986 XMLFile *file = NULL;
987 gchar *fileSpec = NULL;
989 g_return_val_if_fail(book != NULL, -1);
992 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
993 addrcache_get_name( book->addressCache ) );
996 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
997 book->fileName, NULL);
998 book->retVal = MGU_OPEN_FILE;
999 addrcache_clear(book->addressCache);
1000 book->addressCache->modified = FALSE;
1001 book->addressCache->accessFlag = FALSE;
1002 file = xml_open_file(fileSpec);
1005 book->tempList = NULL;
1006 /* Trap for parsing errors. */
1007 if (setjmp( book->jumper)) {
1008 xml_close_file(file);
1009 return book->retVal;
1011 addrbook_read_tree(book, file);
1012 xml_close_file(file);
1013 /* Resolve folder items */
1014 addrbook_resolve_folder_items(book);
1015 book->tempList = NULL;
1016 book->addressCache->modified = FALSE;
1017 book->addressCache->dataRead = TRUE;
1018 addrcache_set_dirty(book->addressCache, FALSE);
1020 return book->retVal;
1024 * Write start element to file.
1025 * \param fp File handle.
1026 * \param lvl Indent level.
1027 * \param name Element name.
1029 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
1032 for (i = 0; i < lvl; i++)
1039 * Write end element to file.
1040 * \param fp File handle.
1041 * \param lvl Indent level.
1042 * \param name Element name.
1044 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
1047 for(i = 0; i < lvl; i++)
1055 * Write attribute name/value pair to file.
1056 * \param fp File handle.
1057 * \param name Attribute name.
1058 * \param value Attribute value.
1060 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
1065 xml_file_put_escape_str(fp, value);
1070 * Write person and associated addresses and attributes to file.
1071 * file hash table visitor function.
1072 * \param key Table key.
1073 * \param value Reference to person.
1074 * \param data File pointer.
1076 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1079 AddrItemObject *obj = (AddrItemObject *) value;
1080 FILE *fp = (FILE *) data;
1085 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1086 ItemPerson *person = (ItemPerson *) value;
1088 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
1089 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
1090 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
1091 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
1092 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
1093 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
1096 /* Output email addresses */
1097 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
1099 node = person->listEMail;
1101 ItemEMail *email = node->data;
1102 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
1103 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
1104 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
1105 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
1106 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
1108 node = g_list_next(node);
1110 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
1112 /* Output user attributes */
1113 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1115 node = person->listAttrib;
1117 UserAttribute *attrib = node->data;
1118 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
1119 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
1120 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
1122 xml_file_put_escape_str(fp, attrib->value);
1123 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
1124 node = g_list_next(node);
1126 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1127 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
1133 * Write group and associated references to addresses to file.
1134 * file hash table visitor function.
1135 * \param key Table key.
1136 * \param value Reference to group.
1137 * \param data File pointer.
1139 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1142 AddrItemObject *obj = (AddrItemObject *) value;
1143 FILE *fp = (FILE *) data;
1148 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1149 ItemGroup *group = (ItemGroup *) value;
1151 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
1152 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
1153 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
1154 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
1157 /* Output email address links */
1158 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
1160 node = group->listEMail;
1162 ItemEMail *email = node->data;
1163 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1164 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1165 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1166 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1168 node = g_list_next(node);
1170 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1171 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1177 * Write folder and associated references to addresses to file.
1178 * file hash table visitor function.
1179 * \param key Table key.
1180 * \param value Reference to folder.
1181 * \param data File pointer.
1183 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1186 AddrItemObject *obj = (AddrItemObject *) value;
1187 FILE *fp = (FILE *) data;
1192 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1193 ItemFolder *folder = (ItemFolder *) value;
1195 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1196 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1197 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1198 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1200 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1203 /* Output persons */
1204 node = folder->listPerson;
1206 ItemPerson *item = node->data;
1207 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1208 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1209 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1211 node = g_list_next(node);
1215 node = folder->listGroup;
1217 ItemGroup *item = node->data;
1218 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1219 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1220 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1222 node = g_list_next(node);
1225 /* Output folders */
1226 node = folder->listFolder;
1228 ItemFolder *item = node->data;
1229 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1230 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1231 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1233 node = g_list_next(node);
1235 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1236 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1242 * Output address book data to specified file.
1243 * \param book Address book.
1244 * \param newFile Filename of new file (in book's filepath).
1245 * \return Status code.
1247 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1251 #ifndef DEV_STANDALONE
1255 g_return_val_if_fail(book != NULL, -1);
1256 g_return_val_if_fail(newFile != NULL, -1);
1258 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1260 book->retVal = MGU_OPEN_FILE;
1261 #ifdef DEV_STANDALONE
1262 fp = g_fopen(fileSpec, "wb");
1265 fputs("<?xml version=\"1.0\" ?>\n", fp);
1267 pfile = prefs_write_open(fileSpec);
1271 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
1273 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1274 addrbook_write_attr(fp, AB_ATTAG_NAME,
1275 addrcache_get_name(book->addressCache));
1278 /* Output all persons */
1279 g_hash_table_foreach(book->addressCache->itemHash,
1280 addrbook_write_item_person_vis, fp);
1282 /* Output all groups */
1283 g_hash_table_foreach(book->addressCache->itemHash,
1284 addrbook_write_item_group_vis, fp);
1286 /* Output all folders */
1287 g_hash_table_foreach(book->addressCache->itemHash,
1288 addrbook_write_item_folder_vis, fp);
1290 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1291 book->retVal = MGU_SUCCESS;
1292 #ifdef DEV_STANDALONE
1295 if (prefs_file_close( pfile ) < 0)
1296 book->retVal = MGU_ERROR_WRITE;
1301 return book->retVal;
1305 * Output address book data to original file.
1306 * \param book Address book.
1307 * \return Status code.
1309 gint addrbook_save_data(AddressBookFile *book)
1311 g_return_val_if_fail(book != NULL, -1);
1313 book->retVal = MGU_NO_FILE;
1314 if (book->fileName == NULL || *book->fileName == '\0')
1315 return book->retVal;
1316 if (book->path == NULL || *book->path == '\0')
1317 return book->retVal;
1319 addrbook_write_to(book, book->fileName);
1320 if (book->retVal == MGU_SUCCESS)
1321 addrcache_set_dirty(book->addressCache, FALSE);
1322 return book->retVal;
1326 * **********************************************************************
1327 * Address book edit interface functions.
1328 * **********************************************************************
1332 * Move email item within list of person's email items.
1333 * \param book Address book.
1334 * \param person Person.
1335 * \param itemMove EMail item to move.
1336 * \param itemTarget EMail item to move before.
1337 * \return Moved item.
1339 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1340 ItemEMail *itemMove, ItemEMail *itemTarget)
1342 ItemEMail *email = NULL;
1344 g_return_val_if_fail(book != NULL, NULL);
1346 email = addritem_move_email_before(person, itemMove, itemTarget);
1348 addrcache_set_dirty(book->addressCache, TRUE);
1353 * Move email item within list of person's email items.
1354 * \param book Address book.
1355 * \param person Person.
1356 * \param itemMove EMail item to move.
1357 * \param itemTarget EMail item after which to move.
1358 * \return Moved item.
1360 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1361 ItemEMail *itemMove, ItemEMail *itemTarget)
1363 ItemEMail *email = NULL;
1365 g_return_val_if_fail(book != NULL, NULL);
1367 email = addritem_move_email_after(person, itemMove, itemTarget);
1369 addrcache_set_dirty(book->addressCache, TRUE);
1374 * Hash table callback function for simple deletion of hashtable entries.
1375 * \param key Table key (will be freed).
1376 * \param value Value stored in table.
1377 * \param data User data.
1378 * \return <i>TRUE</i> to indicate that entry freed.
1380 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1390 * Update address book email list for specified person. Note: The existing
1391 * email addresses are replaced with the new addresses. Any references to
1392 * old addresses in the groups are re-linked to the new addresses. All old
1393 * addresses linked to the person are removed.
1394 * \param book Address book.
1395 * \param person Person to update.
1396 * \param listEMail List of new email addresses.
1398 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1405 g_return_if_fail(book != NULL);
1406 g_return_if_fail(person != NULL);
1408 /* Get groups where person's existing email addresses are listed */
1409 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1411 GHashTable *hashEMail;
1412 GHashTable *hashEMailAlias;
1415 /* Load hash table with new address entries */
1416 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1417 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1420 ItemEMail *email = node->data;
1421 gchar *addr = g_strdup(email->address);
1422 gchar *alias = email->obj.name ;
1424 if (!g_hash_table_lookup(hashEMail, addr)) {
1425 g_hash_table_insert(hashEMail, addr, email);
1427 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1429 g_hash_table_insert(hashEMailAlias, alias, email);
1431 node = g_list_next(node);
1434 /* Re-parent new addresses to existing groups, where email address match. */
1435 nodeGrp = listGroup;
1437 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1438 GList *groupEMail = group->listEMail;
1440 GList *listRemove = NULL;
1442 /* Process each email item linked to group */
1443 nodeGrpEM = groupEMail;
1445 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1447 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1448 /* Found an email address for this person */
1449 ItemEMail *emailNew = NULL;
1450 gchar *addr = g_strdup(emailGrp->address);
1451 gchar *alias = emailGrp->obj.name;
1453 emailNew = (ItemEMail *)
1454 g_hash_table_lookup(hashEMail, addr);
1456 /* If no match by e-mail, try to match by e-mail alias */
1457 if (!emailNew && *alias != '\0') {
1458 emailNew = (ItemEMail *)
1459 g_hash_table_lookup(hashEMailAlias, alias);
1463 /* Point to this entry */
1464 nodeGrpEM->data = emailNew;
1465 else if (g_hash_table_size(hashEMail)==1)
1466 /* If the person has just one e-mail address, then
1467 change e-mail address in group list */
1468 nodeGrpEM->data = listEMail->data;
1470 /* Mark for removal */
1471 listRemove = g_list_append(listRemove, emailGrp);
1473 /* Move on to next email link */
1474 nodeGrpEM = g_list_next(nodeGrpEM);
1477 /* Process all removed links in current group */
1478 nodeGrpEM = listRemove;
1480 ItemEMail *emailGrp = nodeGrpEM->data;
1481 groupEMail = g_list_remove(groupEMail, emailGrp);
1482 nodeGrpEM = g_list_next(nodeGrpEM);
1485 g_list_free(listRemove);
1487 /* Move on to next group */
1488 nodeGrp = g_list_next(nodeGrp);
1491 /* Clear hash table */
1492 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1493 addrbook_free_simple_hash_vis, NULL);
1494 g_hash_table_destroy(hashEMail);
1496 g_hash_table_destroy(hashEMailAlias);
1497 hashEMailAlias = NULL;
1498 g_list_free(listGroup);
1501 /* Remove old addresses from person and cache */
1503 node = person->listEMail;
1505 ItemEMail *email = node->data;
1507 if (addrcache_person_remove_email(book->addressCache, person, email))
1508 addrcache_remove_email(book->addressCache, email);
1510 listDelete = g_list_append(listDelete, email);
1511 node = person->listEMail;
1513 /* Add new address entries */
1516 ItemEMail *email = node->data;
1518 if (ADDRITEM_ID(email) == NULL)
1519 /* Allocate an ID for new address */
1520 addrcache_id_email(book->addressCache, email);
1522 addrcache_person_add_email( book->addressCache, person, email );
1523 node = g_list_next( node );
1526 addrcache_set_dirty(book->addressCache, TRUE);
1528 /* Free up memory */
1529 g_list_free(listEMail);
1534 ItemEMail *email = node->data;
1536 addritem_free_item_email(email);
1537 node = g_list_next(node);
1539 g_list_free(listDelete);
1545 * Create person object and add person with specified address data to address
1546 * book. Note: A new person is created with specified list of email addresses.
1547 * All objects inserted into address book.
1549 * \param book Address book.
1550 * \param folder Parent folder where to add person, or <i>NULL</i> for
1552 * \param listEMail List of new email addresses to associate with person.
1553 * \return Person object created.
1555 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1559 ItemFolder *f = folder;
1562 g_return_val_if_fail(book != NULL, NULL);
1565 f = book->addressCache->rootFolder;
1566 person = addritem_create_item_person();
1567 addrcache_id_person(book->addressCache, person);
1568 addrcache_folder_add_person(book->addressCache, f, person);
1572 ItemEMail *email = node->data;
1573 if (ADDRITEM_ID(email) == NULL)
1574 addrcache_id_email(book->addressCache, email);
1576 addrcache_person_add_email(book->addressCache, person, email);
1577 node = g_list_next(node);
1583 * Build available email list visitor function.
1584 * \param key Table key.
1585 * \param value Value stored in table.
1586 * \param data Reference to address book.
1588 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1591 AddrItemObject *obj = (AddrItemObject *) value;
1593 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1594 AddressBookFile *book = data;
1595 ItemPerson *person = (ItemPerson *) obj;
1596 GList *node = person->listEMail;
1598 ItemEMail *email = node->data;
1599 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1601 if (!g_hash_table_lookup(book->tempHash,
1602 ADDRITEM_ID(email)))
1603 book->tempList = g_list_append(book->tempList, email);
1605 node = g_list_next(node);
1611 * Return link list of available email items that have not already been linked
1612 * to groups. Note that the list contains references to items and should be
1613 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1614 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1617 * \param book Address book.
1618 * \param group Group to process.
1619 * \return List of items, or <i>NULL</i> if none.
1621 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1626 g_return_val_if_fail(book != NULL, NULL);
1628 /* Load hash table with group email entries */
1629 table = g_hash_table_new(g_str_hash, g_str_equal);
1631 list = group->listEMail;
1633 ItemEMail *email = list->data;
1634 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1635 list = g_list_next(list);
1639 /* Build list of available email addresses which exclude those already in groups */
1640 book->tempList = NULL;
1641 book->tempHash = table;
1642 g_hash_table_foreach(book->addressCache->itemHash,
1643 addrbook_build_avail_email_vis, book);
1644 list = book->tempList;
1645 book->tempList = NULL;
1646 book->tempHash = NULL;
1648 /* Clear hash table */
1649 g_hash_table_destroy(table);
1656 * Update address book email list for specified group. Note: The existing email
1657 * addresses are replaced with the new addresses. Any references to old addresses
1658 * in the groups are re-linked to the new addresses. All old addresses linked to
1659 * the person are removed.
1661 * \param book Address book.
1662 * \param group Group to process.
1663 * \param listEMail List of email items. This should <b>*NOT*</b> be
1664 * <code>g_free()</code> when done.
1666 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1671 g_return_if_fail(book != NULL);
1672 g_return_if_fail(group != NULL);
1674 addrcache_set_dirty(book->addressCache, TRUE);
1676 /* Remember old list */
1677 oldData = group->listEMail;
1678 group->listEMail = listEMail;
1679 mgu_clear_list(oldData);
1684 * Create group object and add with specifed list of email addresses to
1685 * address book. Note: The existing email addresses are replaced with the new
1686 * addresses. Any references to old addresses in the groups are re-linked to
1687 * the new addresses. All old addresses linked to the person are removed.
1689 * \param book Address book.
1690 * \param folder Parent folder where to add group, or <i>NULL</i> for
1692 * \param listEMail List of email items. This should <b>*NOT*</b> be
1693 * <code>g_free()</code> when done.
1694 * \return Group object created.
1696 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1699 ItemGroup *group = NULL;
1700 ItemFolder *f = folder;
1702 g_return_val_if_fail(book != NULL, NULL);
1705 f = book->addressCache->rootFolder;
1706 group = addritem_create_item_group();
1707 addrcache_id_group(book->addressCache, group);
1708 addrcache_folder_add_group(book->addressCache, f, group);
1709 group->listEMail = listEMail;
1714 * Create a new folder and add to address book.
1715 * \param book Address book.
1716 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1718 * \return Folder that was created. This should <b>*NOT*</b> be
1719 * <code>g_free()</code> when done.
1721 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1723 g_return_val_if_fail(book != NULL, NULL);
1724 return addrcache_add_new_folder( book->addressCache, parent );
1728 * Update address book attribute list for specified person. Note: The existing
1729 * attributes are replaced with the new addresses. All old attributes linked
1730 * to the person are removed.
1732 * \param book Address book.
1733 * \param person Person to receive attributes.
1734 * \param listAttrib New list of attributes.
1736 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1742 g_return_if_fail(book != NULL);
1743 g_return_if_fail(person != NULL);
1745 /* Remember old list */
1746 oldData = person->listAttrib;
1748 /* Attach new address list to person. */
1751 UserAttribute *attrib = node->data;
1752 if (attrib->uid == NULL) {
1753 /* Allocate an ID */
1754 addrcache_id_attribute(book->addressCache, attrib);
1756 node = g_list_next(node);
1758 person->listAttrib = listAttrib;
1759 addrcache_set_dirty(book->addressCache, TRUE);
1761 /* Free up old data */
1762 addritem_free_list_attribute(oldData);
1767 * Add attribute data for specified person to address book. Note: Only
1768 * attributes are inserted into address book.
1769 * \param book Address book.
1770 * \param person Person to receive attributes.
1771 * \param listAttrib List of attributes.
1773 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1776 g_return_if_fail( book != NULL );
1777 g_return_if_fail( person != NULL );
1781 UserAttribute *attrib = node->data;
1782 if( attrib->uid == NULL ) {
1783 addrcache_id_attribute( book->addressCache, attrib );
1785 addritem_person_add_attribute( person, attrib );
1786 node = g_list_next( node );
1788 addrcache_set_dirty( book->addressCache, TRUE );
1792 * Return reference to address book file for specified object by traversing up
1793 * address book heirarchy.
1795 * \param aio Book item object.
1796 * \return Address book, or <i>NULL</i> if not found.
1798 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1800 AddressBookFile *book = NULL;
1803 ItemFolder *parent = NULL;
1804 ItemFolder *root = NULL;
1805 if (aio->type == ITEMTYPE_EMAIL) {
1806 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1808 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1811 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1814 root = addrcache_find_root_folder(parent);
1816 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1822 * Remove folder from address book. Children are re-parented to the parent
1824 * \param book Address book.
1825 * \param folder Folder to remove.
1826 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1829 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1833 g_return_val_if_fail(book != NULL, NULL);
1835 f = addrcache_remove_folder(book->addressCache, folder);
1840 * Remove folder from address book. Children are deleted.
1841 * \param book Address book.
1842 * \param folder Folder to remove.
1843 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1846 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1851 g_return_val_if_fail(book != NULL, NULL);
1853 f = addrcache_remove_folder_delete(book->addressCache, folder);
1857 #define WORK_BUFLEN 1024
1858 #define ADDRBOOK_DIGITS "0123456789"
1861 * Return list of existing address book files.
1862 * \param book Address book.
1863 * \return List of files (as strings).
1865 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1868 const gchar *dir_name;
1869 struct stat statbuf;
1870 gchar buf[WORK_BUFLEN];
1871 gchar numbuf[WORK_BUFLEN];
1872 gint len, lenpre, lensuf, lennum;
1873 long int val, maxval;
1874 GList *fileList = NULL;
1876 g_return_val_if_fail(book != NULL, NULL);
1878 if (book->path == NULL || *book->path == '\0') {
1879 book->retVal = MGU_NO_PATH;
1883 strcpy(buf, book->path);
1886 if (buf[len-1] != G_DIR_SEPARATOR) {
1887 buf[len] = G_DIR_SEPARATOR;
1892 adbookdir = g_strdup(buf);
1893 strcat(buf, ADDRBOOK_PREFIX);
1895 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1896 book->retVal = MGU_OPEN_DIRECTORY;
1901 lenpre = strlen(ADDRBOOK_PREFIX);
1902 lensuf = strlen(ADDRBOOK_SUFFIX);
1903 lennum = FILE_NUMDIGITS + lenpre;
1906 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1907 gchar *endptr = NULL;
1911 strcpy(buf, adbookdir);
1912 strcat( buf, dir_name );
1913 stat(buf, &statbuf);
1914 if (S_ISREG(statbuf.st_mode)) {
1917 ADDRBOOK_PREFIX, lenpre) == 0)
1920 (dir_name) + lennum,
1921 ADDRBOOK_SUFFIX, lensuf) == 0)
1924 (dir_name) + lenpre,
1926 numbuf[FILE_NUMDIGITS] = '\0';
1928 for(i = 0; i < FILE_NUMDIGITS; i++) {
1929 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1936 val = strtol(numbuf, &endptr, 10);
1937 if (endptr && val > -1) {
1938 if (val > maxval) maxval = val;
1939 fileList = g_list_append(
1941 g_strdup(dir_name));
1951 book->maxValue = maxval;
1952 book->retVal = MGU_SUCCESS;
1957 * Return file name for specified file number.
1958 * \param fileNum File number.
1959 * \return File name, or <i>NULL</i> if file number too large. Should be
1960 * <code>g_free()</code> when done.
1962 gchar *addrbook_gen_new_file_name(gint fileNum) {
1964 gchar buf[WORK_BUFLEN];
1970 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1973 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1974 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1975 return g_strdup(buf);
1979 * **********************************************************************
1980 * Address book test functions...
1981 * **********************************************************************
1985 * Attempt to parse list of email address from file.
1986 * \param book Address book.
1987 * \param file XML file handle.
1989 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1994 prev_level = file->level;
1995 if (xml_parse_next_tag(file))
1996 longjmp(book->jumper, 1);
1997 if (file->level < prev_level)
1999 attr = xml_get_current_tag_attr(file);
2000 /* addrbook_show_attribs( attr ); */
2001 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
2002 addrbook_chkparse_addr_list(book, file);
2007 * Attempt to parse attributes for person address from file.
2008 * \param book Address book.
2009 * \param file XML file handle.
2011 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
2016 attr = xml_get_current_tag_attr(file);
2017 /* addrbook_show_attribs( attr ); */
2018 element = xml_get_element(file);
2019 /* printf( "\t\tattrib value : %s\n", element ); */
2023 * Attempt to parse list of attributes for person address from file.
2024 * \param book Address book.
2025 * \param file XML file handle.
2027 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
2032 prev_level = file->level;
2033 if (xml_parse_next_tag(file))
2034 longjmp(book->jumper, 1);
2035 if (file->level < prev_level)
2037 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
2038 addrbook_chkparse_attribute(book, file);
2039 addrbook_chkparse_attr_list(book, file);
2045 * Attempt to parse person from file.
2046 * \param book Address book.
2047 * \param file XML file handle.
2049 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
2053 attr = xml_get_current_tag_attr(file);
2054 /* addrbook_show_attribs( attr ); */
2055 if (xml_parse_next_tag(file)) /* Consume closing tag */
2056 longjmp(book->jumper, 1);
2058 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
2059 addrbook_chkparse_addr_list(book, file);
2061 if (xml_parse_next_tag(file)) /* Consume closing tag */
2062 longjmp(book->jumper, 1);
2064 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
2065 addrbook_chkparse_attr_list(book, file);
2069 * Attempt to parse list of members from file.
2070 * \param book Address book.
2071 * \param file XML file handle.
2073 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2079 prev_level = file->level;
2080 if (xml_parse_next_tag(file))
2081 longjmp(book->jumper, 1);
2083 if (file->level < prev_level)
2086 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2087 attr = xml_get_current_tag_attr(file);
2088 /* addrbook_show_attribs( attr ); */
2089 addrbook_chkparse_member_list(book, file);
2092 attr = xml_get_current_tag_attr(file);
2093 /* addrbook_show_attribs( attr ); */
2099 * Attempt to parse group from file.
2100 * \param book Address book.
2101 * \param file XML file handle.
2103 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2107 attr = xml_get_current_tag_attr(file);
2108 /* addrbook_show_attribs( attr ); */
2109 if (xml_parse_next_tag(file)) /* Consume closing tag */
2110 longjmp(book->jumper, 1);
2112 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2113 addrbook_chkparse_member_list(book, file);
2117 * Attempt to parse list of folders from file.
2118 * \param book Address book.
2119 * \param file XML file handle.
2121 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2127 prev_level = file->level;
2128 if (xml_parse_next_tag(file))
2129 longjmp(book->jumper, 1);
2131 if (file->level < prev_level)
2134 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2135 attr = xml_get_current_tag_attr(file);
2136 /* addrbook_show_attribs( attr ); */
2137 addrbook_chkparse_folder_list(book, file);
2140 attr = xml_get_current_tag_attr(file);
2141 /* addrbook_show_attribs( attr ); */
2147 * Attempt to parse a folder from file.
2148 * \param book Address book.
2149 * \param file XML file handle.
2151 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2155 attr = xml_get_current_tag_attr(file);
2156 /* addrbook_show_attribs( attr ); */
2157 if (xml_parse_next_tag(file)) /* Consume closing tag */
2158 longjmp(book->jumper, 1);
2160 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2161 addrbook_chkparse_folder_list(book, file);
2165 * Attempt to parse (DOM) tree from file.
2166 * \param book Address book.
2167 * \param file XML file handle.
2169 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2174 if (xml_get_dtd(file))
2177 if (xml_parse_next_tag(file))
2180 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2183 attr = xml_get_current_tag_attr(file);
2184 /* addrbook_show_attribs( attr ); */
2191 if (xml_parse_next_tag(file))
2192 longjmp(book->jumper, 1);
2194 /* Get next tag (person, group or folder) */
2195 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2196 addrbook_chkparse_person( book, file );
2197 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2198 addrbook_chkparse_group(book, file);
2199 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2200 addrbook_chkparse_folder(book, file);
2206 * Test address book file by parsing contents.
2207 * \param book Address book.
2208 * \param fileName Filename of XML file.
2209 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2211 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2213 XMLFile *file = NULL;
2214 gchar *fileSpec = NULL;
2216 g_return_val_if_fail(book != NULL, -1);
2218 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2219 book->retVal = MGU_OPEN_FILE;
2220 file = xml_open_file(fileSpec);
2223 book->retVal = MGU_BAD_FORMAT;
2224 if (setjmp(book->jumper)) {
2225 /* printf( "Caught Ya!!!\n" ); */
2226 xml_close_file(file);
2227 return book->retVal;
2229 if (addrbook_chkread_tree(book, file))
2230 book->retVal = MGU_SUCCESS;
2232 xml_close_file( file );
2234 return book->retVal;
2238 * Return link list of all persons in address book. Note that the list
2239 * contains references to items. Do <b>*NOT*</b> attempt to use the
2240 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2242 * \param book Address book.
2243 * \return List of persons, or NULL if none.
2245 GList *addrbook_get_all_persons(AddressBookFile *book)
2247 g_return_val_if_fail(book != NULL, NULL);
2248 return addrcache_get_all_persons(book->addressCache);
2252 * Add person and address data to address book.
2253 * \param book Address book.
2254 * \param folder Folder where to add person, or NULL for root folder.
2255 * \param name Common name.
2256 * \param address EMail address.
2257 * \param remarks Remarks.
2258 * \return Person added. Do not <b>*NOT*</b> to use the
2259 * <code>addrbook_free_xxx()</code> functions... this will destroy
2260 * the address book data.
2262 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2263 const gchar *name,const gchar *address,
2264 const gchar *remarks)
2268 g_return_val_if_fail(book != NULL, NULL);
2269 person = addrcache_add_contact(
2270 book->addressCache, folder, name, address, remarks );
2275 * Return file name for next address book file.
2276 * \param book Address book.
2277 * \return File name, or <i>NULL</i> if could not create. This should be
2278 * <code>g_free()</code> when done.
2280 gchar *addrbook_guess_next_file(AddressBookFile *book)
2282 gchar *newFile = NULL;
2283 GList *fileList = NULL;
2285 fileList = addrbook_get_bookfile_list(book);
2287 fileNum = 1 + book->maxValue;
2289 newFile = addrbook_gen_new_file_name(fileNum);
2290 g_list_free(fileList);