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 3 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, see <http://www.gnu.org/licenses/>.
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
48 static void addrbook_print_book ( AddressBookFile *book, FILE *stream );
51 * Create new address book
52 * \return Address book.
54 AddressBookFile *addrbook_create_book()
56 AddressBookFile *book;
58 book = g_new0(AddressBookFile, 1);
59 book->type = ADBOOKTYPE_BOOK;
60 book->addressCache = addrcache_create();
61 book->retVal = MGU_SUCCESS;
63 book->fileName = NULL;
65 book->tempList = NULL;
66 book->tempHash = NULL;
67 book->addressCache->modified = TRUE;
73 * Specify name to be used
74 * \param book Address book.
77 void addrbook_set_name(AddressBookFile *book, const gchar *value)
79 g_return_if_fail(book != NULL);
80 addrcache_set_name(book->addressCache, value);
83 gchar *addrbook_get_name(AddressBookFile *book)
85 g_return_val_if_fail(book != NULL, NULL);
86 return addrcache_get_name(book->addressCache);
90 * Specify path to address book file.
91 * \param book Address book.
94 void addrbook_set_path(AddressBookFile *book, const gchar *value)
96 g_return_if_fail(book != NULL);
97 book->path = mgu_replace_string(book->path, value);
98 addrcache_set_dirty(book->addressCache, TRUE);
102 * Specify filename to be used
103 * \param book Address book.
104 * \param value Filename.
106 void addrbook_set_file(AddressBookFile *book, const gchar *value)
108 g_return_if_fail(book != NULL);
109 book->fileName = mgu_replace_string(book->fileName, value);
110 addrcache_set_dirty(book->addressCache, TRUE);
113 gboolean addrbook_get_modified(AddressBookFile *book)
115 g_return_val_if_fail(book != NULL, FALSE);
116 return book->addressCache->modified;
119 gboolean addrbook_get_accessed(AddressBookFile *book)
121 g_return_val_if_fail(book != NULL, FALSE);
122 return book->addressCache->accessFlag;
126 * Specify address book as accessed.
127 * \param book Address book.
128 * \param value Value.
130 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
132 g_return_if_fail(book != NULL);
133 book->addressCache->accessFlag = value;
136 gboolean addrbook_get_read_flag(AddressBookFile *book)
138 g_return_val_if_fail(book != NULL, FALSE);
139 return book->addressCache->dataRead;
142 gint addrbook_get_status(AddressBookFile *book)
144 g_return_val_if_fail(book != NULL, -1);
148 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
150 g_return_val_if_fail(book != NULL, NULL);
151 return addrcache_get_root_folder(book->addressCache);
154 GList *addrbook_get_list_folder(AddressBookFile *book)
156 g_return_val_if_fail(book != NULL, NULL);
157 return addrcache_get_list_folder(book->addressCache);
160 GList *addrbook_get_list_person(AddressBookFile *book)
162 g_return_val_if_fail(book != NULL, NULL);
163 return addrcache_get_list_person(book->addressCache);
166 gboolean addrbook_get_dirty(AddressBookFile *book)
168 g_return_val_if_fail(book != NULL, FALSE);
169 return addrcache_get_dirty(book->addressCache);
173 * Set address book as dirty (needs to be written to file).
174 * \param book Address book.
175 * \param value Dirty flag.
177 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
179 g_return_if_fail(book != NULL);
180 addrcache_set_dirty(book->addressCache, value);
185 * \param book Address book.
187 void addrbook_free_book(AddressBookFile *book)
189 g_return_if_fail(book != NULL);
192 addrcache_free(book->addressCache);
194 /* Free up internal objects */
196 g_free(book->fileName);
197 g_list_free(book->tempList);
200 book->fileName = NULL;
202 book->tempList = NULL;
203 book->tempHash = NULL;
205 book->type = ADBOOKTYPE_NONE;
206 book->addressCache = NULL;
207 book->retVal = MGU_SUCCESS;
213 * Print address book header.
214 * \param book Address book.
215 * \param stream Output stream.
217 static void addrbook_print_book(AddressBookFile *book, FILE *stream)
219 g_return_if_fail(book != NULL);
221 fprintf(stream, "AddressBook:\n");
222 fprintf(stream, "\tpath : '%s'\n", book->path);
223 fprintf(stream, "\tfile : '%s'\n", book->fileName);
224 fprintf(stream, "\tstatus : %d\n", book->retVal );
225 addrcache_print(book->addressCache, stream);
229 * Dump entire address book traversing folders.
230 * \param book Address book.
231 * \param stream Output stream.
233 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
237 g_return_if_fail(book != NULL);
239 addrbook_print_book(book, stream);
240 folder = book->addressCache->rootFolder;
241 addritem_print_item_folder(folder, stream);
245 * Remove specified group from address book. Note that object should still
247 * Specify name to be used
248 * \param book Address book.
249 * \param group Group to remove.
251 * \return Group, or NULL if not found.
253 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
255 g_return_val_if_fail(book != NULL, NULL);
256 return addrcache_remove_group(book->addressCache, group);
260 * Remove specified person from address book. Note that object should still
262 * \param book Address book.
263 * \param person Person to remove.
264 * \return Person, or NULL if not found.
266 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
268 g_return_val_if_fail(book != NULL, NULL);
269 return addrcache_remove_person(book->addressCache, person);
273 * Remove specified email address in address book for specified person.
274 * Note that object should still be freed.
275 * \param book Address book.
276 * \param person Person.
277 * \param email EMail to remove.
278 * \return EMail object, or NULL if not found.
280 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
281 ItemPerson *person, ItemEMail *email)
283 g_return_val_if_fail(book != NULL, NULL);
284 return addrcache_person_remove_email(book->addressCache, person, email);
288 * ***********************************************************************
289 * Read/Write XML data file...
290 * ===========================
292 * 1) The address book is structured as follows:
307 * 2) This sequence of elements was chosen so that the most important
308 * elements (person and their email addresses) appear first.
310 * 3) Groups then appear. When groups are loaded, person's email
311 * addresses have already been loaded and can be found.
313 * 4) Finally folders are loaded. Any forward and backward references
314 * to folders, groups and persons in the folders are resolved after
317 * ***********************************************************************
320 /* Element tag names */
321 #define AB_ELTAG_ADDRESS "address"
322 #define AB_ELTAG_ATTRIBUTE "attribute"
323 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
324 #define AB_ELTAG_ADDRESS_LIST "address-list"
325 #define AB_ELTAG_MEMBER "member"
326 #define AB_ELTAG_MEMBER_LIST "member-list"
327 #define AB_ELTAG_ITEM "item"
328 #define AB_ELTAG_ITEM_LIST "item-list"
329 #define AB_ELTAG_ADDRESS_BOOK "address-book"
330 #define AB_ELTAG_PERSON "person"
331 #define AB_ELTAG_GROUP "group"
332 #define AB_ELTAG_FOLDER "folder"
334 /* Attribute tag names */
335 #define AB_ATTAG_TYPE "type"
336 #define AB_ATTAG_UID "uid"
337 #define AB_ATTAG_NAME "name"
338 #define AB_ATTAG_REMARKS "remarks"
339 #define AB_ATTAG_FIRST_NAME "first-name"
340 #define AB_ATTAG_LAST_NAME "last-name"
341 #define AB_ATTAG_NICK_NAME "nick-name"
342 #define AB_ATTAG_COMMON_NAME "cn"
343 #define AB_ATTAG_ALIAS "alias"
344 #define AB_ATTAG_EMAIL "email"
345 #define AB_ATTAG_EID "eid"
346 #define AB_ATTAG_PID "pid"
348 /* Attribute values */
349 #define AB_ATTAG_VAL_PERSON "person"
350 #define AB_ATTAG_VAL_GROUP "group"
351 #define AB_ATTAG_VAL_FOLDER "folder"
354 * Parse address item for person from XML file.
355 * \param book Address book.
356 * \param file XML file handle.
357 * \param person Person.
359 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
364 ItemEMail *email = NULL;
366 attr = xml_get_current_tag_attr(file);
368 name = ((XMLAttr *)attr->data)->name;
369 value = ((XMLAttr *)attr->data)->value;
371 email = addritem_create_item_email();
372 if (strcmp(name, AB_ATTAG_UID) == 0)
373 ADDRITEM_ID(email) = g_strdup(value);
374 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
375 ADDRITEM_NAME(email) = g_strdup(value);
376 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
377 email->address = g_strdup(value);
378 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
379 email->remarks = g_strdup(value);
380 attr = g_list_next(attr);
384 addrcache_person_add_email(book->addressCache, person,
388 addritem_free_item_email(email);
395 * Parse list of email address for person from XML file.
396 * \param book Address book.
397 * \param file XML file handle.
398 * \param person Person.
400 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
407 prev_level = file->level;
408 if (xml_parse_next_tag(file)) {
409 longjmp(book->jumper, 1);
411 if (file->level < prev_level) return;
412 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
413 attr = xml_get_current_tag_attr(file);
414 addrbook_parse_address(book, file, person);
415 addrbook_parse_addr_list(book, file, person);
421 * Parse attribute for person from XML file.
422 * \param book Address book.
423 * \param file XML file handle.
424 * \param person Person.
426 static void addrbook_parse_attribute(XMLFile *file, ItemPerson *person)
431 UserAttribute *uAttr = NULL;
433 attr = xml_get_current_tag_attr(file);
435 name = ((XMLAttr *)attr->data)->name;
436 value = ((XMLAttr *)attr->data)->value;
437 if (!uAttr) uAttr = addritem_create_attribute();
438 if (strcmp(name, AB_ATTAG_UID) == 0)
439 addritem_attrib_set_id(uAttr, value);
440 else if (strcmp(name, AB_ATTAG_NAME) == 0)
441 addritem_attrib_set_name(uAttr, value);
442 attr = g_list_next(attr);
445 element = xml_get_element(file);
446 addritem_attrib_set_value(uAttr, element);
451 addritem_person_add_attribute(person, uAttr);
454 addritem_free_attribute(uAttr);
461 * Parse list of attributes for person from XML file.
462 * \param book Address book.
463 * \param file XML file handle.
464 * \param person Person.
466 static void addrbook_parse_attr_list(AddressBookFile *book, XMLFile *file,
473 prev_level = file->level;
474 if (xml_parse_next_tag(file)) {
475 longjmp( book->jumper, 1 );
477 if (file->level < prev_level) return;
478 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
479 attr = xml_get_current_tag_attr(file);
480 addrbook_parse_attribute(file, person);
481 addrbook_parse_attr_list(book, file, person);
487 * Parse person from XML file.
488 * \param book Address book.
489 * \param file XML file handle.
491 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
495 ItemPerson *person = NULL;
497 attr = xml_get_current_tag_attr(file);
499 name = ((XMLAttr *)attr->data)->name;
500 value = ((XMLAttr *)attr->data)->value;
502 person = addritem_create_item_person();
503 if (strcmp(name, AB_ATTAG_UID) == 0) {
504 ADDRITEM_ID(person) = g_strdup(value);
505 person->picture = g_strdup(value);
507 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
508 person->firstName = g_strdup(value);
509 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
510 person->lastName = g_strdup(value);
511 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
512 person->nickName = g_strdup(value);
513 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
514 ADDRITEM_NAME(person) = g_strdup(value);
515 attr = g_list_next(attr);
517 if (xml_parse_next_tag(file)) { /* Consume closing tag */
518 longjmp(book->jumper, 1);
520 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
521 addrbook_parse_addr_list(book, file, person);
523 addrcache_hash_add_person(book->addressCache, person);
526 if (xml_parse_next_tag(file)) { /* Consume closing tag */
527 longjmp(book->jumper, 1);
529 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
530 addrbook_parse_attr_list(book, file, person);
535 * Parse group member from XML file.
536 * \param book Address book.
537 * \param file XML file handle.
538 * \param group Group.
540 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
546 /* gchar *pid = NULL; */
547 ItemEMail *email = NULL;
549 attr = xml_get_current_tag_attr(file);
551 name = ((XMLAttr *)attr->data)->name;
552 value = ((XMLAttr *)attr->data)->value;
553 if( strcmp( name, AB_ATTAG_EID ) == 0 )
554 eid = g_strdup( value );
555 attr = g_list_next(attr);
557 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
558 email = addrcache_get_email(book->addressCache, eid);
562 addrcache_group_add_email(book->addressCache, group,
566 addritem_free_item_email(email);
573 * Parse list of group members from XML file.
574 * \param book Address book.
575 * \param file XML file handle.
576 * \param group Group.
578 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
585 prev_level = file->level;
586 if (xml_parse_next_tag(file)) {
587 longjmp(book->jumper, 1);
589 if (file->level < prev_level)
591 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
592 attr = xml_get_current_tag_attr(file);
593 addrbook_parse_member(book, file, group);
594 addrbook_parse_member_list(book, file, group);
597 attr = xml_get_current_tag_attr(file);
603 * Parse group object from XML file.
604 * \param book Address book.
605 * \param file XML file handle.
607 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
611 ItemGroup *group = NULL;
613 attr = xml_get_current_tag_attr(file);
615 name = ((XMLAttr *)attr->data)->name;
616 value = ((XMLAttr *)attr->data)->value;
618 group = addritem_create_item_group();
619 if (strcmp(name, AB_ATTAG_UID) == 0)
620 ADDRITEM_ID(group) = g_strdup(value);
621 else if (strcmp(name, AB_ATTAG_NAME) == 0)
622 ADDRITEM_NAME(group) = g_strdup(value);
623 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
624 group->remarks = g_strdup(value);
625 attr = g_list_next(attr);
627 if (xml_parse_next_tag(file)) { /* Consume closing tag */
628 longjmp(book->jumper, 1);
630 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
632 addrcache_hash_add_group(book->addressCache, group);
634 addrbook_parse_member_list(book, file, group);
639 * Parse folder item from XML file.
640 * \param book Address book.
641 * \param file XML file handle.
642 * \param folder Folder.
644 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
651 attr = xml_get_current_tag_attr(file);
653 name = ((XMLAttr *)attr->data)->name;
654 value = ((XMLAttr *)attr->data)->value;
655 if (strcmp(name, AB_ATTAG_UID) == 0) {
656 uid = g_strdup(value);
658 attr = g_list_next(attr);
662 folder->listItems = g_list_append(folder->listItems, uid);
668 * Parse list of folder items from XML file.
669 * \param book Address book.
670 * \param file XML file handle.
671 * \param folder Folder.
673 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
680 prev_level = file->level;
681 if (xml_parse_next_tag(file)) {
682 longjmp(book->jumper, 1);
684 if (file->level < prev_level)
686 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
687 attr = xml_get_current_tag_attr(file);
688 addrbook_parse_folder_item(book, file, folder);
689 addrbook_parse_folder_list(book, file, folder);
692 attr = xml_get_current_tag_attr(file);
698 * Parse folder from XML file.
699 * \param book Address book.
700 * \param file XML file handle.
702 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
706 ItemFolder *folder = NULL;
708 attr = xml_get_current_tag_attr(file);
710 name = ((XMLAttr *)attr->data)->name;
711 value = ((XMLAttr *)attr->data)->value;
713 folder = addritem_create_item_folder();
714 if (strcmp(name, AB_ATTAG_UID) == 0)
715 ADDRITEM_ID(folder) = g_strdup(value);
716 else if (strcmp(name, AB_ATTAG_NAME) == 0)
717 ADDRITEM_NAME(folder) = g_strdup(value);
718 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
719 folder->remarks = g_strdup(value);
720 attr = g_list_next(attr);
722 if (xml_parse_next_tag(file)) { /* Consume closing tag */
723 longjmp(book->jumper, 1);
725 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
727 if (addrcache_hash_add_folder(book->addressCache,
729 book->tempList = g_list_append(book->tempList,
731 /* We will resolve folder later */
732 ADDRITEM_PARENT(folder) = NULL;
735 addrbook_parse_folder_list(book, file, folder);
740 * Read address book (DOM) tree from file.
741 * \param book Address book.
742 * \param file XML file handle.
743 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
746 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
752 book->retVal = MGU_BAD_FORMAT;
753 if (xml_get_dtd(file))
755 if (xml_parse_next_tag(file))
756 longjmp(book->jumper, 1);
757 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
760 attr = xml_get_current_tag_attr(file);
762 name = ((XMLAttr *)attr->data)->name;
763 value = ((XMLAttr *)attr->data)->value;
764 if (strcmp( name, AB_ATTAG_NAME) == 0)
765 addrbook_set_name( book, value );
766 attr = g_list_next( attr );
773 /* Get next item tag (person, group or folder) */
774 if (xml_parse_next_tag(file))
775 longjmp( book->jumper, 1 );
777 if (xml_compare_tag(file, AB_ELTAG_PERSON))
778 addrbook_parse_person(book, file);
779 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
780 addrbook_parse_group(book, file);
781 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
782 addrbook_parse_folder(book, file);
784 if (retVal) book->retVal = MGU_SUCCESS;
789 * Resolve folder items callback function.
790 * \param key Table key.
791 * \param value Reference to object contained in folder.
792 * \param data Reference to address book.
794 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
796 AddressBookFile *book = data;
797 AddrItemObject *obj = (AddrItemObject *) value;
798 ItemFolder *rootFolder = book->addressCache->rootFolder;
799 if (obj->parent == NULL) {
800 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
801 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
803 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
805 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
806 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
808 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
814 * Resolve folder items. Lists of UID's are replaced with pointers to
816 * \param book Address book.
818 static void addrbook_resolve_folder_items(AddressBookFile *book)
820 GList *nodeFolder = NULL;
821 GList *listRemove = NULL;
823 ItemFolder *rootFolder = book->addressCache->rootFolder;
824 nodeFolder = book->tempList;
827 ItemFolder *folder = nodeFolder->data;
829 node = folder->listItems;
831 gchar *uid = node->data;
832 AddrItemObject *aio = addrcache_get_object(book->addressCache,
835 if (aio->type == ITEMTYPE_FOLDER) {
836 ItemFolder *item = (ItemFolder *) aio;
837 folder->listFolder = g_list_append(folder->listFolder, item);
838 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
839 addrcache_hash_add_folder(book->addressCache, folder);
841 else if (aio->type == ITEMTYPE_PERSON) {
842 ItemPerson *item = (ItemPerson *) aio;
843 folder->listPerson = g_list_append(folder->listPerson, item);
844 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
846 else if (aio->type == ITEMTYPE_GROUP) {
847 ItemGroup *item = (ItemGroup *) aio;
848 folder->listGroup = g_list_append(folder->listGroup, item);
849 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
851 /* Replace data with pointer to item */
855 else { /* Not found, append to remove list. */
856 listRemove = g_list_append(listRemove, uid);
858 node = g_list_next(node);
860 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
862 /* Process remove list */
865 gchar *uid = node->data;
866 folder->listItems = g_list_remove(folder->listItems,
869 node = g_list_next(node);
871 g_list_free(listRemove);
872 nodeFolder = g_list_next(nodeFolder);
874 /* Remove folders with parents. */
876 node = rootFolder->listFolder;
878 ItemFolder *folder = (ItemFolder *) node->data;
879 if (ADDRITEM_PARENT(folder))
880 /* Remove folders with parents */
881 listRemove = g_list_append(listRemove, folder);
882 else /* Add to root folder */
883 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
885 node = g_list_next( node );
887 /* Process remove list */
890 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
892 node = g_list_next(node);
894 g_list_free(listRemove);
896 /* Move all unparented persons and groups into root folder */
897 g_hash_table_foreach(book->addressCache->itemHash,
898 addrbook_res_items_vis, book);
900 /* Free up some more */
901 nodeFolder = book->tempList;
903 ItemFolder *folder = nodeFolder->data;
904 g_list_free(folder->listItems);
905 folder->listItems = NULL;
906 nodeFolder = g_list_next(nodeFolder);
908 g_list_free(book->tempList);
909 book->tempList = NULL;
914 * \param book Address book.
915 * \return Status code.
917 gint addrbook_read_data(AddressBookFile *book)
919 XMLFile *file = NULL;
920 gchar *fileSpec = NULL;
922 g_return_val_if_fail(book != NULL, -1);
925 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
926 addrcache_get_name( book->addressCache ) );
929 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
930 book->fileName, NULL);
931 book->retVal = MGU_OPEN_FILE;
932 addrcache_clear(book->addressCache);
933 book->addressCache->modified = FALSE;
934 book->addressCache->accessFlag = FALSE;
935 file = xml_open_file(fileSpec);
938 book->tempList = NULL;
939 /* Trap for parsing errors. */
940 if (setjmp( book->jumper)) {
941 xml_close_file(file);
944 addrbook_read_tree(book, file);
945 xml_close_file(file);
946 /* Resolve folder items */
947 addrbook_resolve_folder_items(book);
948 book->tempList = NULL;
949 book->addressCache->modified = FALSE;
950 book->addressCache->dataRead = TRUE;
951 addrcache_set_dirty(book->addressCache, FALSE);
957 * Write start element to file.
958 * \param fp File handle.
959 * \param lvl Indent level.
960 * \param name Element name.
962 static int addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
965 for (i = 0; i < lvl; i++)
966 if (fputs(" ", fp) == EOF)
968 if (fputs("<", fp) == EOF)
970 if (fputs(name, fp) == EOF)
977 * Write end element to file.
978 * \param fp File handle.
979 * \param lvl Indent level.
980 * \param name Element name.
982 static int addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
985 for(i = 0; i < lvl; i++)
986 if (fputs(" ", fp) == EOF)
988 if (fputs("</", fp) == EOF)
990 if (fputs(name, fp) == EOF)
992 if (fputs(">\n", fp) == EOF)
999 * Write attribute name/value pair to file.
1000 * \param fp File handle.
1001 * \param name Attribute name.
1002 * \param value Attribute value.
1004 static int addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
1006 if (fputs(" ", fp) == EOF)
1008 if (fputs(name, fp) == EOF)
1010 if (fputs("=\"", fp) == EOF)
1012 if (xml_file_put_escape_str(fp, value) < 0)
1014 if (fputs("\"", fp) == EOF)
1020 typedef struct _HashLoopData {
1026 * Write person and associated addresses and attributes to file.
1027 * file hash table visitor function.
1028 * \param key Table key.
1029 * \param value Reference to person.
1030 * \param data File pointer.
1032 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1035 AddrItemObject *obj = (AddrItemObject *) value;
1036 HashLoopData *data = (HashLoopData *)d;
1037 FILE *fp = data->fp;
1042 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1043 ItemPerson *person = (ItemPerson *) value;
1045 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON) < 0)
1047 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person)) < 0)
1049 if (addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName) < 0)
1051 if (addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName) < 0)
1053 if (addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName) < 0)
1055 if (addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person)) < 0)
1057 if (fputs(" >\n", fp) == EOF)
1060 /* Output email addresses */
1061 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0)
1063 if (fputs(">\n", fp) == EOF)
1065 node = person->listEMail;
1067 ItemEMail *email = node->data;
1068 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS) < 0)
1070 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email)) < 0)
1072 if (addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email)) < 0)
1074 if (addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address) < 0)
1076 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks) < 0)
1078 if (fputs(" />\n", fp) == EOF)
1080 node = g_list_next(node);
1082 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0)
1085 /* Output user attributes */
1086 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0)
1088 if (fputs(">\n", fp) == EOF)
1090 node = person->listAttrib;
1092 UserAttribute *attrib = node->data;
1093 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE) < 0)
1095 if (addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid) < 0)
1097 if (addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name) < 0)
1099 if (fputs(" >", fp) == EOF)
1101 if (xml_file_put_escape_str(fp, attrib->value) < 0)
1103 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE) < 0)
1105 node = g_list_next(node);
1107 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0)
1109 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON) < 0)
1116 * Write group and associated references to addresses to file.
1117 * file hash table visitor function.
1118 * \param key Table key.
1119 * \param value Reference to group.
1120 * \param data File pointer.
1122 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1125 AddrItemObject *obj = (AddrItemObject *) value;
1126 HashLoopData *data = (HashLoopData *)d;
1127 FILE *fp = data->fp;
1133 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1134 ItemGroup *group = (ItemGroup *) value;
1136 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP) < 0)
1138 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group)) < 0)
1140 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group)) < 0)
1142 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks) < 0)
1144 if (fputs(" >\n", fp) == EOF)
1147 /* Output email address links */
1148 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST) < 0)
1150 if (fputs(">\n", fp) == EOF)
1152 node = group->listEMail;
1154 ItemEMail *email = node->data;
1155 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1156 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER) < 0)
1158 if (addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person)) < 0)
1160 if (addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email)) < 0)
1162 if (fputs(" />\n", fp) == EOF)
1164 node = g_list_next(node);
1166 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST) < 0)
1168 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP) < 0)
1175 * Write folder and associated references to addresses to file.
1176 * file hash table visitor function.
1177 * \param key Table key.
1178 * \param value Reference to folder.
1179 * \param data File pointer.
1181 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1184 AddrItemObject *obj = (AddrItemObject *) value;
1185 HashLoopData *data = (HashLoopData *)d;
1186 FILE *fp = data->fp;
1191 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1192 ItemFolder *folder = (ItemFolder *) value;
1194 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER) < 0)
1196 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder)) < 0)
1198 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder)) < 0)
1200 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks) < 0)
1202 if (fputs(" >\n", fp) == EOF)
1204 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST) < 0)
1206 if (fputs(">\n", fp) == EOF)
1209 /* Output persons */
1210 node = folder->listPerson;
1212 ItemPerson *item = node->data;
1213 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1215 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON) < 0)
1217 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1219 if (fputs(" />\n", fp) == EOF)
1221 node = g_list_next(node);
1225 node = folder->listGroup;
1227 ItemGroup *item = node->data;
1228 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1230 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP) < 0)
1232 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1234 if (fputs(" />\n", fp) == EOF)
1236 node = g_list_next(node);
1239 /* Output folders */
1240 node = folder->listFolder;
1242 ItemFolder *item = node->data;
1243 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1245 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER) < 0)
1247 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1249 if (fputs(" />\n", fp) == EOF)
1251 node = g_list_next(node);
1253 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST) < 0)
1255 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER) < 0)
1262 * Output address book data to specified file.
1263 * \param book Address book.
1264 * \param newFile Filename of new file (in book's filepath).
1265 * \return Status code.
1267 static gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1272 #ifndef DEV_STANDALONE
1276 g_return_val_if_fail(book != NULL, -1);
1277 g_return_val_if_fail(newFile != NULL, -1);
1279 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1281 book->retVal = MGU_OPEN_FILE;
1282 #ifdef DEV_STANDALONE
1283 fp = g_fopen(fileSpec, "wb");
1286 if (fputs("<?xml version=\"1.0\" ?>\n", fp) == EOF) {
1287 book->retVal = MGU_ERROR_WRITE;
1288 return book->retVal;
1291 pfile = prefs_write_open(fileSpec);
1295 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0)
1298 if (addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0)
1300 if (addrbook_write_attr(fp, AB_ATTAG_NAME,
1301 addrcache_get_name(book->addressCache)) < 0)
1303 if (fputs(" >\n", fp) == EOF)
1306 /* Output all persons */
1310 g_hash_table_foreach(book->addressCache->itemHash,
1311 addrbook_write_item_person_vis, &data);
1315 /* Output all groups */
1316 g_hash_table_foreach(book->addressCache->itemHash,
1317 addrbook_write_item_group_vis, &data);
1322 /* Output all folders */
1323 g_hash_table_foreach(book->addressCache->itemHash,
1324 addrbook_write_item_folder_vis, &data);
1329 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0)
1332 book->retVal = MGU_SUCCESS;
1333 #ifdef DEV_STANDALONE
1336 if (prefs_file_close( pfile ) < 0)
1337 book->retVal = MGU_ERROR_WRITE;
1342 return book->retVal;
1344 g_warning("error writing AB\n");
1345 book->retVal = MGU_ERROR_WRITE;
1347 prefs_file_close_revert( pfile );
1348 return book->retVal;
1352 * Output address book data to original file.
1353 * \param book Address book.
1354 * \return Status code.
1356 gint addrbook_save_data(AddressBookFile *book)
1358 g_return_val_if_fail(book != NULL, -1);
1360 book->retVal = MGU_NO_FILE;
1361 if (book->fileName == NULL || *book->fileName == '\0')
1362 return book->retVal;
1363 if (book->path == NULL || *book->path == '\0')
1364 return book->retVal;
1366 addrbook_write_to(book, book->fileName);
1367 if (book->retVal == MGU_SUCCESS)
1368 addrcache_set_dirty(book->addressCache, FALSE);
1369 return book->retVal;
1373 * **********************************************************************
1374 * Address book edit interface functions.
1375 * **********************************************************************
1379 * Hash table callback function for simple deletion of hashtable entries.
1380 * \param key Table key (will be freed).
1381 * \param value Value stored in table.
1382 * \param data User data.
1383 * \return <i>TRUE</i> to indicate that entry freed.
1385 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1395 * Update address book email list for specified person. Note: The existing
1396 * email addresses are replaced with the new addresses. Any references to
1397 * old addresses in the groups are re-linked to the new addresses. All old
1398 * addresses linked to the person are removed.
1399 * \param book Address book.
1400 * \param person Person to update.
1401 * \param listEMail List of new email addresses.
1403 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1410 g_return_if_fail(book != NULL);
1411 g_return_if_fail(person != NULL);
1413 /* Get groups where person's existing email addresses are listed */
1414 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1416 GHashTable *hashEMail;
1417 GHashTable *hashEMailAlias;
1420 /* Load hash table with new address entries */
1421 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1422 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1425 ItemEMail *email = node->data;
1426 gchar *alias = email->obj.name ;
1427 gchar *addr = g_utf8_strdown(email->address, -1);
1428 if (!g_hash_table_lookup(hashEMail, addr)) {
1429 g_hash_table_insert(hashEMail, addr, email);
1431 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1433 g_hash_table_insert(hashEMailAlias, alias, email);
1435 node = g_list_next(node);
1438 /* Re-parent new addresses to existing groups, where email address match. */
1439 nodeGrp = listGroup;
1441 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1442 GList *groupEMail = group->listEMail;
1444 GList *listRemove = NULL;
1446 /* Process each email item linked to group */
1447 nodeGrpEM = groupEMail;
1449 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1451 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1452 /* Found an email address for this person */
1453 ItemEMail *emailNew = NULL;
1454 gchar *alias = emailGrp->obj.name;
1455 gchar *addr = g_utf8_strdown(emailGrp->address, -1);
1456 emailNew = (ItemEMail *)
1457 g_hash_table_lookup(hashEMail, addr);
1459 /* If no match by e-mail, try to match by e-mail alias */
1460 if (!emailNew && *alias != '\0') {
1461 emailNew = (ItemEMail *)
1462 g_hash_table_lookup(hashEMailAlias, alias);
1466 /* Point to this entry */
1467 nodeGrpEM->data = emailNew;
1468 else if (g_hash_table_size(hashEMail)==1)
1469 /* If the person has just one e-mail address, then
1470 change e-mail address in group list */
1471 nodeGrpEM->data = listEMail->data;
1473 /* Mark for removal */
1474 listRemove = g_list_append(listRemove, emailGrp);
1476 /* Move on to next email link */
1477 nodeGrpEM = g_list_next(nodeGrpEM);
1480 /* Process all removed links in current group */
1481 nodeGrpEM = listRemove;
1483 ItemEMail *emailGrp = nodeGrpEM->data;
1484 groupEMail = g_list_remove(groupEMail, emailGrp);
1485 nodeGrpEM = g_list_next(nodeGrpEM);
1488 g_list_free(listRemove);
1490 /* Move on to next group */
1491 nodeGrp = g_list_next(nodeGrp);
1494 /* Clear hash table */
1495 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1496 addrbook_free_simple_hash_vis, NULL);
1497 g_hash_table_destroy(hashEMail);
1499 g_hash_table_destroy(hashEMailAlias);
1500 hashEMailAlias = NULL;
1501 g_list_free(listGroup);
1504 /* Remove old addresses from person and cache */
1506 node = person->listEMail;
1508 ItemEMail *email = node->data;
1510 if (addrcache_person_remove_email(book->addressCache, person, email))
1511 addrcache_remove_email(book->addressCache, email);
1513 listDelete = g_list_append(listDelete, email);
1514 node = person->listEMail;
1516 /* Add new address entries */
1519 ItemEMail *email = node->data;
1521 if (ADDRITEM_ID(email) == NULL)
1522 /* Allocate an ID for new address */
1523 addrcache_id_email(book->addressCache, email);
1525 addrcache_person_add_email( book->addressCache, person, email );
1526 node = g_list_next( node );
1529 addrcache_set_dirty(book->addressCache, TRUE);
1531 /* Free up memory */
1532 g_list_free(listEMail);
1537 ItemEMail *email = node->data;
1539 addritem_free_item_email(email);
1540 node = g_list_next(node);
1542 g_list_free(listDelete);
1548 * Create person object and add person with specified address data to address
1549 * book. Note: A new person is created with specified list of email addresses.
1550 * All objects inserted into address book.
1552 * \param book Address book.
1553 * \param folder Parent folder where to add person, or <i>NULL</i> for
1555 * \param listEMail List of new email addresses to associate with person.
1556 * \return Person object created.
1558 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1562 ItemFolder *f = folder;
1565 g_return_val_if_fail(book != NULL, NULL);
1568 f = book->addressCache->rootFolder;
1569 person = addritem_create_item_person();
1570 addrcache_id_person(book->addressCache, person);
1571 addrcache_folder_add_person(book->addressCache, f, person);
1575 ItemEMail *email = node->data;
1576 if (ADDRITEM_ID(email) == NULL)
1577 addrcache_id_email(book->addressCache, email);
1579 addrcache_person_add_email(book->addressCache, person, email);
1580 node = g_list_next(node);
1586 * Build available email list visitor function.
1587 * \param key Table key.
1588 * \param value Value stored in table.
1589 * \param data Reference to address book.
1591 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1594 AddrItemObject *obj = (AddrItemObject *) value;
1596 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1597 AddressBookFile *book = data;
1598 ItemPerson *person = (ItemPerson *) obj;
1599 GList *node = person->listEMail;
1601 ItemEMail *email = node->data;
1602 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1604 if (!g_hash_table_lookup(book->tempHash,
1605 ADDRITEM_ID(email)))
1606 book->tempList = g_list_append(book->tempList, email);
1608 node = g_list_next(node);
1614 * Return link list of available email items that have not already been linked
1615 * to groups. Note that the list contains references to items and should be
1616 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1617 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1620 * \param book Address book.
1621 * \param group Group to process.
1622 * \return List of items, or <i>NULL</i> if none.
1624 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1629 g_return_val_if_fail(book != NULL, NULL);
1631 /* Load hash table with group email entries */
1632 table = g_hash_table_new(g_str_hash, g_str_equal);
1634 list = group->listEMail;
1636 ItemEMail *email = list->data;
1637 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1638 list = g_list_next(list);
1642 /* Build list of available email addresses which exclude those already in groups */
1643 book->tempList = NULL;
1644 book->tempHash = table;
1645 g_hash_table_foreach(book->addressCache->itemHash,
1646 addrbook_build_avail_email_vis, book);
1647 list = book->tempList;
1648 book->tempList = NULL;
1649 book->tempHash = NULL;
1651 /* Clear hash table */
1652 g_hash_table_destroy(table);
1659 * Update address book email list for specified group. Note: The existing email
1660 * addresses are replaced with the new addresses. Any references to old addresses
1661 * in the groups are re-linked to the new addresses. All old addresses linked to
1662 * the person are removed.
1664 * \param book Address book.
1665 * \param group Group to process.
1666 * \param listEMail List of email items. This should <b>*NOT*</b> be
1667 * <code>g_free()</code> when done.
1669 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1674 g_return_if_fail(book != NULL);
1675 g_return_if_fail(group != NULL);
1677 addrcache_set_dirty(book->addressCache, TRUE);
1679 /* Remember old list */
1680 oldData = group->listEMail;
1681 group->listEMail = listEMail;
1682 mgu_clear_list(oldData);
1687 * Create group object and add with specifed list of email addresses to
1688 * address book. Note: The existing email addresses are replaced with the new
1689 * addresses. Any references to old addresses in the groups are re-linked to
1690 * the new addresses. All old addresses linked to the person are removed.
1692 * \param book Address book.
1693 * \param folder Parent folder where to add group, or <i>NULL</i> for
1695 * \param listEMail List of email items. This should <b>*NOT*</b> be
1696 * <code>g_free()</code> when done.
1697 * \return Group object created.
1699 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1702 ItemGroup *group = NULL;
1703 ItemFolder *f = folder;
1705 g_return_val_if_fail(book != NULL, NULL);
1708 f = book->addressCache->rootFolder;
1709 group = addritem_create_item_group();
1710 addrcache_id_group(book->addressCache, group);
1711 addrcache_folder_add_group(book->addressCache, f, group);
1712 group->listEMail = listEMail;
1717 * Create a new folder and add to address book.
1718 * \param book Address book.
1719 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1721 * \return Folder that was created. This should <b>*NOT*</b> be
1722 * <code>g_free()</code> when done.
1724 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1726 g_return_val_if_fail(book != NULL, NULL);
1727 return addrcache_add_new_folder( book->addressCache, parent );
1731 * Update address book attribute list for specified person. Note: The existing
1732 * attributes are replaced with the new addresses. All old attributes linked
1733 * to the person are removed.
1735 * \param book Address book.
1736 * \param person Person to receive attributes.
1737 * \param listAttrib New list of attributes.
1739 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1745 g_return_if_fail(book != NULL);
1746 g_return_if_fail(person != NULL);
1748 /* Remember old list */
1749 oldData = person->listAttrib;
1751 /* Attach new address list to person. */
1754 UserAttribute *attrib = node->data;
1755 if (attrib->uid == NULL) {
1756 /* Allocate an ID */
1757 addrcache_id_attribute(book->addressCache, attrib);
1759 node = g_list_next(node);
1761 person->listAttrib = listAttrib;
1762 addrcache_set_dirty(book->addressCache, TRUE);
1764 /* Free up old data */
1765 addritem_free_list_attribute(oldData);
1770 * Add attribute data for specified person to address book. Note: Only
1771 * attributes are inserted into address book.
1772 * \param book Address book.
1773 * \param person Person to receive attributes.
1774 * \param listAttrib List of attributes.
1776 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1779 g_return_if_fail( book != NULL );
1780 g_return_if_fail( person != NULL );
1784 UserAttribute *attrib = node->data;
1785 if( attrib->uid == NULL ) {
1786 addrcache_id_attribute( book->addressCache, attrib );
1788 addritem_person_add_attribute( person, attrib );
1789 node = g_list_next( node );
1791 addrcache_set_dirty( book->addressCache, TRUE );
1794 #define WORK_BUFLEN 1024
1795 #define ADDRBOOK_DIGITS "0123456789"
1798 * Return list of existing address book files.
1799 * \param book Address book.
1800 * \return List of files (as strings).
1802 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1805 const gchar *dir_name;
1806 struct stat statbuf;
1807 gchar buf[WORK_BUFLEN];
1808 gchar numbuf[WORK_BUFLEN];
1809 gint len, lenpre, lensuf, lennum;
1810 long int val, maxval;
1811 GList *fileList = NULL;
1813 g_return_val_if_fail(book != NULL, NULL);
1815 if (book->path == NULL || *book->path == '\0') {
1816 book->retVal = MGU_NO_PATH;
1820 strcpy(buf, book->path);
1823 if (buf[len-1] != G_DIR_SEPARATOR) {
1824 buf[len] = G_DIR_SEPARATOR;
1829 adbookdir = g_strdup(buf);
1830 strcat(buf, ADDRBOOK_PREFIX);
1832 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1833 book->retVal = MGU_OPEN_DIRECTORY;
1838 lenpre = strlen(ADDRBOOK_PREFIX);
1839 lensuf = strlen(ADDRBOOK_SUFFIX);
1840 lennum = FILE_NUMDIGITS + lenpre;
1843 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1844 gchar *endptr = NULL;
1848 strcpy(buf, adbookdir);
1849 strcat( buf, dir_name );
1850 stat(buf, &statbuf);
1851 if (S_ISREG(statbuf.st_mode)) {
1854 ADDRBOOK_PREFIX, lenpre) == 0)
1857 (dir_name) + lennum,
1858 ADDRBOOK_SUFFIX, lensuf) == 0)
1861 (dir_name) + lenpre,
1863 numbuf[FILE_NUMDIGITS] = '\0';
1865 for(i = 0; i < FILE_NUMDIGITS; i++) {
1866 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1873 val = strtol(numbuf, &endptr, 10);
1874 if (endptr && val > -1) {
1875 if (val > maxval) maxval = val;
1876 fileList = g_list_append(
1878 g_strdup(dir_name));
1888 book->maxValue = maxval;
1889 book->retVal = MGU_SUCCESS;
1894 * Return file name for specified file number.
1895 * \param fileNum File number.
1896 * \return File name, or <i>NULL</i> if file number too large. Should be
1897 * <code>g_free()</code> when done.
1899 gchar *addrbook_gen_new_file_name(gint fileNum) {
1901 gchar buf[WORK_BUFLEN];
1907 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1910 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1911 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1912 return g_strdup(buf);
1916 * **********************************************************************
1917 * Address book test functions...
1918 * **********************************************************************
1922 * Attempt to parse list of email address from file.
1923 * \param book Address book.
1924 * \param file XML file handle.
1926 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1931 prev_level = file->level;
1932 if (xml_parse_next_tag(file))
1933 longjmp(book->jumper, 1);
1934 if (file->level < prev_level)
1936 attr = xml_get_current_tag_attr(file);
1937 /* addrbook_show_attribs( attr ); */
1938 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1939 addrbook_chkparse_addr_list(book, file);
1944 * Attempt to parse attributes for person address from file.
1945 * \param book Address book.
1946 * \param file XML file handle.
1948 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1953 attr = xml_get_current_tag_attr(file);
1954 /* addrbook_show_attribs( attr ); */
1955 element = xml_get_element(file);
1956 /* g_print( "\t\tattrib value : %s\n", element ); */
1960 * Attempt to parse list of attributes for person address from file.
1961 * \param book Address book.
1962 * \param file XML file handle.
1964 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1969 prev_level = file->level;
1970 if (xml_parse_next_tag(file))
1971 longjmp(book->jumper, 1);
1972 if (file->level < prev_level)
1974 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1975 addrbook_chkparse_attribute(book, file);
1976 addrbook_chkparse_attr_list(book, file);
1982 * Attempt to parse person from file.
1983 * \param book Address book.
1984 * \param file XML file handle.
1986 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1990 attr = xml_get_current_tag_attr(file);
1991 /* addrbook_show_attribs( attr ); */
1992 if (xml_parse_next_tag(file)) /* Consume closing tag */
1993 longjmp(book->jumper, 1);
1995 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1996 addrbook_chkparse_addr_list(book, file);
1998 if (xml_parse_next_tag(file)) /* Consume closing tag */
1999 longjmp(book->jumper, 1);
2001 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
2002 addrbook_chkparse_attr_list(book, file);
2006 * Attempt to parse list of members from file.
2007 * \param book Address book.
2008 * \param file XML file handle.
2010 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2016 prev_level = file->level;
2017 if (xml_parse_next_tag(file))
2018 longjmp(book->jumper, 1);
2020 if (file->level < prev_level)
2023 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2024 attr = xml_get_current_tag_attr(file);
2025 /* addrbook_show_attribs( attr ); */
2026 addrbook_chkparse_member_list(book, file);
2029 attr = xml_get_current_tag_attr(file);
2030 /* addrbook_show_attribs( attr ); */
2036 * Attempt to parse group from file.
2037 * \param book Address book.
2038 * \param file XML file handle.
2040 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2044 attr = xml_get_current_tag_attr(file);
2045 /* addrbook_show_attribs( attr ); */
2046 if (xml_parse_next_tag(file)) /* Consume closing tag */
2047 longjmp(book->jumper, 1);
2049 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2050 addrbook_chkparse_member_list(book, file);
2054 * Attempt to parse list of folders from file.
2055 * \param book Address book.
2056 * \param file XML file handle.
2058 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2064 prev_level = file->level;
2065 if (xml_parse_next_tag(file))
2066 longjmp(book->jumper, 1);
2068 if (file->level < prev_level)
2071 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2072 attr = xml_get_current_tag_attr(file);
2073 /* addrbook_show_attribs( attr ); */
2074 addrbook_chkparse_folder_list(book, file);
2077 attr = xml_get_current_tag_attr(file);
2078 /* addrbook_show_attribs( attr ); */
2084 * Attempt to parse a folder from file.
2085 * \param book Address book.
2086 * \param file XML file handle.
2088 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2092 attr = xml_get_current_tag_attr(file);
2093 /* addrbook_show_attribs( attr ); */
2094 if (xml_parse_next_tag(file)) /* Consume closing tag */
2095 longjmp(book->jumper, 1);
2097 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2098 addrbook_chkparse_folder_list(book, file);
2102 * Attempt to parse (DOM) tree from file.
2103 * \param book Address book.
2104 * \param file XML file handle.
2106 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2111 if (xml_get_dtd(file))
2114 if (xml_parse_next_tag(file))
2117 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2120 attr = xml_get_current_tag_attr(file);
2121 /* addrbook_show_attribs( attr ); */
2128 if (xml_parse_next_tag(file))
2129 longjmp(book->jumper, 1);
2131 /* Get next tag (person, group or folder) */
2132 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2133 addrbook_chkparse_person( book, file );
2134 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2135 addrbook_chkparse_group(book, file);
2136 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2137 addrbook_chkparse_folder(book, file);
2143 * Test address book file by parsing contents.
2144 * \param book Address book.
2145 * \param fileName Filename of XML file.
2146 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2148 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2150 XMLFile *file = NULL;
2151 gchar *fileSpec = NULL;
2153 g_return_val_if_fail(book != NULL, -1);
2155 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2156 book->retVal = MGU_OPEN_FILE;
2157 file = xml_open_file(fileSpec);
2160 book->retVal = MGU_BAD_FORMAT;
2161 if (setjmp(book->jumper)) {
2162 /* g_print( "Caught Ya!!!\n" ); */
2163 xml_close_file(file);
2164 return book->retVal;
2166 if (addrbook_chkread_tree(book, file))
2167 book->retVal = MGU_SUCCESS;
2169 xml_close_file( file );
2171 return book->retVal;
2175 * Return link list of all persons in address book. Note that the list
2176 * contains references to items. Do <b>*NOT*</b> attempt to use the
2177 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2179 * \param book Address book.
2180 * \return List of persons, or NULL if none.
2182 GList *addrbook_get_all_persons(AddressBookFile *book)
2184 g_return_val_if_fail(book != NULL, NULL);
2185 return addrcache_get_all_persons(book->addressCache);
2188 GList *addrbook_get_all_groups(AddressBookFile *book)
2190 g_return_val_if_fail(book != NULL, NULL);
2191 return addrcache_get_all_groups(book->addressCache);
2195 * Add person and address data to address book.
2196 * \param book Address book.
2197 * \param folder Folder where to add person, or NULL for root folder.
2198 * \param name Common name.
2199 * \param address EMail address.
2200 * \param remarks Remarks.
2201 * \return Person added. Do not <b>*NOT*</b> to use the
2202 * <code>addrbook_free_xxx()</code> functions... this will destroy
2203 * the address book data.
2205 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2206 const gchar *name,const gchar *address,
2207 const gchar *remarks)
2211 g_return_val_if_fail(book != NULL, NULL);
2212 person = addrcache_add_contact(
2213 book->addressCache, folder, name, address, remarks );
2218 * Return file name for next address book file.
2219 * \param book Address book.
2220 * \return File name, or <i>NULL</i> if could not create. This should be
2221 * <code>g_free()</code> when done.
2223 gchar *addrbook_guess_next_file(AddressBookFile *book)
2225 gchar *newFile = NULL;
2226 GList *fileList = NULL;
2228 fileList = addrbook_get_bookfile_list(book);
2230 fileNum = 1 + book->maxValue;
2232 newFile = addrbook_gen_new_file_name(fileNum);
2233 g_list_free(fileList);