2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2002 Match Grun and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 /* General functions for accessing address book files */
33 #include "addrcache.h"
35 #include "adbookbase.h"
37 #ifndef DEV_STANDALONE
38 #include "prefs_gtk.h"
42 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
43 #define ADDRBOOK_PREFIX "addrbook-"
44 #define ADDRBOOK_SUFFIX ".xml"
45 #define FILE_NUMDIGITS 6
47 #define ID_TIME_OFFSET 998000000
50 * Create new address book
51 * \return Address book.
53 AddressBookFile *addrbook_create_book()
55 AddressBookFile *book;
57 book = g_new0(AddressBookFile, 1);
58 book->type = ADBOOKTYPE_BOOK;
59 book->addressCache = addrcache_create();
60 book->retVal = MGU_SUCCESS;
62 book->fileName = NULL;
64 book->tempList = NULL;
65 book->tempHash = NULL;
66 book->addressCache->modified = TRUE;
72 * Specify name to be used
73 * \param book Address book.
76 void addrbook_set_name(AddressBookFile *book, const gchar *value)
78 g_return_if_fail(book != NULL);
79 addrcache_set_name(book->addressCache, value);
82 gchar *addrbook_get_name(AddressBookFile *book)
84 g_return_val_if_fail(book != NULL, NULL);
85 return addrcache_get_name(book->addressCache);
89 * Specify path to address book file.
90 * \param book Address book.
93 void addrbook_set_path(AddressBookFile *book, const gchar *value)
95 g_return_if_fail(book != NULL);
96 book->path = mgu_replace_string(book->path, value);
97 addrcache_set_dirty(book->addressCache, TRUE);
101 * Specify filename to be used
102 * \param book Address book.
103 * \param value Filename.
105 void addrbook_set_file(AddressBookFile *book, const gchar *value)
107 g_return_if_fail(book != NULL);
108 book->fileName = mgu_replace_string(book->fileName, value);
109 addrcache_set_dirty(book->addressCache, TRUE);
112 gboolean addrbook_get_modified(AddressBookFile *book)
114 g_return_val_if_fail(book != NULL, FALSE);
115 return book->addressCache->modified;
119 * Specify book as modified.
120 * \param book Address book.
121 * \param value Indicator.
123 void addrbook_set_modified(AddressBookFile *book, const gboolean value)
125 g_return_if_fail(book != NULL);
126 book->addressCache->modified = value;
129 gboolean addrbook_get_accessed(AddressBookFile *book)
131 g_return_val_if_fail(book != NULL, FALSE);
132 return book->addressCache->accessFlag;
136 * Specify address book as accessed.
137 * \param book Address book.
138 * \param value Value.
140 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
142 g_return_if_fail(book != NULL);
143 book->addressCache->accessFlag = value;
146 gboolean addrbook_get_read_flag(AddressBookFile *book)
148 g_return_val_if_fail(book != NULL, FALSE);
149 return book->addressCache->dataRead;
153 * Specify address book as read.
154 * \param book Address book.
155 * \param value Value.
157 void addrbook_set_read_flag(AddressBookFile *book, const gboolean value)
159 g_return_if_fail(book != NULL);
160 book->addressCache->dataRead = value;
163 gint addrbook_get_status(AddressBookFile *book)
165 g_return_val_if_fail(book != NULL, -1);
169 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
171 g_return_val_if_fail(book != NULL, NULL);
172 return addrcache_get_root_folder(book->addressCache);
175 GList *addrbook_get_list_folder(AddressBookFile *book)
177 g_return_val_if_fail(book != NULL, NULL);
178 return addrcache_get_list_folder(book->addressCache);
181 GList *addrbook_get_list_person(AddressBookFile *book)
183 g_return_val_if_fail(book != NULL, NULL);
184 return addrcache_get_list_person(book->addressCache);
187 gboolean addrbook_get_dirty(AddressBookFile *book)
189 g_return_val_if_fail(book != NULL, FALSE);
190 return addrcache_get_dirty(book->addressCache);
194 * Set address book as dirty (needs to be written to file).
195 * \param book Address book.
196 * \param value Dirty flag.
198 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
200 g_return_if_fail(book != NULL);
201 addrcache_set_dirty(book->addressCache, value);
205 * Empty address book contents.
206 * \param book Address book.
208 void addrbook_empty_book(AddressBookFile *book)
210 g_return_if_fail(book != NULL);
212 /* Free up internal objects */
213 addrcache_clear(book->addressCache);
214 addrcache_set_dirty(book->addressCache, FALSE);
215 g_list_free(book->tempList);
217 /* Reset to initial state */
218 book->tempList = NULL;
219 book->tempHash = NULL;
220 book->addressCache->dataRead = FALSE;
221 book->addressCache->modified = FALSE;
222 book->addressCache->accessFlag = FALSE;
223 book->retVal = MGU_SUCCESS;
228 * \param book Address book.
230 void addrbook_free_book(AddressBookFile *book)
232 g_return_if_fail(book != NULL);
235 addrcache_free(book->addressCache);
237 /* Free up internal objects */
239 g_free(book->fileName);
240 g_list_free(book->tempList);
243 book->fileName = NULL;
245 book->tempList = NULL;
246 book->tempHash = NULL;
248 book->type = ADBOOKTYPE_NONE;
249 book->addressCache = NULL;
250 book->retVal = MGU_SUCCESS;
256 * Print list of items.
257 * \param book Address book.
258 * \param stream Output stream.
260 void addrbook_print_item_list(GList *list, FILE *stream)
265 AddrItemObject *obj = node->data;
266 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON)
267 addritem_print_item_person((ItemPerson *) obj, stream);
268 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP)
269 addritem_print_item_group((ItemGroup *) obj, stream);
270 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER)
271 addritem_print_item_folder((ItemFolder *) obj, stream);
272 node = g_list_next(node);
274 fprintf(stream, "\t---\n");
278 * Print address book header.
279 * \param book Address book.
280 * \param stream Output stream.
282 void addrbook_print_book(AddressBookFile *book, FILE *stream)
284 g_return_if_fail(book != NULL);
286 fprintf(stream, "AddressBook:\n");
287 fprintf(stream, "\tpath : '%s'\n", book->path);
288 fprintf(stream, "\tfile : '%s'\n", book->fileName);
289 fprintf(stream, "\tstatus : %d\n", book->retVal );
290 addrcache_print(book->addressCache, stream);
294 * Dump entire address book traversing folders.
295 * \param book Address book.
296 * \param stream Output stream.
298 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
302 g_return_if_fail(book != NULL);
304 addrbook_print_book(book, stream);
305 folder = book->addressCache->rootFolder;
306 addritem_print_item_folder(folder, stream);
310 * Remove specified group from address book. Note that object should still
312 * Specify name to be used
313 * \param book Address book.
314 * \param group Group to remove.
316 * \return Group, or NULL if not found.
318 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
320 g_return_val_if_fail(book != NULL, NULL);
321 return addrcache_remove_group(book->addressCache, group);
325 * Remove specified person from address book. Note that object should still
327 * \param book Address book.
328 * \param person Person to remove.
329 * \return Person, or NULL if not found.
331 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
333 g_return_val_if_fail(book != NULL, NULL);
334 return addrcache_remove_person(book->addressCache, person);
338 * Remove specified email address in address book for specified person.
339 * Note that object should still be freed.
340 * \param book Address book.
341 * \param person Person.
342 * \param email EMail to remove.
343 * \return EMail object, or NULL if not found.
345 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
346 ItemPerson *person, ItemEMail *email)
348 g_return_val_if_fail(book != NULL, NULL);
349 return addrcache_person_remove_email(book->addressCache, person, email);
353 * ***********************************************************************
354 * Read/Write XML data file...
355 * ===========================
357 * 1) The address book is structured as follows:
372 * 2) This sequence of elements was chosen so that the most important
373 * elements (person and their email addresses) appear first.
375 * 3) Groups then appear. When groups are loaded, person's email
376 * addresses have already been loaded and can be found.
378 * 4) Finally folders are loaded. Any forward and backward references
379 * to folders, groups and persons in the folders are resolved after
382 * ***********************************************************************
385 /* Element tag names */
386 #define AB_ELTAG_ADDRESS "address"
387 #define AB_ELTAG_ATTRIBUTE "attribute"
388 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
389 #define AB_ELTAG_ADDRESS_LIST "address-list"
390 #define AB_ELTAG_MEMBER "member"
391 #define AB_ELTAG_MEMBER_LIST "member-list"
392 #define AB_ELTAG_ITEM "item"
393 #define AB_ELTAG_ITEM_LIST "item-list"
394 #define AB_ELTAG_ADDRESS_BOOK "address-book"
395 #define AB_ELTAG_PERSON "person"
396 #define AB_ELTAG_GROUP "group"
397 #define AB_ELTAG_FOLDER "folder"
399 /* Attribute tag names */
400 #define AB_ATTAG_TYPE "type"
401 #define AB_ATTAG_UID "uid"
402 #define AB_ATTAG_NAME "name"
403 #define AB_ATTAG_REMARKS "remarks"
404 #define AB_ATTAG_FIRST_NAME "first-name"
405 #define AB_ATTAG_LAST_NAME "last-name"
406 #define AB_ATTAG_NICK_NAME "nick-name"
407 #define AB_ATTAG_COMMON_NAME "cn"
408 #define AB_ATTAG_ALIAS "alias"
409 #define AB_ATTAG_EMAIL "email"
410 #define AB_ATTAG_EID "eid"
411 #define AB_ATTAG_PID "pid"
413 /* Attribute values */
414 #define AB_ATTAG_VAL_PERSON "person"
415 #define AB_ATTAG_VAL_GROUP "group"
416 #define AB_ATTAG_VAL_FOLDER "folder"
419 * Parse address item for person from XML file.
420 * \param book Address book.
421 * \param file XML file handle.
422 * \param person Person.
424 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
429 ItemEMail *email = NULL;
431 attr = xml_get_current_tag_attr(file);
433 name = ((XMLAttr *)attr->data)->name;
434 value = ((XMLAttr *)attr->data)->value;
436 email = addritem_create_item_email();
437 if (strcmp(name, AB_ATTAG_UID) == 0)
438 ADDRITEM_ID(email) = g_strdup(value);
439 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
440 ADDRITEM_NAME(email) = g_strdup(value);
441 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
442 email->address = g_strdup(value);
443 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
444 email->remarks = g_strdup(value);
445 attr = g_list_next(attr);
449 addrcache_person_add_email(book->addressCache, person,
453 addritem_free_item_email(email);
460 * Parse list of email address for person from XML file.
461 * \param book Address book.
462 * \param file XML file handle.
463 * \param person Person.
465 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
472 prev_level = file->level;
473 if (xml_parse_next_tag(file)) {
474 longjmp(book->jumper, 1);
476 if (file->level < prev_level) return;
477 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
478 attr = xml_get_current_tag_attr(file);
479 addrbook_parse_address(book, file, person);
480 addrbook_parse_addr_list(book, file, person);
486 * Parse attribute for person from XML file.
487 * \param book Address book.
488 * \param file XML file handle.
489 * \param person Person.
491 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
496 UserAttribute *uAttr = NULL;
498 attr = xml_get_current_tag_attr(file);
500 name = ((XMLAttr *)attr->data)->name;
501 value = ((XMLAttr *)attr->data)->value;
502 if (!uAttr) uAttr = addritem_create_attribute();
503 if (strcmp(name, AB_ATTAG_UID) == 0)
504 addritem_attrib_set_id(uAttr, value);
505 else if (strcmp(name, AB_ATTAG_NAME) == 0)
506 addritem_attrib_set_name(uAttr, value);
507 attr = g_list_next(attr);
510 element = xml_get_element(file);
511 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 = 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",
1272 conv_get_current_charset_str());
1274 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1275 addrbook_write_attr(fp, AB_ATTAG_NAME,
1276 addrcache_get_name(book->addressCache));
1279 /* Output all persons */
1280 g_hash_table_foreach(book->addressCache->itemHash,
1281 addrbook_write_item_person_vis, fp);
1283 /* Output all groups */
1284 g_hash_table_foreach(book->addressCache->itemHash,
1285 addrbook_write_item_group_vis, fp);
1287 /* Output all folders */
1288 g_hash_table_foreach(book->addressCache->itemHash,
1289 addrbook_write_item_folder_vis, fp);
1291 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1292 book->retVal = MGU_SUCCESS;
1293 #ifdef DEV_STANDALONE
1296 if (prefs_file_close( pfile ) < 0)
1297 book->retVal = MGU_ERROR_WRITE;
1302 return book->retVal;
1306 * Output address book data to original file.
1307 * \param book Address book.
1308 * \return Status code.
1310 gint addrbook_save_data(AddressBookFile *book)
1312 g_return_val_if_fail(book != NULL, -1);
1314 book->retVal = MGU_NO_FILE;
1315 if (book->fileName == NULL || *book->fileName == '\0')
1316 return book->retVal;
1317 if (book->path == NULL || *book->path == '\0')
1318 return book->retVal;
1320 addrbook_write_to(book, book->fileName);
1321 if (book->retVal == MGU_SUCCESS)
1322 addrcache_set_dirty(book->addressCache, FALSE);
1323 return book->retVal;
1327 * **********************************************************************
1328 * Address book edit interface functions.
1329 * **********************************************************************
1333 * Move email item within list of person's email items.
1334 * \param book Address book.
1335 * \param person Person.
1336 * \param itemMove EMail item to move.
1337 * \param itemTarget EMail item to move before.
1338 * \return Moved item.
1340 ItemEMail *addrbook_move_email_before(AddressBookFile *book, ItemPerson *person,
1341 ItemEMail *itemMove, ItemEMail *itemTarget)
1343 ItemEMail *email = NULL;
1345 g_return_val_if_fail(book != NULL, NULL);
1347 email = addritem_move_email_before(person, itemMove, itemTarget);
1349 addrcache_set_dirty(book->addressCache, TRUE);
1354 * Move email item within list of person's email items.
1355 * \param book Address book.
1356 * \param person Person.
1357 * \param itemMove EMail item to move.
1358 * \param itemTarget EMail item after which to move.
1359 * \return Moved item.
1361 ItemEMail *addrbook_move_email_after(AddressBookFile *book, ItemPerson *person,
1362 ItemEMail *itemMove, ItemEMail *itemTarget)
1364 ItemEMail *email = NULL;
1366 g_return_val_if_fail(book != NULL, NULL);
1368 email = addritem_move_email_after(person, itemMove, itemTarget);
1370 addrcache_set_dirty(book->addressCache, TRUE);
1375 * Hash table callback function for simple deletion of hashtable entries.
1376 * \param key Table key (will be freed).
1377 * \param value Value stored in table.
1378 * \param data User data.
1379 * \return <i>TRUE</i> to indicate that entry freed.
1381 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1391 * Update address book email list for specified person. Note: The existing
1392 * email addresses are replaced with the new addresses. Any references to
1393 * old addresses in the groups are re-linked to the new addresses. All old
1394 * addresses linked to the person are removed.
1395 * \param book Address book.
1396 * \param person Person to update.
1397 * \param listEMail List of new email addresses.
1399 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1406 g_return_if_fail(book != NULL);
1407 g_return_if_fail(person != NULL);
1409 /* Get groups where person's existing email addresses are listed */
1410 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1412 GHashTable *hashEMail;
1413 GHashTable *hashEMailAlias;
1416 /* Load hash table with new address entries */
1417 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1418 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1421 ItemEMail *email = node->data;
1422 gchar *addr = g_strdup(email->address);
1423 gchar *alias = email->obj.name ;
1425 if (!g_hash_table_lookup(hashEMail, addr)) {
1426 g_hash_table_insert(hashEMail, addr, email);
1428 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1430 g_hash_table_insert(hashEMailAlias, alias, email);
1432 node = g_list_next(node);
1435 /* Re-parent new addresses to existing groups, where email address match. */
1436 nodeGrp = listGroup;
1438 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1439 GList *groupEMail = group->listEMail;
1441 GList *listRemove = NULL;
1443 /* Process each email item linked to group */
1444 nodeGrpEM = groupEMail;
1446 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1448 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1449 /* Found an email address for this person */
1450 ItemEMail *emailNew = NULL;
1451 gchar *addr = g_strdup(emailGrp->address);
1452 gchar *alias = emailGrp->obj.name;
1454 emailNew = (ItemEMail *)
1455 g_hash_table_lookup(hashEMail, addr);
1457 /* If no match by e-mail, try to match by e-mail alias */
1458 if (!emailNew && *alias != '\0') {
1459 emailNew = (ItemEMail *)
1460 g_hash_table_lookup(hashEMailAlias, alias);
1464 /* Point to this entry */
1465 nodeGrpEM->data = emailNew;
1466 else if (g_hash_table_size(hashEMail)==1)
1467 /* If the person has just one e-mail address, then
1468 change e-mail address in group list */
1469 nodeGrpEM->data = listEMail->data;
1471 /* Mark for removal */
1472 listRemove = g_list_append(listRemove, emailGrp);
1474 /* Move on to next email link */
1475 nodeGrpEM = g_list_next(nodeGrpEM);
1478 /* Process all removed links in current group */
1479 nodeGrpEM = listRemove;
1481 ItemEMail *emailGrp = nodeGrpEM->data;
1482 groupEMail = g_list_remove(groupEMail, emailGrp);
1483 nodeGrpEM = g_list_next(nodeGrpEM);
1486 g_list_free(listRemove);
1488 /* Move on to next group */
1489 nodeGrp = g_list_next(nodeGrp);
1492 /* Clear hash table */
1493 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1494 addrbook_free_simple_hash_vis, NULL);
1495 g_hash_table_destroy(hashEMail);
1497 g_hash_table_destroy(hashEMailAlias);
1498 hashEMailAlias = NULL;
1499 g_list_free(listGroup);
1502 /* Remove old addresses from person and cache */
1504 node = person->listEMail;
1506 ItemEMail *email = node->data;
1508 if (addrcache_person_remove_email(book->addressCache, person, email))
1509 addrcache_remove_email(book->addressCache, email);
1511 listDelete = g_list_append(listDelete, email);
1512 node = person->listEMail;
1514 /* Add new address entries */
1517 ItemEMail *email = node->data;
1519 if (ADDRITEM_ID(email) == NULL)
1520 /* Allocate an ID for new address */
1521 addrcache_id_email(book->addressCache, email);
1523 addrcache_person_add_email( book->addressCache, person, email );
1524 node = g_list_next( node );
1527 addrcache_set_dirty(book->addressCache, TRUE);
1529 /* Free up memory */
1530 g_list_free(listEMail);
1535 ItemEMail *email = node->data;
1537 addritem_free_item_email(email);
1538 node = g_list_next(node);
1540 g_list_free(listDelete);
1546 * Create person object and add person with specified address data to address
1547 * book. Note: A new person is created with specified list of email addresses.
1548 * All objects inserted into address book.
1550 * \param book Address book.
1551 * \param folder Parent folder where to add person, or <i>NULL</i> for
1553 * \param listEMail List of new email addresses to associate with person.
1554 * \return Person object created.
1556 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1560 ItemFolder *f = folder;
1563 g_return_val_if_fail(book != NULL, NULL);
1566 f = book->addressCache->rootFolder;
1567 person = addritem_create_item_person();
1568 addrcache_id_person(book->addressCache, person);
1569 addrcache_folder_add_person(book->addressCache, f, person);
1573 ItemEMail *email = node->data;
1574 if (ADDRITEM_ID(email) == NULL)
1575 addrcache_id_email(book->addressCache, email);
1577 addrcache_person_add_email(book->addressCache, person, email);
1578 node = g_list_next(node);
1584 * Build available email list visitor function.
1585 * \param key Table key.
1586 * \param value Value stored in table.
1587 * \param data Reference to address book.
1589 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1592 AddrItemObject *obj = (AddrItemObject *) value;
1594 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1595 AddressBookFile *book = data;
1596 ItemPerson *person = (ItemPerson *) obj;
1597 GList *node = person->listEMail;
1599 ItemEMail *email = node->data;
1600 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1602 if (!g_hash_table_lookup(book->tempHash,
1603 ADDRITEM_ID(email)))
1604 book->tempList = g_list_append(book->tempList, email);
1606 node = g_list_next(node);
1612 * Return link list of available email items that have not already been linked
1613 * to groups. Note that the list contains references to items and should be
1614 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1615 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1618 * \param book Address book.
1619 * \param group Group to process.
1620 * \return List of items, or <i>NULL</i> if none.
1622 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1627 g_return_val_if_fail(book != NULL, NULL);
1629 /* Load hash table with group email entries */
1630 table = g_hash_table_new(g_str_hash, g_str_equal);
1632 list = group->listEMail;
1634 ItemEMail *email = list->data;
1635 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1636 list = g_list_next(list);
1640 /* Build list of available email addresses which exclude those already in groups */
1641 book->tempList = NULL;
1642 book->tempHash = table;
1643 g_hash_table_foreach(book->addressCache->itemHash,
1644 addrbook_build_avail_email_vis, book);
1645 list = book->tempList;
1646 book->tempList = NULL;
1647 book->tempHash = NULL;
1649 /* Clear hash table */
1650 g_hash_table_destroy(table);
1657 * Update address book email list for specified group. Note: The existing email
1658 * addresses are replaced with the new addresses. Any references to old addresses
1659 * in the groups are re-linked to the new addresses. All old addresses linked to
1660 * the person are removed.
1662 * \param book Address book.
1663 * \param group Group to process.
1664 * \param listEMail List of email items. This should <b>*NOT*</b> be
1665 * <code>g_free()</code> when done.
1667 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1672 g_return_if_fail(book != NULL);
1673 g_return_if_fail(group != NULL);
1675 addrcache_set_dirty(book->addressCache, TRUE);
1677 /* Remember old list */
1678 oldData = group->listEMail;
1679 group->listEMail = listEMail;
1680 mgu_clear_list(oldData);
1685 * Create group object and add with specifed list of email addresses to
1686 * address book. Note: The existing email addresses are replaced with the new
1687 * addresses. Any references to old addresses in the groups are re-linked to
1688 * the new addresses. All old addresses linked to the person are removed.
1690 * \param book Address book.
1691 * \param folder Parent folder where to add group, or <i>NULL</i> for
1693 * \param listEMail List of email items. This should <b>*NOT*</b> be
1694 * <code>g_free()</code> when done.
1695 * \return Group object created.
1697 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1700 ItemGroup *group = NULL;
1701 ItemFolder *f = folder;
1703 g_return_val_if_fail(book != NULL, NULL);
1706 f = book->addressCache->rootFolder;
1707 group = addritem_create_item_group();
1708 addrcache_id_group(book->addressCache, group);
1709 addrcache_folder_add_group(book->addressCache, f, group);
1710 group->listEMail = listEMail;
1715 * Create a new folder and add to address book.
1716 * \param book Address book.
1717 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1719 * \return Folder that was created. This should <b>*NOT*</b> be
1720 * <code>g_free()</code> when done.
1722 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1724 g_return_val_if_fail(book != NULL, NULL);
1725 return addrcache_add_new_folder( book->addressCache, parent );
1729 ItemFolder *folder = NULL;
1730 ItemFolder *p = parent;
1732 g_return_val_if_fail(book != NULL, NULL);
1735 p = book->addressCache->rootFolder;
1736 folder = addritem_create_item_folder();
1737 addrcache_id_folder(book->addressCache, folder);
1738 if (addrcache_hash_add_folder(book->addressCache, folder)) {
1739 p->listFolder = g_list_append(p->listFolder, folder);
1740 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1741 addrcache_set_dirty(book->addressCache, TRUE);
1744 addritem_free_item_folder(folder);
1752 * Update address book attribute list for specified person. Note: The existing
1753 * attributes are replaced with the new addresses. All old attributes linked
1754 * to the person are removed.
1756 * \param book Address book.
1757 * \param person Person to receive attributes.
1758 * \param listAttrib New list of attributes.
1760 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1766 g_return_if_fail(book != NULL);
1767 g_return_if_fail(person != NULL);
1769 /* Remember old list */
1770 oldData = person->listAttrib;
1772 /* Attach new address list to person. */
1775 UserAttribute *attrib = node->data;
1776 if (attrib->uid == NULL) {
1777 /* Allocate an ID */
1778 addrcache_id_attribute(book->addressCache, attrib);
1780 node = g_list_next(node);
1782 person->listAttrib = listAttrib;
1783 addrcache_set_dirty(book->addressCache, TRUE);
1785 /* Free up old data */
1786 addritem_free_list_attribute(oldData);
1791 * Add attribute data for specified person to address book. Note: Only
1792 * attributes are inserted into address book.
1793 * \param book Address book.
1794 * \param person Person to receive attributes.
1795 * \param listAttrib List of attributes.
1797 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1800 g_return_if_fail( book != NULL );
1801 g_return_if_fail( person != NULL );
1805 UserAttribute *attrib = node->data;
1806 if( attrib->uid == NULL ) {
1807 addrcache_id_attribute( book->addressCache, attrib );
1809 addritem_person_add_attribute( person, attrib );
1810 node = g_list_next( node );
1812 addrcache_set_dirty( book->addressCache, TRUE );
1816 * Return reference to address book file for specified object by traversing up
1817 * address book heirarchy.
1819 * \param aio Book item object.
1820 * \return Address book, or <i>NULL</i> if not found.
1822 AddressBookFile *addrbook_item_get_bookfile(AddrItemObject *aio)
1824 AddressBookFile *book = NULL;
1827 ItemFolder *parent = NULL;
1828 ItemFolder *root = NULL;
1829 if (aio->type == ITEMTYPE_EMAIL) {
1830 ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(aio);
1832 parent = (ItemFolder *)ADDRITEM_PARENT(person);
1835 parent = (ItemFolder *)ADDRITEM_PARENT(aio);
1838 root = addrcache_find_root_folder(parent);
1840 book = (AddressBookFile *)ADDRITEM_PARENT(root);
1846 * Remove folder from address book. Children are re-parented to the parent
1848 * \param book Address book.
1849 * \param folder Folder to remove.
1850 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1853 ItemFolder *addrbook_remove_folder(AddressBookFile *book, ItemFolder *folder)
1857 g_return_val_if_fail(book != NULL, NULL);
1859 f = addrcache_remove_folder(book->addressCache, folder);
1864 * Remove folder from address book. Children are deleted.
1865 * \param book Address book.
1866 * \param folder Folder to remove.
1867 * \return Folder, or <i>NULL</i> if not found. Note that object should still
1870 ItemFolder *addrbook_remove_folder_delete(AddressBookFile *book,
1875 g_return_val_if_fail(book != NULL, NULL);
1877 f = addrcache_remove_folder_delete(book->addressCache, folder);
1881 #define WORK_BUFLEN 1024
1882 #define ADDRBOOK_DIGITS "0123456789"
1885 * Return list of existing address book files.
1886 * \param book Address book.
1887 * \return List of files (as strings).
1889 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1892 struct dirent *entry;
1893 struct stat statbuf;
1894 gchar buf[WORK_BUFLEN];
1895 gchar numbuf[WORK_BUFLEN];
1896 gint len, lenpre, lensuf, lennum;
1897 long int val, maxval;
1898 GList *fileList = NULL;
1900 g_return_val_if_fail(book != NULL, NULL);
1902 if (book->path == NULL || *book->path == '\0') {
1903 book->retVal = MGU_NO_PATH;
1907 strcpy(buf, book->path);
1910 if (buf[len-1] != G_DIR_SEPARATOR) {
1911 buf[len] = G_DIR_SEPARATOR;
1916 adbookdir = g_strdup(buf);
1917 strcat(buf, ADDRBOOK_PREFIX);
1919 if ((dp = opendir(adbookdir)) == NULL) {
1920 book->retVal = MGU_OPEN_DIRECTORY;
1925 lenpre = strlen(ADDRBOOK_PREFIX);
1926 lensuf = strlen(ADDRBOOK_SUFFIX);
1927 lennum = FILE_NUMDIGITS + lenpre;
1930 while ((entry = readdir(dp)) != NULL) {
1931 gchar *endptr = NULL;
1935 strcpy(buf, adbookdir);
1936 strcat(buf, entry->d_name);
1937 stat(buf, &statbuf);
1938 if (S_IFREG & statbuf.st_mode) {
1941 ADDRBOOK_PREFIX, lenpre) == 0)
1944 (entry->d_name) + lennum,
1945 ADDRBOOK_SUFFIX, lensuf) == 0)
1948 (entry->d_name) + lenpre,
1950 numbuf[FILE_NUMDIGITS] = '\0';
1952 for(i = 0; i < FILE_NUMDIGITS; i++) {
1953 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1960 val = strtol(numbuf, &endptr, 10);
1961 if (endptr && val > -1) {
1962 if (val > maxval) maxval = val;
1963 fileList = g_list_append(
1965 g_strdup(entry->d_name));
1975 book->maxValue = maxval;
1976 book->retVal = MGU_SUCCESS;
1981 * Return file name for specified file number.
1982 * \param fileNum File number.
1983 * \return File name, or <i>NULL</i> if file number too large. Should be
1984 * <code>g_free()</code> when done.
1986 gchar *addrbook_gen_new_file_name(gint fileNum) {
1988 gchar buf[WORK_BUFLEN];
1994 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1997 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1998 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1999 return g_strdup(buf);
2003 * **********************************************************************
2004 * Address book test functions...
2005 * **********************************************************************
2009 * Attempt to parse list of email address from file.
2010 * \param book Address book.
2011 * \param file XML file handle.
2013 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
2018 prev_level = file->level;
2019 if (xml_parse_next_tag(file))
2020 longjmp(book->jumper, 1);
2021 if (file->level < prev_level)
2023 attr = xml_get_current_tag_attr(file);
2024 /* addrbook_show_attribs( attr ); */
2025 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
2026 addrbook_chkparse_addr_list(book, file);
2031 * Attempt to parse attributes for person address from file.
2032 * \param book Address book.
2033 * \param file XML file handle.
2035 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
2040 attr = xml_get_current_tag_attr(file);
2041 /* addrbook_show_attribs( attr ); */
2042 element = xml_get_element(file);
2043 /* printf( "\t\tattrib value : %s\n", element ); */
2047 * Attempt to parse list of attributes for person address from file.
2048 * \param book Address book.
2049 * \param file XML file handle.
2051 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
2056 prev_level = file->level;
2057 if (xml_parse_next_tag(file))
2058 longjmp(book->jumper, 1);
2059 if (file->level < prev_level)
2061 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
2062 addrbook_chkparse_attribute(book, file);
2063 addrbook_chkparse_attr_list(book, file);
2069 * Attempt to parse person from file.
2070 * \param book Address book.
2071 * \param file XML file handle.
2073 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
2077 attr = xml_get_current_tag_attr(file);
2078 /* addrbook_show_attribs( attr ); */
2079 if (xml_parse_next_tag(file)) /* Consume closing tag */
2080 longjmp(book->jumper, 1);
2082 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
2083 addrbook_chkparse_addr_list(book, file);
2085 if (xml_parse_next_tag(file)) /* Consume closing tag */
2086 longjmp(book->jumper, 1);
2088 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
2089 addrbook_chkparse_attr_list(book, file);
2093 * Attempt to parse list of members from file.
2094 * \param book Address book.
2095 * \param file XML file handle.
2097 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2103 prev_level = file->level;
2104 if (xml_parse_next_tag(file))
2105 longjmp(book->jumper, 1);
2107 if (file->level < prev_level)
2110 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2111 attr = xml_get_current_tag_attr(file);
2112 /* addrbook_show_attribs( attr ); */
2113 addrbook_chkparse_member_list(book, file);
2116 attr = xml_get_current_tag_attr(file);
2117 /* addrbook_show_attribs( attr ); */
2123 * Attempt to parse group from file.
2124 * \param book Address book.
2125 * \param file XML file handle.
2127 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2131 attr = xml_get_current_tag_attr(file);
2132 /* addrbook_show_attribs( attr ); */
2133 if (xml_parse_next_tag(file)) /* Consume closing tag */
2134 longjmp(book->jumper, 1);
2136 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2137 addrbook_chkparse_member_list(book, file);
2141 * Attempt to parse list of folders from file.
2142 * \param book Address book.
2143 * \param file XML file handle.
2145 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2151 prev_level = file->level;
2152 if (xml_parse_next_tag(file))
2153 longjmp(book->jumper, 1);
2155 if (file->level < prev_level)
2158 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2159 attr = xml_get_current_tag_attr(file);
2160 /* addrbook_show_attribs( attr ); */
2161 addrbook_chkparse_folder_list(book, file);
2164 attr = xml_get_current_tag_attr(file);
2165 /* addrbook_show_attribs( attr ); */
2171 * Attempt to parse a folder from file.
2172 * \param book Address book.
2173 * \param file XML file handle.
2175 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2179 attr = xml_get_current_tag_attr(file);
2180 /* addrbook_show_attribs( attr ); */
2181 if (xml_parse_next_tag(file)) /* Consume closing tag */
2182 longjmp(book->jumper, 1);
2184 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2185 addrbook_chkparse_folder_list(book, file);
2189 * Attempt to parse (DOM) tree from file.
2190 * \param book Address book.
2191 * \param file XML file handle.
2193 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2198 if (xml_get_dtd(file))
2201 if (xml_parse_next_tag(file))
2204 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2207 attr = xml_get_current_tag_attr(file);
2208 /* addrbook_show_attribs( attr ); */
2215 if (xml_parse_next_tag(file))
2216 longjmp(book->jumper, 1);
2218 /* Get next tag (person, group or folder) */
2219 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2220 addrbook_chkparse_person( book, file );
2221 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2222 addrbook_chkparse_group(book, file);
2223 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2224 addrbook_chkparse_folder(book, file);
2230 * Test address book file by parsing contents.
2231 * \param book Address book.
2232 * \param fileName Filename of XML file.
2233 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2235 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2237 XMLFile *file = NULL;
2238 gchar *fileSpec = NULL;
2240 g_return_val_if_fail(book != NULL, -1);
2242 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2243 book->retVal = MGU_OPEN_FILE;
2244 file = xml_open_file(fileSpec);
2247 book->retVal = MGU_BAD_FORMAT;
2248 if (setjmp(book->jumper)) {
2249 /* printf( "Caught Ya!!!\n" ); */
2250 xml_close_file(file);
2251 return book->retVal;
2253 if (addrbook_chkread_tree(book, file))
2254 book->retVal = MGU_SUCCESS;
2256 xml_close_file( file );
2258 return book->retVal;
2262 * Return link list of all persons in address book. Note that the list
2263 * contains references to items. Do <b>*NOT*</b> attempt to use the
2264 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2266 * \param book Address book.
2267 * \return List of persons, or NULL if none.
2269 GList *addrbook_get_all_persons(AddressBookFile *book)
2271 g_return_val_if_fail(book != NULL, NULL);
2272 return addrcache_get_all_persons(book->addressCache);
2276 * Add person and address data to address book.
2277 * \param book Address book.
2278 * \param folder Folder where to add person, or NULL for root folder.
2279 * \param name Common name.
2280 * \param address EMail address.
2281 * \param remarks Remarks.
2282 * \return Person added. Do not <b>*NOT*</b> to use the
2283 * <code>addrbook_free_xxx()</code> functions... this will destroy
2284 * the address book data.
2286 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2287 const gchar *name,const gchar *address,
2288 const gchar *remarks)
2292 g_return_val_if_fail(book != NULL, NULL);
2293 person = addrcache_add_contact(
2294 book->addressCache, folder, name, address, remarks );
2299 * Return file name for next address book file.
2300 * \param book Address book.
2301 * \return File name, or <i>NULL</i> if could not create. This should be
2302 * <code>g_free()</code> when done.
2304 gchar *addrbook_guess_next_file(AddressBookFile *book)
2306 gchar *newFile = NULL;
2307 GList *fileList = NULL;
2309 fileList = addrbook_get_bookfile_list(book);
2311 fileNum = 1 + book->maxValue;
2313 newFile = addrbook_gen_new_file_name(fileNum);
2314 g_list_free(fileList);