2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2012 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 */
33 #include "addrcache.h"
35 #include "adbookbase.h"
38 #ifndef DEV_STANDALONE
39 #include "prefs_gtk.h"
43 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
44 #define ADDRBOOK_PREFIX "addrbook-"
45 #define ADDRBOOK_SUFFIX ".xml"
46 #define FILE_NUMDIGITS 6
48 #define ID_TIME_OFFSET 998000000
50 static void addrbook_print_book ( AddressBookFile *book, FILE *stream );
53 * Create new address book
54 * \return Address book.
56 AddressBookFile *addrbook_create_book()
58 AddressBookFile *book;
60 book = g_new0(AddressBookFile, 1);
61 book->type = ADBOOKTYPE_BOOK;
62 book->addressCache = addrcache_create();
63 book->retVal = MGU_SUCCESS;
65 book->fileName = NULL;
67 book->tempList = NULL;
68 book->tempHash = NULL;
69 book->addressCache->modified = TRUE;
75 * Specify name to be used
76 * \param book Address book.
79 void addrbook_set_name(AddressBookFile *book, const gchar *value)
81 cm_return_if_fail(book != NULL);
82 addrcache_set_name(book->addressCache, value);
85 gchar *addrbook_get_name(AddressBookFile *book)
87 cm_return_val_if_fail(book != NULL, NULL);
88 return addrcache_get_name(book->addressCache);
92 * Specify path to address book file.
93 * \param book Address book.
96 void addrbook_set_path(AddressBookFile *book, const gchar *value)
98 cm_return_if_fail(book != NULL);
99 book->path = mgu_replace_string(book->path, value);
100 addrcache_set_dirty(book->addressCache, TRUE);
104 * Specify filename to be used
105 * \param book Address book.
106 * \param value Filename.
108 void addrbook_set_file(AddressBookFile *book, const gchar *value)
110 cm_return_if_fail(book != NULL);
111 book->fileName = mgu_replace_string(book->fileName, value);
112 addrcache_set_dirty(book->addressCache, TRUE);
115 gboolean addrbook_get_modified(AddressBookFile *book)
117 cm_return_val_if_fail(book != NULL, FALSE);
118 return book->addressCache->modified;
121 gboolean addrbook_get_accessed(AddressBookFile *book)
123 cm_return_val_if_fail(book != NULL, FALSE);
124 return book->addressCache->accessFlag;
128 * Specify address book as accessed.
129 * \param book Address book.
130 * \param value Value.
132 void addrbook_set_accessed(AddressBookFile *book, const gboolean value)
134 cm_return_if_fail(book != NULL);
135 book->addressCache->accessFlag = value;
138 gboolean addrbook_get_read_flag(AddressBookFile *book)
140 cm_return_val_if_fail(book != NULL, FALSE);
141 return book->addressCache->dataRead;
144 gint addrbook_get_status(AddressBookFile *book)
146 cm_return_val_if_fail(book != NULL, -1);
150 ItemFolder *addrbook_get_root_folder(AddressBookFile *book)
152 cm_return_val_if_fail(book != NULL, NULL);
153 return addrcache_get_root_folder(book->addressCache);
156 GList *addrbook_get_list_folder(AddressBookFile *book)
158 cm_return_val_if_fail(book != NULL, NULL);
159 return addrcache_get_list_folder(book->addressCache);
162 GList *addrbook_get_list_person(AddressBookFile *book)
164 cm_return_val_if_fail(book != NULL, NULL);
165 return addrcache_get_list_person(book->addressCache);
168 gboolean addrbook_get_dirty(AddressBookFile *book)
170 cm_return_val_if_fail(book != NULL, FALSE);
171 return addrcache_get_dirty(book->addressCache);
175 * Set address book as dirty (needs to be written to file).
176 * \param book Address book.
177 * \param value Dirty flag.
179 void addrbook_set_dirty(AddressBookFile *book, const gboolean value)
181 cm_return_if_fail(book != NULL);
182 addrcache_set_dirty(book->addressCache, value);
187 * \param book Address book.
189 void addrbook_free_book(AddressBookFile *book)
191 cm_return_if_fail(book != NULL);
194 addrcache_free(book->addressCache);
196 /* Free up internal objects */
198 g_free(book->fileName);
199 g_list_free(book->tempList);
202 book->fileName = NULL;
204 book->tempList = NULL;
205 book->tempHash = NULL;
207 book->type = ADBOOKTYPE_NONE;
208 book->addressCache = NULL;
209 book->retVal = MGU_SUCCESS;
215 * Print address book header.
216 * \param book Address book.
217 * \param stream Output stream.
219 static void addrbook_print_book(AddressBookFile *book, FILE *stream)
221 cm_return_if_fail(book != NULL);
223 fprintf(stream, "AddressBook:\n");
224 fprintf(stream, "\tpath : '%s'\n", book->path);
225 fprintf(stream, "\tfile : '%s'\n", book->fileName);
226 fprintf(stream, "\tstatus : %d\n", book->retVal );
227 addrcache_print(book->addressCache, stream);
231 * Dump entire address book traversing folders.
232 * \param book Address book.
233 * \param stream Output stream.
235 void addrbook_dump_book(AddressBookFile *book, FILE *stream)
239 cm_return_if_fail(book != NULL);
241 addrbook_print_book(book, stream);
242 folder = book->addressCache->rootFolder;
243 addritem_print_item_folder(folder, stream);
247 * Remove specified group from address book. Note that object should still
249 * Specify name to be used
250 * \param book Address book.
251 * \param group Group to remove.
253 * \return Group, or NULL if not found.
255 ItemGroup *addrbook_remove_group(AddressBookFile *book, ItemGroup *group)
257 cm_return_val_if_fail(book != NULL, NULL);
258 return addrcache_remove_group(book->addressCache, group);
262 * Remove specified person from address book. Note that object should still
264 * \param book Address book.
265 * \param person Person to remove.
266 * \return Person, or NULL if not found.
268 ItemPerson *addrbook_remove_person(AddressBookFile *book, ItemPerson *person)
270 cm_return_val_if_fail(book != NULL, NULL);
271 return addrcache_remove_person(book->addressCache, person);
275 * Remove specified email address in address book for specified person.
276 * Note that object should still be freed.
277 * \param book Address book.
278 * \param person Person.
279 * \param email EMail to remove.
280 * \return EMail object, or NULL if not found.
282 ItemEMail *addrbook_person_remove_email(AddressBookFile *book,
283 ItemPerson *person, ItemEMail *email)
285 cm_return_val_if_fail(book != NULL, NULL);
286 return addrcache_person_remove_email(book->addressCache, person, email);
290 * ***********************************************************************
291 * Read/Write XML data file...
292 * ===========================
294 * 1) The address book is structured as follows:
309 * 2) This sequence of elements was chosen so that the most important
310 * elements (person and their email addresses) appear first.
312 * 3) Groups then appear. When groups are loaded, person's email
313 * addresses have already been loaded and can be found.
315 * 4) Finally folders are loaded. Any forward and backward references
316 * to folders, groups and persons in the folders are resolved after
319 * ***********************************************************************
322 /* Element tag names */
323 #define AB_ELTAG_ADDRESS "address"
324 #define AB_ELTAG_ATTRIBUTE "attribute"
325 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
326 #define AB_ELTAG_ADDRESS_LIST "address-list"
327 #define AB_ELTAG_MEMBER "member"
328 #define AB_ELTAG_MEMBER_LIST "member-list"
329 #define AB_ELTAG_ITEM "item"
330 #define AB_ELTAG_ITEM_LIST "item-list"
331 #define AB_ELTAG_ADDRESS_BOOK "address-book"
332 #define AB_ELTAG_PERSON "person"
333 #define AB_ELTAG_GROUP "group"
334 #define AB_ELTAG_FOLDER "folder"
336 /* Attribute tag names */
337 #define AB_ATTAG_TYPE "type"
338 #define AB_ATTAG_UID "uid"
339 #define AB_ATTAG_NAME "name"
340 #define AB_ATTAG_REMARKS "remarks"
341 #define AB_ATTAG_FIRST_NAME "first-name"
342 #define AB_ATTAG_LAST_NAME "last-name"
343 #define AB_ATTAG_NICK_NAME "nick-name"
344 #define AB_ATTAG_COMMON_NAME "cn"
345 #define AB_ATTAG_ALIAS "alias"
346 #define AB_ATTAG_EMAIL "email"
347 #define AB_ATTAG_EID "eid"
348 #define AB_ATTAG_PID "pid"
350 /* Attribute values */
351 #define AB_ATTAG_VAL_PERSON "person"
352 #define AB_ATTAG_VAL_GROUP "group"
353 #define AB_ATTAG_VAL_FOLDER "folder"
356 * Parse address item for person from XML file.
357 * \param book Address book.
358 * \param file XML file handle.
359 * \param person Person.
361 static void addrbook_parse_address(AddressBookFile *book, XMLFile *file,
366 ItemEMail *email = NULL;
368 attr = xml_get_current_tag_attr(file);
370 name = ((XMLAttr *)attr->data)->name;
371 value = ((XMLAttr *)attr->data)->value;
373 email = addritem_create_item_email();
374 if (strcmp(name, AB_ATTAG_UID) == 0)
375 ADDRITEM_ID(email) = g_strdup(value);
376 else if (strcmp(name, AB_ATTAG_ALIAS) == 0)
377 ADDRITEM_NAME(email) = g_strdup(value);
378 else if (strcmp(name, AB_ATTAG_EMAIL) == 0)
379 email->address = g_strdup(value);
380 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
381 email->remarks = g_strdup(value);
382 attr = g_list_next(attr);
386 addrcache_person_add_email(book->addressCache, person,
390 addritem_free_item_email(email);
397 * Parse list of email address for person from XML file.
398 * \param book Address book.
399 * \param file XML file handle.
400 * \param person Person.
402 static void addrbook_parse_addr_list(AddressBookFile *book, XMLFile *file,
408 prev_level = file->level;
409 if (xml_parse_next_tag(file)) {
410 longjmp(book->jumper, 1);
412 if (file->level < prev_level) return;
413 if (xml_compare_tag(file, AB_ELTAG_ADDRESS)) {
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,
472 prev_level = file->level;
473 if (xml_parse_next_tag(file)) {
474 longjmp( book->jumper, 1 );
476 if (file->level < prev_level) return;
477 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
478 addrbook_parse_attribute(file, person);
479 addrbook_parse_attr_list(book, file, person);
485 * Parse person from XML file.
486 * \param book Address book.
487 * \param file XML file handle.
489 static void addrbook_parse_person(AddressBookFile *book, XMLFile *file)
493 ItemPerson *person = NULL;
495 attr = xml_get_current_tag_attr(file);
497 name = ((XMLAttr *)attr->data)->name;
498 value = ((XMLAttr *)attr->data)->value;
500 person = addritem_create_item_person();
501 if (strcmp(name, AB_ATTAG_UID) == 0) {
502 ADDRITEM_ID(person) = g_strdup(value);
503 person->picture = 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,
582 prev_level = file->level;
583 if (xml_parse_next_tag(file)) {
584 longjmp(book->jumper, 1);
586 if (file->level < prev_level)
588 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
589 addrbook_parse_member(book, file, group);
590 addrbook_parse_member_list(book, file, group);
596 * Parse group object from XML file.
597 * \param book Address book.
598 * \param file XML file handle.
600 static void addrbook_parse_group(AddressBookFile *book, XMLFile *file)
604 ItemGroup *group = NULL;
606 attr = xml_get_current_tag_attr(file);
608 name = ((XMLAttr *)attr->data)->name;
609 value = ((XMLAttr *)attr->data)->value;
611 group = addritem_create_item_group();
612 if (strcmp(name, AB_ATTAG_UID) == 0)
613 ADDRITEM_ID(group) = g_strdup(value);
614 else if (strcmp(name, AB_ATTAG_NAME) == 0)
615 ADDRITEM_NAME(group) = g_strdup(value);
616 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
617 group->remarks = g_strdup(value);
618 attr = g_list_next(attr);
620 if (xml_parse_next_tag(file)) { /* Consume closing tag */
621 longjmp(book->jumper, 1);
623 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST)) {
625 addrcache_hash_add_group(book->addressCache, group);
627 addrbook_parse_member_list(book, file, group);
632 * Parse folder item from XML file.
633 * \param book Address book.
634 * \param file XML file handle.
635 * \param folder Folder.
637 static void addrbook_parse_folder_item(AddressBookFile *book, XMLFile *file,
644 attr = xml_get_current_tag_attr(file);
646 name = ((XMLAttr *)attr->data)->name;
647 value = ((XMLAttr *)attr->data)->value;
648 if (strcmp(name, AB_ATTAG_UID) == 0) {
649 uid = g_strdup(value);
651 attr = g_list_next(attr);
655 folder->listItems = g_list_append(folder->listItems, uid);
661 * Parse list of folder items from XML file.
662 * \param book Address book.
663 * \param file XML file handle.
664 * \param folder Folder.
666 static void addrbook_parse_folder_list(AddressBookFile *book, XMLFile *file,
672 prev_level = file->level;
673 if (xml_parse_next_tag(file)) {
674 longjmp(book->jumper, 1);
676 if (file->level < prev_level)
678 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
679 addrbook_parse_folder_item(book, file, folder);
680 addrbook_parse_folder_list(book, file, folder);
686 * Parse folder from XML file.
687 * \param book Address book.
688 * \param file XML file handle.
690 static void addrbook_parse_folder(AddressBookFile *book, XMLFile *file)
694 ItemFolder *folder = NULL;
696 attr = xml_get_current_tag_attr(file);
698 name = ((XMLAttr *)attr->data)->name;
699 value = ((XMLAttr *)attr->data)->value;
701 folder = addritem_create_item_folder();
702 if (strcmp(name, AB_ATTAG_UID) == 0)
703 ADDRITEM_ID(folder) = g_strdup(value);
704 else if (strcmp(name, AB_ATTAG_NAME) == 0)
705 ADDRITEM_NAME(folder) = g_strdup(value);
706 else if (strcmp(name, AB_ATTAG_REMARKS) == 0)
707 folder->remarks = g_strdup(value);
708 attr = g_list_next(attr);
710 if (xml_parse_next_tag(file)) { /* Consume closing tag */
711 longjmp(book->jumper, 1);
713 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST)) {
715 if (addrcache_hash_add_folder(book->addressCache,
717 book->tempList = g_list_append(book->tempList,
719 /* We will resolve folder later */
720 ADDRITEM_PARENT(folder) = NULL;
723 addrbook_parse_folder_list(book, file, folder);
728 * Read address book (DOM) tree from file.
729 * \param book Address book.
730 * \param file XML file handle.
731 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
734 static gboolean addrbook_read_tree(AddressBookFile *book, XMLFile *file)
740 book->retVal = MGU_BAD_FORMAT;
741 if (xml_get_dtd(file))
743 if (xml_parse_next_tag(file))
744 longjmp(book->jumper, 1);
745 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
748 attr = xml_get_current_tag_attr(file);
750 name = ((XMLAttr *)attr->data)->name;
751 value = ((XMLAttr *)attr->data)->value;
752 if (strcmp( name, AB_ATTAG_NAME) == 0)
753 addrbook_set_name( book, value );
754 attr = g_list_next( attr );
761 /* Get next item tag (person, group or folder) */
762 if (xml_parse_next_tag(file))
763 longjmp( book->jumper, 1 );
765 if (xml_compare_tag(file, AB_ELTAG_PERSON))
766 addrbook_parse_person(book, file);
767 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
768 addrbook_parse_group(book, file);
769 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
770 addrbook_parse_folder(book, file);
772 if (retVal) book->retVal = MGU_SUCCESS;
777 * Resolve folder items callback function.
778 * \param key Table key.
779 * \param value Reference to object contained in folder.
780 * \param data Reference to address book.
782 static void addrbook_res_items_vis(gpointer key, gpointer value, gpointer data)
784 AddressBookFile *book = data;
785 AddrItemObject *obj = (AddrItemObject *) value;
786 ItemFolder *rootFolder = book->addressCache->rootFolder;
787 if (obj->parent == NULL) {
788 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
789 rootFolder->listPerson = g_list_append(rootFolder->listPerson,
791 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
793 else if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
794 rootFolder->listGroup = g_list_append(rootFolder->listGroup,
796 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
802 * Resolve folder items. Lists of UID's are replaced with pointers to
804 * \param book Address book.
806 static void addrbook_resolve_folder_items(AddressBookFile *book)
808 GList *nodeFolder = NULL;
809 GList *listRemove = NULL;
811 ItemFolder *rootFolder = book->addressCache->rootFolder;
812 nodeFolder = book->tempList;
815 ItemFolder *folder = nodeFolder->data;
817 node = folder->listItems;
819 gchar *uid = node->data;
820 AddrItemObject *aio = addrcache_get_object(book->addressCache,
823 if (aio->type == ITEMTYPE_FOLDER) {
824 ItemFolder *item = (ItemFolder *) aio;
825 folder->listFolder = g_list_append(folder->listFolder, item);
826 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
827 addrcache_hash_add_folder(book->addressCache, folder);
829 else if (aio->type == ITEMTYPE_PERSON) {
830 ItemPerson *item = (ItemPerson *) aio;
831 folder->listPerson = g_list_append(folder->listPerson, item);
832 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
834 else if (aio->type == ITEMTYPE_GROUP) {
835 ItemGroup *item = (ItemGroup *) aio;
836 folder->listGroup = g_list_append(folder->listGroup, item);
837 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
839 /* Replace data with pointer to item */
843 else { /* Not found, append to remove list. */
844 listRemove = g_list_append(listRemove, uid);
846 node = g_list_next(node);
848 rootFolder->listFolder = g_list_append(rootFolder->listFolder,
850 /* Process remove list */
853 gchar *uid = node->data;
854 folder->listItems = g_list_remove(folder->listItems,
857 node = g_list_next(node);
859 g_list_free(listRemove);
860 nodeFolder = g_list_next(nodeFolder);
862 /* Remove folders with parents. */
864 node = rootFolder->listFolder;
866 ItemFolder *folder = (ItemFolder *) node->data;
867 if (ADDRITEM_PARENT(folder))
868 /* Remove folders with parents */
869 listRemove = g_list_append(listRemove, folder);
870 else /* Add to root folder */
871 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
873 node = g_list_next( node );
875 /* Process remove list */
878 rootFolder->listFolder = g_list_remove(rootFolder->listFolder,
880 node = g_list_next(node);
882 g_list_free(listRemove);
884 /* Move all unparented persons and groups into root folder */
885 g_hash_table_foreach(book->addressCache->itemHash,
886 addrbook_res_items_vis, book);
888 /* Free up some more */
889 nodeFolder = book->tempList;
891 ItemFolder *folder = nodeFolder->data;
892 g_list_free(folder->listItems);
893 folder->listItems = NULL;
894 nodeFolder = g_list_next(nodeFolder);
896 g_list_free(book->tempList);
897 book->tempList = NULL;
902 * \param book Address book.
903 * \return Status code.
905 gint addrbook_read_data(AddressBookFile *book)
907 XMLFile *file = NULL;
908 gchar *fileSpec = NULL;
910 cm_return_val_if_fail(book != NULL, -1);
913 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
914 addrcache_get_name( book->addressCache ) );
917 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S,
918 book->fileName, NULL);
919 book->retVal = MGU_OPEN_FILE;
920 addrcache_clear(book->addressCache);
921 book->addressCache->modified = FALSE;
922 book->addressCache->accessFlag = FALSE;
923 file = xml_open_file(fileSpec);
926 book->tempList = NULL;
927 /* Trap for parsing errors. */
928 if (setjmp( book->jumper)) {
929 xml_close_file(file);
932 addrbook_read_tree(book, file);
933 xml_close_file(file);
934 /* Resolve folder items */
935 addrbook_resolve_folder_items(book);
936 book->tempList = NULL;
937 book->addressCache->modified = FALSE;
938 book->addressCache->dataRead = TRUE;
939 addrcache_set_dirty(book->addressCache, FALSE);
945 * Write start element to file.
946 * \param fp File handle.
947 * \param lvl Indent level.
948 * \param name Element name.
950 static int addrbook_write_elem_s(FILE *fp, gint lvl, gchar *name)
953 for (i = 0; i < lvl; i++)
954 if (fputs(" ", fp) == EOF)
956 if (fputs("<", fp) == EOF)
958 if (fputs(name, fp) == EOF)
965 * Write end element to file.
966 * \param fp File handle.
967 * \param lvl Indent level.
968 * \param name Element name.
970 static int addrbook_write_elem_e(FILE *fp, gint lvl, gchar *name)
973 for(i = 0; i < lvl; i++)
974 if (fputs(" ", fp) == EOF)
976 if (fputs("</", fp) == EOF)
978 if (fputs(name, fp) == EOF)
980 if (fputs(">\n", fp) == EOF)
987 * Write attribute name/value pair to file.
988 * \param fp File handle.
989 * \param name Attribute name.
990 * \param value Attribute value.
992 static int addrbook_write_attr(FILE *fp, gchar *name, gchar *value)
994 if (fputs(" ", fp) == EOF)
996 if (fputs(name, fp) == EOF)
998 if (fputs("=\"", fp) == EOF)
1000 if (xml_file_put_escape_str(fp, value) < 0)
1002 if (fputs("\"", fp) == EOF)
1008 typedef struct _HashLoopData {
1014 * Write person and associated addresses and attributes to file.
1015 * file hash table visitor function.
1016 * \param key Table key.
1017 * \param value Reference to person.
1018 * \param data File pointer.
1020 static void addrbook_write_item_person_vis(gpointer key, gpointer value,
1023 AddrItemObject *obj = (AddrItemObject *) value;
1024 HashLoopData *data = (HashLoopData *)d;
1025 FILE *fp = data->fp;
1030 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1031 ItemPerson *person = (ItemPerson *) value;
1033 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_PERSON) < 0)
1035 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(person)) < 0)
1037 if (addrbook_write_attr(fp, AB_ATTAG_FIRST_NAME, person->firstName) < 0)
1039 if (addrbook_write_attr(fp, AB_ATTAG_LAST_NAME, person->lastName) < 0)
1041 if (addrbook_write_attr(fp, AB_ATTAG_NICK_NAME, person->nickName) < 0)
1043 if (addrbook_write_attr(fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person)) < 0)
1045 if (fputs(" >\n", fp) == EOF)
1048 /* Output email addresses */
1049 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0)
1051 if (fputs(">\n", fp) == EOF)
1053 node = person->listEMail;
1055 ItemEMail *email = node->data;
1056 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ADDRESS) < 0)
1058 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(email)) < 0)
1060 if (addrbook_write_attr(fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email)) < 0)
1062 if (addrbook_write_attr(fp, AB_ATTAG_EMAIL, email->address) < 0)
1064 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, email->remarks) < 0)
1066 if (fputs(" />\n", fp) == EOF)
1068 node = g_list_next(node);
1070 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ADDRESS_LIST) < 0)
1073 /* Output user attributes */
1074 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0)
1076 if (fputs(">\n", fp) == EOF)
1078 node = person->listAttrib;
1080 UserAttribute *attrib = node->data;
1081 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ATTRIBUTE) < 0)
1083 if (addrbook_write_attr(fp, AB_ATTAG_UID, attrib->uid) < 0)
1085 if (addrbook_write_attr(fp, AB_ATTAG_NAME, attrib->name) < 0)
1087 if (fputs(" >", fp) == EOF)
1089 if (xml_file_put_escape_str(fp, attrib->value) < 0)
1091 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ATTRIBUTE) < 0)
1093 node = g_list_next(node);
1095 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ATTRIBUTE_LIST) < 0)
1097 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_PERSON) < 0)
1104 * Write group and associated references to addresses to file.
1105 * file hash table visitor function.
1106 * \param key Table key.
1107 * \param value Reference to group.
1108 * \param data File pointer.
1110 static void addrbook_write_item_group_vis(gpointer key, gpointer value,
1113 AddrItemObject *obj = (AddrItemObject *) value;
1114 HashLoopData *data = (HashLoopData *)d;
1115 FILE *fp = data->fp;
1121 if (ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP) {
1122 ItemGroup *group = (ItemGroup *) value;
1124 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_GROUP) < 0)
1126 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(group)) < 0)
1128 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(group)) < 0)
1130 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, group->remarks) < 0)
1132 if (fputs(" >\n", fp) == EOF)
1135 /* Output email address links */
1136 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_MEMBER_LIST) < 0)
1138 if (fputs(">\n", fp) == EOF)
1140 node = group->listEMail;
1142 ItemEMail *email = node->data;
1143 ItemPerson *person = (ItemPerson *) ADDRITEM_PARENT(email);
1144 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_MEMBER) < 0)
1146 if (addrbook_write_attr(fp, AB_ATTAG_PID, ADDRITEM_ID(person)) < 0)
1148 if (addrbook_write_attr(fp, AB_ATTAG_EID, ADDRITEM_ID(email)) < 0)
1150 if (fputs(" />\n", fp) == EOF)
1152 node = g_list_next(node);
1154 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_MEMBER_LIST) < 0)
1156 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_GROUP) < 0)
1163 * Write folder and associated references to addresses to file.
1164 * file hash table visitor function.
1165 * \param key Table key.
1166 * \param value Reference to folder.
1167 * \param data File pointer.
1169 static void addrbook_write_item_folder_vis(gpointer key, gpointer value,
1172 AddrItemObject *obj = (AddrItemObject *) value;
1173 HashLoopData *data = (HashLoopData *)d;
1174 FILE *fp = data->fp;
1179 if (ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER) {
1180 ItemFolder *folder = (ItemFolder *) value;
1182 if (addrbook_write_elem_s(fp, 1, AB_ELTAG_FOLDER) < 0)
1184 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(folder)) < 0)
1186 if (addrbook_write_attr(fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder)) < 0)
1188 if (addrbook_write_attr(fp, AB_ATTAG_REMARKS, folder->remarks) < 0)
1190 if (fputs(" >\n", fp) == EOF)
1192 if (addrbook_write_elem_s(fp, 2, AB_ELTAG_ITEM_LIST) < 0)
1194 if (fputs(">\n", fp) == EOF)
1197 /* Output persons */
1198 node = folder->listPerson;
1200 ItemPerson *item = node->data;
1201 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1203 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON) < 0)
1205 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1207 if (fputs(" />\n", fp) == EOF)
1209 node = g_list_next(node);
1213 node = folder->listGroup;
1215 ItemGroup *item = node->data;
1216 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1218 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP) < 0)
1220 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1222 if (fputs(" />\n", fp) == EOF)
1224 node = g_list_next(node);
1227 /* Output folders */
1228 node = folder->listFolder;
1230 ItemFolder *item = node->data;
1231 if (addrbook_write_elem_s(fp, 3, AB_ELTAG_ITEM) < 0)
1233 if (addrbook_write_attr(fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER) < 0)
1235 if (addrbook_write_attr(fp, AB_ATTAG_UID, ADDRITEM_ID(item)) < 0)
1237 if (fputs(" />\n", fp) == EOF)
1239 node = g_list_next(node);
1241 if (addrbook_write_elem_e(fp, 2, AB_ELTAG_ITEM_LIST) < 0)
1243 if (addrbook_write_elem_e(fp, 1, AB_ELTAG_FOLDER) < 0)
1250 * Output address book data to specified file.
1251 * \param book Address book.
1252 * \param newFile Filename of new file (in book's filepath).
1253 * \return Status code.
1255 static gint addrbook_write_to(AddressBookFile *book, gchar *newFile)
1260 #ifndef DEV_STANDALONE
1264 cm_return_val_if_fail(book != NULL, -1);
1265 cm_return_val_if_fail(newFile != NULL, -1);
1267 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, newFile, NULL);
1269 book->retVal = MGU_OPEN_FILE;
1270 #ifdef DEV_STANDALONE
1271 fp = g_fopen(fileSpec, "wb");
1274 if (fputs("<?xml version=\"1.0\" ?>\n", fp) == EOF) {
1275 book->retVal = MGU_ERROR_WRITE;
1276 return book->retVal;
1279 pfile = prefs_write_open(fileSpec);
1283 if (fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL ) < 0)
1286 if (addrbook_write_elem_s(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0)
1288 if (addrbook_write_attr(fp, AB_ATTAG_NAME,
1289 addrcache_get_name(book->addressCache)) < 0)
1291 if (fputs(" >\n", fp) == EOF)
1294 /* Output all persons */
1298 g_hash_table_foreach(book->addressCache->itemHash,
1299 addrbook_write_item_person_vis, &data);
1303 /* Output all groups */
1304 g_hash_table_foreach(book->addressCache->itemHash,
1305 addrbook_write_item_group_vis, &data);
1310 /* Output all folders */
1311 g_hash_table_foreach(book->addressCache->itemHash,
1312 addrbook_write_item_folder_vis, &data);
1317 if (addrbook_write_elem_e(fp, 0, AB_ELTAG_ADDRESS_BOOK) < 0)
1320 book->retVal = MGU_SUCCESS;
1321 #ifdef DEV_STANDALONE
1324 if (prefs_file_close( pfile ) < 0)
1325 book->retVal = MGU_ERROR_WRITE;
1330 return book->retVal;
1332 g_warning("error writing AB");
1333 book->retVal = MGU_ERROR_WRITE;
1335 prefs_file_close_revert( pfile );
1336 return book->retVal;
1340 * Output address book data to original file.
1341 * \param book Address book.
1342 * \return Status code.
1344 gint addrbook_save_data(AddressBookFile *book)
1346 cm_return_val_if_fail(book != NULL, -1);
1348 book->retVal = MGU_NO_FILE;
1349 if (book->fileName == NULL || *book->fileName == '\0')
1350 return book->retVal;
1351 if (book->path == NULL || *book->path == '\0')
1352 return book->retVal;
1354 addrbook_write_to(book, book->fileName);
1355 if (book->retVal == MGU_SUCCESS)
1356 addrcache_set_dirty(book->addressCache, FALSE);
1357 return book->retVal;
1361 * **********************************************************************
1362 * Address book edit interface functions.
1363 * **********************************************************************
1367 * Hash table callback function for simple deletion of hashtable entries.
1368 * \param key Table key (will be freed).
1369 * \param value Value stored in table.
1370 * \param data User data.
1371 * \return <i>TRUE</i> to indicate that entry freed.
1373 static gboolean addrbook_free_simple_hash_vis(gpointer *key, gpointer *value,
1383 * Update address book email list for specified person. Note: The existing
1384 * email addresses are replaced with the new addresses. Any references to
1385 * old addresses in the groups are re-linked to the new addresses. All old
1386 * addresses linked to the person are removed.
1387 * \param book Address book.
1388 * \param person Person to update.
1389 * \param listEMail List of new email addresses.
1391 void addrbook_update_address_list(AddressBookFile *book, ItemPerson *person,
1398 cm_return_if_fail(book != NULL);
1399 cm_return_if_fail(person != NULL);
1401 /* Get groups where person's existing email addresses are listed */
1402 listGroup = addrcache_get_group_for_person(book->addressCache, person);
1404 GHashTable *hashEMail;
1405 GHashTable *hashEMailAlias;
1408 /* Load hash table with new address entries */
1409 hashEMail = g_hash_table_new(g_str_hash, g_str_equal);
1410 hashEMailAlias = g_hash_table_new(g_str_hash, g_str_equal);
1413 ItemEMail *email = node->data;
1414 gchar *alias = email->obj.name ;
1415 gchar *addr = g_utf8_strdown(email->address, -1);
1416 if (!g_hash_table_lookup(hashEMail, addr)) {
1417 g_hash_table_insert(hashEMail, addr, email);
1419 if (*alias != '\0' && ! g_hash_table_lookup(hashEMailAlias,
1421 g_hash_table_insert(hashEMailAlias, alias, email);
1423 node = g_list_next(node);
1426 /* Re-parent new addresses to existing groups, where email address match. */
1427 nodeGrp = listGroup;
1429 ItemGroup *group = (ItemGroup *) nodeGrp->data;
1430 GList *groupEMail = group->listEMail;
1432 GList *listRemove = NULL;
1434 /* Process each email item linked to group */
1435 nodeGrpEM = groupEMail;
1437 ItemEMail *emailGrp = (ItemEMail *) nodeGrpEM->data;
1439 if (ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person)) {
1440 /* Found an email address for this person */
1441 ItemEMail *emailNew = NULL;
1442 gchar *alias = emailGrp->obj.name;
1443 gchar *addr = g_utf8_strdown(emailGrp->address, -1);
1444 emailNew = (ItemEMail *)
1445 g_hash_table_lookup(hashEMail, addr);
1447 /* If no match by e-mail, try to match by e-mail alias */
1448 if (!emailNew && *alias != '\0') {
1449 emailNew = (ItemEMail *)
1450 g_hash_table_lookup(hashEMailAlias, alias);
1454 /* Point to this entry */
1455 nodeGrpEM->data = emailNew;
1456 else if (g_hash_table_size(hashEMail)==1)
1457 /* If the person has just one e-mail address, then
1458 change e-mail address in group list */
1459 nodeGrpEM->data = listEMail->data;
1461 /* Mark for removal */
1462 listRemove = g_list_append(listRemove, emailGrp);
1464 /* Move on to next email link */
1465 nodeGrpEM = g_list_next(nodeGrpEM);
1468 /* Process all removed links in current group */
1469 nodeGrpEM = listRemove;
1471 ItemEMail *emailGrp = nodeGrpEM->data;
1472 groupEMail = g_list_remove(groupEMail, emailGrp);
1473 nodeGrpEM = g_list_next(nodeGrpEM);
1476 g_list_free(listRemove);
1478 /* Move on to next group */
1479 nodeGrp = g_list_next(nodeGrp);
1482 /* Clear hash table */
1483 g_hash_table_foreach_remove(hashEMail, (GHRFunc)
1484 addrbook_free_simple_hash_vis, NULL);
1485 g_hash_table_destroy(hashEMail);
1487 g_hash_table_destroy(hashEMailAlias);
1488 hashEMailAlias = NULL;
1489 g_list_free(listGroup);
1492 /* Remove old addresses from person and cache */
1494 node = person->listEMail;
1496 ItemEMail *email = node->data;
1498 if (addrcache_person_remove_email(book->addressCache, person, email))
1499 addrcache_remove_email(book->addressCache, email);
1501 listDelete = g_list_append(listDelete, email);
1502 node = person->listEMail;
1504 /* Add new address entries */
1507 ItemEMail *email = node->data;
1509 if (ADDRITEM_ID(email) == NULL)
1510 /* Allocate an ID for new address */
1511 addrcache_id_email(book->addressCache, email);
1513 addrcache_person_add_email( book->addressCache, person, email );
1514 node = g_list_next( node );
1517 addrcache_set_dirty(book->addressCache, TRUE);
1519 /* Free up memory */
1520 g_list_free(listEMail);
1525 ItemEMail *email = node->data;
1527 addritem_free_item_email(email);
1528 node = g_list_next(node);
1530 g_list_free(listDelete);
1536 * Create person object and add person with specified address data to address
1537 * book. Note: A new person is created with specified list of email addresses.
1538 * All objects inserted into address book.
1540 * \param book Address book.
1541 * \param folder Parent folder where to add person, or <i>NULL</i> for
1543 * \param listEMail List of new email addresses to associate with person.
1544 * \return Person object created.
1546 ItemPerson *addrbook_add_address_list(AddressBookFile *book, ItemFolder *folder,
1550 ItemFolder *f = folder;
1553 cm_return_val_if_fail(book != NULL, NULL);
1556 f = book->addressCache->rootFolder;
1557 person = addritem_create_item_person();
1558 addrcache_id_person(book->addressCache, person);
1559 addrcache_folder_add_person(book->addressCache, f, person);
1563 ItemEMail *email = node->data;
1564 if (ADDRITEM_ID(email) == NULL)
1565 addrcache_id_email(book->addressCache, email);
1567 addrcache_person_add_email(book->addressCache, person, email);
1568 node = g_list_next(node);
1574 * Build available email list visitor function.
1575 * \param key Table key.
1576 * \param value Value stored in table.
1577 * \param data Reference to address book.
1579 static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
1582 AddrItemObject *obj = (AddrItemObject *) value;
1584 if (ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON) {
1585 AddressBookFile *book = data;
1586 ItemPerson *person = (ItemPerson *) obj;
1587 GList *node = person->listEMail;
1589 ItemEMail *email = node->data;
1590 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1592 if (!g_hash_table_lookup(book->tempHash,
1593 ADDRITEM_ID(email)))
1594 book->tempList = g_list_append(book->tempList, email);
1596 node = g_list_next(node);
1602 * Return link list of available email items that have not already been linked
1603 * to groups. Note that the list contains references to items and should be
1604 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1605 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1608 * \param book Address book.
1609 * \param group Group to process.
1610 * \return List of items, or <i>NULL</i> if none.
1612 GList *addrbook_get_available_email_list(AddressBookFile *book, ItemGroup *group)
1617 cm_return_val_if_fail(book != NULL, NULL);
1619 /* Load hash table with group email entries */
1620 table = g_hash_table_new(g_str_hash, g_str_equal);
1622 list = group->listEMail;
1624 ItemEMail *email = list->data;
1625 g_hash_table_insert(table, ADDRITEM_ID(email), email);
1626 list = g_list_next(list);
1630 /* Build list of available email addresses which exclude those already in groups */
1631 book->tempList = NULL;
1632 book->tempHash = table;
1633 g_hash_table_foreach(book->addressCache->itemHash,
1634 addrbook_build_avail_email_vis, book);
1635 list = book->tempList;
1636 book->tempList = NULL;
1637 book->tempHash = NULL;
1639 /* Clear hash table */
1640 g_hash_table_destroy(table);
1647 * Update address book email list for specified group. Note: The existing email
1648 * addresses are replaced with the new addresses. Any references to old addresses
1649 * in the groups are re-linked to the new addresses. All old addresses linked to
1650 * the person are removed.
1652 * \param book Address book.
1653 * \param group Group to process.
1654 * \param listEMail List of email items. This should <b>*NOT*</b> be
1655 * <code>g_free()</code> when done.
1657 void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
1662 cm_return_if_fail(book != NULL);
1663 cm_return_if_fail(group != NULL);
1665 addrcache_set_dirty(book->addressCache, TRUE);
1667 /* Remember old list */
1668 oldData = group->listEMail;
1669 group->listEMail = listEMail;
1670 mgu_clear_list(oldData);
1675 * Create group object and add with specifed list of email addresses to
1676 * address book. Note: The existing email addresses are replaced with the new
1677 * addresses. Any references to old addresses in the groups are re-linked to
1678 * the new addresses. All old addresses linked to the person are removed.
1680 * \param book Address book.
1681 * \param folder Parent folder where to add group, or <i>NULL</i> for
1683 * \param listEMail List of email items. This should <b>*NOT*</b> be
1684 * <code>g_free()</code> when done.
1685 * \return Group object created.
1687 ItemGroup *addrbook_add_group_list(AddressBookFile *book, ItemFolder *folder,
1690 ItemGroup *group = NULL;
1691 ItemFolder *f = folder;
1693 cm_return_val_if_fail(book != NULL, NULL);
1696 f = book->addressCache->rootFolder;
1697 group = addritem_create_item_group();
1698 addrcache_id_group(book->addressCache, group);
1699 addrcache_folder_add_group(book->addressCache, f, group);
1700 group->listEMail = listEMail;
1705 * Create a new folder and add to address book.
1706 * \param book Address book.
1707 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1709 * \return Folder that was created. This should <b>*NOT*</b> be
1710 * <code>g_free()</code> when done.
1712 ItemFolder *addrbook_add_new_folder(AddressBookFile *book, ItemFolder *parent)
1714 cm_return_val_if_fail(book != NULL, NULL);
1715 return addrcache_add_new_folder( book->addressCache, parent );
1719 * Update address book attribute list for specified person. Note: The existing
1720 * attributes are replaced with the new addresses. All old attributes linked
1721 * to the person are removed.
1723 * \param book Address book.
1724 * \param person Person to receive attributes.
1725 * \param listAttrib New list of attributes.
1727 void addrbook_update_attrib_list(AddressBookFile *book, ItemPerson *person,
1733 cm_return_if_fail(book != NULL);
1734 cm_return_if_fail(person != NULL);
1736 /* Remember old list */
1737 oldData = person->listAttrib;
1739 /* Attach new address list to person. */
1742 UserAttribute *attrib = node->data;
1743 if (attrib->uid == NULL) {
1744 /* Allocate an ID */
1745 addrcache_id_attribute(book->addressCache, attrib);
1747 node = g_list_next(node);
1749 person->listAttrib = listAttrib;
1750 addrcache_set_dirty(book->addressCache, TRUE);
1752 /* Free up old data */
1753 addritem_free_list_attribute(oldData);
1758 * Add attribute data for specified person to address book. Note: Only
1759 * attributes are inserted into address book.
1760 * \param book Address book.
1761 * \param person Person to receive attributes.
1762 * \param listAttrib List of attributes.
1764 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1767 cm_return_if_fail( book != NULL );
1768 cm_return_if_fail( person != NULL );
1772 UserAttribute *attrib = node->data;
1773 if( attrib->uid == NULL ) {
1774 addrcache_id_attribute( book->addressCache, attrib );
1776 addritem_person_add_attribute( person, attrib );
1777 node = g_list_next( node );
1779 addrcache_set_dirty( book->addressCache, TRUE );
1782 #define WORK_BUFLEN 1024
1783 #define ADDRBOOK_DIGITS "0123456789"
1786 * Return list of existing address book files.
1787 * \param book Address book.
1788 * \return List of files (as strings).
1790 GList *addrbook_get_bookfile_list(AddressBookFile *book) {
1793 const gchar *dir_name;
1795 gchar buf[WORK_BUFLEN + 1];
1796 gchar numbuf[WORK_BUFLEN];
1797 gint len, lenpre, lensuf, lennum;
1798 long int val, maxval;
1799 GList *fileList = NULL;
1801 cm_return_val_if_fail(book != NULL, NULL);
1803 if (book->path == NULL || *book->path == '\0') {
1804 book->retVal = MGU_NO_PATH;
1808 strncpy(buf, book->path, WORK_BUFLEN);
1811 if (buf[len-1] != G_DIR_SEPARATOR) {
1812 buf[len] = G_DIR_SEPARATOR;
1817 adbookdir = g_strdup(buf);
1818 strncat(buf, ADDRBOOK_PREFIX, WORK_BUFLEN - strlen(buf));
1820 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1821 book->retVal = MGU_OPEN_DIRECTORY;
1826 lenpre = strlen(ADDRBOOK_PREFIX);
1827 lensuf = strlen(ADDRBOOK_SUFFIX);
1828 lennum = FILE_NUMDIGITS + lenpre;
1831 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1832 gchar *endptr = NULL;
1836 strncpy(buf, adbookdir, WORK_BUFLEN);
1837 strncat(buf, dir_name, WORK_BUFLEN - strlen(buf));
1838 r = g_stat(buf, &statbuf);
1839 if (r == 0 && S_ISREG(statbuf.st_mode)) {
1842 ADDRBOOK_PREFIX, lenpre) == 0)
1845 (dir_name) + lennum,
1846 ADDRBOOK_SUFFIX, lensuf) == 0)
1849 (dir_name) + lenpre,
1851 numbuf[FILE_NUMDIGITS] = '\0';
1853 for(i = 0; i < FILE_NUMDIGITS; i++) {
1854 if(!strchr(ADDRBOOK_DIGITS, numbuf[i])) {
1861 val = strtol(numbuf, &endptr, 10);
1862 if (endptr && val > -1) {
1863 if (val > maxval) maxval = val;
1864 fileList = g_list_append(
1866 g_strdup(dir_name));
1876 book->maxValue = maxval;
1877 book->retVal = MGU_SUCCESS;
1882 * Return file name for specified file number.
1883 * \param fileNum File number.
1884 * \return File name, or <i>NULL</i> if file number too large. Should be
1885 * <code>g_free()</code> when done.
1887 gchar *addrbook_gen_new_file_name(gint fileNum) {
1889 gchar buf[WORK_BUFLEN];
1895 nmax = -1 + (long int) pow(10, FILE_NUMDIGITS);
1898 g_snprintf(fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS);
1899 g_snprintf(buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX);
1900 return g_strdup(buf);
1904 * **********************************************************************
1905 * Address book test functions...
1906 * **********************************************************************
1910 * Attempt to parse list of email address from file.
1911 * \param book Address book.
1912 * \param file XML file handle.
1914 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file )
1920 prev_level = file->level;
1921 if (xml_parse_next_tag(file))
1922 longjmp(book->jumper, 1);
1923 if (file->level < prev_level)
1925 /* attr = xml_get_current_tag_attr(file); */
1926 /* addrbook_show_attribs( attr ); */
1927 if (xml_compare_tag(file, AB_ELTAG_ADDRESS))
1928 addrbook_chkparse_addr_list(book, file);
1933 * Attempt to parse attributes for person address from file.
1934 * \param book Address book.
1935 * \param file XML file handle.
1937 static void addrbook_chkparse_attribute(AddressBookFile *book, XMLFile *file)
1940 /* gchar *element; */
1942 /* attr = xml_get_current_tag_attr(file); */
1943 /* addrbook_show_attribs( attr ); */
1944 /* element = xml_get_element(file); */
1945 /* g_print( "\t\tattrib value : %s\n", element ); */
1949 * Attempt to parse list of attributes for person address from file.
1950 * \param book Address book.
1951 * \param file XML file handle.
1953 static void addrbook_chkparse_attr_list(AddressBookFile *book, XMLFile *file)
1958 prev_level = file->level;
1959 if (xml_parse_next_tag(file))
1960 longjmp(book->jumper, 1);
1961 if (file->level < prev_level)
1963 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE)) {
1964 addrbook_chkparse_attribute(book, file);
1965 addrbook_chkparse_attr_list(book, file);
1971 * Attempt to parse person from file.
1972 * \param book Address book.
1973 * \param file XML file handle.
1975 static void addrbook_chkparse_person(AddressBookFile *book, XMLFile *file)
1979 /* attr = xml_get_current_tag_attr(file); */
1980 /* addrbook_show_attribs( attr ); */
1981 if (xml_parse_next_tag(file)) /* Consume closing tag */
1982 longjmp(book->jumper, 1);
1984 if (xml_compare_tag(file, AB_ELTAG_ADDRESS_LIST))
1985 addrbook_chkparse_addr_list(book, file);
1987 if (xml_parse_next_tag(file)) /* Consume closing tag */
1988 longjmp(book->jumper, 1);
1990 if (xml_compare_tag(file, AB_ELTAG_ATTRIBUTE_LIST))
1991 addrbook_chkparse_attr_list(book, file);
1995 * Attempt to parse list of members from file.
1996 * \param book Address book.
1997 * \param file XML file handle.
1999 static void addrbook_chkparse_member_list(AddressBookFile *book, XMLFile *file)
2005 prev_level = file->level;
2006 if (xml_parse_next_tag(file))
2007 longjmp(book->jumper, 1);
2009 if (file->level < prev_level)
2012 if (xml_compare_tag(file, AB_ELTAG_MEMBER)) {
2013 /* attr = xml_get_current_tag_attr(file); */
2014 /* addrbook_show_attribs( attr ); */
2015 addrbook_chkparse_member_list(book, file);
2018 /* attr = xml_get_current_tag_attr(file); */
2019 /* addrbook_show_attribs( attr ); */
2025 * Attempt to parse group from file.
2026 * \param book Address book.
2027 * \param file XML file handle.
2029 static void addrbook_chkparse_group(AddressBookFile *book, XMLFile *file)
2033 /* attr = xml_get_current_tag_attr(file); */
2034 /* addrbook_show_attribs( attr ); */
2035 if (xml_parse_next_tag(file)) /* Consume closing tag */
2036 longjmp(book->jumper, 1);
2038 if (xml_compare_tag(file, AB_ELTAG_MEMBER_LIST))
2039 addrbook_chkparse_member_list(book, file);
2043 * Attempt to parse list of folders from file.
2044 * \param book Address book.
2045 * \param file XML file handle.
2047 static void addrbook_chkparse_folder_list(AddressBookFile *book, XMLFile *file)
2053 prev_level = file->level;
2054 if (xml_parse_next_tag(file))
2055 longjmp(book->jumper, 1);
2057 if (file->level < prev_level)
2060 if (xml_compare_tag(file, AB_ELTAG_ITEM)) {
2061 /* attr = xml_get_current_tag_attr(file); */
2062 /* addrbook_show_attribs( attr ); */
2063 addrbook_chkparse_folder_list(book, file);
2066 /* attr = xml_get_current_tag_attr(file); */
2067 /* addrbook_show_attribs( attr ); */
2073 * Attempt to parse a folder from file.
2074 * \param book Address book.
2075 * \param file XML file handle.
2077 static void addrbook_chkparse_folder(AddressBookFile *book, XMLFile *file)
2081 /* attr = xml_get_current_tag_attr(file); */
2082 /* addrbook_show_attribs( attr ); */
2083 if (xml_parse_next_tag(file)) /* Consume closing tag */
2084 longjmp(book->jumper, 1);
2086 if (xml_compare_tag(file, AB_ELTAG_ITEM_LIST))
2087 addrbook_chkparse_folder_list(book, file);
2091 * Attempt to parse (DOM) tree from file.
2092 * \param book Address book.
2093 * \param file XML file handle.
2095 static gboolean addrbook_chkread_tree(AddressBookFile *book, XMLFile *file)
2100 if (xml_get_dtd(file))
2103 if (xml_parse_next_tag(file))
2106 if (!xml_compare_tag(file, AB_ELTAG_ADDRESS_BOOK))
2109 /* attr = xml_get_current_tag_attr(file); */
2110 /* addrbook_show_attribs( attr ); */
2117 if (xml_parse_next_tag(file))
2118 longjmp(book->jumper, 1);
2120 /* Get next tag (person, group or folder) */
2121 if (xml_compare_tag(file, AB_ELTAG_PERSON))
2122 addrbook_chkparse_person( book, file );
2123 else if (xml_compare_tag(file, AB_ELTAG_GROUP))
2124 addrbook_chkparse_group(book, file);
2125 else if (xml_compare_tag(file, AB_ELTAG_FOLDER))
2126 addrbook_chkparse_folder(book, file);
2132 * Test address book file by parsing contents.
2133 * \param book Address book.
2134 * \param fileName Filename of XML file.
2135 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2137 gint addrbook_test_read_file(AddressBookFile *book, gchar *fileName)
2139 XMLFile *file = NULL;
2140 gchar *fileSpec = NULL;
2142 cm_return_val_if_fail(book != NULL, -1);
2144 fileSpec = g_strconcat(book->path, G_DIR_SEPARATOR_S, fileName, NULL);
2145 book->retVal = MGU_OPEN_FILE;
2146 file = xml_open_file(fileSpec);
2149 book->retVal = MGU_BAD_FORMAT;
2150 if (setjmp(book->jumper)) {
2151 /* g_print( "Caught Ya!!!\n" ); */
2152 xml_close_file(file);
2153 return book->retVal;
2155 if (addrbook_chkread_tree(book, file))
2156 book->retVal = MGU_SUCCESS;
2158 xml_close_file( file );
2160 return book->retVal;
2164 * Return link list of all persons in address book. Note that the list
2165 * contains references to items. Do <b>*NOT*</b> attempt to use the
2166 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2168 * \param book Address book.
2169 * \return List of persons, or NULL if none.
2171 GList *addrbook_get_all_persons(AddressBookFile *book)
2173 cm_return_val_if_fail(book != NULL, NULL);
2174 return addrcache_get_all_persons(book->addressCache);
2177 GList *addrbook_get_all_groups(AddressBookFile *book)
2179 cm_return_val_if_fail(book != NULL, NULL);
2180 return addrcache_get_all_groups(book->addressCache);
2184 * Add person and address data to address book.
2185 * \param book Address book.
2186 * \param folder Folder where to add person, or NULL for root folder.
2187 * \param name Common name.
2188 * \param address EMail address.
2189 * \param remarks Remarks.
2190 * \return Person added. Do not <b>*NOT*</b> to use the
2191 * <code>addrbook_free_xxx()</code> functions... this will destroy
2192 * the address book data.
2194 ItemPerson *addrbook_add_contact(AddressBookFile *book, ItemFolder *folder,
2195 const gchar *name,const gchar *address,
2196 const gchar *remarks)
2200 cm_return_val_if_fail(book != NULL, NULL);
2201 person = addrcache_add_contact(
2202 book->addressCache, folder, name, address, remarks );
2207 * Return file name for next address book file.
2208 * \param book Address book.
2209 * \return File name, or <i>NULL</i> if could not create. This should be
2210 * <code>g_free()</code> when done.
2212 gchar *addrbook_guess_next_file(AddressBookFile *book)
2214 gchar *newFile = NULL;
2215 GList *fileList = NULL;
2217 fileList = addrbook_get_bookfile_list(book);
2219 fileNum = 1 + book->maxValue;
2221 newFile = addrbook_gen_new_file_name(fileNum);
2222 g_list_free(fileList);
2227 void addrbook_delete_book_file(AddressBookFile *book)
2231 if (!book->path || !book->fileName)
2234 book_path = g_strconcat(book->path, G_DIR_SEPARATOR_S,
2235 book->fileName, NULL);
2236 claws_unlink(book_path);