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 else if (strcmp(name, AB_ATTAG_FIRST_NAME) == 0)
506 person->firstName = g_strdup(value);
507 else if (strcmp(name, AB_ATTAG_LAST_NAME) == 0)
508 person->lastName = g_strdup(value);
509 else if (strcmp(name, AB_ATTAG_NICK_NAME) == 0)
510 person->nickName = g_strdup(value);
511 else if (strcmp(name, AB_ATTAG_COMMON_NAME) == 0)
512 ADDRITEM_NAME(person) = g_strdup(value);
513 attr = g_list_next(attr);
515 if (xml_parse_next_tag(file)) { /* Consume closing tag */
516 longjmp(book->jumper, 1);
518 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST)) {
519 addrbook_parse_addr_list(book, file, person);
521 addrcache_hash_add_person(book->addressCache, person);
524 if (xml_parse_next_tag(file)) { /* Consume closing tag */
525 longjmp(book->jumper, 1);
527 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST)) {
528 addrbook_parse_attr_list(book, file, person);
533 * Parse group member from XML file.
534 * \param book Address book.
535 * \param file XML file handle.
536 * \param group Group.
538 static void addrbook_parse_member(AddressBookFile *book, XMLFile *file,
544 /* gchar *pid = NULL; */
545 ItemEMail *email = NULL;
547 attr = xml_get_current_tag_attr(file);
549 name = ((XMLAttr *)attr->data)->name;
550 value = ((XMLAttr *)attr->data)->value;
551 if( strcmp( name, AB_ATTAG_EID ) == 0 )
552 eid = g_strdup( value );
553 attr = g_list_next(attr);
555 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
556 email = addrcache_get_email(book->addressCache, eid);
560 addrcache_group_add_email(book->addressCache, group,
564 addritem_free_item_email(email);
571 * Parse list of group members from XML file.
572 * \param book Address book.
573 * \param file XML file handle.
574 * \param group Group.
576 static void addrbook_parse_member_list(AddressBookFile *book, XMLFile *file,
583 prev_level = file->level;
584 if (xml_parse_next_tag(file)) {
585 longjmp(book->jumper, 1);
587 if (file->level < prev_level)
589 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
590 attr = xml_get_current_tag_attr(file);
591 addrbook_parse_member(book, file, group);
592 addrbook_parse_member_list(book, file, group);
595 attr = xml_get_current_tag_attr(file);
601 * Parse group object from XML file.
602 * \param book Address book.
603 * \param file XML file handle.
605 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
609 ItemGroup *group = NULL;
611 attr = xml_get_current_tag_attr(file);
613 name = ((XMLAttr *)attr->data)->name;
614 value = ((XMLAttr *)attr->data)->value;
616 group = addritem_create_item_group();
617 if (strcmp(name, AB_ATTAG_UID) == 0)
618 ADDRITEM_ID(group) = g_strdup(value);
619 else if (strcmp(name, AB_ATTAG_NAME) == 0)
620 ADDRITEM_NAME(group) = g_strdup(value);
621 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
622 group->remarks = g_strdup(value);
623 attr = g_list_next(attr);
625 if (xml_parse_next_tag(file)) { /* Consume closing tag */
626 longjmp(book->jumper, 1);
628 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
630 addrcache_hash_add_group(book->addressCache, group);
632 addrbook_parse_member_list(book, file, group);
637 * Parse folder item from XML file.
638 * \param book Address book.
639 * \param file XML file handle.
640 * \param folder Folder.
642 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
649 attr = xml_get_current_tag_attr(file);
651 name = ((XMLAttr *)attr->data)->name;
652 value = ((XMLAttr *)attr->data)->value;
653 if (strcmp(name, AB_ATTAG_UID) == 0) {
654 uid = g_strdup(value);
656 attr = g_list_next(attr);
660 folder->listItems = g_list_append(folder->listItems, uid);
666 * Parse list of folder items from XML file.
667 * \param book Address book.
668 * \param file XML file handle.
669 * \param folder Folder.
671 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
678 prev_level = file->level;
679 if (xml_parse_next_tag(file)) {
680 longjmp(book->jumper, 1);
682 if (file->level < prev_level)
684 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
685 attr = xml_get_current_tag_attr(file);
686 addrbook_parse_folder_item(book, file, folder);
687 addrbook_parse_folder_list(book, file, folder);
690 attr = xml_get_current_tag_attr(file);
696 * Parse folder from XML file.
697 * \param book Address book.
698 * \param file XML file handle.
700 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
704 ItemFolder *folder = NULL;
706 attr = xml_get_current_tag_attr(file);
708 name = ((XMLAttr *)attr->data)->name;
709 value = ((XMLAttr *)attr->data)->value;
711 folder = addritem_create_item_folder();
712 if (strcmp(name, AB_ATTAG_UID) == 0)
713 ADDRITEM_ID(folder) = g_strdup(value);
714 else if (strcmp(name, AB_ATTAG_NAME) == 0)
715 ADDRITEM_NAME(folder) = g_strdup(value);
716 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
717 folder->remarks = g_strdup(value);
718 attr = g_list_next(attr);
720 if (xml_parse_next_tag(file)) { /* Consume closing tag */
721 longjmp(book->jumper, 1);
723 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
725 if (addrcache_hash_add_folder(book->addressCache,
727 book->tempList = g_list_append(book->tempList,
729 /* We will resolve folder later */
730 ADDRITEM_PARENT(folder) = NULL;
733 addrbook_parse_folder_list(book, file, folder);
738 * Read address book (DOM) tree from file.
739 * \param book Address book.
740 * \param file XML file handle.
741 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
744 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
750 book->retVal = MGU_BAD_FORMAT;
751 if (xml_get_dtd(file))
753 if (xml_parse_next_tag(file))
754 longjmp(book->jumper, 1);
755 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
758 attr = xml_get_current_tag_attr(file);
760 name = ((XMLAttr *)attr->data)->name;
761 value = ((XMLAttr *)attr->data)->value;
762 if (strcmp( name, AB_ATTAG_NAME) == 0)
763 addrbook_set_name( book, value );
764 attr = g_list_next( attr );
771 /* Get next item tag (person, group or folder) */
772 if (xml_parse_next_tag(file))
773 longjmp( book->jumper, 1 );
775 if (xml_compare_tag(file, AB_ELTAG_PERSON))
776 addrbook_parse_person(book, file);
777 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
778 addrbook_parse_group(book, file);
779 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
780 addrbook_parse_folder(book, file);
782 if (retVal) book->retVal = MGU_SUCCESS;
787 * Resolve folder items callback function.
788 * \param key Table key.
789 * \param value Reference to object contained in folder.
790 * \param data Reference to address book.
792 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
794 AddressBookFile *book = data;
795 AddrItemObject *obj = (AddrItemObject *) value;
796 ItemFolder *rootFolder = book->addressCache->rootFolder;
797 if (obj->parent == NULL) {
798 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
799 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
801 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
803 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
804 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
806 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
812 * Resolve folder items. Lists of UID's are replaced with pointers to
814 * \param book Address book.
816 static void addrbook_resolve_folder_items(AddressBookFile *book)
818 GList *nodeFolder = NULL;
819 GList *listRemove = NULL;
821 ItemFolder *rootFolder = book->addressCache->rootFolder;
822 nodeFolder = book->tempList;
825 ItemFolder *folder = nodeFolder->data;
827 node = folder->listItems;
829 gchar *uid = node->data;
830 AddrItemObject *aio = addrcache_get_object(book->addressCache,
833 if (aio->type == ITEMTYPE_FOLDER) {
834 ItemFolder *item = (ItemFolder *) aio;
835 folder->listFolder = g_list_append(folder->listFolder, item);
836 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
837 addrcache_hash_add_folder(book->addressCache, folder);
839 else if (aio->type == ITEMTYPE_PERSON) {
840 ItemPerson *item = (ItemPerson *) aio;
841 folder->listPerson = g_list_append(folder->listPerson, item);
842 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
844 else if (aio->type == ITEMTYPE_GROUP) {
845 ItemGroup *item = (ItemGroup *) aio;
846 folder->listGroup = g_list_append(folder->listGroup, item);
847 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
849 /* Replace data with pointer to item */
853 else { /* Not found, append to remove list. */
854 listRemove = g_list_append(listRemove, uid);
856 node = g_list_next(node);
858 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
860 /* Process remove list */
863 gchar *uid = node->data;
864 folder->listItems = g_list_remove(folder->listItems,
867 node = g_list_next(node);
869 g_list_free(listRemove);
870 nodeFolder = g_list_next(nodeFolder);
872 /* Remove folders with parents. */
874 node = rootFolder->listFolder;
876 ItemFolder *folder = (ItemFolder *) node->data;
877 if (ADDRITEM_PARENT(folder))
878 /* Remove folders with parents */
879 listRemove = g_list_append(listRemove, folder);
880 else /* Add to root folder */
881 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
883 node = g_list_next( node );
885 /* Process remove list */
888 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
890 node = g_list_next(node);
892 g_list_free(listRemove);
894 /* Move all unparented persons and groups into root folder */
895 g_hash_table_foreach(book->addressCache->itemHash,
896 addrbook_res_items_vis, book);
898 /* Free up some more */
899 nodeFolder = book->tempList;
901 ItemFolder *folder = nodeFolder->data;
902 g_list_free(folder->listItems);
903 folder->listItems = NULL;
904 nodeFolder = g_list_next(nodeFolder);
906 g_list_free(book->tempList);
907 book->tempList = NULL;
912 * \param book Address book.
913 * \return Status code.
915 gint addrbook_read_data(AddressBookFile *book)
917 XMLFile *file = NULL;
918 gchar *fileSpec = NULL;
920 g_return_val_if_fail(book != NULL, -1);
923 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
924 addrcache_get_name( book->addressCache ) );
927 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
928 book->fileName, NULL);
929 book->retVal = MGU_OPEN_FILE;
930 addrcache_clear(book->addressCache);
931 book->addressCache->modified = FALSE;
932 book->addressCache->accessFlag = FALSE;
933 file = xml_open_file(fileSpec);
936 book->tempList = NULL;
937 /* Trap for parsing errors. */
938 if (setjmp( book->jumper)) {
939 xml_close_file(file);
942 addrbook_read_tree(book, file);
943 xml_close_file(file);
944 /* Resolve folder items */
945 addrbook_resolve_folder_items(book);
946 book->tempList = NULL;
947 book->addressCache->modified = FALSE;
948 book->addressCache->dataRead = TRUE;
949 addrcache_set_dirty(book->addressCache, FALSE);
955 * Write start element to file.
956 * \param fp File handle.
957 * \param lvl Indent level.
958 * \param name Element name.
960 static void addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
963 for (i = 0; i < lvl; i++)
970 * Write end element to file.
971 * \param fp File handle.
972 * \param lvl Indent level.
973 * \param name Element name.
975 static void addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
978 for(i = 0; i < lvl; i++)
986 * Write attribute name/value pair to file.
987 * \param fp File handle.
988 * \param name Attribute name.
989 * \param value Attribute value.
991 static void addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
996 xml_file_put_escape_str(fp, value);
1001 * Write person and associated addresses and attributes to file.
1002 * file hash table visitor function.
1003 * \param key Table key.
1004 * \param value Reference to person.
1005 * \param data File pointer.
1007 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1010 AddrItemObject *obj = (AddrItemObject *) value;
1011 FILE *fp = (FILE *) data;
1016 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1017 ItemPerson *person = (ItemPerson *) value;
1019 addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON);
1020 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person));
1021 addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName);
1022 addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName);
1023 addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName);
1024 addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person));
1027 /* Output email addresses */
1028 addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST);
1030 node = person->listEMail;
1032 ItemEMail *email = node->data;
1033 addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS);
1034 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email));
1035 addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email));
1036 addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address);
1037 addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks);
1039 node = g_list_next(node);
1041 addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST);
1043 /* Output user attributes */
1044 addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1046 node = person->listAttrib;
1048 UserAttribute *attrib = node->data;
1049 addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE);
1050 addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid);
1051 addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name);
1053 xml_file_put_escape_str(fp, attrib->value);
1054 addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE);
1055 node = g_list_next(node);
1057 addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST);
1058 addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON);
1064 * Write group and associated references to addresses to file.
1065 * file hash table visitor function.
1066 * \param key Table key.
1067 * \param value Reference to group.
1068 * \param data File pointer.
1070 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1073 AddrItemObject *obj = (AddrItemObject *) value;
1074 FILE *fp = (FILE *) data;
1079 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1080 ItemGroup *group = (ItemGroup *) value;
1082 addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP);
1083 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group));
1084 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group));
1085 addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks);
1088 /* Output email address links */
1089 addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST);
1091 node = group->listEMail;
1093 ItemEMail *email = node->data;
1094 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1095 addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER);
1096 addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person));
1097 addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email));
1099 node = g_list_next(node);
1101 addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST);
1102 addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP);
1108 * Write folder and associated references to addresses to file.
1109 * file hash table visitor function.
1110 * \param key Table key.
1111 * \param value Reference to folder.
1112 * \param data File pointer.
1114 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1117 AddrItemObject *obj = (AddrItemObject *) value;
1118 FILE *fp = (FILE *) data;
1123 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1124 ItemFolder *folder = (ItemFolder *) value;
1126 addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER);
1127 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder));
1128 addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder));
1129 addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks);
1131 addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST);
1134 /* Output persons */
1135 node = folder->listPerson;
1137 ItemPerson *item = node->data;
1138 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1139 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON);
1140 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1142 node = g_list_next(node);
1146 node = folder->listGroup;
1148 ItemGroup *item = node->data;
1149 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1150 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP);
1151 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1153 node = g_list_next(node);
1156 /* Output folders */
1157 node = folder->listFolder;
1159 ItemFolder *item = node->data;
1160 addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM);
1161 addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER);
1162 addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item));
1164 node = g_list_next(node);
1166 addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST);
1167 addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER);
1173 * Output address book data to specified file.
1174 * \param book Address book.
1175 * \param newFile Filename of new file (in book's filepath).
1176 * \return Status code.
1178 static gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1182 #ifndef DEV_STANDALONE
1186 g_return_val_if_fail(book != NULL, -1);
1187 g_return_val_if_fail(newFile != NULL, -1);
1189 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1191 book->retVal = MGU_OPEN_FILE;
1192 #ifdef DEV_STANDALONE
1193 fp = g_fopen(fileSpec, "wb");
1196 fputs("<?xml version=\"1.0\" ?>\n", fp);
1198 pfile = prefs_write_open(fileSpec);
1202 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
1204 addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1205 addrbook_write_attr(fp, AB_ATTAG_NAME,
1206 addrcache_get_name(book->addressCache));
1209 /* Output all persons */
1210 g_hash_table_foreach(book->addressCache->itemHash,
1211 addrbook_write_item_person_vis, fp);
1213 /* Output all groups */
1214 g_hash_table_foreach(book->addressCache->itemHash,
1215 addrbook_write_item_group_vis, fp);
1217 /* Output all folders */
1218 g_hash_table_foreach(book->addressCache->itemHash,
1219 addrbook_write_item_folder_vis, fp);
1221 addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK);
1222 book->retVal = MGU_SUCCESS;
1223 #ifdef DEV_STANDALONE
1226 if (prefs_file_close( pfile ) < 0)
1227 book->retVal = MGU_ERROR_WRITE;
1232 return book->retVal;
1236 * Output address book data to original file.
1237 * \param book Address book.
1238 * \return Status code.
1240 gint addrbook_save_data(AddressBookFile *book)
1242 g_return_val_if_fail(book != NULL, -1);
1244 book->retVal = MGU_NO_FILE;
1245 if (book->fileName == NULL || *book->fileName == '\0')
1246 return book->retVal;
1247 if (book->path == NULL || *book->path == '\0')
1248 return book->retVal;
1250 addrbook_write_to(book, book->fileName);
1251 if (book->retVal == MGU_SUCCESS)
1252 addrcache_set_dirty(book->addressCache, FALSE);
1253 return book->retVal;
1257 * **********************************************************************
1258 * Address book edit interface functions.
1259 * **********************************************************************
1263 * Hash table callback function for simple deletion of hashtable entries.
1264 * \param key Table key (will be freed).
1265 * \param value Value stored in table.
1266 * \param data User data.
1267 * \return <i>TRUE</i> to indicate that entry freed.
1269 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1279 * Update address book email list for specified person. Note: The existing
1280 * email addresses are replaced with the new addresses. Any references to
1281 * old addresses in the groups are re-linked to the new addresses. All old
1282 * addresses linked to the person are removed.
1283 * \param book Address book.
1284 * \param person Person to update.
1285 * \param listEMail List of new email addresses.
1287 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1294 g_return_if_fail(book != NULL);
1295 g_return_if_fail(person != NULL);
1297 /* Get groups where person's existing email addresses are listed */
1298 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1300 GHashTable *hashEMail;
1301 GHashTable *hashEMailAlias;
1304 /* Load hash table with new address entries */
1305 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1306 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1309 ItemEMail *email = node->data;
1310 gchar *addr = g_strdup(email->address);
1311 gchar *alias = email->obj.name ;
1313 if (!g_hash_table_lookup(hashEMail, addr)) {
1314 g_hash_table_insert(hashEMail, addr, email);
1316 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1318 g_hash_table_insert(hashEMailAlias, alias, email);
1320 node = g_list_next(node);
1323 /* Re-parent new addresses to existing groups, where email address match. */
1324 nodeGrp = listGroup;
1326 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1327 GList *groupEMail = group->listEMail;
1329 GList *listRemove = NULL;
1331 /* Process each email item linked to group */
1332 nodeGrpEM = groupEMail;
1334 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1336 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1337 /* Found an email address for this person */
1338 ItemEMail *emailNew = NULL;
1339 gchar *addr = g_strdup(emailGrp->address);
1340 gchar *alias = emailGrp->obj.name;
1342 emailNew = (ItemEMail *)
1343 g_hash_table_lookup(hashEMail, addr);
1345 /* If no match by e-mail, try to match by e-mail alias */
1346 if (!emailNew && *alias != '\0') {
1347 emailNew = (ItemEMail *)
1348 g_hash_table_lookup(hashEMailAlias, alias);
1352 /* Point to this entry */
1353 nodeGrpEM->data = emailNew;
1354 else if (g_hash_table_size(hashEMail)==1)
1355 /* If the person has just one e-mail address, then
1356 change e-mail address in group list */
1357 nodeGrpEM->data = listEMail->data;
1359 /* Mark for removal */
1360 listRemove = g_list_append(listRemove, emailGrp);
1362 /* Move on to next email link */
1363 nodeGrpEM = g_list_next(nodeGrpEM);
1366 /* Process all removed links in current group */
1367 nodeGrpEM = listRemove;
1369 ItemEMail *emailGrp = nodeGrpEM->data;
1370 groupEMail = g_list_remove(groupEMail, emailGrp);
1371 nodeGrpEM = g_list_next(nodeGrpEM);
1374 g_list_free(listRemove);
1376 /* Move on to next group */
1377 nodeGrp = g_list_next(nodeGrp);
1380 /* Clear hash table */
1381 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1382 addrbook_free_simple_hash_vis, NULL);
1383 g_hash_table_destroy(hashEMail);
1385 g_hash_table_destroy(hashEMailAlias);
1386 hashEMailAlias = NULL;
1387 g_list_free(listGroup);
1390 /* Remove old addresses from person and cache */
1392 node = person->listEMail;
1394 ItemEMail *email = node->data;
1396 if (addrcache_person_remove_email(book->addressCache, person, email))
1397 addrcache_remove_email(book->addressCache, email);
1399 listDelete = g_list_append(listDelete, email);
1400 node = person->listEMail;
1402 /* Add new address entries */
1405 ItemEMail *email = node->data;
1407 if (ADDRITEM_ID(email) == NULL)
1408 /* Allocate an ID for new address */
1409 addrcache_id_email(book->addressCache, email);
1411 addrcache_person_add_email( book->addressCache, person, email );
1412 node = g_list_next( node );
1415 addrcache_set_dirty(book->addressCache, TRUE);
1417 /* Free up memory */
1418 g_list_free(listEMail);
1423 ItemEMail *email = node->data;
1425 addritem_free_item_email(email);
1426 node = g_list_next(node);
1428 g_list_free(listDelete);
1434 * Create person object and add person with specified address data to address
1435 * book. Note: A new person is created with specified list of email addresses.
1436 * All objects inserted into address book.
1438 * \param book Address book.
1439 * \param folder Parent folder where to add person, or <i>NULL</i> for
1441 * \param listEMail List of new email addresses to associate with person.
1442 * \return Person object created.
1444 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1448 ItemFolder *f = folder;
1451 g_return_val_if_fail(book != NULL, NULL);
1454 f = book->addressCache->rootFolder;
1455 person = addritem_create_item_person();
1456 addrcache_id_person(book->addressCache, person);
1457 addrcache_folder_add_person(book->addressCache, f, person);
1461 ItemEMail *email = node->data;
1462 if (ADDRITEM_ID(email) == NULL)
1463 addrcache_id_email(book->addressCache, email);
1465 addrcache_person_add_email(book->addressCache, person, email);
1466 node = g_list_next(node);
1472 * Build available email list visitor function.
1473 * \param key Table key.
1474 * \param value Value stored in table.
1475 * \param data Reference to address book.
1477 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1480 AddrItemObject *obj = (AddrItemObject *) value;
1482 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1483 AddressBookFile *book = data;
1484 ItemPerson *person = (ItemPerson *) obj;
1485 GList *node = person->listEMail;
1487 ItemEMail *email = node->data;
1488 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1490 if (!g_hash_table_lookup(book->tempHash,
1491 ADDRITEM_ID(email)))
1492 book->tempList = g_list_append(book->tempList, email);
1494 node = g_list_next(node);
1500 * Return link list of available email items that have not already been linked
1501 * to groups. Note that the list contains references to items and should be
1502 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1503 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1506 * \param book Address book.
1507 * \param group Group to process.
1508 * \return List of items, or <i>NULL</i> if none.
1510 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1515 g_return_val_if_fail(book != NULL, NULL);
1517 /* Load hash table with group email entries */
1518 table = g_hash_table_new(g_str_hash, g_str_equal);
1520 list = group->listEMail;
1522 ItemEMail *email = list->data;
1523 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1524 list = g_list_next(list);
1528 /* Build list of available email addresses which exclude those already in groups */
1529 book->tempList = NULL;
1530 book->tempHash = table;
1531 g_hash_table_foreach(book->addressCache->itemHash,
1532 addrbook_build_avail_email_vis, book);
1533 list = book->tempList;
1534 book->tempList = NULL;
1535 book->tempHash = NULL;
1537 /* Clear hash table */
1538 g_hash_table_destroy(table);
1545 * Update address book email list for specified group. Note: The existing email
1546 * addresses are replaced with the new addresses. Any references to old addresses
1547 * in the groups are re-linked to the new addresses. All old addresses linked to
1548 * the person are removed.
1550 * \param book Address book.
1551 * \param group Group to process.
1552 * \param listEMail List of email items. This should <b>*NOT*</b> be
1553 * <code>g_free()</code> when done.
1555 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1560 g_return_if_fail(book != NULL);
1561 g_return_if_fail(group != NULL);
1563 addrcache_set_dirty(book->addressCache, TRUE);
1565 /* Remember old list */
1566 oldData = group->listEMail;
1567 group->listEMail = listEMail;
1568 mgu_clear_list(oldData);
1573 * Create group object and add with specifed list of email addresses to
1574 * address book. Note: The existing email addresses are replaced with the new
1575 * addresses. Any references to old addresses in the groups are re-linked to
1576 * the new addresses. All old addresses linked to the person are removed.
1578 * \param book Address book.
1579 * \param folder Parent folder where to add group, or <i>NULL</i> for
1581 * \param listEMail List of email items. This should <b>*NOT*</b> be
1582 * <code>g_free()</code> when done.
1583 * \return Group object created.
1585 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1588 ItemGroup *group = NULL;
1589 ItemFolder *f = folder;
1591 g_return_val_if_fail(book != NULL, NULL);
1594 f = book->addressCache->rootFolder;
1595 group = addritem_create_item_group();
1596 addrcache_id_group(book->addressCache, group);
1597 addrcache_folder_add_group(book->addressCache, f, group);
1598 group->listEMail = listEMail;
1603 * Create a new folder and add to address book.
1604 * \param book Address book.
1605 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1607 * \return Folder that was created. This should <b>*NOT*</b> be
1608 * <code>g_free()</code> when done.
1610 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1612 g_return_val_if_fail(book != NULL, NULL);
1613 return addrcache_add_new_folder( book->addressCache, parent );
1617 * Update address book attribute list for specified person. Note: The existing
1618 * attributes are replaced with the new addresses. All old attributes linked
1619 * to the person are removed.
1621 * \param book Address book.
1622 * \param person Person to receive attributes.
1623 * \param listAttrib New list of attributes.
1625 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1631 g_return_if_fail(book != NULL);
1632 g_return_if_fail(person != NULL);
1634 /* Remember old list */
1635 oldData = person->listAttrib;
1637 /* Attach new address list to person. */
1640 UserAttribute *attrib = node->data;
1641 if (attrib->uid == NULL) {
1642 /* Allocate an ID */
1643 addrcache_id_attribute(book->addressCache, attrib);
1645 node = g_list_next(node);
1647 person->listAttrib = listAttrib;
1648 addrcache_set_dirty(book->addressCache, TRUE);
1650 /* Free up old data */
1651 addritem_free_list_attribute(oldData);
1656 * Add attribute data for specified person to address book. Note: Only
1657 * attributes are inserted into address book.
1658 * \param book Address book.
1659 * \param person Person to receive attributes.
1660 * \param listAttrib List of attributes.
1662 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1665 g_return_if_fail( book != NULL );
1666 g_return_if_fail( person != NULL );
1670 UserAttribute *attrib = node->data;
1671 if( attrib->uid == NULL ) {
1672 addrcache_id_attribute( book->addressCache, attrib );
1674 addritem_person_add_attribute( person, attrib );
1675 node = g_list_next( node );
1677 addrcache_set_dirty( book->addressCache, TRUE );
1680 #define WORK_BUFLEN 1024
1681 #define ADDRBOOK_DIGITS "0123456789"
1684 * Return list of existing address book files.
1685 * \param book Address book.
1686 * \return List of files (as strings).
1688 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1691 const gchar *dir_name;
1692 struct stat statbuf;
1693 gchar buf[WORK_BUFLEN];
1694 gchar numbuf[WORK_BUFLEN];
1695 gint len, lenpre, lensuf, lennum;
1696 long int val, maxval;
1697 GList *fileList = NULL;
1699 g_return_val_if_fail(book != NULL, NULL);
1701 if (book->path == NULL || *book->path == '\0') {
1702 book->retVal = MGU_NO_PATH;
1706 strcpy(buf, book->path);
1709 if (buf[len-1] != G_DIR_SEPARATOR) {
1710 buf[len] = G_DIR_SEPARATOR;
1715 adbookdir = g_strdup(buf);
1716 strcat(buf, ADDRBOOK_PREFIX);
1718 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1719 book->retVal = MGU_OPEN_DIRECTORY;
1724 lenpre = strlen(ADDRBOOK_PREFIX);
1725 lensuf = strlen(ADDRBOOK_SUFFIX);
1726 lennum = FILE_NUMDIGITS + lenpre;
1729 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1730 gchar *endptr = NULL;
1734 strcpy(buf, adbookdir);
1735 strcat( buf, dir_name );
1736 stat(buf, &statbuf);
1737 if (S_ISREG(statbuf.st_mode)) {
1740 ADDRBOOK_PREFIX, lenpre) == 0)
1743 (dir_name) + lennum,
1744 ADDRBOOK_SUFFIX, lensuf) == 0)
1747 (dir_name) + lenpre,
1749 numbuf[FILE_NUMDIGITS] = '\0';
1751 for(i = 0; i < FILE_NUMDIGITS; i++) {
1752 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1759 val = strtol(numbuf, &endptr, 10);
1760 if (endptr && val > -1) {
1761 if (val > maxval) maxval = val;
1762 fileList = g_list_append(
1764 g_strdup(dir_name));
1774 book->maxValue = maxval;
1775 book->retVal = MGU_SUCCESS;
1780 * Return file name for specified file number.
1781 * \param fileNum File number.
1782 * \return File name, or <i>NULL</i> if file number too large. Should be
1783 * <code>g_free()</code> when done.
1785 gchar *addrbook_gen_new_file_name(gint fileNum) {
1787 gchar buf[WORK_BUFLEN];
1793 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1796 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1797 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1798 return g_strdup(buf);
1802 * **********************************************************************
1803 * Address book test functions...
1804 * **********************************************************************
1808 * Attempt to parse list of email address from file.
1809 * \param book Address book.
1810 * \param file XML file handle.
1812 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1817 prev_level = file->level;
1818 if (xml_parse_next_tag(file))
1819 longjmp(book->jumper, 1);
1820 if (file->level < prev_level)
1822 attr = xml_get_current_tag_attr(file);
1823 /* addrbook_show_attribs( attr ); */
1824 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1825 addrbook_chkparse_addr_list(book, file);
1830 * Attempt to parse attributes for person address from file.
1831 * \param book Address book.
1832 * \param file XML file handle.
1834 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1839 attr = xml_get_current_tag_attr(file);
1840 /* addrbook_show_attribs( attr ); */
1841 element = xml_get_element(file);
1842 /* g_print( "\t\tattrib value : %s\n", element ); */
1846 * Attempt to parse list of attributes for person address from file.
1847 * \param book Address book.
1848 * \param file XML file handle.
1850 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1855 prev_level = file->level;
1856 if (xml_parse_next_tag(file))
1857 longjmp(book->jumper, 1);
1858 if (file->level < prev_level)
1860 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1861 addrbook_chkparse_attribute(book, file);
1862 addrbook_chkparse_attr_list(book, file);
1868 * Attempt to parse person from file.
1869 * \param book Address book.
1870 * \param file XML file handle.
1872 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1876 attr = xml_get_current_tag_attr(file);
1877 /* addrbook_show_attribs( attr ); */
1878 if (xml_parse_next_tag(file)) /* Consume closing tag */
1879 longjmp(book->jumper, 1);
1881 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1882 addrbook_chkparse_addr_list(book, file);
1884 if (xml_parse_next_tag(file)) /* Consume closing tag */
1885 longjmp(book->jumper, 1);
1887 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1888 addrbook_chkparse_attr_list(book, file);
1892 * Attempt to parse list of members from file.
1893 * \param book Address book.
1894 * \param file XML file handle.
1896 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
1902 prev_level = file->level;
1903 if (xml_parse_next_tag(file))
1904 longjmp(book->jumper, 1);
1906 if (file->level < prev_level)
1909 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
1910 attr = xml_get_current_tag_attr(file);
1911 /* addrbook_show_attribs( attr ); */
1912 addrbook_chkparse_member_list(book, file);
1915 attr = xml_get_current_tag_attr(file);
1916 /* addrbook_show_attribs( attr ); */
1922 * Attempt to parse group from file.
1923 * \param book Address book.
1924 * \param file XML file handle.
1926 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
1930 attr = xml_get_current_tag_attr(file);
1931 /* addrbook_show_attribs( attr ); */
1932 if (xml_parse_next_tag(file)) /* Consume closing tag */
1933 longjmp(book->jumper, 1);
1935 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
1936 addrbook_chkparse_member_list(book, file);
1940 * Attempt to parse list of folders from file.
1941 * \param book Address book.
1942 * \param file XML file handle.
1944 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
1950 prev_level = file->level;
1951 if (xml_parse_next_tag(file))
1952 longjmp(book->jumper, 1);
1954 if (file->level < prev_level)
1957 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
1958 attr = xml_get_current_tag_attr(file);
1959 /* addrbook_show_attribs( attr ); */
1960 addrbook_chkparse_folder_list(book, file);
1963 attr = xml_get_current_tag_attr(file);
1964 /* addrbook_show_attribs( attr ); */
1970 * Attempt to parse a folder from file.
1971 * \param book Address book.
1972 * \param file XML file handle.
1974 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
1978 attr = xml_get_current_tag_attr(file);
1979 /* addrbook_show_attribs( attr ); */
1980 if (xml_parse_next_tag(file)) /* Consume closing tag */
1981 longjmp(book->jumper, 1);
1983 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
1984 addrbook_chkparse_folder_list(book, file);
1988 * Attempt to parse (DOM) tree from file.
1989 * \param book Address book.
1990 * \param file XML file handle.
1992 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
1997 if (xml_get_dtd(file))
2000 if (xml_parse_next_tag(file))
2003 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2006 attr = xml_get_current_tag_attr(file);
2007 /* addrbook_show_attribs( attr ); */
2014 if (xml_parse_next_tag(file))
2015 longjmp(book->jumper, 1);
2017 /* Get next tag (person, group or folder) */
2018 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2019 addrbook_chkparse_person( book, file );
2020 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2021 addrbook_chkparse_group(book, file);
2022 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2023 addrbook_chkparse_folder(book, file);
2029 * Test address book file by parsing contents.
2030 * \param book Address book.
2031 * \param fileName Filename of XML file.
2032 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2034 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2036 XMLFile *file = NULL;
2037 gchar *fileSpec = NULL;
2039 g_return_val_if_fail(book != NULL, -1);
2041 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2042 book->retVal = MGU_OPEN_FILE;
2043 file = xml_open_file(fileSpec);
2046 book->retVal = MGU_BAD_FORMAT;
2047 if (setjmp(book->jumper)) {
2048 /* g_print( "Caught Ya!!!\n" ); */
2049 xml_close_file(file);
2050 return book->retVal;
2052 if (addrbook_chkread_tree(book, file))
2053 book->retVal = MGU_SUCCESS;
2055 xml_close_file( file );
2057 return book->retVal;
2061 * Return link list of all persons in address book. Note that the list
2062 * contains references to items. Do <b>*NOT*</b> attempt to use the
2063 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2065 * \param book Address book.
2066 * \return List of persons, or NULL if none.
2068 GList *addrbook_get_all_persons(AddressBookFile *book)
2070 g_return_val_if_fail(book != NULL, NULL);
2071 return addrcache_get_all_persons(book->addressCache);
2074 GList *addrbook_get_all_groups(AddressBookFile *book)
2076 g_return_val_if_fail(book != NULL, NULL);
2077 return addrcache_get_all_groups(book->addressCache);
2081 * Add person and address data to address book.
2082 * \param book Address book.
2083 * \param folder Folder where to add person, or NULL for root folder.
2084 * \param name Common name.
2085 * \param address EMail address.
2086 * \param remarks Remarks.
2087 * \return Person added. Do not <b>*NOT*</b> to use the
2088 * <code>addrbook_free_xxx()</code> functions... this will destroy
2089 * the address book data.
2091 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2092 const gchar *name,const gchar *address,
2093 const gchar *remarks)
2097 g_return_val_if_fail(book != NULL, NULL);
2098 person = addrcache_add_contact(
2099 book->addressCache, folder, name, address, remarks );
2104 * Return file name for next address book file.
2105 * \param book Address book.
2106 * \return File name, or <i>NULL</i> if could not create. This should be
2107 * <code>g_free()</code> when done.
2109 gchar *addrbook_guess_next_file(AddressBookFile *book)
2111 gchar *newFile = NULL;
2112 GList *fileList = NULL;
2114 fileList = addrbook_get_bookfile_list(book);
2116 fileNum = 1 + book->maxValue;
2118 newFile = addrbook_gen_new_file_name(fileNum);
2119 g_list_free(fileList);