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"
37 #ifndef DEV_STANDALONE
38 #include "prefs_gtk.h"
42 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
43 #define ADDRBOOK_PREFIX "addrbook-"
44 #define ADDRBOOK_SUFFIX ".xml"
45 #define FILE_NUMDIGITS 6
47 #define ID_TIME_OFFSET 998000000
49 static void addrbook_print_book ( AddressBookFile
*book
, FILE *stream
);
52 * Create new address book
53 * \return Address book.
55 AddressBookFile
*addrbook_create_book()
57 AddressBookFile
*book
;
59 book
= g_new0(AddressBookFile
, 1);
60 book
->type
= ADBOOKTYPE_BOOK
;
61 book
->addressCache
= addrcache_create();
62 book
->retVal
= MGU_SUCCESS
;
64 book
->fileName
= NULL
;
66 book
->tempList
= NULL
;
67 book
->tempHash
= NULL
;
68 book
->addressCache
->modified
= TRUE
;
74 * Specify name to be used
75 * \param book Address book.
78 void addrbook_set_name(AddressBookFile
*book
, const gchar
*value
)
80 cm_return_if_fail(book
!= NULL
);
81 addrcache_set_name(book
->addressCache
, value
);
84 gchar
*addrbook_get_name(AddressBookFile
*book
)
86 cm_return_val_if_fail(book
!= NULL
, NULL
);
87 return addrcache_get_name(book
->addressCache
);
91 * Specify path to address book file.
92 * \param book Address book.
95 void addrbook_set_path(AddressBookFile
*book
, const gchar
*value
)
97 cm_return_if_fail(book
!= NULL
);
98 book
->path
= mgu_replace_string(book
->path
, value
);
99 addrcache_set_dirty(book
->addressCache
, TRUE
);
103 * Specify filename to be used
104 * \param book Address book.
105 * \param value Filename.
107 void addrbook_set_file(AddressBookFile
*book
, const gchar
*value
)
109 cm_return_if_fail(book
!= NULL
);
110 book
->fileName
= mgu_replace_string(book
->fileName
, value
);
111 addrcache_set_dirty(book
->addressCache
, TRUE
);
114 gboolean
addrbook_get_modified(AddressBookFile
*book
)
116 cm_return_val_if_fail(book
!= NULL
, FALSE
);
117 return book
->addressCache
->modified
;
120 gboolean
addrbook_get_accessed(AddressBookFile
*book
)
122 cm_return_val_if_fail(book
!= NULL
, FALSE
);
123 return book
->addressCache
->accessFlag
;
127 * Specify address book as accessed.
128 * \param book Address book.
129 * \param value Value.
131 void addrbook_set_accessed(AddressBookFile
*book
, const gboolean value
)
133 cm_return_if_fail(book
!= NULL
);
134 book
->addressCache
->accessFlag
= value
;
137 gboolean
addrbook_get_read_flag(AddressBookFile
*book
)
139 cm_return_val_if_fail(book
!= NULL
, FALSE
);
140 return book
->addressCache
->dataRead
;
143 gint
addrbook_get_status(AddressBookFile
*book
)
145 cm_return_val_if_fail(book
!= NULL
, -1);
149 ItemFolder
*addrbook_get_root_folder(AddressBookFile
*book
)
151 cm_return_val_if_fail(book
!= NULL
, NULL
);
152 return addrcache_get_root_folder(book
->addressCache
);
155 GList
*addrbook_get_list_folder(AddressBookFile
*book
)
157 cm_return_val_if_fail(book
!= NULL
, NULL
);
158 return addrcache_get_list_folder(book
->addressCache
);
161 GList
*addrbook_get_list_person(AddressBookFile
*book
)
163 cm_return_val_if_fail(book
!= NULL
, NULL
);
164 return addrcache_get_list_person(book
->addressCache
);
167 gboolean
addrbook_get_dirty(AddressBookFile
*book
)
169 cm_return_val_if_fail(book
!= NULL
, FALSE
);
170 return addrcache_get_dirty(book
->addressCache
);
174 * Set address book as dirty (needs to be written to file).
175 * \param book Address book.
176 * \param value Dirty flag.
178 void addrbook_set_dirty(AddressBookFile
*book
, const gboolean value
)
180 cm_return_if_fail(book
!= NULL
);
181 addrcache_set_dirty(book
->addressCache
, value
);
186 * \param book Address book.
188 void addrbook_free_book(AddressBookFile
*book
)
190 cm_return_if_fail(book
!= NULL
);
193 addrcache_free(book
->addressCache
);
195 /* Free up internal objects */
197 g_free(book
->fileName
);
198 g_list_free(book
->tempList
);
201 book
->fileName
= NULL
;
203 book
->tempList
= NULL
;
204 book
->tempHash
= NULL
;
206 book
->type
= ADBOOKTYPE_NONE
;
207 book
->addressCache
= NULL
;
208 book
->retVal
= MGU_SUCCESS
;
214 * Print address book header.
215 * \param book Address book.
216 * \param stream Output stream.
218 static void addrbook_print_book(AddressBookFile
*book
, FILE *stream
)
220 cm_return_if_fail(book
!= NULL
);
222 fprintf(stream
, "AddressBook:\n");
223 fprintf(stream
, "\tpath : '%s'\n", book
->path
);
224 fprintf(stream
, "\tfile : '%s'\n", book
->fileName
);
225 fprintf(stream
, "\tstatus : %d\n", book
->retVal
);
226 addrcache_print(book
->addressCache
, stream
);
230 * Dump entire address book traversing folders.
231 * \param book Address book.
232 * \param stream Output stream.
234 void addrbook_dump_book(AddressBookFile
*book
, FILE *stream
)
238 cm_return_if_fail(book
!= NULL
);
240 addrbook_print_book(book
, stream
);
241 folder
= book
->addressCache
->rootFolder
;
242 addritem_print_item_folder(folder
, stream
);
246 * Remove specified group from address book. Note that object should still
248 * Specify name to be used
249 * \param book Address book.
250 * \param group Group to remove.
252 * \return Group, or NULL if not found.
254 ItemGroup
*addrbook_remove_group(AddressBookFile
*book
, ItemGroup
*group
)
256 cm_return_val_if_fail(book
!= NULL
, NULL
);
257 return addrcache_remove_group(book
->addressCache
, group
);
261 * Remove specified person from address book. Note that object should still
263 * \param book Address book.
264 * \param person Person to remove.
265 * \return Person, or NULL if not found.
267 ItemPerson
*addrbook_remove_person(AddressBookFile
*book
, ItemPerson
*person
)
269 cm_return_val_if_fail(book
!= NULL
, NULL
);
270 return addrcache_remove_person(book
->addressCache
, person
);
274 * Remove specified email address in address book for specified person.
275 * Note that object should still be freed.
276 * \param book Address book.
277 * \param person Person.
278 * \param email EMail to remove.
279 * \return EMail object, or NULL if not found.
281 ItemEMail
*addrbook_person_remove_email(AddressBookFile
*book
,
282 ItemPerson
*person
, ItemEMail
*email
)
284 cm_return_val_if_fail(book
!= NULL
, NULL
);
285 return addrcache_person_remove_email(book
->addressCache
, person
, email
);
289 * ***********************************************************************
290 * Read/Write XML data file...
291 * ===========================
293 * 1) The address book is structured as follows:
308 * 2) This sequence of elements was chosen so that the most important
309 * elements (person and their email addresses) appear first.
311 * 3) Groups then appear. When groups are loaded, person's email
312 * addresses have already been loaded and can be found.
314 * 4) Finally folders are loaded. Any forward and backward references
315 * to folders, groups and persons in the folders are resolved after
318 * ***********************************************************************
321 /* Element tag names */
322 #define AB_ELTAG_ADDRESS "address"
323 #define AB_ELTAG_ATTRIBUTE "attribute"
324 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
325 #define AB_ELTAG_ADDRESS_LIST "address-list"
326 #define AB_ELTAG_MEMBER "member"
327 #define AB_ELTAG_MEMBER_LIST "member-list"
328 #define AB_ELTAG_ITEM "item"
329 #define AB_ELTAG_ITEM_LIST "item-list"
330 #define AB_ELTAG_ADDRESS_BOOK "address-book"
331 #define AB_ELTAG_PERSON "person"
332 #define AB_ELTAG_GROUP "group"
333 #define AB_ELTAG_FOLDER "folder"
335 /* Attribute tag names */
336 #define AB_ATTAG_TYPE "type"
337 #define AB_ATTAG_UID "uid"
338 #define AB_ATTAG_NAME "name"
339 #define AB_ATTAG_REMARKS "remarks"
340 #define AB_ATTAG_FIRST_NAME "first-name"
341 #define AB_ATTAG_LAST_NAME "last-name"
342 #define AB_ATTAG_NICK_NAME "nick-name"
343 #define AB_ATTAG_COMMON_NAME "cn"
344 #define AB_ATTAG_ALIAS "alias"
345 #define AB_ATTAG_EMAIL "email"
346 #define AB_ATTAG_EID "eid"
347 #define AB_ATTAG_PID "pid"
349 /* Attribute values */
350 #define AB_ATTAG_VAL_PERSON "person"
351 #define AB_ATTAG_VAL_GROUP "group"
352 #define AB_ATTAG_VAL_FOLDER "folder"
355 * Parse address item for person from XML file.
356 * \param book Address book.
357 * \param file XML file handle.
358 * \param person Person.
360 static void addrbook_parse_address(AddressBookFile
*book
, XMLFile
*file
,
365 ItemEMail
*email
= NULL
;
367 attr
= xml_get_current_tag_attr(file
);
369 name
= ((XMLAttr
*)attr
->data
)->name
;
370 value
= ((XMLAttr
*)attr
->data
)->value
;
372 email
= addritem_create_item_email();
373 if (strcmp(name
, AB_ATTAG_UID
) == 0)
374 ADDRITEM_ID(email
) = g_strdup(value
);
375 else if (strcmp(name
, AB_ATTAG_ALIAS
) == 0)
376 ADDRITEM_NAME(email
) = g_strdup(value
);
377 else if (strcmp(name
, AB_ATTAG_EMAIL
) == 0)
378 email
->address
= g_strdup(value
);
379 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
380 email
->remarks
= g_strdup(value
);
381 attr
= g_list_next(attr
);
385 addrcache_person_add_email(book
->addressCache
, person
,
389 addritem_free_item_email(email
);
396 * Parse list of email address for person from XML file.
397 * \param book Address book.
398 * \param file XML file handle.
399 * \param person Person.
401 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 addrbook_parse_address(book
, file
, person
);
414 addrbook_parse_addr_list(book
, file
, person
);
420 * Parse attribute for person from XML file.
421 * \param book Address book.
422 * \param file XML file handle.
423 * \param person Person.
425 static void addrbook_parse_attribute(XMLFile
*file
, ItemPerson
*person
)
430 UserAttribute
*uAttr
= NULL
;
432 attr
= xml_get_current_tag_attr(file
);
434 name
= ((XMLAttr
*)attr
->data
)->name
;
435 value
= ((XMLAttr
*)attr
->data
)->value
;
436 if (!uAttr
) uAttr
= addritem_create_attribute();
437 if (strcmp(name
, AB_ATTAG_UID
) == 0)
438 addritem_attrib_set_id(uAttr
, value
);
439 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
440 addritem_attrib_set_name(uAttr
, value
);
441 attr
= g_list_next(attr
);
444 element
= xml_get_element(file
);
445 addritem_attrib_set_value(uAttr
, element
);
450 addritem_person_add_attribute(person
, uAttr
);
453 addritem_free_attribute(uAttr
);
460 * Parse list of attributes for person from XML file.
461 * \param book Address book.
462 * \param file XML file handle.
463 * \param person Person.
465 static void addrbook_parse_attr_list(AddressBookFile
*book
, XMLFile
*file
,
471 prev_level
= file
->level
;
472 if (xml_parse_next_tag(file
)) {
473 longjmp( book
->jumper
, 1 );
475 if (file
->level
< prev_level
) return;
476 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE
)) {
477 addrbook_parse_attribute(file
, person
);
478 addrbook_parse_attr_list(book
, file
, person
);
484 * Parse person from XML file.
485 * \param book Address book.
486 * \param file XML file handle.
488 static void addrbook_parse_person(AddressBookFile
*book
, XMLFile
*file
)
492 ItemPerson
*person
= NULL
;
494 attr
= xml_get_current_tag_attr(file
);
496 name
= ((XMLAttr
*)attr
->data
)->name
;
497 value
= ((XMLAttr
*)attr
->data
)->value
;
499 person
= addritem_create_item_person();
500 if (strcmp(name
, AB_ATTAG_UID
) == 0) {
501 ADDRITEM_ID(person
) = g_strdup(value
);
502 person
->picture
= g_strdup(value
);
504 else if (strcmp(name
, AB_ATTAG_FIRST_NAME
) == 0)
505 person
->firstName
= g_strdup(value
);
506 else if (strcmp(name
, AB_ATTAG_LAST_NAME
) == 0)
507 person
->lastName
= g_strdup(value
);
508 else if (strcmp(name
, AB_ATTAG_NICK_NAME
) == 0)
509 person
->nickName
= g_strdup(value
);
510 else if (strcmp(name
, AB_ATTAG_COMMON_NAME
) == 0)
511 ADDRITEM_NAME(person
) = g_strdup(value
);
512 attr
= g_list_next(attr
);
514 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
515 longjmp(book
->jumper
, 1);
517 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS_LIST
)) {
518 addrbook_parse_addr_list(book
, file
, person
);
520 addrcache_hash_add_person(book
->addressCache
, person
);
523 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
524 longjmp(book
->jumper
, 1);
526 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE_LIST
)) {
527 addrbook_parse_attr_list(book
, file
, person
);
532 * Parse group member from XML file.
533 * \param book Address book.
534 * \param file XML file handle.
535 * \param group Group.
537 static void addrbook_parse_member(AddressBookFile
*book
, XMLFile
*file
,
543 /* gchar *pid = NULL; */
544 ItemEMail
*email
= NULL
;
546 attr
= xml_get_current_tag_attr(file
);
548 name
= ((XMLAttr
*)attr
->data
)->name
;
549 value
= ((XMLAttr
*)attr
->data
)->value
;
550 if( strcmp( name
, AB_ATTAG_EID
) == 0 )
551 eid
= g_strdup( value
);
552 attr
= g_list_next(attr
);
554 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
555 email
= addrcache_get_email(book
->addressCache
, eid
);
559 addrcache_group_add_email(book
->addressCache
, group
,
563 addritem_free_item_email(email
);
570 * Parse list of group members from XML file.
571 * \param book Address book.
572 * \param file XML file handle.
573 * \param group Group.
575 static void addrbook_parse_member_list(AddressBookFile
*book
, XMLFile
*file
,
581 prev_level
= file
->level
;
582 if (xml_parse_next_tag(file
)) {
583 longjmp(book
->jumper
, 1);
585 if (file
->level
< prev_level
)
587 if (xml_compare_tag(file
, AB_ELTAG_MEMBER
)) {
588 addrbook_parse_member(book
, file
, group
);
589 addrbook_parse_member_list(book
, file
, group
);
595 * Parse group object from XML file.
596 * \param book Address book.
597 * \param file XML file handle.
599 static void addrbook_parse_group(AddressBookFile
*book
, XMLFile
*file
)
603 ItemGroup
*group
= NULL
;
605 attr
= xml_get_current_tag_attr(file
);
607 name
= ((XMLAttr
*)attr
->data
)->name
;
608 value
= ((XMLAttr
*)attr
->data
)->value
;
610 group
= addritem_create_item_group();
611 if (strcmp(name
, AB_ATTAG_UID
) == 0)
612 ADDRITEM_ID(group
) = g_strdup(value
);
613 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
614 ADDRITEM_NAME(group
) = g_strdup(value
);
615 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
616 group
->remarks
= g_strdup(value
);
617 attr
= g_list_next(attr
);
619 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
620 longjmp(book
->jumper
, 1);
622 if (xml_compare_tag(file
, AB_ELTAG_MEMBER_LIST
)) {
624 addrcache_hash_add_group(book
->addressCache
, group
);
626 addrbook_parse_member_list(book
, file
, group
);
631 * Parse folder item from XML file.
632 * \param book Address book.
633 * \param file XML file handle.
634 * \param folder Folder.
636 static void addrbook_parse_folder_item(AddressBookFile
*book
, XMLFile
*file
,
643 attr
= xml_get_current_tag_attr(file
);
645 name
= ((XMLAttr
*)attr
->data
)->name
;
646 value
= ((XMLAttr
*)attr
->data
)->value
;
647 if (strcmp(name
, AB_ATTAG_UID
) == 0) {
648 uid
= g_strdup(value
);
650 attr
= g_list_next(attr
);
654 folder
->listItems
= g_list_append(folder
->listItems
, uid
);
660 * Parse list of folder items from XML file.
661 * \param book Address book.
662 * \param file XML file handle.
663 * \param folder Folder.
665 static void addrbook_parse_folder_list(AddressBookFile
*book
, XMLFile
*file
,
671 prev_level
= file
->level
;
672 if (xml_parse_next_tag(file
)) {
673 longjmp(book
->jumper
, 1);
675 if (file
->level
< prev_level
)
677 if (xml_compare_tag(file
, AB_ELTAG_ITEM
)) {
678 addrbook_parse_folder_item(book
, file
, folder
);
679 addrbook_parse_folder_list(book
, file
, folder
);
685 * Parse folder from XML file.
686 * \param book Address book.
687 * \param file XML file handle.
689 static void addrbook_parse_folder(AddressBookFile
*book
, XMLFile
*file
)
693 ItemFolder
*folder
= NULL
;
695 attr
= xml_get_current_tag_attr(file
);
697 name
= ((XMLAttr
*)attr
->data
)->name
;
698 value
= ((XMLAttr
*)attr
->data
)->value
;
700 folder
= addritem_create_item_folder();
701 if (strcmp(name
, AB_ATTAG_UID
) == 0)
702 ADDRITEM_ID(folder
) = g_strdup(value
);
703 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
704 ADDRITEM_NAME(folder
) = g_strdup(value
);
705 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
706 folder
->remarks
= g_strdup(value
);
707 attr
= g_list_next(attr
);
709 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
710 longjmp(book
->jumper
, 1);
712 if (xml_compare_tag(file
, AB_ELTAG_ITEM_LIST
)) {
714 if (addrcache_hash_add_folder(book
->addressCache
,
716 book
->tempList
= g_list_append(book
->tempList
,
718 /* We will resolve folder later */
719 ADDRITEM_PARENT(folder
) = NULL
;
722 addrbook_parse_folder_list(book
, file
, folder
);
727 * Read address book (DOM) tree from file.
728 * \param book Address book.
729 * \param file XML file handle.
730 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
733 static gboolean
addrbook_read_tree(AddressBookFile
*book
, XMLFile
*file
)
739 book
->retVal
= MGU_BAD_FORMAT
;
740 if (xml_get_dtd(file
))
742 if (xml_parse_next_tag(file
))
743 longjmp(book
->jumper
, 1);
744 if (!xml_compare_tag(file
, AB_ELTAG_ADDRESS_BOOK
))
747 attr
= xml_get_current_tag_attr(file
);
749 name
= ((XMLAttr
*)attr
->data
)->name
;
750 value
= ((XMLAttr
*)attr
->data
)->value
;
751 if (strcmp( name
, AB_ATTAG_NAME
) == 0)
752 addrbook_set_name( book
, value
);
753 attr
= g_list_next( attr
);
760 /* Get next item tag (person, group or folder) */
761 if (xml_parse_next_tag(file
))
762 longjmp( book
->jumper
, 1 );
764 if (xml_compare_tag(file
, AB_ELTAG_PERSON
))
765 addrbook_parse_person(book
, file
);
766 else if (xml_compare_tag(file
, AB_ELTAG_GROUP
))
767 addrbook_parse_group(book
, file
);
768 else if (xml_compare_tag(file
, AB_ELTAG_FOLDER
))
769 addrbook_parse_folder(book
, file
);
771 if (retVal
) book
->retVal
= MGU_SUCCESS
;
776 * Resolve folder items callback function.
777 * \param key Table key.
778 * \param value Reference to object contained in folder.
779 * \param data Reference to address book.
781 static void addrbook_res_items_vis(gpointer key
, gpointer value
, gpointer data
)
783 AddressBookFile
*book
= data
;
784 AddrItemObject
*obj
= (AddrItemObject
*) value
;
785 ItemFolder
*rootFolder
= book
->addressCache
->rootFolder
;
786 if (obj
->parent
== NULL
) {
787 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
788 rootFolder
->listPerson
= g_list_append(rootFolder
->listPerson
,
790 ADDRITEM_PARENT(obj
) = ADDRITEM_OBJECT(rootFolder
);
792 else if (ADDRITEM_TYPE(obj
) == ITEMTYPE_GROUP
) {
793 rootFolder
->listGroup
= g_list_append(rootFolder
->listGroup
,
795 ADDRITEM_PARENT(obj
) = ADDRITEM_OBJECT(rootFolder
);
801 * Resolve folder items. Lists of UID's are replaced with pointers to
803 * \param book Address book.
805 static void addrbook_resolve_folder_items(AddressBookFile
*book
)
807 GList
*nodeFolder
= NULL
;
808 GList
*listRemove
= NULL
;
810 ItemFolder
*rootFolder
= book
->addressCache
->rootFolder
;
811 nodeFolder
= book
->tempList
;
814 ItemFolder
*folder
= nodeFolder
->data
;
816 node
= folder
->listItems
;
818 gchar
*uid
= node
->data
;
819 AddrItemObject
*aio
= addrcache_get_object(book
->addressCache
,
822 if (aio
->type
== ITEMTYPE_FOLDER
) {
823 ItemFolder
*item
= (ItemFolder
*) aio
;
824 folder
->listFolder
= g_list_append(folder
->listFolder
, item
);
825 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
826 addrcache_hash_add_folder(book
->addressCache
, folder
);
828 else if (aio
->type
== ITEMTYPE_PERSON
) {
829 ItemPerson
*item
= (ItemPerson
*) aio
;
830 folder
->listPerson
= g_list_append(folder
->listPerson
, item
);
831 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
833 else if (aio
->type
== ITEMTYPE_GROUP
) {
834 ItemGroup
*item
= (ItemGroup
*) aio
;
835 folder
->listGroup
= g_list_append(folder
->listGroup
, item
);
836 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
838 /* Replace data with pointer to item */
842 else { /* Not found, append to remove list. */
843 listRemove
= g_list_append(listRemove
, uid
);
845 node
= g_list_next(node
);
847 rootFolder
->listFolder
= g_list_append(rootFolder
->listFolder
,
849 /* Process remove list */
852 gchar
*uid
= node
->data
;
853 folder
->listItems
= g_list_remove(folder
->listItems
,
856 node
= g_list_next(node
);
858 g_list_free(listRemove
);
859 nodeFolder
= g_list_next(nodeFolder
);
861 /* Remove folders with parents. */
863 node
= rootFolder
->listFolder
;
865 ItemFolder
*folder
= (ItemFolder
*) node
->data
;
866 if (ADDRITEM_PARENT(folder
))
867 /* Remove folders with parents */
868 listRemove
= g_list_append(listRemove
, folder
);
869 else /* Add to root folder */
870 ADDRITEM_PARENT(folder
) = ADDRITEM_OBJECT(book
->addressCache
->rootFolder
);
872 node
= g_list_next( node
);
874 /* Process remove list */
877 rootFolder
->listFolder
= g_list_remove(rootFolder
->listFolder
,
879 node
= g_list_next(node
);
881 g_list_free(listRemove
);
883 /* Move all unparented persons and groups into root folder */
884 g_hash_table_foreach(book
->addressCache
->itemHash
,
885 addrbook_res_items_vis
, book
);
887 /* Free up some more */
888 nodeFolder
= book
->tempList
;
890 ItemFolder
*folder
= nodeFolder
->data
;
891 g_list_free(folder
->listItems
);
892 folder
->listItems
= NULL
;
893 nodeFolder
= g_list_next(nodeFolder
);
895 g_list_free(book
->tempList
);
896 book
->tempList
= NULL
;
901 * \param book Address book.
902 * \return Status code.
904 gint
addrbook_read_data(AddressBookFile
*book
)
906 XMLFile
*file
= NULL
;
907 gchar
*fileSpec
= NULL
;
909 cm_return_val_if_fail(book
!= NULL
, -1);
912 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
913 addrcache_get_name( book->addressCache ) );
916 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
,
917 book
->fileName
, NULL
);
918 book
->retVal
= MGU_OPEN_FILE
;
919 addrcache_clear(book
->addressCache
);
920 book
->addressCache
->modified
= FALSE
;
921 book
->addressCache
->accessFlag
= FALSE
;
922 file
= xml_open_file(fileSpec
);
925 book
->tempList
= NULL
;
926 /* Trap for parsing errors. */
927 if (setjmp( book
->jumper
)) {
928 xml_close_file(file
);
931 addrbook_read_tree(book
, file
);
932 xml_close_file(file
);
933 /* Resolve folder items */
934 addrbook_resolve_folder_items(book
);
935 book
->tempList
= NULL
;
936 book
->addressCache
->modified
= FALSE
;
937 book
->addressCache
->dataRead
= TRUE
;
938 addrcache_set_dirty(book
->addressCache
, FALSE
);
944 * Write start element to file.
945 * \param fp File handle.
946 * \param lvl Indent level.
947 * \param name Element name.
949 static int addrbook_write_elem_s(FILE *fp
, gint lvl
, gchar
*name
)
952 for (i
= 0; i
< lvl
; i
++)
953 if (fputs(" ", fp
) == EOF
)
955 if (fputs("<", fp
) == EOF
)
957 if (fputs(name
, fp
) == EOF
)
964 * Write end element to file.
965 * \param fp File handle.
966 * \param lvl Indent level.
967 * \param name Element name.
969 static int addrbook_write_elem_e(FILE *fp
, gint lvl
, gchar
*name
)
972 for(i
= 0; i
< lvl
; i
++)
973 if (fputs(" ", fp
) == EOF
)
975 if (fputs("</", fp
) == EOF
)
977 if (fputs(name
, fp
) == EOF
)
979 if (fputs(">\n", fp
) == EOF
)
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 int addrbook_write_attr(FILE *fp
, gchar
*name
, gchar
*value
)
993 if (fputs(" ", fp
) == EOF
)
995 if (fputs(name
, fp
) == EOF
)
997 if (fputs("=\"", fp
) == EOF
)
999 if (xml_file_put_escape_str(fp
, value
) < 0)
1001 if (fputs("\"", fp
) == EOF
)
1007 typedef struct _HashLoopData
{
1013 * Write person and associated addresses and attributes to file.
1014 * file hash table visitor function.
1015 * \param key Table key.
1016 * \param value Reference to person.
1017 * \param data File pointer.
1019 static void addrbook_write_item_person_vis(gpointer key
, gpointer value
,
1022 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1023 HashLoopData
*data
= (HashLoopData
*)d
;
1024 FILE *fp
= data
->fp
;
1029 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
1030 ItemPerson
*person
= (ItemPerson
*) value
;
1032 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_PERSON
) < 0)
1034 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(person
)) < 0)
1036 if (addrbook_write_attr(fp
, AB_ATTAG_FIRST_NAME
, person
->firstName
) < 0)
1038 if (addrbook_write_attr(fp
, AB_ATTAG_LAST_NAME
, person
->lastName
) < 0)
1040 if (addrbook_write_attr(fp
, AB_ATTAG_NICK_NAME
, person
->nickName
) < 0)
1042 if (addrbook_write_attr(fp
, AB_ATTAG_COMMON_NAME
, ADDRITEM_NAME(person
)) < 0)
1044 if (fputs(" >\n", fp
) == EOF
)
1047 /* Output email addresses */
1048 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ADDRESS_LIST
) < 0)
1050 if (fputs(">\n", fp
) == EOF
)
1052 node
= person
->listEMail
;
1054 ItemEMail
*email
= node
->data
;
1055 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ADDRESS
) < 0)
1057 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(email
)) < 0)
1059 if (addrbook_write_attr(fp
, AB_ATTAG_ALIAS
, ADDRITEM_NAME(email
)) < 0)
1061 if (addrbook_write_attr(fp
, AB_ATTAG_EMAIL
, email
->address
) < 0)
1063 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, email
->remarks
) < 0)
1065 if (fputs(" />\n", fp
) == EOF
)
1067 node
= g_list_next(node
);
1069 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ADDRESS_LIST
) < 0)
1072 /* Output user attributes */
1073 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ATTRIBUTE_LIST
) < 0)
1075 if (fputs(">\n", fp
) == EOF
)
1077 node
= person
->listAttrib
;
1079 UserAttribute
*attrib
= node
->data
;
1080 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ATTRIBUTE
) < 0)
1082 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, attrib
->uid
) < 0)
1084 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, attrib
->name
) < 0)
1086 if (fputs(" >", fp
) == EOF
)
1088 if (xml_file_put_escape_str(fp
, attrib
->value
) < 0)
1090 if (addrbook_write_elem_e(fp
, 0, AB_ELTAG_ATTRIBUTE
) < 0)
1092 node
= g_list_next(node
);
1094 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ATTRIBUTE_LIST
) < 0)
1096 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_PERSON
) < 0)
1103 * Write group and associated references to addresses to file.
1104 * file hash table visitor function.
1105 * \param key Table key.
1106 * \param value Reference to group.
1107 * \param data File pointer.
1109 static void addrbook_write_item_group_vis(gpointer key
, gpointer value
,
1112 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1113 HashLoopData
*data
= (HashLoopData
*)d
;
1114 FILE *fp
= data
->fp
;
1120 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_GROUP
) {
1121 ItemGroup
*group
= (ItemGroup
*) value
;
1123 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_GROUP
) < 0)
1125 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(group
)) < 0)
1127 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, ADDRITEM_NAME(group
)) < 0)
1129 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, group
->remarks
) < 0)
1131 if (fputs(" >\n", fp
) == EOF
)
1134 /* Output email address links */
1135 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_MEMBER_LIST
) < 0)
1137 if (fputs(">\n", fp
) == EOF
)
1139 node
= group
->listEMail
;
1141 ItemEMail
*email
= node
->data
;
1142 ItemPerson
*person
= (ItemPerson
*) ADDRITEM_PARENT(email
);
1143 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_MEMBER
) < 0)
1145 if (addrbook_write_attr(fp
, AB_ATTAG_PID
, ADDRITEM_ID(person
)) < 0)
1147 if (addrbook_write_attr(fp
, AB_ATTAG_EID
, ADDRITEM_ID(email
)) < 0)
1149 if (fputs(" />\n", fp
) == EOF
)
1151 node
= g_list_next(node
);
1153 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_MEMBER_LIST
) < 0)
1155 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_GROUP
) < 0)
1162 * Write folder and associated references to addresses to file.
1163 * file hash table visitor function.
1164 * \param key Table key.
1165 * \param value Reference to folder.
1166 * \param data File pointer.
1168 static void addrbook_write_item_folder_vis(gpointer key
, gpointer value
,
1171 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1172 HashLoopData
*data
= (HashLoopData
*)d
;
1173 FILE *fp
= data
->fp
;
1178 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_FOLDER
) {
1179 ItemFolder
*folder
= (ItemFolder
*) value
;
1181 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_FOLDER
) < 0)
1183 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(folder
)) < 0)
1185 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, ADDRITEM_NAME(folder
)) < 0)
1187 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, folder
->remarks
) < 0)
1189 if (fputs(" >\n", fp
) == EOF
)
1191 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ITEM_LIST
) < 0)
1193 if (fputs(">\n", fp
) == EOF
)
1196 /* Output persons */
1197 node
= folder
->listPerson
;
1199 ItemPerson
*item
= node
->data
;
1200 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1202 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_PERSON
) < 0)
1204 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1206 if (fputs(" />\n", fp
) == EOF
)
1208 node
= g_list_next(node
);
1212 node
= folder
->listGroup
;
1214 ItemGroup
*item
= node
->data
;
1215 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1217 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_GROUP
) < 0)
1219 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1221 if (fputs(" />\n", fp
) == EOF
)
1223 node
= g_list_next(node
);
1226 /* Output folders */
1227 node
= folder
->listFolder
;
1229 ItemFolder
*item
= node
->data
;
1230 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1232 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_FOLDER
) < 0)
1234 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1236 if (fputs(" />\n", fp
) == EOF
)
1238 node
= g_list_next(node
);
1240 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ITEM_LIST
) < 0)
1242 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_FOLDER
) < 0)
1249 * Output address book data to specified file.
1250 * \param book Address book.
1251 * \param newFile Filename of new file (in book's filepath).
1252 * \return Status code.
1254 static gint
addrbook_write_to(AddressBookFile
*book
, gchar
*newFile
)
1259 #ifndef DEV_STANDALONE
1263 cm_return_val_if_fail(book
!= NULL
, -1);
1264 cm_return_val_if_fail(newFile
!= NULL
, -1);
1266 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
, newFile
, NULL
);
1268 book
->retVal
= MGU_OPEN_FILE
;
1269 #ifdef DEV_STANDALONE
1270 fp
= g_fopen(fileSpec
, "wb");
1273 if (fputs("<?xml version=\"1.0\" ?>\n", fp
) == EOF
) {
1274 book
->retVal
= MGU_ERROR_WRITE
;
1275 return book
->retVal
;
1278 pfile
= prefs_write_open(fileSpec
);
1282 if (fprintf( fp
, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL
) < 0)
1285 if (addrbook_write_elem_s(fp
, 0, AB_ELTAG_ADDRESS_BOOK
) < 0)
1287 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
,
1288 addrcache_get_name(book
->addressCache
)) < 0)
1290 if (fputs(" >\n", fp
) == EOF
)
1293 /* Output all persons */
1297 g_hash_table_foreach(book
->addressCache
->itemHash
,
1298 addrbook_write_item_person_vis
, &data
);
1302 /* Output all groups */
1303 g_hash_table_foreach(book
->addressCache
->itemHash
,
1304 addrbook_write_item_group_vis
, &data
);
1309 /* Output all folders */
1310 g_hash_table_foreach(book
->addressCache
->itemHash
,
1311 addrbook_write_item_folder_vis
, &data
);
1316 if (addrbook_write_elem_e(fp
, 0, AB_ELTAG_ADDRESS_BOOK
) < 0)
1319 book
->retVal
= MGU_SUCCESS
;
1320 #ifdef DEV_STANDALONE
1323 if (prefs_file_close( pfile
) < 0)
1324 book
->retVal
= MGU_ERROR_WRITE
;
1329 return book
->retVal
;
1331 g_warning("error writing AB");
1332 book
->retVal
= MGU_ERROR_WRITE
;
1334 prefs_file_close_revert( pfile
);
1335 return book
->retVal
;
1339 * Output address book data to original file.
1340 * \param book Address book.
1341 * \return Status code.
1343 gint
addrbook_save_data(AddressBookFile
*book
)
1345 cm_return_val_if_fail(book
!= NULL
, -1);
1347 book
->retVal
= MGU_NO_FILE
;
1348 if (book
->fileName
== NULL
|| *book
->fileName
== '\0')
1349 return book
->retVal
;
1350 if (book
->path
== NULL
|| *book
->path
== '\0')
1351 return book
->retVal
;
1353 addrbook_write_to(book
, book
->fileName
);
1354 if (book
->retVal
== MGU_SUCCESS
)
1355 addrcache_set_dirty(book
->addressCache
, FALSE
);
1356 return book
->retVal
;
1360 * **********************************************************************
1361 * Address book edit interface functions.
1362 * **********************************************************************
1366 * Hash table callback function for simple deletion of hashtable entries.
1367 * \param key Table key (will be freed).
1368 * \param value Value stored in table.
1369 * \param data User data.
1370 * \return <i>TRUE</i> to indicate that entry freed.
1372 static gboolean
addrbook_free_simple_hash_vis(gpointer
*key
, gpointer
*value
,
1382 * Update address book email list for specified person. Note: The existing
1383 * email addresses are replaced with the new addresses. Any references to
1384 * old addresses in the groups are re-linked to the new addresses. All old
1385 * addresses linked to the person are removed.
1386 * \param book Address book.
1387 * \param person Person to update.
1388 * \param listEMail List of new email addresses.
1390 void addrbook_update_address_list(AddressBookFile
*book
, ItemPerson
*person
,
1397 cm_return_if_fail(book
!= NULL
);
1398 cm_return_if_fail(person
!= NULL
);
1400 /* Get groups where person's existing email addresses are listed */
1401 listGroup
= addrcache_get_group_for_person(book
->addressCache
, person
);
1403 GHashTable
*hashEMail
;
1404 GHashTable
*hashEMailAlias
;
1407 /* Load hash table with new address entries */
1408 hashEMail
= g_hash_table_new(g_str_hash
, g_str_equal
);
1409 hashEMailAlias
= g_hash_table_new(g_str_hash
, g_str_equal
);
1412 ItemEMail
*email
= node
->data
;
1413 gchar
*alias
= email
->obj
.name
;
1414 gchar
*addr
= g_utf8_strdown(email
->address
, -1);
1415 if (!g_hash_table_lookup(hashEMail
, addr
)) {
1416 g_hash_table_insert(hashEMail
, addr
, email
);
1418 if (*alias
!= '\0' && ! g_hash_table_lookup(hashEMailAlias
,
1420 g_hash_table_insert(hashEMailAlias
, alias
, email
);
1422 node
= g_list_next(node
);
1425 /* Re-parent new addresses to existing groups, where email address match. */
1426 nodeGrp
= listGroup
;
1428 ItemGroup
*group
= (ItemGroup
*) nodeGrp
->data
;
1429 GList
*groupEMail
= group
->listEMail
;
1431 GList
*listRemove
= NULL
;
1433 /* Process each email item linked to group */
1434 nodeGrpEM
= groupEMail
;
1436 ItemEMail
*emailGrp
= (ItemEMail
*) nodeGrpEM
->data
;
1438 if (ADDRITEM_PARENT(emailGrp
) == ADDRITEM_OBJECT(person
)) {
1439 /* Found an email address for this person */
1440 ItemEMail
*emailNew
= NULL
;
1441 gchar
*alias
= emailGrp
->obj
.name
;
1442 gchar
*addr
= g_utf8_strdown(emailGrp
->address
, -1);
1443 emailNew
= (ItemEMail
*)
1444 g_hash_table_lookup(hashEMail
, addr
);
1446 /* If no match by e-mail, try to match by e-mail alias */
1447 if (!emailNew
&& *alias
!= '\0') {
1448 emailNew
= (ItemEMail
*)
1449 g_hash_table_lookup(hashEMailAlias
, alias
);
1453 /* Point to this entry */
1454 nodeGrpEM
->data
= emailNew
;
1455 else if (g_hash_table_size(hashEMail
)==1)
1456 /* If the person has just one e-mail address, then
1457 change e-mail address in group list */
1458 nodeGrpEM
->data
= listEMail
->data
;
1460 /* Mark for removal */
1461 listRemove
= g_list_append(listRemove
, emailGrp
);
1463 /* Move on to next email link */
1464 nodeGrpEM
= g_list_next(nodeGrpEM
);
1467 /* Process all removed links in current group */
1468 nodeGrpEM
= listRemove
;
1470 ItemEMail
*emailGrp
= nodeGrpEM
->data
;
1471 groupEMail
= g_list_remove(groupEMail
, emailGrp
);
1472 nodeGrpEM
= g_list_next(nodeGrpEM
);
1475 g_list_free(listRemove
);
1477 /* Move on to next group */
1478 nodeGrp
= g_list_next(nodeGrp
);
1481 /* Clear hash table */
1482 g_hash_table_foreach_remove(hashEMail
, (GHRFunc
)
1483 addrbook_free_simple_hash_vis
, NULL
);
1484 g_hash_table_destroy(hashEMail
);
1486 g_hash_table_destroy(hashEMailAlias
);
1487 hashEMailAlias
= NULL
;
1488 g_list_free(listGroup
);
1491 /* Remove old addresses from person and cache */
1493 node
= person
->listEMail
;
1495 ItemEMail
*email
= node
->data
;
1497 if (addrcache_person_remove_email(book
->addressCache
, person
, email
))
1498 addrcache_remove_email(book
->addressCache
, email
);
1500 listDelete
= g_list_append(listDelete
, email
);
1501 node
= person
->listEMail
;
1503 /* Add new address entries */
1506 ItemEMail
*email
= node
->data
;
1508 if (ADDRITEM_ID(email
) == NULL
)
1509 /* Allocate an ID for new address */
1510 addrcache_id_email(book
->addressCache
, email
);
1512 addrcache_person_add_email( book
->addressCache
, person
, email
);
1513 node
= g_list_next( node
);
1516 addrcache_set_dirty(book
->addressCache
, TRUE
);
1518 /* Free up memory */
1519 g_list_free(listEMail
);
1524 ItemEMail
*email
= node
->data
;
1526 addritem_free_item_email(email
);
1527 node
= g_list_next(node
);
1529 g_list_free(listDelete
);
1535 * Create person object and add person with specified address data to address
1536 * book. Note: A new person is created with specified list of email addresses.
1537 * All objects inserted into address book.
1539 * \param book Address book.
1540 * \param folder Parent folder where to add person, or <i>NULL</i> for
1542 * \param listEMail List of new email addresses to associate with person.
1543 * \return Person object created.
1545 ItemPerson
*addrbook_add_address_list(AddressBookFile
*book
, ItemFolder
*folder
,
1549 ItemFolder
*f
= folder
;
1552 cm_return_val_if_fail(book
!= NULL
, NULL
);
1555 f
= book
->addressCache
->rootFolder
;
1556 person
= addritem_create_item_person();
1557 addrcache_id_person(book
->addressCache
, person
);
1558 addrcache_folder_add_person(book
->addressCache
, f
, person
);
1562 ItemEMail
*email
= node
->data
;
1563 if (ADDRITEM_ID(email
) == NULL
)
1564 addrcache_id_email(book
->addressCache
, email
);
1566 addrcache_person_add_email(book
->addressCache
, person
, email
);
1567 node
= g_list_next(node
);
1573 * Build available email list visitor function.
1574 * \param key Table key.
1575 * \param value Value stored in table.
1576 * \param data Reference to address book.
1578 static void addrbook_build_avail_email_vis(gpointer key
, gpointer value
,
1581 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1583 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
1584 AddressBookFile
*book
= data
;
1585 ItemPerson
*person
= (ItemPerson
*) obj
;
1586 GList
*node
= person
->listEMail
;
1588 ItemEMail
*email
= node
->data
;
1589 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1591 if (!g_hash_table_lookup(book
->tempHash
,
1592 ADDRITEM_ID(email
)))
1593 book
->tempList
= g_list_append(book
->tempList
, email
);
1595 node
= g_list_next(node
);
1601 * Return link list of available email items that have not already been linked
1602 * to groups. Note that the list contains references to items and should be
1603 * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1604 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1607 * \param book Address book.
1608 * \param group Group to process.
1609 * \return List of items, or <i>NULL</i> if none.
1611 GList
*addrbook_get_available_email_list(AddressBookFile
*book
, ItemGroup
*group
)
1616 cm_return_val_if_fail(book
!= NULL
, NULL
);
1618 /* Load hash table with group email entries */
1619 table
= g_hash_table_new(g_str_hash
, g_str_equal
);
1621 list
= group
->listEMail
;
1623 ItemEMail
*email
= list
->data
;
1624 g_hash_table_insert(table
, ADDRITEM_ID(email
), email
);
1625 list
= g_list_next(list
);
1629 /* Build list of available email addresses which exclude those already in groups */
1630 book
->tempList
= NULL
;
1631 book
->tempHash
= table
;
1632 g_hash_table_foreach(book
->addressCache
->itemHash
,
1633 addrbook_build_avail_email_vis
, book
);
1634 list
= book
->tempList
;
1635 book
->tempList
= NULL
;
1636 book
->tempHash
= NULL
;
1638 /* Clear hash table */
1639 g_hash_table_destroy(table
);
1646 * Update address book email list for specified group. Note: The existing email
1647 * addresses are replaced with the new addresses. Any references to old addresses
1648 * in the groups are re-linked to the new addresses. All old addresses linked to
1649 * the person are removed.
1651 * \param book Address book.
1652 * \param group Group to process.
1653 * \param listEMail List of email items. This should <b>*NOT*</b> be
1654 * <code>g_free()</code> when done.
1656 void addrbook_update_group_list(AddressBookFile
*book
, ItemGroup
*group
,
1661 cm_return_if_fail(book
!= NULL
);
1662 cm_return_if_fail(group
!= NULL
);
1664 addrcache_set_dirty(book
->addressCache
, TRUE
);
1666 /* Remember old list */
1667 oldData
= group
->listEMail
;
1668 group
->listEMail
= listEMail
;
1669 mgu_clear_list(oldData
);
1674 * Create group object and add with specifed list of email addresses to
1675 * address book. Note: The existing email addresses are replaced with the new
1676 * addresses. Any references to old addresses in the groups are re-linked to
1677 * the new addresses. All old addresses linked to the person are removed.
1679 * \param book Address book.
1680 * \param folder Parent folder where to add group, or <i>NULL</i> for
1682 * \param listEMail List of email items. This should <b>*NOT*</b> be
1683 * <code>g_free()</code> when done.
1684 * \return Group object created.
1686 ItemGroup
*addrbook_add_group_list(AddressBookFile
*book
, ItemFolder
*folder
,
1689 ItemGroup
*group
= NULL
;
1690 ItemFolder
*f
= folder
;
1692 cm_return_val_if_fail(book
!= NULL
, NULL
);
1695 f
= book
->addressCache
->rootFolder
;
1696 group
= addritem_create_item_group();
1697 addrcache_id_group(book
->addressCache
, group
);
1698 addrcache_folder_add_group(book
->addressCache
, f
, group
);
1699 group
->listEMail
= listEMail
;
1704 * Create a new folder and add to address book.
1705 * \param book Address book.
1706 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1708 * \return Folder that was created. This should <b>*NOT*</b> be
1709 * <code>g_free()</code> when done.
1711 ItemFolder
*addrbook_add_new_folder(AddressBookFile
*book
, ItemFolder
*parent
)
1713 cm_return_val_if_fail(book
!= NULL
, NULL
);
1714 return addrcache_add_new_folder( book
->addressCache
, parent
);
1718 * Update address book attribute list for specified person. Note: The existing
1719 * attributes are replaced with the new addresses. All old attributes linked
1720 * to the person are removed.
1722 * \param book Address book.
1723 * \param person Person to receive attributes.
1724 * \param listAttrib New list of attributes.
1726 void addrbook_update_attrib_list(AddressBookFile
*book
, ItemPerson
*person
,
1732 cm_return_if_fail(book
!= NULL
);
1733 cm_return_if_fail(person
!= NULL
);
1735 /* Remember old list */
1736 oldData
= person
->listAttrib
;
1738 /* Attach new address list to person. */
1741 UserAttribute
*attrib
= node
->data
;
1742 if (attrib
->uid
== NULL
) {
1743 /* Allocate an ID */
1744 addrcache_id_attribute(book
->addressCache
, attrib
);
1746 node
= g_list_next(node
);
1748 person
->listAttrib
= listAttrib
;
1749 addrcache_set_dirty(book
->addressCache
, TRUE
);
1751 /* Free up old data */
1752 addritem_free_list_attribute(oldData
);
1757 * Add attribute data for specified person to address book. Note: Only
1758 * attributes are inserted into address book.
1759 * \param book Address book.
1760 * \param person Person to receive attributes.
1761 * \param listAttrib List of attributes.
1763 void addrbook_add_attrib_list( AddressBookFile
*book
, ItemPerson
*person
, GList
*listAttrib
) {
1766 cm_return_if_fail( book
!= NULL
);
1767 cm_return_if_fail( person
!= NULL
);
1771 UserAttribute
*attrib
= node
->data
;
1772 if( attrib
->uid
== NULL
) {
1773 addrcache_id_attribute( book
->addressCache
, attrib
);
1775 addritem_person_add_attribute( person
, attrib
);
1776 node
= g_list_next( node
);
1778 addrcache_set_dirty( book
->addressCache
, TRUE
);
1781 #define WORK_BUFLEN 1024
1782 #define ADDRBOOK_DIGITS "0123456789"
1785 * Return list of existing address book files.
1786 * \param book Address book.
1787 * \return List of files (as strings).
1789 GList
*addrbook_get_bookfile_list(AddressBookFile
*book
) {
1792 const gchar
*dir_name
;
1794 gchar buf
[WORK_BUFLEN
+ 1];
1795 gchar numbuf
[WORK_BUFLEN
];
1796 gint len
, lenpre
, lensuf
, lennum
;
1797 long int val
, maxval
;
1798 GList
*fileList
= NULL
;
1800 cm_return_val_if_fail(book
!= NULL
, NULL
);
1802 if (book
->path
== NULL
|| *book
->path
== '\0') {
1803 book
->retVal
= MGU_NO_PATH
;
1807 strncpy(buf
, book
->path
, WORK_BUFLEN
);
1810 if (buf
[len
-1] != G_DIR_SEPARATOR
) {
1811 buf
[len
] = G_DIR_SEPARATOR
;
1816 adbookdir
= g_strdup(buf
);
1817 strncat(buf
, ADDRBOOK_PREFIX
, WORK_BUFLEN
- strlen(buf
));
1819 if( ( dir
= g_dir_open( adbookdir
, 0, NULL
) ) == NULL
) {
1820 book
->retVal
= MGU_OPEN_DIRECTORY
;
1825 lenpre
= strlen(ADDRBOOK_PREFIX
);
1826 lensuf
= strlen(ADDRBOOK_SUFFIX
);
1827 lennum
= FILE_NUMDIGITS
+ lenpre
;
1830 while( ( dir_name
= g_dir_read_name( dir
) ) != NULL
) {
1831 gchar
*endptr
= NULL
;
1835 strncpy(buf
, adbookdir
, WORK_BUFLEN
);
1836 strncat(buf
, dir_name
, WORK_BUFLEN
- strlen(buf
));
1837 r
= g_stat(buf
, &statbuf
);
1838 if (r
== 0 && S_ISREG(statbuf
.st_mode
)) {
1841 ADDRBOOK_PREFIX
, lenpre
) == 0)
1844 (dir_name
) + lennum
,
1845 ADDRBOOK_SUFFIX
, lensuf
) == 0)
1848 (dir_name
) + lenpre
,
1850 numbuf
[FILE_NUMDIGITS
] = '\0';
1852 for(i
= 0; i
< FILE_NUMDIGITS
; i
++) {
1853 if(!strchr(ADDRBOOK_DIGITS
, numbuf
[i
])) {
1860 val
= strtol(numbuf
, &endptr
, 10);
1861 if (endptr
&& val
> -1) {
1862 if (val
> maxval
) maxval
= val
;
1863 fileList
= g_list_append(
1865 g_strdup(dir_name
));
1875 book
->maxValue
= maxval
;
1876 book
->retVal
= MGU_SUCCESS
;
1881 * Return file name for specified file number.
1882 * \param fileNum File number.
1883 * \return File name, or <i>NULL</i> if file number too large. Should be
1884 * <code>g_free()</code> when done.
1886 gchar
*addrbook_gen_new_file_name(gint fileNum
) {
1888 gchar buf
[WORK_BUFLEN
];
1894 nmax
= -1 + (long int) pow(10, FILE_NUMDIGITS
);
1897 g_snprintf(fmt
, sizeof(fmt
), "%%s%%0%dd%%s", FILE_NUMDIGITS
);
1898 g_snprintf(buf
, sizeof(buf
), fmt
, ADDRBOOK_PREFIX
, n
, ADDRBOOK_SUFFIX
);
1899 return g_strdup(buf
);
1903 * **********************************************************************
1904 * Address book test functions...
1905 * **********************************************************************
1909 * Attempt to parse list of email address from file.
1910 * \param book Address book.
1911 * \param file XML file handle.
1913 static void addrbook_chkparse_addr_list( AddressBookFile
*book
, XMLFile
*file
)
1919 prev_level
= file
->level
;
1920 if (xml_parse_next_tag(file
))
1921 longjmp(book
->jumper
, 1);
1922 if (file
->level
< prev_level
)
1924 /* attr = xml_get_current_tag_attr(file); */
1925 /* addrbook_show_attribs( attr ); */
1926 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS
))
1927 addrbook_chkparse_addr_list(book
, file
);
1932 * Attempt to parse attributes for person address from file.
1933 * \param book Address book.
1934 * \param file XML file handle.
1936 static void addrbook_chkparse_attribute(AddressBookFile
*book
, XMLFile
*file
)
1939 /* gchar *element; */
1941 /* attr = xml_get_current_tag_attr(file); */
1942 /* addrbook_show_attribs( attr ); */
1943 /* element = xml_get_element(file); */
1944 /* g_print( "\t\tattrib value : %s\n", element ); */
1948 * Attempt to parse list of attributes for person address from file.
1949 * \param book Address book.
1950 * \param file XML file handle.
1952 static void addrbook_chkparse_attr_list(AddressBookFile
*book
, XMLFile
*file
)
1957 prev_level
= file
->level
;
1958 if (xml_parse_next_tag(file
))
1959 longjmp(book
->jumper
, 1);
1960 if (file
->level
< prev_level
)
1962 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE
)) {
1963 addrbook_chkparse_attribute(book
, file
);
1964 addrbook_chkparse_attr_list(book
, file
);
1970 * Attempt to parse person from file.
1971 * \param book Address book.
1972 * \param file XML file handle.
1974 static void addrbook_chkparse_person(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_ADDRESS_LIST
))
1984 addrbook_chkparse_addr_list(book
, file
);
1986 if (xml_parse_next_tag(file
)) /* Consume closing tag */
1987 longjmp(book
->jumper
, 1);
1989 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE_LIST
))
1990 addrbook_chkparse_attr_list(book
, file
);
1994 * Attempt to parse list of members from file.
1995 * \param book Address book.
1996 * \param file XML file handle.
1998 static void addrbook_chkparse_member_list(AddressBookFile
*book
, XMLFile
*file
)
2004 prev_level
= file
->level
;
2005 if (xml_parse_next_tag(file
))
2006 longjmp(book
->jumper
, 1);
2008 if (file
->level
< prev_level
)
2011 if (xml_compare_tag(file
, AB_ELTAG_MEMBER
)) {
2012 /* attr = xml_get_current_tag_attr(file); */
2013 /* addrbook_show_attribs( attr ); */
2014 addrbook_chkparse_member_list(book
, file
);
2017 /* attr = xml_get_current_tag_attr(file); */
2018 /* addrbook_show_attribs( attr ); */
2024 * Attempt to parse group from file.
2025 * \param book Address book.
2026 * \param file XML file handle.
2028 static void addrbook_chkparse_group(AddressBookFile
*book
, XMLFile
*file
)
2032 /* attr = xml_get_current_tag_attr(file); */
2033 /* addrbook_show_attribs( attr ); */
2034 if (xml_parse_next_tag(file
)) /* Consume closing tag */
2035 longjmp(book
->jumper
, 1);
2037 if (xml_compare_tag(file
, AB_ELTAG_MEMBER_LIST
))
2038 addrbook_chkparse_member_list(book
, file
);
2042 * Attempt to parse list of folders from file.
2043 * \param book Address book.
2044 * \param file XML file handle.
2046 static void addrbook_chkparse_folder_list(AddressBookFile
*book
, XMLFile
*file
)
2052 prev_level
= file
->level
;
2053 if (xml_parse_next_tag(file
))
2054 longjmp(book
->jumper
, 1);
2056 if (file
->level
< prev_level
)
2059 if (xml_compare_tag(file
, AB_ELTAG_ITEM
)) {
2060 /* attr = xml_get_current_tag_attr(file); */
2061 /* addrbook_show_attribs( attr ); */
2062 addrbook_chkparse_folder_list(book
, file
);
2065 /* attr = xml_get_current_tag_attr(file); */
2066 /* addrbook_show_attribs( attr ); */
2072 * Attempt to parse a folder from file.
2073 * \param book Address book.
2074 * \param file XML file handle.
2076 static void addrbook_chkparse_folder(AddressBookFile
*book
, XMLFile
*file
)
2080 /* attr = xml_get_current_tag_attr(file); */
2081 /* addrbook_show_attribs( attr ); */
2082 if (xml_parse_next_tag(file
)) /* Consume closing tag */
2083 longjmp(book
->jumper
, 1);
2085 if (xml_compare_tag(file
, AB_ELTAG_ITEM_LIST
))
2086 addrbook_chkparse_folder_list(book
, file
);
2090 * Attempt to parse (DOM) tree from file.
2091 * \param book Address book.
2092 * \param file XML file handle.
2094 static gboolean
addrbook_chkread_tree(AddressBookFile
*book
, XMLFile
*file
)
2099 if (xml_get_dtd(file
))
2102 if (xml_parse_next_tag(file
))
2105 if (!xml_compare_tag(file
, AB_ELTAG_ADDRESS_BOOK
))
2108 /* attr = xml_get_current_tag_attr(file); */
2109 /* addrbook_show_attribs( attr ); */
2116 if (xml_parse_next_tag(file
))
2117 longjmp(book
->jumper
, 1);
2119 /* Get next tag (person, group or folder) */
2120 if (xml_compare_tag(file
, AB_ELTAG_PERSON
))
2121 addrbook_chkparse_person( book
, file
);
2122 else if (xml_compare_tag(file
, AB_ELTAG_GROUP
))
2123 addrbook_chkparse_group(book
, file
);
2124 else if (xml_compare_tag(file
, AB_ELTAG_FOLDER
))
2125 addrbook_chkparse_folder(book
, file
);
2131 * Test address book file by parsing contents.
2132 * \param book Address book.
2133 * \param fileName Filename of XML file.
2134 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2136 gint
addrbook_test_read_file(AddressBookFile
*book
, gchar
*fileName
)
2138 XMLFile
*file
= NULL
;
2139 gchar
*fileSpec
= NULL
;
2141 cm_return_val_if_fail(book
!= NULL
, -1);
2143 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
, fileName
, NULL
);
2144 book
->retVal
= MGU_OPEN_FILE
;
2145 file
= xml_open_file(fileSpec
);
2148 book
->retVal
= MGU_BAD_FORMAT
;
2149 if (setjmp(book
->jumper
)) {
2150 /* g_print( "Caught Ya!!!\n" ); */
2151 xml_close_file(file
);
2152 return book
->retVal
;
2154 if (addrbook_chkread_tree(book
, file
))
2155 book
->retVal
= MGU_SUCCESS
;
2157 xml_close_file( file
);
2159 return book
->retVal
;
2163 * Return link list of all persons in address book. Note that the list
2164 * contains references to items. Do <b>*NOT*</b> attempt to use the
2165 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2167 * \param book Address book.
2168 * \return List of persons, or NULL if none.
2170 GList
*addrbook_get_all_persons(AddressBookFile
*book
)
2172 cm_return_val_if_fail(book
!= NULL
, NULL
);
2173 return addrcache_get_all_persons(book
->addressCache
);
2176 GList
*addrbook_get_all_groups(AddressBookFile
*book
)
2178 cm_return_val_if_fail(book
!= NULL
, NULL
);
2179 return addrcache_get_all_groups(book
->addressCache
);
2183 * Add person and address data to address book.
2184 * \param book Address book.
2185 * \param folder Folder where to add person, or NULL for root folder.
2186 * \param name Common name.
2187 * \param address EMail address.
2188 * \param remarks Remarks.
2189 * \return Person added. Do not <b>*NOT*</b> to use the
2190 * <code>addrbook_free_xxx()</code> functions... this will destroy
2191 * the address book data.
2193 ItemPerson
*addrbook_add_contact(AddressBookFile
*book
, ItemFolder
*folder
,
2194 const gchar
*name
,const gchar
*address
,
2195 const gchar
*remarks
)
2199 cm_return_val_if_fail(book
!= NULL
, NULL
);
2200 person
= addrcache_add_contact(
2201 book
->addressCache
, folder
, name
, address
, remarks
);
2206 * Return file name for next address book file.
2207 * \param book Address book.
2208 * \return File name, or <i>NULL</i> if could not create. This should be
2209 * <code>g_free()</code> when done.
2211 gchar
*addrbook_guess_next_file(AddressBookFile
*book
)
2213 gchar
*newFile
= NULL
;
2214 GList
*fileList
= NULL
;
2216 fileList
= addrbook_get_bookfile_list(book
);
2218 fileNum
= 1 + book
->maxValue
;
2220 newFile
= addrbook_gen_new_file_name(fileNum
);
2221 g_list_free(fileList
);
2226 void addrbook_delete_book_file(AddressBookFile
*book
)
2230 if (!book
->path
|| !book
->fileName
)
2233 book_path
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
,
2234 book
->fileName
, NULL
);
2235 claws_unlink(book_path
);