2 * Claws Mail -- 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 */
24 #include "claws-features.h"
38 #include "addrcache.h"
40 #include "adbookbase.h"
41 #include "file-utils.h"
43 #ifndef DEV_STANDALONE
44 #include "prefs_gtk.h"
48 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
49 #define ADDRBOOK_PREFIX "addrbook-"
50 #define ADDRBOOK_SUFFIX ".xml"
51 #define FILE_NUMDIGITS 6
53 #define ID_TIME_OFFSET 998000000
55 static void addrbook_print_book ( AddressBookFile
*book
, FILE *stream
);
58 * Create new address book
59 * \return Address book.
61 AddressBookFile
*addrbook_create_book()
63 AddressBookFile
*book
;
65 book
= g_new0(AddressBookFile
, 1);
66 book
->type
= ADBOOKTYPE_BOOK
;
67 book
->addressCache
= addrcache_create();
68 book
->retVal
= MGU_SUCCESS
;
70 book
->fileName
= NULL
;
72 book
->tempList
= NULL
;
73 book
->tempHash
= NULL
;
74 book
->addressCache
->modified
= TRUE
;
80 * Specify name to be used
81 * \param book Address book.
84 void addrbook_set_name(AddressBookFile
*book
, const gchar
*value
)
86 cm_return_if_fail(book
!= NULL
);
87 addrcache_set_name(book
->addressCache
, value
);
90 gchar
*addrbook_get_name(AddressBookFile
*book
)
92 cm_return_val_if_fail(book
!= NULL
, NULL
);
93 return addrcache_get_name(book
->addressCache
);
97 * Specify path to address book file.
98 * \param book Address book.
101 void addrbook_set_path(AddressBookFile
*book
, const gchar
*value
)
103 cm_return_if_fail(book
!= NULL
);
104 book
->path
= mgu_replace_string(book
->path
, value
);
105 addrcache_set_dirty(book
->addressCache
, TRUE
);
109 * Specify filename to be used
110 * \param book Address book.
111 * \param value Filename.
113 void addrbook_set_file(AddressBookFile
*book
, const gchar
*value
)
115 cm_return_if_fail(book
!= NULL
);
116 book
->fileName
= mgu_replace_string(book
->fileName
, value
);
117 addrcache_set_dirty(book
->addressCache
, TRUE
);
120 gboolean
addrbook_get_modified(AddressBookFile
*book
)
122 cm_return_val_if_fail(book
!= NULL
, FALSE
);
123 return book
->addressCache
->modified
;
126 gboolean
addrbook_get_accessed(AddressBookFile
*book
)
128 cm_return_val_if_fail(book
!= NULL
, FALSE
);
129 return book
->addressCache
->accessFlag
;
133 * Specify address book as accessed.
134 * \param book Address book.
135 * \param value Value.
137 void addrbook_set_accessed(AddressBookFile
*book
, const gboolean value
)
139 cm_return_if_fail(book
!= NULL
);
140 book
->addressCache
->accessFlag
= value
;
143 gboolean
addrbook_get_read_flag(AddressBookFile
*book
)
145 cm_return_val_if_fail(book
!= NULL
, FALSE
);
146 return book
->addressCache
->dataRead
;
149 gint
addrbook_get_status(AddressBookFile
*book
)
151 cm_return_val_if_fail(book
!= NULL
, -1);
155 ItemFolder
*addrbook_get_root_folder(AddressBookFile
*book
)
157 cm_return_val_if_fail(book
!= NULL
, NULL
);
158 return addrcache_get_root_folder(book
->addressCache
);
161 GList
*addrbook_get_list_folder(AddressBookFile
*book
)
163 cm_return_val_if_fail(book
!= NULL
, NULL
);
164 return addrcache_get_list_folder(book
->addressCache
);
167 GList
*addrbook_get_list_person(AddressBookFile
*book
)
169 cm_return_val_if_fail(book
!= NULL
, NULL
);
170 return addrcache_get_list_person(book
->addressCache
);
173 gboolean
addrbook_get_dirty(AddressBookFile
*book
)
175 cm_return_val_if_fail(book
!= NULL
, FALSE
);
176 return addrcache_get_dirty(book
->addressCache
);
180 * Set address book as dirty (needs to be written to file).
181 * \param book Address book.
182 * \param value Dirty flag.
184 void addrbook_set_dirty(AddressBookFile
*book
, const gboolean value
)
186 cm_return_if_fail(book
!= NULL
);
187 addrcache_set_dirty(book
->addressCache
, value
);
192 * \param book Address book.
194 void addrbook_free_book(AddressBookFile
*book
)
196 cm_return_if_fail(book
!= NULL
);
199 addrcache_free(book
->addressCache
);
201 /* Free up internal objects */
203 g_free(book
->fileName
);
204 g_list_free(book
->tempList
);
207 book
->fileName
= NULL
;
209 book
->tempList
= NULL
;
210 book
->tempHash
= NULL
;
212 book
->type
= ADBOOKTYPE_NONE
;
213 book
->addressCache
= NULL
;
214 book
->retVal
= MGU_SUCCESS
;
220 * Print address book header.
221 * \param book Address book.
222 * \param stream Output stream.
224 static void addrbook_print_book(AddressBookFile
*book
, FILE *stream
)
226 cm_return_if_fail(book
!= NULL
);
228 fprintf(stream
, "AddressBook:\n");
229 fprintf(stream
, "\tpath : '%s'\n", book
->path
);
230 fprintf(stream
, "\tfile : '%s'\n", book
->fileName
);
231 fprintf(stream
, "\tstatus : %d\n", book
->retVal
);
232 addrcache_print(book
->addressCache
, stream
);
236 * Dump entire address book traversing folders.
237 * \param book Address book.
238 * \param stream Output stream.
240 void addrbook_dump_book(AddressBookFile
*book
, FILE *stream
)
244 cm_return_if_fail(book
!= NULL
);
246 addrbook_print_book(book
, stream
);
247 folder
= book
->addressCache
->rootFolder
;
248 addritem_print_item_folder(folder
, stream
);
252 * Remove specified group from address book. Note that object should still
254 * Specify name to be used
255 * \param book Address book.
256 * \param group Group to remove.
258 * \return Group, or NULL if not found.
260 ItemGroup
*addrbook_remove_group(AddressBookFile
*book
, ItemGroup
*group
)
262 cm_return_val_if_fail(book
!= NULL
, NULL
);
263 return addrcache_remove_group(book
->addressCache
, group
);
267 * Remove specified person from address book. Note that object should still
269 * \param book Address book.
270 * \param person Person to remove.
271 * \return Person, or NULL if not found.
273 ItemPerson
*addrbook_remove_person(AddressBookFile
*book
, ItemPerson
*person
)
275 cm_return_val_if_fail(book
!= NULL
, NULL
);
276 return addrcache_remove_person(book
->addressCache
, person
);
280 * Remove specified email address in address book for specified person.
281 * Note that object should still be freed.
282 * \param book Address book.
283 * \param person Person.
284 * \param email EMail to remove.
285 * \return EMail object, or NULL if not found.
287 ItemEMail
*addrbook_person_remove_email(AddressBookFile
*book
,
288 ItemPerson
*person
, ItemEMail
*email
)
290 cm_return_val_if_fail(book
!= NULL
, NULL
);
291 return addrcache_person_remove_email(book
->addressCache
, person
, email
);
295 * ***********************************************************************
296 * Read/Write XML data file...
297 * ===========================
299 * 1) The address book is structured as follows:
314 * 2) This sequence of elements was chosen so that the most important
315 * elements (person and their email addresses) appear first.
317 * 3) Groups then appear. When groups are loaded, person's email
318 * addresses have already been loaded and can be found.
320 * 4) Finally folders are loaded. Any forward and backward references
321 * to folders, groups and persons in the folders are resolved after
324 * ***********************************************************************
327 /* Element tag names */
328 #define AB_ELTAG_ADDRESS "address"
329 #define AB_ELTAG_ATTRIBUTE "attribute"
330 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
331 #define AB_ELTAG_ADDRESS_LIST "address-list"
332 #define AB_ELTAG_MEMBER "member"
333 #define AB_ELTAG_MEMBER_LIST "member-list"
334 #define AB_ELTAG_ITEM "item"
335 #define AB_ELTAG_ITEM_LIST "item-list"
336 #define AB_ELTAG_ADDRESS_BOOK "address-book"
337 #define AB_ELTAG_PERSON "person"
338 #define AB_ELTAG_GROUP "group"
339 #define AB_ELTAG_FOLDER "folder"
341 /* Attribute tag names */
342 #define AB_ATTAG_TYPE "type"
343 #define AB_ATTAG_UID "uid"
344 #define AB_ATTAG_NAME "name"
345 #define AB_ATTAG_REMARKS "remarks"
346 #define AB_ATTAG_FIRST_NAME "first-name"
347 #define AB_ATTAG_LAST_NAME "last-name"
348 #define AB_ATTAG_NICK_NAME "nick-name"
349 #define AB_ATTAG_COMMON_NAME "cn"
350 #define AB_ATTAG_ALIAS "alias"
351 #define AB_ATTAG_EMAIL "email"
352 #define AB_ATTAG_EID "eid"
353 #define AB_ATTAG_PID "pid"
355 /* Attribute values */
356 #define AB_ATTAG_VAL_PERSON "person"
357 #define AB_ATTAG_VAL_GROUP "group"
358 #define AB_ATTAG_VAL_FOLDER "folder"
361 * Parse address item for person from XML file.
362 * \param book Address book.
363 * \param file XML file handle.
364 * \param person Person.
366 static void addrbook_parse_address(AddressBookFile
*book
, XMLFile
*file
,
371 ItemEMail
*email
= NULL
;
373 attr
= xml_get_current_tag_attr(file
);
375 name
= ((XMLAttr
*)attr
->data
)->name
;
376 value
= ((XMLAttr
*)attr
->data
)->value
;
378 email
= addritem_create_item_email();
379 if (strcmp(name
, AB_ATTAG_UID
) == 0)
380 ADDRITEM_ID(email
) = g_strdup(value
);
381 else if (strcmp(name
, AB_ATTAG_ALIAS
) == 0)
382 ADDRITEM_NAME(email
) = g_strdup(value
);
383 else if (strcmp(name
, AB_ATTAG_EMAIL
) == 0)
384 email
->address
= g_strdup(value
);
385 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
386 email
->remarks
= g_strdup(value
);
387 attr
= g_list_next(attr
);
391 addrcache_person_add_email(book
->addressCache
, person
,
395 addritem_free_item_email(email
);
402 * Parse list of email address for person from XML file.
403 * \param book Address book.
404 * \param file XML file handle.
405 * \param person Person.
407 static void addrbook_parse_addr_list(AddressBookFile
*book
, XMLFile
*file
,
413 prev_level
= file
->level
;
414 if (xml_parse_next_tag(file
)) {
415 longjmp(book
->jumper
, 1);
417 if (file
->level
< prev_level
) return;
418 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS
)) {
419 addrbook_parse_address(book
, file
, person
);
420 addrbook_parse_addr_list(book
, file
, person
);
426 * Parse attribute for person from XML file.
427 * \param book Address book.
428 * \param file XML file handle.
429 * \param person Person.
431 static void addrbook_parse_attribute(XMLFile
*file
, ItemPerson
*person
)
436 UserAttribute
*uAttr
= NULL
;
438 attr
= xml_get_current_tag_attr(file
);
440 name
= ((XMLAttr
*)attr
->data
)->name
;
441 value
= ((XMLAttr
*)attr
->data
)->value
;
442 if (!uAttr
) uAttr
= addritem_create_attribute();
443 if (strcmp(name
, AB_ATTAG_UID
) == 0)
444 addritem_attrib_set_id(uAttr
, value
);
445 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
446 addritem_attrib_set_name(uAttr
, value
);
447 attr
= g_list_next(attr
);
450 element
= xml_get_element(file
);
451 addritem_attrib_set_value(uAttr
, element
);
456 addritem_person_add_attribute(person
, uAttr
);
459 addritem_free_attribute(uAttr
);
466 * Parse list of attributes for person from XML file.
467 * \param book Address book.
468 * \param file XML file handle.
469 * \param person Person.
471 static void addrbook_parse_attr_list(AddressBookFile
*book
, XMLFile
*file
,
477 prev_level
= file
->level
;
478 if (xml_parse_next_tag(file
)) {
479 longjmp( book
->jumper
, 1 );
481 if (file
->level
< prev_level
) return;
482 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE
)) {
483 addrbook_parse_attribute(file
, person
);
484 addrbook_parse_attr_list(book
, file
, person
);
490 * Parse person from XML file.
491 * \param book Address book.
492 * \param file XML file handle.
494 static void addrbook_parse_person(AddressBookFile
*book
, XMLFile
*file
)
498 ItemPerson
*person
= NULL
;
500 attr
= xml_get_current_tag_attr(file
);
502 name
= ((XMLAttr
*)attr
->data
)->name
;
503 value
= ((XMLAttr
*)attr
->data
)->value
;
505 person
= addritem_create_item_person();
506 if (strcmp(name
, AB_ATTAG_UID
) == 0) {
507 ADDRITEM_ID(person
) = g_strdup(value
);
508 person
->picture
= g_strdup(value
);
510 else if (strcmp(name
, AB_ATTAG_FIRST_NAME
) == 0)
511 person
->firstName
= g_strdup(value
);
512 else if (strcmp(name
, AB_ATTAG_LAST_NAME
) == 0)
513 person
->lastName
= g_strdup(value
);
514 else if (strcmp(name
, AB_ATTAG_NICK_NAME
) == 0)
515 person
->nickName
= g_strdup(value
);
516 else if (strcmp(name
, AB_ATTAG_COMMON_NAME
) == 0)
517 ADDRITEM_NAME(person
) = g_strdup(value
);
518 attr
= g_list_next(attr
);
520 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
521 longjmp(book
->jumper
, 1);
523 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS_LIST
)) {
524 addrbook_parse_addr_list(book
, file
, person
);
526 addrcache_hash_add_person(book
->addressCache
, person
);
529 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
530 longjmp(book
->jumper
, 1);
532 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE_LIST
)) {
533 addrbook_parse_attr_list(book
, file
, person
);
538 * Parse group member from XML file.
539 * \param book Address book.
540 * \param file XML file handle.
541 * \param group Group.
543 static void addrbook_parse_member(AddressBookFile
*book
, XMLFile
*file
,
549 /* gchar *pid = NULL; */
550 ItemEMail
*email
= NULL
;
552 attr
= xml_get_current_tag_attr(file
);
554 name
= ((XMLAttr
*)attr
->data
)->name
;
555 value
= ((XMLAttr
*)attr
->data
)->value
;
556 if( strcmp( name
, AB_ATTAG_EID
) == 0 )
557 eid
= g_strdup( value
);
558 attr
= g_list_next(attr
);
560 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
561 email
= addrcache_get_email(book
->addressCache
, eid
);
565 addrcache_group_add_email(book
->addressCache
, group
,
569 addritem_free_item_email(email
);
576 * Parse list of group members from XML file.
577 * \param book Address book.
578 * \param file XML file handle.
579 * \param group Group.
581 static void addrbook_parse_member_list(AddressBookFile
*book
, XMLFile
*file
,
587 prev_level
= file
->level
;
588 if (xml_parse_next_tag(file
)) {
589 longjmp(book
->jumper
, 1);
591 if (file
->level
< prev_level
)
593 if (xml_compare_tag(file
, AB_ELTAG_MEMBER
)) {
594 addrbook_parse_member(book
, file
, group
);
595 addrbook_parse_member_list(book
, file
, group
);
601 * Parse group object from XML file.
602 * \param book Address book.
603 * \param file XML file handle.
605 static void addrbook_parse_group(AddressBookFile
*book
, XMLFile
*file
)
609 ItemGroup
*group
= NULL
;
611 attr
= xml_get_current_tag_attr(file
);
613 name
= ((XMLAttr
*)attr
->data
)->name
;
614 value
= ((XMLAttr
*)attr
->data
)->value
;
616 group
= addritem_create_item_group();
617 if (strcmp(name
, AB_ATTAG_UID
) == 0)
618 ADDRITEM_ID(group
) = g_strdup(value
);
619 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
620 ADDRITEM_NAME(group
) = g_strdup(value
);
621 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
622 group
->remarks
= g_strdup(value
);
623 attr
= g_list_next(attr
);
625 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
626 longjmp(book
->jumper
, 1);
628 if (xml_compare_tag(file
, AB_ELTAG_MEMBER_LIST
)) {
630 addrcache_hash_add_group(book
->addressCache
, group
);
632 addrbook_parse_member_list(book
, file
, group
);
635 addritem_free_item_group(group
);
640 * Parse folder item from XML file.
641 * \param book Address book.
642 * \param file XML file handle.
643 * \param folder Folder.
645 static void addrbook_parse_folder_item(AddressBookFile
*book
, XMLFile
*file
,
652 attr
= xml_get_current_tag_attr(file
);
654 name
= ((XMLAttr
*)attr
->data
)->name
;
655 value
= ((XMLAttr
*)attr
->data
)->value
;
656 if (strcmp(name
, AB_ATTAG_UID
) == 0) {
657 uid
= g_strdup(value
);
659 attr
= g_list_next(attr
);
663 folder
->listItems
= g_list_append(folder
->listItems
, uid
);
669 * Parse list of folder items from XML file.
670 * \param book Address book.
671 * \param file XML file handle.
672 * \param folder Folder.
674 static void addrbook_parse_folder_list(AddressBookFile
*book
, XMLFile
*file
,
680 prev_level
= file
->level
;
681 if (xml_parse_next_tag(file
)) {
682 longjmp(book
->jumper
, 1);
684 if (file
->level
< prev_level
)
686 if (xml_compare_tag(file
, AB_ELTAG_ITEM
)) {
687 addrbook_parse_folder_item(book
, file
, folder
);
688 addrbook_parse_folder_list(book
, file
, folder
);
694 * Parse folder from XML file.
695 * \param book Address book.
696 * \param file XML file handle.
698 static void addrbook_parse_folder(AddressBookFile
*book
, XMLFile
*file
)
702 ItemFolder
*folder
= NULL
;
704 attr
= xml_get_current_tag_attr(file
);
706 name
= ((XMLAttr
*)attr
->data
)->name
;
707 value
= ((XMLAttr
*)attr
->data
)->value
;
709 folder
= addritem_create_item_folder();
710 if (strcmp(name
, AB_ATTAG_UID
) == 0)
711 ADDRITEM_ID(folder
) = g_strdup(value
);
712 else if (strcmp(name
, AB_ATTAG_NAME
) == 0)
713 ADDRITEM_NAME(folder
) = g_strdup(value
);
714 else if (strcmp(name
, AB_ATTAG_REMARKS
) == 0)
715 folder
->remarks
= g_strdup(value
);
716 attr
= g_list_next(attr
);
718 if (xml_parse_next_tag(file
)) { /* Consume closing tag */
719 longjmp(book
->jumper
, 1);
721 if (xml_compare_tag(file
, AB_ELTAG_ITEM_LIST
)) {
723 if (addrcache_hash_add_folder(book
->addressCache
,
725 book
->tempList
= g_list_append(book
->tempList
,
727 /* We will resolve folder later */
728 ADDRITEM_PARENT(folder
) = NULL
;
731 addrbook_parse_folder_list(book
, file
, folder
);
734 addritem_free_item_folder(folder
);
739 * Read address book (DOM) tree from file.
740 * \param book Address book.
741 * \param file XML file handle.
742 * \return <i>TRUE</i> if data read successfully, <i>FALSE</i> if error
745 static gboolean
addrbook_read_tree(AddressBookFile
*book
, XMLFile
*file
)
751 book
->retVal
= MGU_BAD_FORMAT
;
752 if (xml_get_dtd(file
))
754 if (xml_parse_next_tag(file
))
755 longjmp(book
->jumper
, 1);
756 if (!xml_compare_tag(file
, AB_ELTAG_ADDRESS_BOOK
))
759 attr
= xml_get_current_tag_attr(file
);
761 name
= ((XMLAttr
*)attr
->data
)->name
;
762 value
= ((XMLAttr
*)attr
->data
)->value
;
763 if (strcmp( name
, AB_ATTAG_NAME
) == 0)
764 addrbook_set_name( book
, value
);
765 attr
= g_list_next( attr
);
772 /* Get next item tag (person, group or folder) */
773 if (xml_parse_next_tag(file
))
774 longjmp( book
->jumper
, 1 );
776 if (xml_compare_tag(file
, AB_ELTAG_PERSON
))
777 addrbook_parse_person(book
, file
);
778 else if (xml_compare_tag(file
, AB_ELTAG_GROUP
))
779 addrbook_parse_group(book
, file
);
780 else if (xml_compare_tag(file
, AB_ELTAG_FOLDER
))
781 addrbook_parse_folder(book
, file
);
783 if (retVal
) book
->retVal
= MGU_SUCCESS
;
788 * Resolve folder items callback function.
789 * \param key Table key.
790 * \param value Reference to object contained in folder.
791 * \param data Reference to address book.
793 static void addrbook_res_items_vis(gpointer key
, gpointer value
, gpointer data
)
795 AddressBookFile
*book
= data
;
796 AddrItemObject
*obj
= (AddrItemObject
*) value
;
797 ItemFolder
*rootFolder
= book
->addressCache
->rootFolder
;
798 if (obj
->parent
== NULL
) {
799 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
800 rootFolder
->listPerson
= g_list_append(rootFolder
->listPerson
,
802 ADDRITEM_PARENT(obj
) = ADDRITEM_OBJECT(rootFolder
);
804 else if (ADDRITEM_TYPE(obj
) == ITEMTYPE_GROUP
) {
805 rootFolder
->listGroup
= g_list_append(rootFolder
->listGroup
,
807 ADDRITEM_PARENT(obj
) = ADDRITEM_OBJECT(rootFolder
);
813 * Resolve folder items. Lists of UID's are replaced with pointers to
815 * \param book Address book.
817 static void addrbook_resolve_folder_items(AddressBookFile
*book
)
819 GList
*nodeFolder
= NULL
;
820 GList
*listRemove
= NULL
;
822 ItemFolder
*rootFolder
= book
->addressCache
->rootFolder
;
823 nodeFolder
= book
->tempList
;
826 ItemFolder
*folder
= nodeFolder
->data
;
828 node
= folder
->listItems
;
830 gchar
*uid
= node
->data
;
831 AddrItemObject
*aio
= addrcache_get_object(book
->addressCache
,
834 if (aio
->type
== ITEMTYPE_FOLDER
) {
835 ItemFolder
*item
= (ItemFolder
*) aio
;
836 folder
->listFolder
= g_list_append(folder
->listFolder
, item
);
837 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
838 addrcache_hash_add_folder(book
->addressCache
, folder
);
840 else if (aio
->type
== ITEMTYPE_PERSON
) {
841 ItemPerson
*item
= (ItemPerson
*) aio
;
842 folder
->listPerson
= g_list_append(folder
->listPerson
, item
);
843 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
845 else if (aio
->type
== ITEMTYPE_GROUP
) {
846 ItemGroup
*item
= (ItemGroup
*) aio
;
847 folder
->listGroup
= g_list_append(folder
->listGroup
, item
);
848 ADDRITEM_PARENT(item
) = ADDRITEM_OBJECT(folder
);
850 /* Replace data with pointer to item */
854 else { /* Not found, append to remove list. */
855 listRemove
= g_list_append(listRemove
, uid
);
857 node
= g_list_next(node
);
859 rootFolder
->listFolder
= g_list_append(rootFolder
->listFolder
,
861 /* Process remove list */
864 gchar
*uid
= node
->data
;
865 folder
->listItems
= g_list_remove(folder
->listItems
,
868 node
= g_list_next(node
);
870 g_list_free(listRemove
);
871 nodeFolder
= g_list_next(nodeFolder
);
873 /* Remove folders with parents. */
875 node
= rootFolder
->listFolder
;
877 ItemFolder
*folder
= (ItemFolder
*) node
->data
;
878 if (ADDRITEM_PARENT(folder
))
879 /* Remove folders with parents */
880 listRemove
= g_list_append(listRemove
, folder
);
881 else /* Add to root folder */
882 ADDRITEM_PARENT(folder
) = ADDRITEM_OBJECT(book
->addressCache
->rootFolder
);
884 node
= g_list_next( node
);
886 /* Process remove list */
889 rootFolder
->listFolder
= g_list_remove(rootFolder
->listFolder
,
891 node
= g_list_next(node
);
893 g_list_free(listRemove
);
895 /* Move all unparented persons and groups into root folder */
896 g_hash_table_foreach(book
->addressCache
->itemHash
,
897 addrbook_res_items_vis
, book
);
899 /* Free up some more */
900 nodeFolder
= book
->tempList
;
902 ItemFolder
*folder
= nodeFolder
->data
;
903 g_list_free(folder
->listItems
);
904 folder
->listItems
= NULL
;
905 nodeFolder
= g_list_next(nodeFolder
);
907 g_list_free(book
->tempList
);
908 book
->tempList
= NULL
;
913 * \param book Address book.
914 * \return Status code.
916 gint
addrbook_read_data(AddressBookFile
*book
)
918 XMLFile
*file
= NULL
;
919 gchar
*fileSpec
= NULL
;
921 cm_return_val_if_fail(book
!= NULL
, -1);
924 g_print( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
925 addrcache_get_name( book->addressCache ) );
928 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
,
929 book
->fileName
, NULL
);
930 book
->retVal
= MGU_OPEN_FILE
;
931 addrcache_clear(book
->addressCache
);
932 book
->addressCache
->modified
= FALSE
;
933 book
->addressCache
->accessFlag
= FALSE
;
934 file
= xml_open_file(fileSpec
);
937 book
->tempList
= NULL
;
938 /* Trap for parsing errors. */
939 if (setjmp( book
->jumper
)) {
940 xml_close_file(file
);
943 addrbook_read_tree(book
, file
);
944 xml_close_file(file
);
945 /* Resolve folder items */
946 addrbook_resolve_folder_items(book
);
947 book
->tempList
= NULL
;
948 book
->addressCache
->modified
= FALSE
;
949 book
->addressCache
->dataRead
= TRUE
;
950 addrcache_set_dirty(book
->addressCache
, FALSE
);
956 * Write start element to file.
957 * \param fp File handle.
958 * \param lvl Indent level.
959 * \param name Element name.
961 static int addrbook_write_elem_s(FILE *fp
, gint lvl
, gchar
*name
)
964 for (i
= 0; i
< lvl
; i
++)
965 if (claws_fputs(" ", fp
) == EOF
)
967 if (claws_fputs("<", fp
) == EOF
)
969 if (claws_fputs(name
, fp
) == EOF
)
976 * Write end element to file.
977 * \param fp File handle.
978 * \param lvl Indent level.
979 * \param name Element name.
981 static int addrbook_write_elem_e(FILE *fp
, gint lvl
, gchar
*name
)
984 for(i
= 0; i
< lvl
; i
++)
985 if (claws_fputs(" ", fp
) == EOF
)
987 if (claws_fputs("</", fp
) == EOF
)
989 if (claws_fputs(name
, fp
) == EOF
)
991 if (claws_fputs(">\n", fp
) == EOF
)
998 * Write attribute name/value pair to file.
999 * \param fp File handle.
1000 * \param name Attribute name.
1001 * \param value Attribute value.
1003 static int addrbook_write_attr(FILE *fp
, gchar
*name
, gchar
*value
)
1005 if (claws_fputs(" ", fp
) == EOF
)
1007 if (claws_fputs(name
, fp
) == EOF
)
1009 if (claws_fputs("=\"", fp
) == EOF
)
1011 if (xml_file_put_escape_str(fp
, value
) < 0)
1013 if (claws_fputs("\"", fp
) == EOF
)
1019 typedef struct _HashLoopData
{
1025 * Write person and associated addresses and attributes to file.
1026 * file hash table visitor function.
1027 * \param key Table key.
1028 * \param value Reference to person.
1029 * \param data File pointer.
1031 static void addrbook_write_item_person_vis(gpointer key
, gpointer value
,
1034 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1035 HashLoopData
*data
= (HashLoopData
*)d
;
1036 FILE *fp
= data
->fp
;
1041 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
1042 ItemPerson
*person
= (ItemPerson
*) value
;
1044 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_PERSON
) < 0)
1046 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(person
)) < 0)
1048 if (addrbook_write_attr(fp
, AB_ATTAG_FIRST_NAME
, person
->firstName
) < 0)
1050 if (addrbook_write_attr(fp
, AB_ATTAG_LAST_NAME
, person
->lastName
) < 0)
1052 if (addrbook_write_attr(fp
, AB_ATTAG_NICK_NAME
, person
->nickName
) < 0)
1054 if (addrbook_write_attr(fp
, AB_ATTAG_COMMON_NAME
, ADDRITEM_NAME(person
)) < 0)
1056 if (claws_fputs(" >\n", fp
) == EOF
)
1059 /* Output email addresses */
1060 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ADDRESS_LIST
) < 0)
1062 if (claws_fputs(">\n", fp
) == EOF
)
1064 node
= person
->listEMail
;
1066 ItemEMail
*email
= node
->data
;
1067 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ADDRESS
) < 0)
1069 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(email
)) < 0)
1071 if (addrbook_write_attr(fp
, AB_ATTAG_ALIAS
, ADDRITEM_NAME(email
)) < 0)
1073 if (addrbook_write_attr(fp
, AB_ATTAG_EMAIL
, email
->address
) < 0)
1075 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, email
->remarks
) < 0)
1077 if (claws_fputs(" />\n", fp
) == EOF
)
1079 node
= g_list_next(node
);
1081 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ADDRESS_LIST
) < 0)
1084 /* Output user attributes */
1085 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ATTRIBUTE_LIST
) < 0)
1087 if (claws_fputs(">\n", fp
) == EOF
)
1089 node
= person
->listAttrib
;
1091 UserAttribute
*attrib
= node
->data
;
1092 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ATTRIBUTE
) < 0)
1094 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, attrib
->uid
) < 0)
1096 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, attrib
->name
) < 0)
1098 if (claws_fputs(" >", fp
) == EOF
)
1100 if (xml_file_put_escape_str(fp
, attrib
->value
) < 0)
1102 if (addrbook_write_elem_e(fp
, 0, AB_ELTAG_ATTRIBUTE
) < 0)
1104 node
= g_list_next(node
);
1106 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ATTRIBUTE_LIST
) < 0)
1108 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_PERSON
) < 0)
1115 * Write group and associated references to addresses to file.
1116 * file hash table visitor function.
1117 * \param key Table key.
1118 * \param value Reference to group.
1119 * \param data File pointer.
1121 static void addrbook_write_item_group_vis(gpointer key
, gpointer value
,
1124 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1125 HashLoopData
*data
= (HashLoopData
*)d
;
1126 FILE *fp
= data
->fp
;
1132 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_GROUP
) {
1133 ItemGroup
*group
= (ItemGroup
*) value
;
1135 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_GROUP
) < 0)
1137 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(group
)) < 0)
1139 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, ADDRITEM_NAME(group
)) < 0)
1141 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, group
->remarks
) < 0)
1143 if (claws_fputs(" >\n", fp
) == EOF
)
1146 /* Output email address links */
1147 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_MEMBER_LIST
) < 0)
1149 if (claws_fputs(">\n", fp
) == EOF
)
1151 node
= group
->listEMail
;
1153 ItemEMail
*email
= node
->data
;
1154 ItemPerson
*person
= (ItemPerson
*) ADDRITEM_PARENT(email
);
1155 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_MEMBER
) < 0)
1157 if (addrbook_write_attr(fp
, AB_ATTAG_PID
, ADDRITEM_ID(person
)) < 0)
1159 if (addrbook_write_attr(fp
, AB_ATTAG_EID
, ADDRITEM_ID(email
)) < 0)
1161 if (claws_fputs(" />\n", fp
) == EOF
)
1163 node
= g_list_next(node
);
1165 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_MEMBER_LIST
) < 0)
1167 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_GROUP
) < 0)
1174 * Write folder and associated references to addresses to file.
1175 * file hash table visitor function.
1176 * \param key Table key.
1177 * \param value Reference to folder.
1178 * \param data File pointer.
1180 static void addrbook_write_item_folder_vis(gpointer key
, gpointer value
,
1183 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1184 HashLoopData
*data
= (HashLoopData
*)d
;
1185 FILE *fp
= data
->fp
;
1190 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_FOLDER
) {
1191 ItemFolder
*folder
= (ItemFolder
*) value
;
1193 if (addrbook_write_elem_s(fp
, 1, AB_ELTAG_FOLDER
) < 0)
1195 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(folder
)) < 0)
1197 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
, ADDRITEM_NAME(folder
)) < 0)
1199 if (addrbook_write_attr(fp
, AB_ATTAG_REMARKS
, folder
->remarks
) < 0)
1201 if (claws_fputs(" >\n", fp
) == EOF
)
1203 if (addrbook_write_elem_s(fp
, 2, AB_ELTAG_ITEM_LIST
) < 0)
1205 if (claws_fputs(">\n", fp
) == EOF
)
1208 /* Output persons */
1209 node
= folder
->listPerson
;
1211 ItemPerson
*item
= node
->data
;
1212 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1214 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_PERSON
) < 0)
1216 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1218 if (claws_fputs(" />\n", fp
) == EOF
)
1220 node
= g_list_next(node
);
1224 node
= folder
->listGroup
;
1226 ItemGroup
*item
= node
->data
;
1227 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1229 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_GROUP
) < 0)
1231 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1233 if (claws_fputs(" />\n", fp
) == EOF
)
1235 node
= g_list_next(node
);
1238 /* Output folders */
1239 node
= folder
->listFolder
;
1241 ItemFolder
*item
= node
->data
;
1242 if (addrbook_write_elem_s(fp
, 3, AB_ELTAG_ITEM
) < 0)
1244 if (addrbook_write_attr(fp
, AB_ATTAG_TYPE
, AB_ATTAG_VAL_FOLDER
) < 0)
1246 if (addrbook_write_attr(fp
, AB_ATTAG_UID
, ADDRITEM_ID(item
)) < 0)
1248 if (claws_fputs(" />\n", fp
) == EOF
)
1250 node
= g_list_next(node
);
1252 if (addrbook_write_elem_e(fp
, 2, AB_ELTAG_ITEM_LIST
) < 0)
1254 if (addrbook_write_elem_e(fp
, 1, AB_ELTAG_FOLDER
) < 0)
1261 * Output address book data to specified file.
1262 * \param book Address book.
1263 * \param newFile Filename of new file (in book's filepath).
1264 * \return Status code.
1266 static gint
addrbook_write_to(AddressBookFile
*book
, gchar
*newFile
)
1271 #ifndef DEV_STANDALONE
1275 cm_return_val_if_fail(book
!= NULL
, -1);
1276 cm_return_val_if_fail(newFile
!= NULL
, -1);
1278 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
, newFile
, NULL
);
1280 book
->retVal
= MGU_OPEN_FILE
;
1281 #ifdef DEV_STANDALONE
1282 fp
= claws_fopen(fileSpec
, "wb");
1285 if (claws_fputs("<?xml version=\"1.0\" ?>\n", fp
) == EOF
) {
1286 book
->retVal
= MGU_ERROR_WRITE
;
1287 return book
->retVal
;
1290 pfile
= prefs_write_open(fileSpec
);
1294 if (fprintf( fp
, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL
) < 0)
1297 if (addrbook_write_elem_s(fp
, 0, AB_ELTAG_ADDRESS_BOOK
) < 0)
1299 if (addrbook_write_attr(fp
, AB_ATTAG_NAME
,
1300 addrcache_get_name(book
->addressCache
)) < 0)
1302 if (claws_fputs(" >\n", fp
) == EOF
)
1305 /* Output all persons */
1309 g_hash_table_foreach(book
->addressCache
->itemHash
,
1310 addrbook_write_item_person_vis
, &data
);
1314 /* Output all groups */
1315 g_hash_table_foreach(book
->addressCache
->itemHash
,
1316 addrbook_write_item_group_vis
, &data
);
1321 /* Output all folders */
1322 g_hash_table_foreach(book
->addressCache
->itemHash
,
1323 addrbook_write_item_folder_vis
, &data
);
1328 if (addrbook_write_elem_e(fp
, 0, AB_ELTAG_ADDRESS_BOOK
) < 0)
1331 book
->retVal
= MGU_SUCCESS
;
1332 #ifdef DEV_STANDALONE
1333 claws_safe_fclose(fp
);
1335 if (prefs_file_close( pfile
) < 0)
1336 book
->retVal
= MGU_ERROR_WRITE
;
1341 return book
->retVal
;
1343 g_warning("error writing AB");
1344 book
->retVal
= MGU_ERROR_WRITE
;
1346 prefs_file_close_revert( pfile
);
1347 return book
->retVal
;
1351 * Output address book data to original file.
1352 * \param book Address book.
1353 * \return Status code.
1355 gint
addrbook_save_data(AddressBookFile
*book
)
1357 cm_return_val_if_fail(book
!= NULL
, -1);
1359 book
->retVal
= MGU_NO_FILE
;
1360 if (book
->fileName
== NULL
|| *book
->fileName
== '\0')
1361 return book
->retVal
;
1362 if (book
->path
== NULL
|| *book
->path
== '\0')
1363 return book
->retVal
;
1365 addrbook_write_to(book
, book
->fileName
);
1366 if (book
->retVal
== MGU_SUCCESS
)
1367 addrcache_set_dirty(book
->addressCache
, FALSE
);
1368 return book
->retVal
;
1372 * **********************************************************************
1373 * Address book edit interface functions.
1374 * **********************************************************************
1378 * Hash table callback function for simple deletion of hashtable entries.
1379 * \param key Table key (will be freed).
1380 * \param value Value stored in table.
1381 * \param data User data.
1382 * \return <i>TRUE</i> to indicate that entry freed.
1384 static gboolean
addrbook_free_simple_hash_vis(gpointer
*key
, gpointer
*value
,
1394 * Update address book email list for specified person. Note: The existing
1395 * email addresses are replaced with the new addresses. Any references to
1396 * old addresses in the groups are re-linked to the new addresses. All old
1397 * addresses linked to the person are removed.
1398 * \param book Address book.
1399 * \param person Person to update.
1400 * \param listEMail List of new email addresses.
1402 void addrbook_update_address_list(AddressBookFile
*book
, ItemPerson
*person
,
1409 cm_return_if_fail(book
!= NULL
);
1410 cm_return_if_fail(person
!= NULL
);
1412 /* Get groups where person's existing email addresses are listed */
1413 listGroup
= addrcache_get_group_for_person(book
->addressCache
, person
);
1415 GHashTable
*hashEMail
;
1416 GHashTable
*hashEMailAlias
;
1419 /* Load hash table with new address entries */
1420 hashEMail
= g_hash_table_new(g_str_hash
, g_str_equal
);
1421 hashEMailAlias
= g_hash_table_new(g_str_hash
, g_str_equal
);
1424 ItemEMail
*email
= node
->data
;
1425 gchar
*alias
= email
->obj
.name
;
1426 gchar
*addr
= g_utf8_strdown(email
->address
, -1);
1427 if (!g_hash_table_lookup(hashEMail
, addr
)) {
1428 g_hash_table_insert(hashEMail
, addr
, email
);
1430 if (*alias
!= '\0' && ! g_hash_table_lookup(hashEMailAlias
,
1432 g_hash_table_insert(hashEMailAlias
, alias
, email
);
1434 node
= g_list_next(node
);
1437 /* Re-parent new addresses to existing groups, where email address match. */
1438 nodeGrp
= listGroup
;
1440 ItemGroup
*group
= (ItemGroup
*) nodeGrp
->data
;
1441 GList
*groupEMail
= group
->listEMail
;
1443 GList
*listRemove
= NULL
;
1445 /* Process each email item linked to group */
1446 nodeGrpEM
= groupEMail
;
1448 ItemEMail
*emailGrp
= (ItemEMail
*) nodeGrpEM
->data
;
1450 if (ADDRITEM_PARENT(emailGrp
) == ADDRITEM_OBJECT(person
)) {
1451 /* Found an email address for this person */
1452 ItemEMail
*emailNew
= NULL
;
1453 gchar
*alias
= emailGrp
->obj
.name
;
1454 gchar
*addr
= g_utf8_strdown(emailGrp
->address
, -1);
1455 emailNew
= (ItemEMail
*)
1456 g_hash_table_lookup(hashEMail
, addr
);
1458 /* If no match by e-mail, try to match by e-mail alias */
1459 if (!emailNew
&& *alias
!= '\0') {
1460 emailNew
= (ItemEMail
*)
1461 g_hash_table_lookup(hashEMailAlias
, alias
);
1465 /* Point to this entry */
1466 nodeGrpEM
->data
= emailNew
;
1467 else if (g_hash_table_size(hashEMail
)==1)
1468 /* If the person has just one e-mail address, then
1469 change e-mail address in group list */
1470 nodeGrpEM
->data
= listEMail
->data
;
1472 /* Mark for removal */
1473 listRemove
= g_list_append(listRemove
, emailGrp
);
1475 /* Move on to next email link */
1476 nodeGrpEM
= g_list_next(nodeGrpEM
);
1479 /* Process all removed links in current group */
1480 nodeGrpEM
= listRemove
;
1482 ItemEMail
*emailGrp
= nodeGrpEM
->data
;
1483 groupEMail
= g_list_remove(groupEMail
, emailGrp
);
1484 nodeGrpEM
= g_list_next(nodeGrpEM
);
1487 g_list_free(listRemove
);
1489 /* Move on to next group */
1490 nodeGrp
= g_list_next(nodeGrp
);
1493 /* Clear hash table */
1494 g_hash_table_foreach_remove(hashEMail
, (GHRFunc
)
1495 addrbook_free_simple_hash_vis
, NULL
);
1496 g_hash_table_destroy(hashEMail
);
1498 g_hash_table_destroy(hashEMailAlias
);
1499 hashEMailAlias
= NULL
;
1500 g_list_free(listGroup
);
1503 /* Remove old addresses from person and cache */
1505 node
= person
->listEMail
;
1507 ItemEMail
*email
= node
->data
;
1509 if (addrcache_person_remove_email(book
->addressCache
, person
, email
))
1510 addrcache_remove_email(book
->addressCache
, email
);
1512 listDelete
= g_list_append(listDelete
, email
);
1513 node
= person
->listEMail
;
1515 /* Add new address entries */
1518 ItemEMail
*email
= node
->data
;
1520 if (ADDRITEM_ID(email
) == NULL
)
1521 /* Allocate an ID for new address */
1522 addrcache_id_email(book
->addressCache
, email
);
1524 addrcache_person_add_email( book
->addressCache
, person
, email
);
1525 node
= g_list_next( node
);
1528 addrcache_set_dirty(book
->addressCache
, TRUE
);
1530 /* Free up memory */
1531 g_list_free(listEMail
);
1536 ItemEMail
*email
= node
->data
;
1538 addritem_free_item_email(email
);
1539 node
= g_list_next(node
);
1541 g_list_free(listDelete
);
1547 * Create person object and add person with specified address data to address
1548 * book. Note: A new person is created with specified list of email addresses.
1549 * All objects inserted into address book.
1551 * \param book Address book.
1552 * \param folder Parent folder where to add person, or <i>NULL</i> for
1554 * \param listEMail List of new email addresses to associate with person.
1555 * \return Person object created.
1557 ItemPerson
*addrbook_add_address_list(AddressBookFile
*book
, ItemFolder
*folder
,
1561 ItemFolder
*f
= folder
;
1564 cm_return_val_if_fail(book
!= NULL
, NULL
);
1567 f
= book
->addressCache
->rootFolder
;
1568 person
= addritem_create_item_person();
1569 addrcache_id_person(book
->addressCache
, person
);
1570 addrcache_folder_add_person(book
->addressCache
, f
, person
);
1574 ItemEMail
*email
= node
->data
;
1575 if (ADDRITEM_ID(email
) == NULL
)
1576 addrcache_id_email(book
->addressCache
, email
);
1578 addrcache_person_add_email(book
->addressCache
, person
, email
);
1579 node
= g_list_next(node
);
1585 * Build available email list visitor function.
1586 * \param key Table key.
1587 * \param value Value stored in table.
1588 * \param data Reference to address book.
1590 static void addrbook_build_avail_email_vis(gpointer key
, gpointer value
,
1593 AddrItemObject
*obj
= (AddrItemObject
*) value
;
1595 if (ADDRITEM_TYPE(obj
) == ITEMTYPE_PERSON
) {
1596 AddressBookFile
*book
= data
;
1597 ItemPerson
*person
= (ItemPerson
*) obj
;
1598 GList
*node
= person
->listEMail
;
1600 ItemEMail
*email
= node
->data
;
1601 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1603 if (!g_hash_table_lookup(book
->tempHash
,
1604 ADDRITEM_ID(email
)))
1605 book
->tempList
= g_list_append(book
->tempList
, email
);
1607 node
= g_list_next(node
);
1613 * Return link list of available email items that have not already been linked
1614 * to groups. Note that the list contains references to items and should be
1615 * <code>g_list_free()</code> when done. Do <b>*NOT*</b> attempt to used the
1616 * <code>addrbook_free_xxx()<code> functions... this will destroy the
1619 * \param book Address book.
1620 * \param group Group to process.
1621 * \return List of items, or <i>NULL</i> if none.
1623 GList
*addrbook_get_available_email_list(AddressBookFile
*book
, ItemGroup
*group
)
1628 cm_return_val_if_fail(book
!= NULL
, NULL
);
1630 /* Load hash table with group email entries */
1631 table
= g_hash_table_new(g_str_hash
, g_str_equal
);
1633 list
= group
->listEMail
;
1635 ItemEMail
*email
= list
->data
;
1636 g_hash_table_insert(table
, ADDRITEM_ID(email
), email
);
1637 list
= g_list_next(list
);
1641 /* Build list of available email addresses which exclude those already in groups */
1642 book
->tempList
= NULL
;
1643 book
->tempHash
= table
;
1644 g_hash_table_foreach(book
->addressCache
->itemHash
,
1645 addrbook_build_avail_email_vis
, book
);
1646 list
= book
->tempList
;
1647 book
->tempList
= NULL
;
1648 book
->tempHash
= NULL
;
1650 /* Clear hash table */
1651 g_hash_table_destroy(table
);
1658 * Update address book email list for specified group. Note: The existing email
1659 * addresses are replaced with the new addresses. Any references to old addresses
1660 * in the groups are re-linked to the new addresses. All old addresses linked to
1661 * the person are removed.
1663 * \param book Address book.
1664 * \param group Group to process.
1665 * \param listEMail List of email items. This should <b>*NOT*</b> be
1666 * <code>g_free()</code> when done.
1668 void addrbook_update_group_list(AddressBookFile
*book
, ItemGroup
*group
,
1673 cm_return_if_fail(book
!= NULL
);
1674 cm_return_if_fail(group
!= NULL
);
1676 addrcache_set_dirty(book
->addressCache
, TRUE
);
1678 /* Remember old list */
1679 oldData
= group
->listEMail
;
1680 group
->listEMail
= listEMail
;
1681 g_list_free(oldData
);
1685 * Create group object and add with specifed list of email addresses to
1686 * address book. Note: The existing email addresses are replaced with the new
1687 * addresses. Any references to old addresses in the groups are re-linked to
1688 * the new addresses. All old addresses linked to the person are removed.
1690 * \param book Address book.
1691 * \param folder Parent folder where to add group, or <i>NULL</i> for
1693 * \param listEMail List of email items. This should <b>*NOT*</b> be
1694 * <code>g_free()</code> when done.
1695 * \return Group object created.
1697 ItemGroup
*addrbook_add_group_list(AddressBookFile
*book
, ItemFolder
*folder
,
1700 ItemGroup
*group
= NULL
;
1701 ItemFolder
*f
= folder
;
1703 cm_return_val_if_fail(book
!= NULL
, NULL
);
1706 f
= book
->addressCache
->rootFolder
;
1707 group
= addritem_create_item_group();
1708 addrcache_id_group(book
->addressCache
, group
);
1709 addrcache_folder_add_group(book
->addressCache
, f
, group
);
1710 group
->listEMail
= listEMail
;
1715 * Create a new folder and add to address book.
1716 * \param book Address book.
1717 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1719 * \return Folder that was created. This should <b>*NOT*</b> be
1720 * <code>g_free()</code> when done.
1722 ItemFolder
*addrbook_add_new_folder(AddressBookFile
*book
, ItemFolder
*parent
)
1724 cm_return_val_if_fail(book
!= NULL
, NULL
);
1725 return addrcache_add_new_folder( book
->addressCache
, parent
);
1729 * Update address book attribute list for specified person. Note: The existing
1730 * attributes are replaced with the new addresses. All old attributes linked
1731 * to the person are removed.
1733 * \param book Address book.
1734 * \param person Person to receive attributes.
1735 * \param listAttrib New list of attributes.
1737 void addrbook_update_attrib_list(AddressBookFile
*book
, ItemPerson
*person
,
1743 cm_return_if_fail(book
!= NULL
);
1744 cm_return_if_fail(person
!= NULL
);
1746 /* Remember old list */
1747 oldData
= person
->listAttrib
;
1749 /* Attach new address list to person. */
1752 UserAttribute
*attrib
= node
->data
;
1753 if (attrib
->uid
== NULL
) {
1754 /* Allocate an ID */
1755 addrcache_id_attribute(book
->addressCache
, attrib
);
1757 node
= g_list_next(node
);
1759 person
->listAttrib
= listAttrib
;
1760 addrcache_set_dirty(book
->addressCache
, TRUE
);
1762 /* Free up old data */
1763 addritem_free_list_attribute(oldData
);
1768 * Add attribute data for specified person to address book. Note: Only
1769 * attributes are inserted into address book.
1770 * \param book Address book.
1771 * \param person Person to receive attributes.
1772 * \param listAttrib List of attributes.
1774 void addrbook_add_attrib_list( AddressBookFile
*book
, ItemPerson
*person
, GList
*listAttrib
) {
1777 cm_return_if_fail( book
!= NULL
);
1778 cm_return_if_fail( person
!= NULL
);
1782 UserAttribute
*attrib
= node
->data
;
1783 if( attrib
->uid
== NULL
) {
1784 addrcache_id_attribute( book
->addressCache
, attrib
);
1786 addritem_person_add_attribute( person
, attrib
);
1787 node
= g_list_next( node
);
1789 addrcache_set_dirty( book
->addressCache
, TRUE
);
1792 #define WORK_BUFLEN 1024
1793 #define ADDRBOOK_DIGITS "0123456789"
1796 * Return list of existing address book files.
1797 * \param book Address book.
1798 * \return List of files (as strings).
1800 GList
*addrbook_get_bookfile_list(AddressBookFile
*book
) {
1803 const gchar
*dir_name
;
1805 gchar buf
[WORK_BUFLEN
+ 1];
1806 gchar numbuf
[WORK_BUFLEN
];
1807 gint len
, lenpre
, lensuf
, lennum
;
1808 long int val
, maxval
;
1809 GList
*fileList
= NULL
;
1811 cm_return_val_if_fail(book
!= NULL
, NULL
);
1813 if (book
->path
== NULL
|| *book
->path
== '\0') {
1814 book
->retVal
= MGU_NO_PATH
;
1818 strncpy(buf
, book
->path
, WORK_BUFLEN
);
1821 if (buf
[len
-1] != G_DIR_SEPARATOR
) {
1822 buf
[len
] = G_DIR_SEPARATOR
;
1827 adbookdir
= g_strdup(buf
);
1828 strncat(buf
, ADDRBOOK_PREFIX
, WORK_BUFLEN
- strlen(buf
));
1830 if( ( dir
= g_dir_open( adbookdir
, 0, NULL
) ) == NULL
) {
1831 book
->retVal
= MGU_OPEN_DIRECTORY
;
1836 lenpre
= strlen(ADDRBOOK_PREFIX
);
1837 lensuf
= strlen(ADDRBOOK_SUFFIX
);
1838 lennum
= FILE_NUMDIGITS
+ lenpre
;
1841 while( ( dir_name
= g_dir_read_name( dir
) ) != NULL
) {
1842 gchar
*endptr
= NULL
;
1846 strncpy(buf
, adbookdir
, WORK_BUFLEN
);
1847 strncat(buf
, dir_name
, WORK_BUFLEN
- strlen(buf
));
1848 r
= g_stat(buf
, &statbuf
);
1849 if (r
== 0 && S_ISREG(statbuf
.st_mode
)) {
1852 ADDRBOOK_PREFIX
, lenpre
) == 0)
1855 (dir_name
) + lennum
,
1856 ADDRBOOK_SUFFIX
, lensuf
) == 0)
1859 (dir_name
) + lenpre
,
1861 numbuf
[FILE_NUMDIGITS
] = '\0';
1863 for(i
= 0; i
< FILE_NUMDIGITS
; i
++) {
1864 if(!strchr(ADDRBOOK_DIGITS
, numbuf
[i
])) {
1871 val
= strtol(numbuf
, &endptr
, 10);
1872 if (endptr
&& val
> -1) {
1873 if (val
> maxval
) maxval
= val
;
1874 fileList
= g_list_append(
1876 g_strdup(dir_name
));
1886 book
->maxValue
= maxval
;
1887 book
->retVal
= MGU_SUCCESS
;
1892 * Return file name for specified file number.
1893 * \param fileNum File number.
1894 * \return File name, or <i>NULL</i> if file number too large. Should be
1895 * <code>g_free()</code> when done.
1897 gchar
*addrbook_gen_new_file_name(gint fileNum
) {
1899 gchar buf
[WORK_BUFLEN
];
1905 nmax
= -1 + (long int) pow(10, FILE_NUMDIGITS
);
1908 g_snprintf(fmt
, sizeof(fmt
), "%%s%%0%dd%%s", FILE_NUMDIGITS
);
1909 g_snprintf(buf
, sizeof(buf
), fmt
, ADDRBOOK_PREFIX
, n
, ADDRBOOK_SUFFIX
);
1910 return g_strdup(buf
);
1914 * **********************************************************************
1915 * Address book test functions...
1916 * **********************************************************************
1920 * Attempt to parse list of email address from file.
1921 * \param book Address book.
1922 * \param file XML file handle.
1924 static void addrbook_chkparse_addr_list( AddressBookFile
*book
, XMLFile
*file
)
1930 prev_level
= file
->level
;
1931 if (xml_parse_next_tag(file
))
1932 longjmp(book
->jumper
, 1);
1933 if (file
->level
< prev_level
)
1935 /* attr = xml_get_current_tag_attr(file); */
1936 /* addrbook_show_attribs( attr ); */
1937 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS
))
1938 addrbook_chkparse_addr_list(book
, file
);
1943 * Attempt to parse attributes for person address from file.
1944 * \param book Address book.
1945 * \param file XML file handle.
1947 static void addrbook_chkparse_attribute(AddressBookFile
*book
, XMLFile
*file
)
1950 /* gchar *element; */
1952 /* attr = xml_get_current_tag_attr(file); */
1953 /* addrbook_show_attribs( attr ); */
1954 /* element = xml_get_element(file); */
1955 /* g_print( "\t\tattrib value : %s\n", element ); */
1959 * Attempt to parse list of attributes for person address from file.
1960 * \param book Address book.
1961 * \param file XML file handle.
1963 static void addrbook_chkparse_attr_list(AddressBookFile
*book
, XMLFile
*file
)
1968 prev_level
= file
->level
;
1969 if (xml_parse_next_tag(file
))
1970 longjmp(book
->jumper
, 1);
1971 if (file
->level
< prev_level
)
1973 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE
)) {
1974 addrbook_chkparse_attribute(book
, file
);
1975 addrbook_chkparse_attr_list(book
, file
);
1981 * Attempt to parse person from file.
1982 * \param book Address book.
1983 * \param file XML file handle.
1985 static void addrbook_chkparse_person(AddressBookFile
*book
, XMLFile
*file
)
1989 /* attr = xml_get_current_tag_attr(file); */
1990 /* addrbook_show_attribs( attr ); */
1991 if (xml_parse_next_tag(file
)) /* Consume closing tag */
1992 longjmp(book
->jumper
, 1);
1994 if (xml_compare_tag(file
, AB_ELTAG_ADDRESS_LIST
))
1995 addrbook_chkparse_addr_list(book
, file
);
1997 if (xml_parse_next_tag(file
)) /* Consume closing tag */
1998 longjmp(book
->jumper
, 1);
2000 if (xml_compare_tag(file
, AB_ELTAG_ATTRIBUTE_LIST
))
2001 addrbook_chkparse_attr_list(book
, file
);
2005 * Attempt to parse list of members from file.
2006 * \param book Address book.
2007 * \param file XML file handle.
2009 static void addrbook_chkparse_member_list(AddressBookFile
*book
, XMLFile
*file
)
2015 prev_level
= file
->level
;
2016 if (xml_parse_next_tag(file
))
2017 longjmp(book
->jumper
, 1);
2019 if (file
->level
< prev_level
)
2022 if (xml_compare_tag(file
, AB_ELTAG_MEMBER
)) {
2023 /* attr = xml_get_current_tag_attr(file); */
2024 /* addrbook_show_attribs( attr ); */
2025 addrbook_chkparse_member_list(book
, file
);
2028 /* attr = xml_get_current_tag_attr(file); */
2029 /* addrbook_show_attribs( attr ); */
2035 * Attempt to parse group from file.
2036 * \param book Address book.
2037 * \param file XML file handle.
2039 static void addrbook_chkparse_group(AddressBookFile
*book
, XMLFile
*file
)
2043 /* attr = xml_get_current_tag_attr(file); */
2044 /* addrbook_show_attribs( attr ); */
2045 if (xml_parse_next_tag(file
)) /* Consume closing tag */
2046 longjmp(book
->jumper
, 1);
2048 if (xml_compare_tag(file
, AB_ELTAG_MEMBER_LIST
))
2049 addrbook_chkparse_member_list(book
, file
);
2053 * Attempt to parse list of folders from file.
2054 * \param book Address book.
2055 * \param file XML file handle.
2057 static void addrbook_chkparse_folder_list(AddressBookFile
*book
, XMLFile
*file
)
2063 prev_level
= file
->level
;
2064 if (xml_parse_next_tag(file
))
2065 longjmp(book
->jumper
, 1);
2067 if (file
->level
< prev_level
)
2070 if (xml_compare_tag(file
, AB_ELTAG_ITEM
)) {
2071 /* attr = xml_get_current_tag_attr(file); */
2072 /* addrbook_show_attribs( attr ); */
2073 addrbook_chkparse_folder_list(book
, file
);
2076 /* attr = xml_get_current_tag_attr(file); */
2077 /* addrbook_show_attribs( attr ); */
2083 * Attempt to parse a folder from file.
2084 * \param book Address book.
2085 * \param file XML file handle.
2087 static void addrbook_chkparse_folder(AddressBookFile
*book
, XMLFile
*file
)
2091 /* attr = xml_get_current_tag_attr(file); */
2092 /* addrbook_show_attribs( attr ); */
2093 if (xml_parse_next_tag(file
)) /* Consume closing tag */
2094 longjmp(book
->jumper
, 1);
2096 if (xml_compare_tag(file
, AB_ELTAG_ITEM_LIST
))
2097 addrbook_chkparse_folder_list(book
, file
);
2101 * Attempt to parse (DOM) tree from file.
2102 * \param book Address book.
2103 * \param file XML file handle.
2105 static gboolean
addrbook_chkread_tree(AddressBookFile
*book
, XMLFile
*file
)
2110 if (xml_get_dtd(file
))
2113 if (xml_parse_next_tag(file
))
2116 if (!xml_compare_tag(file
, AB_ELTAG_ADDRESS_BOOK
))
2119 /* attr = xml_get_current_tag_attr(file); */
2120 /* addrbook_show_attribs( attr ); */
2127 if (xml_parse_next_tag(file
))
2128 longjmp(book
->jumper
, 1);
2130 /* Get next tag (person, group or folder) */
2131 if (xml_compare_tag(file
, AB_ELTAG_PERSON
))
2132 addrbook_chkparse_person( book
, file
);
2133 else if (xml_compare_tag(file
, AB_ELTAG_GROUP
))
2134 addrbook_chkparse_group(book
, file
);
2135 else if (xml_compare_tag(file
, AB_ELTAG_FOLDER
))
2136 addrbook_chkparse_folder(book
, file
);
2142 * Test address book file by parsing contents.
2143 * \param book Address book.
2144 * \param fileName Filename of XML file.
2145 * \return Status code <i>MGU_SUCCESS</i> if file appears to be valid format.
2147 gint
addrbook_test_read_file(AddressBookFile
*book
, gchar
*fileName
)
2149 XMLFile
*file
= NULL
;
2150 gchar
*fileSpec
= NULL
;
2152 cm_return_val_if_fail(book
!= NULL
, -1);
2154 fileSpec
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
, fileName
, NULL
);
2155 book
->retVal
= MGU_OPEN_FILE
;
2156 file
= xml_open_file(fileSpec
);
2159 book
->retVal
= MGU_BAD_FORMAT
;
2160 if (setjmp(book
->jumper
)) {
2161 /* g_print( "Caught Ya!!!\n" ); */
2162 xml_close_file(file
);
2163 return book
->retVal
;
2165 if (addrbook_chkread_tree(book
, file
))
2166 book
->retVal
= MGU_SUCCESS
;
2168 xml_close_file( file
);
2170 return book
->retVal
;
2174 * Return link list of all persons in address book. Note that the list
2175 * contains references to items. Do <b>*NOT*</b> attempt to use the
2176 * <code>addrbook_free_xxx()</code> functions... this will destroy the
2178 * \param book Address book.
2179 * \return List of persons, or NULL if none.
2181 GList
*addrbook_get_all_persons(AddressBookFile
*book
)
2183 cm_return_val_if_fail(book
!= NULL
, NULL
);
2184 return addrcache_get_all_persons(book
->addressCache
);
2187 GList
*addrbook_get_all_groups(AddressBookFile
*book
)
2189 cm_return_val_if_fail(book
!= NULL
, NULL
);
2190 return addrcache_get_all_groups(book
->addressCache
);
2194 * Add person and address data to address book.
2195 * \param book Address book.
2196 * \param folder Folder where to add person, or NULL for root folder.
2197 * \param name Common name.
2198 * \param address EMail address.
2199 * \param remarks Remarks.
2200 * \return Person added. Do not <b>*NOT*</b> to use the
2201 * <code>addrbook_free_xxx()</code> functions... this will destroy
2202 * the address book data.
2204 ItemPerson
*addrbook_add_contact(AddressBookFile
*book
, ItemFolder
*folder
,
2205 const gchar
*name
,const gchar
*address
,
2206 const gchar
*remarks
)
2210 cm_return_val_if_fail(book
!= NULL
, NULL
);
2211 person
= addrcache_add_contact(
2212 book
->addressCache
, folder
, name
, address
, remarks
);
2217 * Return file name for next address book file.
2218 * \param book Address book.
2219 * \return File name, or <i>NULL</i> if could not create. This should be
2220 * <code>g_free()</code> when done.
2222 gchar
*addrbook_guess_next_file(AddressBookFile
*book
)
2224 gchar
*newFile
= NULL
;
2225 GList
*fileList
= NULL
;
2227 fileList
= addrbook_get_bookfile_list(book
);
2229 fileNum
= 1 + book
->maxValue
;
2231 newFile
= addrbook_gen_new_file_name(fileNum
);
2232 g_list_free(fileList
);
2237 void addrbook_delete_book_file(AddressBookFile
*book
)
2241 if (!book
->path
|| !book
->fileName
)
2244 book_path
= g_strconcat(book
->path
, G_DIR_SEPARATOR_S
,
2245 book
->fileName
, NULL
);
2246 claws_unlink(book_path
);