2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2007 Match Grun and the Claws Mail 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;
615 if( strcmp( name, AB_ATTAG_EID ) == 0 )
616 eid = g_strdup( value );
617 attr = g_list_next(attr);
619 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
620 email = addrcache_get_email(book->addressCache, eid);
624 addrcache_group_add_email(book->addressCache, group,
628 addritem_free_item_email(email);
635 * Parse list of group members from XML file.
636 * \param book Address book.
637 * \param file XML file handle.
638 * \param group Group.
640 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
647 prev_level = file->level;
648 if (xml_parse_next_tag(file)) {
649 longjmp(book->jumper, 1);
651 if (file->level < prev_level)
653 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
654 attr = xml_get_current_tag_attr(file);
655 addrbook_parse_member(book, file, group);
656 addrbook_parse_member_list(book, file, group);
659 attr = xml_get_current_tag_attr(file);
665 * Parse group object from XML file.
666 * \param book Address book.
667 * \param file XML file handle.
669 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
673 ItemGroup *group = NULL;
675 attr = xml_get_current_tag_attr(file);
677 name = ((XMLAttr *)attr->data)->name;
678 value = ((XMLAttr *)attr->data)->value;
680 group = addritem_create_item_group();
681 if (strcmp(name, AB_ATTAG_UID) == 0)
682 ADDRITEM_ID(group) = g_strdup(value);
683 else if (strcmp(name, AB_ATTAG_NAME) == 0)
684 ADDRITEM_NAME(group) = g_strdup(value);
685 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
686 group->remarks = g_strdup(value);
687 attr = g_list_next(attr);
689 if (xml_parse_next_tag(file)) { /* Consume closing tag */
690 longjmp(book->jumper, 1);
692 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
694 addrcache_hash_add_group(book->addressCache, group);
696 addrbook_parse_member_list(book, file, group);
701 * Parse folder item from XML file.
702 * \param book Address book.
703 * \param file XML file handle.
704 * \param folder Folder.
706 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
713 attr = xml_get_current_tag_attr(file);
715 name = ((XMLAttr *)attr->data)->name;
716 value = ((XMLAttr *)attr->data)->value;
717 if (strcmp(name, AB_ATTAG_UID) == 0) {
718 uid = g_strdup(value);
720 attr = g_list_next(attr);
724 folder->listItems = g_list_append(folder->listItems, uid);
730 * Parse list of folder items from XML file.
731 * \param book Address book.
732 * \param file XML file handle.
733 * \param folder Folder.
735 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
742 prev_level = file->level;
743 if (xml_parse_next_tag(file)) {
744 longjmp(book->jumper, 1);
746 if (file->level < prev_level)
748 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
749 attr = xml_get_current_tag_attr(file);
750 addrbook_parse_folder_item(book, file, folder);
751 addrbook_parse_folder_list(book, file, folder);
754 attr = xml_get_current_tag_attr(file);
760 * Parse folder from XML file.
761 * \param book Address book.
762 * \param file XML file handle.
764 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
768 ItemFolder *folder = NULL;
770 attr = xml_get_current_tag_attr(file);
772 name = ((XMLAttr *)attr->data)->name;
773 value = ((XMLAttr *)attr->data)->value;
775 folder = addritem_create_item_folder();
776 if (strcmp(name, AB_ATTAG_UID) == 0)
777 ADDRITEM_ID(folder) = g_strdup(value);
778 else if (strcmp(name, AB_ATTAG_NAME) == 0)
779 ADDRITEM_NAME(folder) = g_strdup(value);
780 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
781 folder->remarks = g_strdup(value);
782 attr = g_list_next(attr);
784 if (xml_parse_next_tag(file)) { /* Consume closing tag */
785 longjmp(book->jumper, 1);
787 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
789 if (addrcache_hash_add_folder(book->addressCache,
791 book->tempList = g_list_append(book->tempList,
793 /* We will resolve folder later */
794 ADDRITEM_PARENT(folder) = NULL;
797 addrbook_parse_folder_list(book, file, folder);
802 * Read address book (DOM) tree from file.
803 * \param book Address book.
804 * \param file XML file handle.
805 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
808 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
814 book->retVal = MGU_BAD_FORMAT;
815 if (xml_get_dtd(file))
817 if (xml_parse_next_tag(file))
818 longjmp(book->jumper, 1);
819 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
822 attr = xml_get_current_tag_attr(file);
824 name = ((XMLAttr *)attr->data)->name;
825 value = ((XMLAttr *)attr->data)->value;
826 if (strcmp( name, AB_ATTAG_NAME) == 0)
827 addrbook_set_name( book, value );
828 attr = g_list_next( attr );
835 /* Get next item tag (person, group or folder) */
836 if (xml_parse_next_tag(file))
837 longjmp( book->jumper, 1 );
839 if (xml_compare_tag(file, AB_ELTAG_PERSON))
840 addrbook_parse_person(book, file);
841 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
842 addrbook_parse_group(book, file);
843 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
844 addrbook_parse_folder(book, file);
846 if (retVal) book->retVal = MGU_SUCCESS;
851 * Resolve folder items callback function.
852 * \param key Table key.
853 * \param value Reference to object contained in folder.
854 * \param data Reference to address book.
856 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
858 AddressBookFile *book = data;
859 AddrItemObject *obj = (AddrItemObject *) value;
860 ItemFolder *rootFolder = book->addressCache->rootFolder;
861 if (obj->parent == NULL) {
862 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
863 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
865 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
867 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
868 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
870 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
876 * Resolve folder items. Lists of UID's are replaced with pointers to
878 * \param book Address book.
880 static void addrbook_resolve_folder_items(AddressBookFile *book)
882 GList *nodeFolder = NULL;
883 GList *listRemove = NULL;
885 ItemFolder *rootFolder = book->addressCache->rootFolder;
886 nodeFolder = book->tempList;
889 ItemFolder *folder = nodeFolder->data;
891 node = folder->listItems;
893 gchar *uid = node->data;
894 AddrItemObject *aio = addrcache_get_object(book->addressCache,
897 if (aio->type == ITEMTYPE_FOLDER) {
898 ItemFolder *item = (ItemFolder *) aio;
899 folder->listFolder = g_list_append(folder->listFolder, item);
900 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
901 addrcache_hash_add_folder(book->addressCache, folder);
903 else if (aio->type == ITEMTYPE_PERSON) {
904 ItemPerson *item = (ItemPerson *) aio;
905 folder->listPerson = g_list_append(folder->listPerson, item);
906 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
908 else if (aio->type == ITEMTYPE_GROUP) {
909 ItemGroup *item = (ItemGroup *) aio;
910 folder->listGroup = g_list_append(folder->listGroup, item);
911 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
913 /* Replace data with pointer to item */
917 else { /* Not found, append to remove list. */
918 listRemove = g_list_append(listRemove, uid);
920 node = g_list_next(node);
922 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
924 /* Process remove list */
927 gchar *uid = node->data;
928 folder->listItems = g_list_remove(folder->listItems,
931 node = g_list_next(node);
933 g_list_free(listRemove);
934 nodeFolder = g_list_next(nodeFolder);
936 /* Remove folders with parents. */
938 node = rootFolder->listFolder;
940 ItemFolder *folder = (ItemFolder *) node->data;
941 if (ADDRITEM_PARENT(folder))
942 /* Remove folders with parents */
943 listRemove = g_list_append(listRemove, folder);
944 else /* Add to root folder */
945 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
947 node = g_list_next( node );
949 /* Process remove list */
952 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
954 node = g_list_next(node);
956 g_list_free(listRemove);
958 /* Move all unparented persons and groups into root folder */
959 g_hash_table_foreach(book->addressCache->itemHash,
960 addrbook_res_items_vis, book);
962 /* Free up some more */
963 nodeFolder = book->tempList;
965 ItemFolder *folder = nodeFolder->data;
966 g_list_free(folder->listItems);
967 folder->listItems = NULL;
968 nodeFolder = g_list_next(nodeFolder);
970 g_list_free(book->tempList);
971 book->tempList = NULL;
976 * \param book Address book.
977 * \return Status code.
979 gint addrbook_read_data(AddressBookFile *book)
981 XMLFile *file = NULL;
982 gchar *fileSpec = NULL;
984 g_return_val_if_fail(book != NULL, -1);
987 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
988 addrcache_get_name( book->addressCache ) );
991 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
992 book->fileName, NULL);
993 book->retVal = MGU_OPEN_FILE;
994 addrcache_clear(book->addressCache);
995 book->addressCache->modified = FALSE;
996 book->addressCache->accessFlag = FALSE;
997 file = xml_open_file(fileSpec);
1000 book->tempList = NULL;
1001 /* Trap for parsing errors. */
1002 if (setjmp( book->jumper)) {
1003 xml_close_file(file);
1004 return book->retVal;
1006 addrbook_read_tree(book, file);
1007 xml_close_file(file);
1008 /* Resolve folder items */
1009 addrbook_resolve_folder_items(book);
1010 book->tempList = NULL;
1011 book->addressCache->modified = FALSE;
1012 book->addressCache->dataRead = TRUE;
1013 addrcache_set_dirty(book->addressCache, FALSE);
1015 return book->retVal;
1019 * Write start element to file.
1020 * \param fp File handle.
1021 * \param lvl Indent level.
1022 * \param name Element name.
1024 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
1027 for (i = 0; i < lvl; i++)
1034 * Write end element to file.
1035 * \param fp File handle.
1036 * \param lvl Indent level.
1037 * \param name Element name.
1039 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
1042 for(i = 0; i < lvl; i++)
1050 * Write attribute name/value pair to file.
1051 * \param fp File handle.
1052 * \param name Attribute name.
1053 * \param value Attribute value.
1055 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
1060 xml_file_put_escape_str(fp, value);
1065 * Write person and associated addresses and attributes to file.
1066 * file hash table visitor function.
1067 * \param key Table key.
1068 * \param value Reference to person.
1069 * \param data File pointer.
1071 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1074 AddrItemObject *obj = (AddrItemObject *) value;
1075 FILE *fp = (FILE *) data;
1080 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1081 ItemPerson *person = (ItemPerson *) value;
1083 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
1084 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
1085 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
1086 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
1087 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
1088 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
1091 /* Output email addresses */
1092 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
1094 node = person->listEMail;
1096 ItemEMail *email = node->data;
1097 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
1098 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
1099 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
1100 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
1101 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
1103 node = g_list_next(node);
1105 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
1107 /* Output user attributes */
1108 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1110 node = person->listAttrib;
1112 UserAttribute *attrib = node->data;
1113 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
1114 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
1115 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
1117 xml_file_put_escape_str(fp, attrib->value);
1118 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
1119 node = g_list_next(node);
1121 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1122 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
1128 * Write group and associated references to addresses to file.
1129 * file hash table visitor function.
1130 * \param key Table key.
1131 * \param value Reference to group.
1132 * \param data File pointer.
1134 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1137 AddrItemObject *obj = (AddrItemObject *) value;
1138 FILE *fp = (FILE *) data;
1143 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1144 ItemGroup *group = (ItemGroup *) value;
1146 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
1147 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
1148 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
1149 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
1152 /* Output email address links */
1153 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
1155 node = group->listEMail;
1157 ItemEMail *email = node->data;
1158 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1159 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1160 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1161 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1163 node = g_list_next(node);
1165 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1166 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1172 * Write folder and associated references to addresses to file.
1173 * file hash table visitor function.
1174 * \param key Table key.
1175 * \param value Reference to folder.
1176 * \param data File pointer.
1178 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1181 AddrItemObject *obj = (AddrItemObject *) value;
1182 FILE *fp = (FILE *) data;
1187 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1188 ItemFolder *folder = (ItemFolder *) value;
1190 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1191 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1192 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1193 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1195 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1198 /* Output persons */
1199 node = folder->listPerson;
1201 ItemPerson *item = node->data;
1202 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1203 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1204 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1206 node = g_list_next(node);
1210 node = folder->listGroup;
1212 ItemGroup *item = node->data;
1213 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1214 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1215 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1217 node = g_list_next(node);
1220 /* Output folders */
1221 node = folder->listFolder;
1223 ItemFolder *item = node->data;
1224 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1225 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1226 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1228 node = g_list_next(node);
1230 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1231 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1237 * Output address book data to specified file.
1238 * \param book Address book.
1239 * \param newFile Filename of new file (in book's filepath).
1240 * \return Status code.
1242 gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1246 #ifndef DEV_STANDALONE
1250 g_return_val_if_fail(book != NULL, -1);
1251 g_return_val_if_fail(newFile != NULL, -1);
1253 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1255 book->retVal = MGU_OPEN_FILE;
1256 #ifdef DEV_STANDALONE
1257 fp = g_fopen(fileSpec, "wb");
1260 fputs("<?xml version=\"1.0\" ?>\n", fp);
1262 pfile = prefs_write_open(fileSpec);
1266 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
1268 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1269 addrbook_write_attr(fp, AB_ATTAG_NAME,
1270 addrcache_get_name(book->addressCache));
1273 /* Output all persons */
1274 g_hash_table_foreach(book->addressCache->itemHash,
1275 addrbook_write_item_person_vis, fp);
1277 /* Output all groups */
1278 g_hash_table_foreach(book->addressCache->itemHash,
1279 addrbook_write_item_group_vis, fp);
1281 /* Output all folders */
1282 g_hash_table_foreach(book->addressCache->itemHash,
1283 addrbook_write_item_folder_vis, fp);
1285 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1286 book->retVal = MGU_SUCCESS;
1287 #ifdef DEV_STANDALONE
1290 if (prefs_file_close( pfile ) < 0)
1291 book->retVal = MGU_ERROR_WRITE;
1296 return book->retVal;
1300 * Output address book data to original file.
1301 * \param book Address book.
1302 * \return Status code.
1304 gint addrbook_save_data(AddressBookFile *book)
1306 g_return_val_if_fail(book != NULL, -1);
1308 book->retVal = MGU_NO_FILE;
1309 if (book->fileName == NULL || *book->fileName == '\0')
1310 return book->retVal;
1311 if (book->path == NULL || *book->path == '\0')
1312 return book->retVal;
1314 addrbook_write_to(book, book->fileName);
1315 if (book->retVal == MGU_SUCCESS)
1316 addrcache_set_dirty(book->addressCache, FALSE);
1317 return book->retVal;
1321 * **********************************************************************
1322 * Address book edit interface functions.
1323 * **********************************************************************
1327 * Move email item within list of person's email items.
1328 * \param book Address book.
1329 * \param person Person.
1330 * \param itemMove EMail item to move.
1331 * \param itemTarget EMail item to move before.
1332 * \return Moved item.
1334 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1335 ItemEMail *itemMove, ItemEMail *itemTarget)
1337 ItemEMail *email = NULL;
1339 g_return_val_if_fail(book != NULL, NULL);
1341 email = addritem_move_email_before(person, itemMove, itemTarget);
1343 addrcache_set_dirty(book->addressCache, TRUE);
1348 * Move email item within list of person's email items.
1349 * \param book Address book.
1350 * \param person Person.
1351 * \param itemMove EMail item to move.
1352 * \param itemTarget EMail item after which to move.
1353 * \return Moved item.
1355 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1356 ItemEMail *itemMove, ItemEMail *itemTarget)
1358 ItemEMail *email = NULL;
1360 g_return_val_if_fail(book != NULL, NULL);
1362 email = addritem_move_email_after(person, itemMove, itemTarget);
1364 addrcache_set_dirty(book->addressCache, TRUE);
1369 * Hash table callback function for simple deletion of hashtable entries.
1370 * \param key Table key (will be freed).
1371 * \param value Value stored in table.
1372 * \param data User data.
1373 * \return <i>TRUE</i> to indicate that entry freed.
1375 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1385 * Update address book email list for specified person. Note: The existing
1386 * email addresses are replaced with the new addresses. Any references to
1387 * old addresses in the groups are re-linked to the new addresses. All old
1388 * addresses linked to the person are removed.
1389 * \param book Address book.
1390 * \param person Person to update.
1391 * \param listEMail List of new email addresses.
1393 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1400 g_return_if_fail(book != NULL);
1401 g_return_if_fail(person != NULL);
1403 /* Get groups where person's existing email addresses are listed */
1404 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1406 GHashTable *hashEMail;
1407 GHashTable *hashEMailAlias;
1410 /* Load hash table with new address entries */
1411 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1412 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1415 ItemEMail *email = node->data;
1416 gchar *addr = g_strdup(email->address);
1417 gchar *alias = email->obj.name ;
1419 if (!g_hash_table_lookup(hashEMail, addr)) {
1420 g_hash_table_insert(hashEMail, addr, email);
1422 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1424 g_hash_table_insert(hashEMailAlias, alias, email);
1426 node = g_list_next(node);
1429 /* Re-parent new addresses to existing groups, where email address match. */
1430 nodeGrp = listGroup;
1432 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1433 GList *groupEMail = group->listEMail;
1435 GList *listRemove = NULL;
1437 /* Process each email item linked to group */
1438 nodeGrpEM = groupEMail;
1440 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1442 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1443 /* Found an email address for this person */
1444 ItemEMail *emailNew = NULL;
1445 gchar *addr = g_strdup(emailGrp->address);
1446 gchar *alias = emailGrp->obj.name;
1448 emailNew = (ItemEMail *)
1449 g_hash_table_lookup(hashEMail, addr);
1451 /* If no match by e-mail, try to match by e-mail alias */
1452 if (!emailNew && *alias != '\0') {
1453 emailNew = (ItemEMail *)
1454 g_hash_table_lookup(hashEMailAlias, alias);
1458 /* Point to this entry */
1459 nodeGrpEM->data = emailNew;
1460 else if (g_hash_table_size(hashEMail)==1)
1461 /* If the person has just one e-mail address, then
1462 change e-mail address in group list */
1463 nodeGrpEM->data = listEMail->data;
1465 /* Mark for removal */
1466 listRemove = g_list_append(listRemove, emailGrp);
1468 /* Move on to next email link */
1469 nodeGrpEM = g_list_next(nodeGrpEM);
1472 /* Process all removed links in current group */
1473 nodeGrpEM = listRemove;
1475 ItemEMail *emailGrp = nodeGrpEM->data;
1476 groupEMail = g_list_remove(groupEMail, emailGrp);
1477 nodeGrpEM = g_list_next(nodeGrpEM);
1480 g_list_free(listRemove);
1482 /* Move on to next group */
1483 nodeGrp = g_list_next(nodeGrp);
1486 /* Clear hash table */
1487 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1488 addrbook_free_simple_hash_vis, NULL);
1489 g_hash_table_destroy(hashEMail);
1491 g_hash_table_destroy(hashEMailAlias);
1492 hashEMailAlias = NULL;
1493 g_list_free(listGroup);
1496 /* Remove old addresses from person and cache */
1498 node = person->listEMail;
1500 ItemEMail *email = node->data;
1502 if (addrcache_person_remove_email(book->addressCache, person, email))
1503 addrcache_remove_email(book->addressCache, email);
1505 listDelete = g_list_append(listDelete, email);
1506 node = person->listEMail;
1508 /* Add new address entries */
1511 ItemEMail *email = node->data;
1513 if (ADDRITEM_ID(email) == NULL)
1514 /* Allocate an ID for new address */
1515 addrcache_id_email(book->addressCache, email);
1517 addrcache_person_add_email( book->addressCache, person, email );
1518 node = g_list_next( node );
1521 addrcache_set_dirty(book->addressCache, TRUE);
1523 /* Free up memory */
1524 g_list_free(listEMail);
1529 ItemEMail *email = node->data;
1531 addritem_free_item_email(email);
1532 node = g_list_next(node);
1534 g_list_free(listDelete);
1540 * Create person object and add person with specified address data to address
1541 * book. Note: A new person is created with specified list of email addresses.
1542 * All objects inserted into address book.
1544 * \param book Address book.
1545 * \param folder Parent folder where to add person, or <i>NULL</i> for
1547 * \param listEMail List of new email addresses to associate with person.
1548 * \return Person object created.
1550 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1554 ItemFolder *f = folder;
1557 g_return_val_if_fail(book != NULL, NULL);
1560 f = book->addressCache->rootFolder;
1561 person = addritem_create_item_person();
1562 addrcache_id_person(book->addressCache, person);
1563 addrcache_folder_add_person(book->addressCache, f, person);
1567 ItemEMail *email = node->data;
1568 if (ADDRITEM_ID(email) == NULL)
1569 addrcache_id_email(book->addressCache, email);
1571 addrcache_person_add_email(book->addressCache, person, email);
1572 node = g_list_next(node);
1578 * Build available email list visitor function.
1579 * \param key Table key.
1580 * \param value Value stored in table.
1581 * \param data Reference to address book.
1583 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1586 AddrItemObject *obj = (AddrItemObject *) value;
1588 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1589 AddressBookFile *book = data;
1590 ItemPerson *person = (ItemPerson *) obj;
1591 GList *node = person->listEMail;
1593 ItemEMail *email = node->data;
1594 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1596 if (!g_hash_table_lookup(book->tempHash,
1597 ADDRITEM_ID(email)))
1598 book->tempList = g_list_append(book->tempList, email);
1600 node = g_list_next(node);
1606 * Return link list of available email items that have not already been linked
1607 * to groups. Note that the list contains references to items and should be
1608 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1609 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1612 * \param book Address book.
1613 * \param group Group to process.
1614 * \return List of items, or <i>NULL</i> if none.
1616 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1621 g_return_val_if_fail(book != NULL, NULL);
1623 /* Load hash table with group email entries */
1624 table = g_hash_table_new(g_str_hash, g_str_equal);
1626 list = group->listEMail;
1628 ItemEMail *email = list->data;
1629 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1630 list = g_list_next(list);
1634 /* Build list of available email addresses which exclude those already in groups */
1635 book->tempList = NULL;
1636 book->tempHash = table;
1637 g_hash_table_foreach(book->addressCache->itemHash,
1638 addrbook_build_avail_email_vis, book);
1639 list = book->tempList;
1640 book->tempList = NULL;
1641 book->tempHash = NULL;
1643 /* Clear hash table */
1644 g_hash_table_destroy(table);
1651 * Update address book email list for specified group. Note: The existing email
1652 * addresses are replaced with the new addresses. Any references to old addresses
1653 * in the groups are re-linked to the new addresses. All old addresses linked to
1654 * the person are removed.
1656 * \param book Address book.
1657 * \param group Group to process.
1658 * \param listEMail List of email items. This should <b>*NOT*</b> be
1659 * <code>g_free()</code> when done.
1661 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1666 g_return_if_fail(book != NULL);
1667 g_return_if_fail(group != NULL);
1669 addrcache_set_dirty(book->addressCache, TRUE);
1671 /* Remember old list */
1672 oldData = group->listEMail;
1673 group->listEMail = listEMail;
1674 mgu_clear_list(oldData);
1679 * Create group object and add with specifed list of email addresses to
1680 * address book. Note: The existing email addresses are replaced with the new
1681 * addresses. Any references to old addresses in the groups are re-linked to
1682 * the new addresses. All old addresses linked to the person are removed.
1684 * \param book Address book.
1685 * \param folder Parent folder where to add group, or <i>NULL</i> for
1687 * \param listEMail List of email items. This should <b>*NOT*</b> be
1688 * <code>g_free()</code> when done.
1689 * \return Group object created.
1691 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1694 ItemGroup *group = NULL;
1695 ItemFolder *f = folder;
1697 g_return_val_if_fail(book != NULL, NULL);
1700 f = book->addressCache->rootFolder;
1701 group = addritem_create_item_group();
1702 addrcache_id_group(book->addressCache, group);
1703 addrcache_folder_add_group(book->addressCache, f, group);
1704 group->listEMail = listEMail;
1709 * Create a new folder and add to address book.
1710 * \param book Address book.
1711 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1713 * \return Folder that was created. This should <b>*NOT*</b> be
1714 * <code>g_free()</code> when done.
1716 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1718 g_return_val_if_fail(book != NULL, NULL);
1719 return addrcache_add_new_folder( book->addressCache, parent );
1723 * Update address book attribute list for specified person. Note: The existing
1724 * attributes are replaced with the new addresses. All old attributes linked
1725 * to the person are removed.
1727 * \param book Address book.
1728 * \param person Person to receive attributes.
1729 * \param listAttrib New list of attributes.
1731 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1737 g_return_if_fail(book != NULL);
1738 g_return_if_fail(person != NULL);
1740 /* Remember old list */
1741 oldData = person->listAttrib;
1743 /* Attach new address list to person. */
1746 UserAttribute *attrib = node->data;
1747 if (attrib->uid == NULL) {
1748 /* Allocate an ID */
1749 addrcache_id_attribute(book->addressCache, attrib);
1751 node = g_list_next(node);
1753 person->listAttrib = listAttrib;
1754 addrcache_set_dirty(book->addressCache, TRUE);
1756 /* Free up old data */
1757 addritem_free_list_attribute(oldData);
1762 * Add attribute data for specified person to address book. Note: Only
1763 * attributes are inserted into address book.
1764 * \param book Address book.
1765 * \param person Person to receive attributes.
1766 * \param listAttrib List of attributes.
1768 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1771 g_return_if_fail( book != NULL );
1772 g_return_if_fail( person != NULL );
1776 UserAttribute *attrib = node->data;
1777 if( attrib->uid == NULL ) {
1778 addrcache_id_attribute( book->addressCache, attrib );
1780 addritem_person_add_attribute( person, attrib );
1781 node = g_list_next( node );
1783 addrcache_set_dirty( book->addressCache, TRUE );
1787 * Return reference to address book file for specified object by traversing up
1788 * address book heirarchy.
1790 * \param aio Book item object.
1791 * \return Address book, or <i>NULL</i> if not found.
1793 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1795 AddressBookFile *book = NULL;
1798 ItemFolder *parent = NULL;
1799 ItemFolder *root = NULL;
1800 if (aio->type == ITEMTYPE_EMAIL) {
1801 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1803 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1806 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1809 root = addrcache_find_root_folder(parent);
1811 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1817 * Remove folder from address book. Children are re-parented to the parent
1819 * \param book Address book.
1820 * \param folder Folder to remove.
1821 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1824 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1828 g_return_val_if_fail(book != NULL, NULL);
1830 f = addrcache_remove_folder(book->addressCache, folder);
1835 * Remove folder from address book. Children are deleted.
1836 * \param book Address book.
1837 * \param folder Folder to remove.
1838 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1841 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1846 g_return_val_if_fail(book != NULL, NULL);
1848 f = addrcache_remove_folder_delete(book->addressCache, folder);
1852 #define WORK_BUFLEN 1024
1853 #define ADDRBOOK_DIGITS "0123456789"
1856 * Return list of existing address book files.
1857 * \param book Address book.
1858 * \return List of files (as strings).
1860 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1863 const gchar *dir_name;
1864 struct stat statbuf;
1865 gchar buf[WORK_BUFLEN];
1866 gchar numbuf[WORK_BUFLEN];
1867 gint len, lenpre, lensuf, lennum;
1868 long int val, maxval;
1869 GList *fileList = NULL;
1871 g_return_val_if_fail(book != NULL, NULL);
1873 if (book->path == NULL || *book->path == '\0') {
1874 book->retVal = MGU_NO_PATH;
1878 strcpy(buf, book->path);
1881 if (buf[len-1] != G_DIR_SEPARATOR) {
1882 buf[len] = G_DIR_SEPARATOR;
1887 adbookdir = g_strdup(buf);
1888 strcat(buf, ADDRBOOK_PREFIX);
1890 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1891 book->retVal = MGU_OPEN_DIRECTORY;
1896 lenpre = strlen(ADDRBOOK_PREFIX);
1897 lensuf = strlen(ADDRBOOK_SUFFIX);
1898 lennum = FILE_NUMDIGITS + lenpre;
1901 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1902 gchar *endptr = NULL;
1906 strcpy(buf, adbookdir);
1907 strcat( buf, dir_name );
1908 stat(buf, &statbuf);
1909 if (S_ISREG(statbuf.st_mode)) {
1912 ADDRBOOK_PREFIX, lenpre) == 0)
1915 (dir_name) + lennum,
1916 ADDRBOOK_SUFFIX, lensuf) == 0)
1919 (dir_name) + lenpre,
1921 numbuf[FILE_NUMDIGITS] = '\0';
1923 for(i = 0; i < FILE_NUMDIGITS; i++) {
1924 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1931 val = strtol(numbuf, &endptr, 10);
1932 if (endptr && val > -1) {
1933 if (val > maxval) maxval = val;
1934 fileList = g_list_append(
1936 g_strdup(dir_name));
1946 book->maxValue = maxval;
1947 book->retVal = MGU_SUCCESS;
1952 * Return file name for specified file number.
1953 * \param fileNum File number.
1954 * \return File name, or <i>NULL</i> if file number too large. Should be
1955 * <code>g_free()</code> when done.
1957 gchar *addrbook_gen_new_file_name(gint fileNum) {
1959 gchar buf[WORK_BUFLEN];
1965 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1968 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1969 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1970 return g_strdup(buf);
1974 * **********************************************************************
1975 * Address book test functions...
1976 * **********************************************************************
1980 * Attempt to parse list of email address from file.
1981 * \param book Address book.
1982 * \param file XML file handle.
1984 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1989 prev_level = file->level;
1990 if (xml_parse_next_tag(file))
1991 longjmp(book->jumper, 1);
1992 if (file->level < prev_level)
1994 attr = xml_get_current_tag_attr(file);
1995 /* addrbook_show_attribs( attr ); */
1996 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1997 addrbook_chkparse_addr_list(book, file);
2002 * Attempt to parse attributes for person address from file.
2003 * \param book Address book.
2004 * \param file XML file handle.
2006 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
2011 attr = xml_get_current_tag_attr(file);
2012 /* addrbook_show_attribs( attr ); */
2013 element = xml_get_element(file);
2014 /* printf( "\t\tattrib value : %s\n", element ); */
2018 * Attempt to parse list of attributes for person address from file.
2019 * \param book Address book.
2020 * \param file XML file handle.
2022 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
2027 prev_level = file->level;
2028 if (xml_parse_next_tag(file))
2029 longjmp(book->jumper, 1);
2030 if (file->level < prev_level)
2032 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
2033 addrbook_chkparse_attribute(book, file);
2034 addrbook_chkparse_attr_list(book, file);
2040 * Attempt to parse person from file.
2041 * \param book Address book.
2042 * \param file XML file handle.
2044 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
2048 attr = xml_get_current_tag_attr(file);
2049 /* addrbook_show_attribs( attr ); */
2050 if (xml_parse_next_tag(file)) /* Consume closing tag */
2051 longjmp(book->jumper, 1);
2053 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
2054 addrbook_chkparse_addr_list(book, file);
2056 if (xml_parse_next_tag(file)) /* Consume closing tag */
2057 longjmp(book->jumper, 1);
2059 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
2060 addrbook_chkparse_attr_list(book, file);
2064 * Attempt to parse list of members from file.
2065 * \param book Address book.
2066 * \param file XML file handle.
2068 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2074 prev_level = file->level;
2075 if (xml_parse_next_tag(file))
2076 longjmp(book->jumper, 1);
2078 if (file->level < prev_level)
2081 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2082 attr = xml_get_current_tag_attr(file);
2083 /* addrbook_show_attribs( attr ); */
2084 addrbook_chkparse_member_list(book, file);
2087 attr = xml_get_current_tag_attr(file);
2088 /* addrbook_show_attribs( attr ); */
2094 * Attempt to parse group from file.
2095 * \param book Address book.
2096 * \param file XML file handle.
2098 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2102 attr = xml_get_current_tag_attr(file);
2103 /* addrbook_show_attribs( attr ); */
2104 if (xml_parse_next_tag(file)) /* Consume closing tag */
2105 longjmp(book->jumper, 1);
2107 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2108 addrbook_chkparse_member_list(book, file);
2112 * Attempt to parse list of folders from file.
2113 * \param book Address book.
2114 * \param file XML file handle.
2116 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2122 prev_level = file->level;
2123 if (xml_parse_next_tag(file))
2124 longjmp(book->jumper, 1);
2126 if (file->level < prev_level)
2129 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2130 attr = xml_get_current_tag_attr(file);
2131 /* addrbook_show_attribs( attr ); */
2132 addrbook_chkparse_folder_list(book, file);
2135 attr = xml_get_current_tag_attr(file);
2136 /* addrbook_show_attribs( attr ); */
2142 * Attempt to parse a folder from file.
2143 * \param book Address book.
2144 * \param file XML file handle.
2146 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2150 attr = xml_get_current_tag_attr(file);
2151 /* addrbook_show_attribs( attr ); */
2152 if (xml_parse_next_tag(file)) /* Consume closing tag */
2153 longjmp(book->jumper, 1);
2155 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2156 addrbook_chkparse_folder_list(book, file);
2160 * Attempt to parse (DOM) tree from file.
2161 * \param book Address book.
2162 * \param file XML file handle.
2164 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2169 if (xml_get_dtd(file))
2172 if (xml_parse_next_tag(file))
2175 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2178 attr = xml_get_current_tag_attr(file);
2179 /* addrbook_show_attribs( attr ); */
2186 if (xml_parse_next_tag(file))
2187 longjmp(book->jumper, 1);
2189 /* Get next tag (person, group or folder) */
2190 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2191 addrbook_chkparse_person( book, file );
2192 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2193 addrbook_chkparse_group(book, file);
2194 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2195 addrbook_chkparse_folder(book, file);
2201 * Test address book file by parsing contents.
2202 * \param book Address book.
2203 * \param fileName Filename of XML file.
2204 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2206 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2208 XMLFile *file = NULL;
2209 gchar *fileSpec = NULL;
2211 g_return_val_if_fail(book != NULL, -1);
2213 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2214 book->retVal = MGU_OPEN_FILE;
2215 file = xml_open_file(fileSpec);
2218 book->retVal = MGU_BAD_FORMAT;
2219 if (setjmp(book->jumper)) {
2220 /* printf( "Caught Ya!!!\n" ); */
2221 xml_close_file(file);
2222 return book->retVal;
2224 if (addrbook_chkread_tree(book, file))
2225 book->retVal = MGU_SUCCESS;
2227 xml_close_file( file );
2229 return book->retVal;
2233 * Return link list of all persons in address book. Note that the list
2234 * contains references to items. Do <b>*NOT*</b> attempt to use the
2235 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2237 * \param book Address book.
2238 * \return List of persons, or NULL if none.
2240 GList *addrbook_get_all_persons(AddressBookFile *book)
2242 g_return_val_if_fail(book != NULL, NULL);
2243 return addrcache_get_all_persons(book->addressCache);
2246 GList *addrbook_get_all_groups(AddressBookFile *book)
2248 g_return_val_if_fail(book != NULL, NULL);
2249 return addrcache_get_all_groups(book->addressCache);
2253 * Add person and address data to address book.
2254 * \param book Address book.
2255 * \param folder Folder where to add person, or NULL for root folder.
2256 * \param name Common name.
2257 * \param address EMail address.
2258 * \param remarks Remarks.
2259 * \return Person added. Do not <b>*NOT*</b> to use the
2260 * <code>addrbook_free_xxx()</code> functions... this will destroy
2261 * the address book data.
2263 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2264 const gchar *name,const gchar *address,
2265 const gchar *remarks)
2269 g_return_val_if_fail(book != NULL, NULL);
2270 person = addrcache_add_contact(
2271 book->addressCache, folder, name, address, remarks );
2276 * Return file name for next address book file.
2277 * \param book Address book.
2278 * \return File name, or <i>NULL</i> if could not create. This should be
2279 * <code>g_free()</code> when done.
2281 gchar *addrbook_guess_next_file(AddressBookFile *book)
2283 gchar *newFile = NULL;
2284 GList *fileList = NULL;
2286 fileList = addrbook_get_bookfile_list(book);
2288 fileNum = 1 + book->maxValue;
2290 newFile = addrbook_gen_new_file_name(fileNum);
2291 g_list_free(fileList);