2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Match Grun
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 2 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * General functions for accessing address book files.
35 #include "addrcache.h"
37 #include "adbookbase.h"
39 #ifndef DEV_STANDALONE
44 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
45 #define ADDRBOOK_PREFIX "addrbook-"
46 #define ADDRBOOK_SUFFIX ".xml"
47 #define FILE_NUMDIGITS 6
49 #define ID_TIME_OFFSET 998000000
51 * Create new address book.
53 AddressBookFile *addrbook_create_book() {
54 AddressBookFile *book;
56 book = g_new0( AddressBookFile, 1 );
57 book->type = ADBOOKTYPE_BOOK;
58 book->addressCache = addrcache_create();
59 book->retVal = MGU_SUCCESS;
61 book->fileName = NULL;
63 book->tempList = NULL;
64 book->tempHash = NULL;
65 book->addressCache->modified = TRUE;
70 * Specify name to be used.
72 void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
73 g_return_if_fail( book != NULL );
74 addrcache_set_name( book->addressCache, value );
76 gchar *addrbook_get_name( AddressBookFile *book ) {
77 g_return_val_if_fail( book != NULL, NULL );
78 return addrcache_get_name( book->addressCache );
80 void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
81 g_return_if_fail( book != NULL );
82 book->path = mgu_replace_string( book->path, value );
83 addrcache_set_dirty( book->addressCache, TRUE );
85 void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
86 g_return_if_fail( book != NULL );
87 book->fileName = mgu_replace_string( book->fileName, value );
88 addrcache_set_dirty( book->addressCache, TRUE );
90 gboolean addrbook_get_modified( AddressBookFile *book ) {
91 g_return_val_if_fail( book != NULL, FALSE );
92 return book->addressCache->modified;
94 void addrbook_set_modified( AddressBookFile *book, const gboolean value ) {
95 g_return_if_fail( book != NULL );
96 book->addressCache->modified = value;
98 gboolean addrbook_get_accessed( AddressBookFile *book ) {
99 g_return_val_if_fail( book != NULL, FALSE );
100 return book->addressCache->accessFlag;
102 void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
103 g_return_if_fail( book != NULL );
104 book->addressCache->accessFlag = value;
106 gboolean addrbook_get_read_flag( AddressBookFile *book ) {
107 g_return_val_if_fail( book != NULL, FALSE );
108 return book->addressCache->dataRead;
110 void addrbook_set_read_flag( AddressBookFile *book, const gboolean value ) {
111 g_return_if_fail( book != NULL );
112 book->addressCache->dataRead = value;
114 gint addrbook_get_status( AddressBookFile *book ) {
115 g_return_val_if_fail( book != NULL, -1 );
118 ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
119 g_return_val_if_fail( book != NULL, NULL );
120 return addrcache_get_root_folder( book->addressCache );
122 GList *addrbook_get_list_folder( AddressBookFile *book ) {
123 g_return_val_if_fail( book != NULL, NULL );
124 return addrcache_get_list_folder( book->addressCache );
126 GList *addrbook_get_list_person( AddressBookFile *book ) {
127 g_return_val_if_fail( book != NULL, NULL );
128 return addrcache_get_list_person( book->addressCache );
130 gboolean addrbook_get_dirty( AddressBookFile *book ) {
131 g_return_val_if_fail( book != NULL, FALSE );
132 return addrcache_get_dirty( book->addressCache );
134 void addrbook_set_dirty( AddressBookFile *book, const gboolean value ) {
135 g_return_if_fail( book != NULL );
136 addrcache_set_dirty( book->addressCache, value );
140 * Empty address book.
142 void addrbook_empty_book( AddressBookFile *book ) {
143 g_return_if_fail( book != NULL );
145 /* Free up internal objects */
146 addrcache_clear( book->addressCache );
147 addrcache_set_dirty( book->addressCache, FALSE );
148 g_list_free( book->tempList );
150 /* Reset to initial state */
151 book->tempList = NULL;
152 book->tempHash = NULL;
153 book->addressCache->dataRead = FALSE;
154 book->addressCache->modified = FALSE;
155 book->addressCache->accessFlag = FALSE;
156 book->retVal = MGU_SUCCESS;
162 void addrbook_free_book( AddressBookFile *book ) {
163 g_return_if_fail( book != NULL );
166 addrcache_clear( book->addressCache );
167 addrcache_free( book->addressCache );
169 /* Free up internal objects */
170 g_free( book->path );
171 g_free( book->fileName );
172 g_list_free( book->tempList );
175 book->fileName = NULL;
177 book->tempList = NULL;
178 book->tempHash = NULL;
180 book->type = ADBOOKTYPE_NONE;
181 book->addressCache = NULL;
182 book->retVal = MGU_SUCCESS;
188 * Print list of items.
190 void addrbook_print_item_list( GList *list, FILE *stream ) {
194 AddrItemObject *obj = node->data;
195 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
196 addritem_print_item_person( ( ItemPerson * ) obj, stream );
198 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
199 addritem_print_item_group( ( ItemGroup * ) obj, stream );
201 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
202 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
204 node = g_list_next( node );
206 fprintf( stream, "\t---\n" );
210 * Print address book.
212 void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
213 g_return_if_fail( book != NULL );
215 fprintf( stream, "AddressBook:\n" );
216 fprintf( stream, "\tpath : '%s'\n", book->path );
217 fprintf( stream, "\tfile : '%s'\n", book->fileName );
218 fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
219 addrcache_print( book->addressCache, stream );
223 * Dump entire address book traversing folders.
225 void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
228 g_return_if_fail( book != NULL );
230 addrbook_print_book( book, stream );
231 folder = book->addressCache->rootFolder;
232 addritem_print_item_folder( folder, stream );
236 * Remove group from address book.
237 * param: group Group to remove.
238 * return: Group, or NULL if not found. Note that object should still be freed.
240 ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
241 g_return_val_if_fail( book != NULL, NULL );
242 return addrcache_remove_group( book->addressCache, group );
246 * Remove specified person from address book.
247 * param: person Person to remove.
248 * return: Person, or NULL if not found. Note that object should still be freed.
250 ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
251 g_return_val_if_fail( book != NULL, NULL );
252 return addrcache_remove_person( book->addressCache, person );
256 * Remove email address in address book for specified person.
257 * param: person Person.
258 * email EMail to remove.
259 * return: EMail object, or NULL if not found. Note that object should still be freed.
261 ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
262 g_return_val_if_fail( book != NULL, NULL );
263 return addrcache_person_remove_email( book->addressCache, person, email );
266 /* **********************************************************************
267 * Read/Write XML data file...
268 * ===========================
270 * 1) The address book is structured as follows:
285 * 2) This sequence of elements was chosen so that the most important
286 * elements (person and their email addresses) appear first.
288 * 3) Groups then appear. When groups are loaded, person's email
289 * addresses have already been loaded and can be found.
291 * 4) Finally folders are loaded. Any forward and backward references
292 * to folders, groups and persons in the folders are resolved after
295 * ***********************************************************************
298 /* Element tag names */
299 #define AB_ELTAG_ADDRESS "address"
300 #define AB_ELTAG_ATTRIBUTE "attribute"
301 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
302 #define AB_ELTAG_ADDRESS_LIST "address-list"
303 #define AB_ELTAG_MEMBER "member"
304 #define AB_ELTAG_MEMBER_LIST "member-list"
305 #define AB_ELTAG_ITEM "item"
306 #define AB_ELTAG_ITEM_LIST "item-list"
307 #define AB_ELTAG_ADDRESS_BOOK "address-book"
308 #define AB_ELTAG_PERSON "person"
309 #define AB_ELTAG_GROUP "group"
310 #define AB_ELTAG_FOLDER "folder"
312 /* Attribute tag names */
313 #define AB_ATTAG_TYPE "type"
314 #define AB_ATTAG_UID "uid"
315 #define AB_ATTAG_NAME "name"
316 #define AB_ATTAG_REMARKS "remarks"
317 #define AB_ATTAG_FIRST_NAME "first-name"
318 #define AB_ATTAG_LAST_NAME "last-name"
319 #define AB_ATTAG_NICK_NAME "nick-name"
320 #define AB_ATTAG_COMMON_NAME "cn"
321 #define AB_ATTAG_ALIAS "alias"
322 #define AB_ATTAG_EMAIL "email"
323 #define AB_ATTAG_EID "eid"
324 #define AB_ATTAG_PID "pid"
326 /* Attribute values */
327 #define AB_ATTAG_VAL_PERSON "person"
328 #define AB_ATTAG_VAL_GROUP "group"
329 #define AB_ATTAG_VAL_FOLDER "folder"
332 * Parse address item for person.
334 static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
337 ItemEMail *email = NULL;
339 attr = xml_get_current_tag_attr(file);
341 name = ((XMLAttr *)attr->data)->name;
342 value = ((XMLAttr *)attr->data)->value;
343 if( ! email ) email = addritem_create_item_email();
344 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
345 ADDRITEM_ID(email) = g_strdup( value );
347 else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
348 ADDRITEM_NAME(email) = g_strdup( value );
350 else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
351 email->address = g_strdup( value );
353 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
354 email->remarks = g_strdup( value );
356 attr = g_list_next( attr );
360 addrcache_person_add_email( book->addressCache, person, email );
363 addritem_free_item_email( email );
370 * Parse email address list.
372 static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
377 prev_level = file->level;
378 if( xml_parse_next_tag( file ) ) {
379 longjmp( book->jumper, 1 );
381 if (file->level < prev_level) return;
382 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
383 attr = xml_get_current_tag_attr(file);
384 addrbook_parse_address( book, file, person );
385 addrbook_parse_addr_list( book, file, person );
391 * Parse attibute for person.
393 static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
397 UserAttribute *uAttr = NULL;
399 attr = xml_get_current_tag_attr(file);
401 name = ((XMLAttr *)attr->data)->name;
402 value = ((XMLAttr *)attr->data)->value;
403 if( ! uAttr ) uAttr = addritem_create_attribute();
404 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
405 addritem_attrib_set_id( uAttr, value );
407 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
408 addritem_attrib_set_name( uAttr, value );
410 attr = g_list_next( attr );
413 element = xml_get_element( file );
414 addritem_attrib_set_value( uAttr, element );
418 addritem_person_add_attribute( person, uAttr );
421 addritem_free_attribute( uAttr );
428 * Parse attribute list.
430 static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
435 prev_level = file->level;
436 if( xml_parse_next_tag( file ) ) {
437 longjmp( book->jumper, 1 );
439 if (file->level < prev_level) return;
440 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
441 attr = xml_get_current_tag_attr(file);
442 addrbook_parse_attribute( file, person );
443 addrbook_parse_attr_list( book, file, person );
451 static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
454 ItemPerson *person = NULL;
456 attr = xml_get_current_tag_attr(file);
458 name = ((XMLAttr *)attr->data)->name;
459 value = ((XMLAttr *)attr->data)->value;
460 if( ! person ) person = addritem_create_item_person();
461 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
462 ADDRITEM_ID(person) = g_strdup( value );
464 else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
465 person->firstName = g_strdup( value );
467 else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
468 person->lastName = g_strdup( value );
470 else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
471 person->nickName = g_strdup( value );
473 else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
474 ADDRITEM_NAME(person) = g_strdup( value );
476 attr = g_list_next( attr );
478 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
479 longjmp( book->jumper, 1 );
481 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
482 addrbook_parse_addr_list( book, file, person );
484 addrcache_hash_add_person( book->addressCache, person );
487 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
488 longjmp( book->jumper, 1 );
490 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
491 addrbook_parse_attr_list( book, file, person );
496 * Parse group member.
498 static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
501 gchar *pid = NULL, *eid = NULL;
502 ItemEMail *email = NULL;
504 attr = xml_get_current_tag_attr(file);
506 name = ((XMLAttr *)attr->data)->name;
507 value = ((XMLAttr *)attr->data)->value;
508 if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
509 pid = g_strdup( value );
511 else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
512 eid = g_strdup( value );
514 attr = g_list_next( attr );
516 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
517 email = addrcache_get_email( book->addressCache, eid );
520 addrcache_group_add_email( book->addressCache, group, email );
523 addritem_free_item_email( email );
530 * Parse group member list.
532 static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
537 prev_level = file->level;
538 if( xml_parse_next_tag( file ) ) {
539 longjmp( book->jumper, 1 );
541 if (file->level < prev_level) return;
542 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
543 attr = xml_get_current_tag_attr(file);
544 addrbook_parse_member( book, file, group );
545 addrbook_parse_member_list( book, file, group );
548 attr = xml_get_current_tag_attr( file );
556 static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
559 ItemGroup *group = NULL;
561 attr = xml_get_current_tag_attr(file);
563 name = ((XMLAttr *)attr->data)->name;
564 value = ((XMLAttr *)attr->data)->value;
565 if( ! group ) group = addritem_create_item_group();
566 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
567 ADDRITEM_ID(group) = g_strdup( value );
569 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
570 ADDRITEM_NAME(group) = g_strdup( value );
572 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
573 group->remarks = g_strdup( value );
575 attr = g_list_next( attr );
577 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
578 longjmp( book->jumper, 1 );
580 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
582 addrcache_hash_add_group( book->addressCache, group );
584 addrbook_parse_member_list( book, file, group );
591 static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
596 attr = xml_get_current_tag_attr(file);
598 name = ((XMLAttr *)attr->data)->name;
599 value = ((XMLAttr *)attr->data)->value;
600 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
601 uid = g_strdup( value );
603 attr = g_list_next( attr );
607 folder->listItems = g_list_append( folder->listItems, uid );
613 * Parse folder item list.
615 static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
620 prev_level = file->level;
621 if( xml_parse_next_tag( file ) ) {
622 longjmp( book->jumper, 1 );
624 if (file->level < prev_level) return;
625 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
626 attr = xml_get_current_tag_attr(file);
627 addrbook_parse_folder_item( book, file, folder );
628 addrbook_parse_folder_list( book, file, folder );
631 attr = xml_get_current_tag_attr( file );
639 static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
642 ItemFolder *folder = NULL;
644 attr = xml_get_current_tag_attr(file);
646 name = ((XMLAttr *)attr->data)->name;
647 value = ((XMLAttr *)attr->data)->value;
649 folder = addritem_create_item_folder();
651 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
652 ADDRITEM_ID(folder) = g_strdup( value );
654 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
655 ADDRITEM_NAME(folder) = g_strdup( value );
657 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
658 folder->remarks = g_strdup( value );
660 attr = g_list_next( attr );
662 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
663 longjmp( book->jumper, 1 );
665 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
667 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
668 book->tempList = g_list_append( book->tempList, folder );
669 ADDRITEM_PARENT(folder) = NULL; /* We will resolve folder later */
672 addrbook_parse_folder_list( book, file, folder );
677 * Parse address book.
678 * Return: TRUE if data read successfully, FALSE if error reading data.
680 static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
685 book->retVal = MGU_BAD_FORMAT;
686 if( xml_get_dtd( file ) ) {
689 if( xml_parse_next_tag( file ) ) {
690 longjmp( book->jumper, 1 );
692 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
696 attr = xml_get_current_tag_attr(file);
698 name = ((XMLAttr *)attr->data)->name;
699 value = ((XMLAttr *)attr->data)->value;
700 if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
701 addrbook_set_name( book, value );
703 attr = g_list_next( attr );
708 if (! file->level ) break;
709 /* Get next item tag (person, group or folder) */
710 if( xml_parse_next_tag( file ) ) {
711 longjmp( book->jumper, 1 );
713 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
714 addrbook_parse_person( book, file );
716 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
717 addrbook_parse_group( book, file );
719 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
720 addrbook_parse_folder( book, file );
723 if( retVal ) book->retVal = MGU_SUCCESS;
728 * Resolve folder items visitor function.
730 static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
731 AddressBookFile *book = data;
732 AddrItemObject *obj = ( AddrItemObject * ) value;
733 ItemFolder *rootFolder = book->addressCache->rootFolder;
734 if( obj->parent == NULL ) {
735 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
736 rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
737 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
739 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
740 rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
741 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
747 * Resolve folder items. Lists of UID's are replaced with pointers to data items.
749 static void addrbook_resolve_folder_items( AddressBookFile *book ) {
750 GList *nodeFolder = NULL;
751 GList *listRemove = NULL;
753 ItemFolder *rootFolder = book->addressCache->rootFolder;
754 nodeFolder = book->tempList;
755 while( nodeFolder ) {
756 ItemFolder *folder = nodeFolder->data;
758 node = folder->listItems;
760 gchar *uid = node->data;
761 AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
763 if( aio->type == ITEMTYPE_FOLDER ) {
764 ItemFolder *item = ( ItemFolder * ) aio;
765 folder->listFolder = g_list_append( folder->listFolder, item );
766 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
767 addrcache_hash_add_folder( book->addressCache, folder );
769 else if( aio->type == ITEMTYPE_PERSON ) {
770 ItemPerson *item = ( ItemPerson * ) aio;
771 folder->listPerson = g_list_append( folder->listPerson, item );
772 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
774 else if( aio->type == ITEMTYPE_GROUP ) {
775 ItemGroup *item = ( ItemGroup * ) aio;
776 folder->listGroup = g_list_append( folder->listGroup, item );
777 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
779 /* Replace data with pointer to item */
784 /* Not found, append to remove list. */
785 listRemove = g_list_append( listRemove, uid );
787 node = g_list_next( node );
789 rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
791 /* Process remove list */
794 gchar *uid = node->data;
795 folder->listItems = g_list_remove( folder->listItems, uid );
797 node = g_list_next( node );
799 g_list_free( listRemove );
800 nodeFolder = g_list_next( nodeFolder );
803 /* Remove folders with parents. */
805 node = rootFolder->listFolder;
807 ItemFolder *folder = ( ItemFolder * ) node->data;
808 if( ADDRITEM_PARENT(folder) ) {
809 /* Remove folders with parents */
810 listRemove = g_list_append( listRemove, folder );
813 /* Add to root folder */
814 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
816 node = g_list_next( node );
819 /* Process remove list */
822 rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
823 node = g_list_next( node );
825 g_list_free( listRemove );
827 /* Move all unparented persons and groups into root folder */
828 g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
830 /* Free up some more */
831 nodeFolder = book->tempList;
832 while( nodeFolder ) {
833 ItemFolder *folder = nodeFolder->data;
834 g_list_free( folder->listItems );
835 folder->listItems = NULL;
836 nodeFolder = g_list_next( nodeFolder );
838 g_list_free( book->tempList );
839 book->tempList = NULL;
844 * Read address book file.
846 gint addrbook_read_data( AddressBookFile *book ) {
847 XMLFile *file = NULL;
848 gchar *fileSpec = NULL;
850 g_return_val_if_fail( book != NULL, -1 );
853 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
854 addrcache_get_name( book->addressCache ) );
857 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
858 book->retVal = MGU_OPEN_FILE;
859 addrcache_clear( book->addressCache );
860 book->addressCache->modified = FALSE;
861 book->addressCache->accessFlag = FALSE;
862 file = xml_open_file( fileSpec );
865 book->tempList = NULL;
867 /* Trap for parsing errors. */
868 if( setjmp( book->jumper ) ) {
869 xml_close_file( file );
872 addrbook_read_tree( book, file );
873 xml_close_file( file );
875 /* Resolve folder items */
876 addrbook_resolve_folder_items( book );
877 book->tempList = NULL;
878 book->addressCache->modified = FALSE;
879 book->addressCache->dataRead = TRUE;
880 addrcache_set_dirty( book->addressCache, FALSE );
885 static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
887 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
892 static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
894 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
900 static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
904 xml_file_put_escape_str( fp, value );
909 * Write file hash table visitor function.
911 static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
912 AddrItemObject *obj = ( AddrItemObject * ) value;
913 FILE *fp = ( FILE * ) data;
917 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
918 ItemPerson *person = ( ItemPerson * ) value;
920 addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
921 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
922 addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
923 addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
924 addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
925 addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
928 /* Output email addresses */
929 addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
931 node = person->listEMail;
933 ItemEMail *email = node->data;
934 addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
935 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
936 addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
937 addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
938 addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
940 node = g_list_next( node );
942 addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
944 /* Output user attributes */
945 addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
947 node = person->listAttrib;
949 UserAttribute *attrib = node->data;
950 addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
951 addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
952 addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
954 xml_file_put_escape_str( fp, attrib->value );
955 addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
956 node = g_list_next( node );
958 addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
959 addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
965 * Write file hash table visitor function.
967 static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
968 AddrItemObject *obj = ( AddrItemObject * ) value;
969 FILE *fp = ( FILE * ) data;
973 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
974 ItemGroup *group = ( ItemGroup * ) value;
976 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
977 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
978 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
979 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
982 /* Output email address links */
983 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
985 node = group->listEMail;
987 ItemEMail *email = node->data;
988 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
989 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
990 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
991 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
992 fputs( " />\n", fp );
993 node = g_list_next( node );
995 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
996 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1002 * Write file hash table visitor function.
1004 static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1005 AddrItemObject *obj = ( AddrItemObject * ) value;
1006 FILE *fp = ( FILE * ) data;
1010 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1011 ItemFolder *folder = ( ItemFolder * ) value;
1013 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1014 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1015 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1016 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1017 fputs( " >\n", fp );
1018 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1021 /* Output persons */
1022 node = folder->listPerson;
1024 ItemPerson *item = node->data;
1025 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1026 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1027 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1028 fputs( " />\n", fp );
1029 node = g_list_next( node );
1033 node = folder->listGroup;
1035 ItemGroup *item = node->data;
1036 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1037 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1038 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1039 fputs( " />\n", fp );
1040 node = g_list_next( node );
1043 /* Output folders */
1044 node = folder->listFolder;
1046 ItemFolder *item = node->data;
1047 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1048 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1049 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1050 fputs( " />\n", fp );
1051 node = g_list_next( node );
1053 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1054 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1060 * Output address book data to specified file.
1061 * return: Status code.
1063 gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1066 #ifndef DEV_STANDALONE
1070 g_return_val_if_fail( book != NULL, -1 );
1071 g_return_val_if_fail( newFile != NULL, -1 );
1073 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1075 book->retVal = MGU_OPEN_FILE;
1076 #ifdef DEV_STANDALONE
1077 fp = fopen( fileSpec, "wb" );
1080 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1082 pfile = prefs_write_open( fileSpec );
1086 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1087 conv_get_current_charset_str() );
1089 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1090 addrbook_write_attr( fp, AB_ATTAG_NAME, addrcache_get_name( book->addressCache ) );
1091 fputs( " >\n", fp );
1093 /* Output all persons */
1094 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1096 /* Output all groups */
1097 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1099 /* Output all folders */
1100 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1102 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1103 book->retVal = MGU_SUCCESS;
1104 #ifdef DEV_STANDALONE
1107 if( prefs_write_close( pfile ) < 0 ) {
1108 book->retVal = MGU_ERROR_WRITE;
1114 return book->retVal;
1118 * Output address book data to original file.
1119 * return: Status code.
1121 gint addrbook_save_data( AddressBookFile *book ) {
1122 g_return_val_if_fail( book != NULL, -1 );
1124 book->retVal = MGU_NO_FILE;
1125 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1126 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1128 addrbook_write_to( book, book->fileName );
1129 if( book->retVal == MGU_SUCCESS ) {
1130 addrcache_set_dirty( book->addressCache, FALSE );
1132 return book->retVal;
1135 /* **********************************************************************
1136 * Address book edit interface functions...
1137 * ***********************************************************************
1141 * Move person's email item.
1142 * param: book Address book.
1144 * itemMove Item to move.
1145 * itemTarget Target item before which to move item.
1147 ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1148 ItemEMail *itemMove, ItemEMail *itemTarget )
1150 ItemEMail *email = NULL;
1152 g_return_val_if_fail( book != NULL, NULL );
1154 email = addritem_move_email_before( person, itemMove, itemTarget );
1156 addrcache_set_dirty( book->addressCache, TRUE );
1162 * Move person's email item.
1163 * param: book Address book.
1165 * itemMove Item to move.
1166 * itemTarget Target item after which to move item.
1168 ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1169 ItemEMail *itemMove, ItemEMail *itemTarget )
1171 ItemEMail *email = NULL;
1173 g_return_val_if_fail( book != NULL, NULL );
1175 email = addritem_move_email_after( person, itemMove, itemTarget );
1177 addrcache_set_dirty( book->addressCache, TRUE );
1183 * Hash table visitor function for deletion of hashtable entries.
1185 static gboolean addrbook_free_simple_hash_vis(
1186 gpointer *key, gpointer *value, gpointer *data )
1195 * Update address book email list for specified person.
1196 * Enter: book Address book.
1197 * person Person to update.
1198 * listEMail List of new email addresses.
1199 * Note: The existing email addresses are replaced with the new addresses. Any references
1200 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1201 * linked to the person are removed.
1203 void addrbook_update_address_list(
1204 AddressBookFile *book, ItemPerson *person, GList *listEMail )
1210 g_return_if_fail( book != NULL );
1211 g_return_if_fail( person != NULL );
1213 /* Get groups where person's existing email addresses are listed */
1214 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1216 GHashTable *hashEMail;
1219 /* Load hash table with new address entries */
1220 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1223 ItemEMail *email = node->data;
1224 gchar *addr = g_strdup( email->address );
1227 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1228 g_hash_table_insert( hashEMail, addr, email );
1230 node = g_list_next( node );
1233 /* Re-parent new addresses to existing groups, where email address match. */
1234 nodeGrp = listGroup;
1236 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1237 GList *groupEMail = group->listEMail;
1239 GList *listRemove = NULL;
1241 /* Process each email item linked to group */
1242 nodeGrpEM = groupEMail;
1243 while( nodeGrpEM ) {
1244 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1246 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1247 /* Found an email address for this person */
1248 ItemEMail *emailNew = NULL;
1249 gchar *addr = g_strdup( emailGrp->address );
1252 emailNew = ( ItemEMail * )
1253 g_hash_table_lookup( hashEMail, addr );
1256 /* Point to this entry */
1257 nodeGrpEM->data = emailNew;
1260 /* Mark for removal */
1261 listRemove = g_list_append( listRemove, emailGrp );
1264 /* Move on to next email link */
1265 nodeGrpEM = g_list_next( nodeGrpEM );
1268 /* Process all removed links in current group */
1269 nodeGrpEM = listRemove;
1270 while( nodeGrpEM ) {
1271 ItemEMail *emailGrp = nodeGrpEM->data;
1272 groupEMail = g_list_remove( groupEMail, emailGrp );
1273 nodeGrpEM = g_list_next( nodeGrpEM );
1276 g_list_free( listRemove );
1278 /* Move on to next group */
1279 nodeGrp = g_list_next( nodeGrp );
1283 /* Clear hash table */
1284 g_hash_table_foreach_remove(
1285 hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1286 g_hash_table_destroy( hashEMail );
1288 g_list_free( listGroup );
1292 /* Remove old addresses from person and cache */
1294 node = person->listEMail;
1296 ItemEMail *email = node->data;
1298 if( addrcache_person_remove_email( book->addressCache, person, email ) ) {
1299 addrcache_remove_email( book->addressCache, email );
1301 listDelete = g_list_append( listDelete, email );
1302 node = person->listEMail;
1305 /* Add new address entries */
1308 ItemEMail *email = node->data;
1310 if( ADDRITEM_ID(email) == NULL ) {
1311 /* Allocate an ID for new address */
1312 addrcache_id_email( book->addressCache, email );
1314 addrcache_person_add_email( book->addressCache, person, email );
1315 node = g_list_next( node );
1318 addrcache_set_dirty( book->addressCache, TRUE );
1320 /* Free up memory */
1321 g_list_free( listEMail );
1326 ItemEMail *email = node->data;
1328 addritem_free_item_email( email );
1329 node = g_list_next( node );
1331 g_list_free( listDelete );
1337 * Add person and address data to address book.
1338 * Enter: book Address book.
1339 * folder Folder where to add person, or NULL for root folder.
1340 * listEMail New list of email addresses.
1341 * Return: Person added.
1342 * Note: A new person is created with specified list of email addresses. All objects inserted
1343 * into address book.
1345 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1347 ItemFolder *f = folder;
1350 g_return_val_if_fail( book != NULL, NULL );
1352 if( ! f ) f = book->addressCache->rootFolder;
1353 person = addritem_create_item_person();
1354 addrcache_id_person( book->addressCache, person );
1355 addrcache_folder_add_person( book->addressCache, f, person );
1359 ItemEMail *email = node->data;
1360 if( ADDRITEM_ID(email) == NULL ) {
1361 addrcache_id_email( book->addressCache, email );
1363 addrcache_person_add_email( book->addressCache, person, email );
1364 node = g_list_next( node );
1370 * Build available email list visitor function.
1372 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1373 AddrItemObject *obj = ( AddrItemObject * ) value;
1375 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1376 AddressBookFile *book = data;
1377 ItemPerson *person = ( ItemPerson * ) obj;
1378 GList *node = person->listEMail;
1380 ItemEMail *email = node->data;
1381 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1383 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1384 book->tempList = g_list_append( book->tempList, email );
1386 node = g_list_next( node );
1392 * Return link list of available email items (which have not already been linked to
1393 * groups). Note that the list contains references to items and should be g_free()
1394 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1395 * destroy the addressbook data!
1396 * Return: List of items, or NULL if none.
1398 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1402 g_return_val_if_fail( book != NULL, NULL );
1404 /* Load hash table with group email entries */
1405 table = g_hash_table_new( g_str_hash, g_str_equal );
1407 list = group->listEMail;
1409 ItemEMail *email = list->data;
1410 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1411 list = g_list_next( list );
1415 /* Build list of available email addresses which exclude those already in groups */
1416 book->tempList = NULL;
1417 book->tempHash = table;
1418 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1419 list = book->tempList;
1420 book->tempList = NULL;
1421 book->tempHash = NULL;
1423 /* Clear hash table */
1424 g_hash_table_destroy( table );
1431 * Update address book email list for specified group.
1432 * Enter: book Address book.
1433 * group group to update.
1434 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1435 * Note: The existing email addresses are replaced with the new addresses. Any references
1436 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1437 * linked to the person are removed.
1439 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1442 g_return_if_fail( book != NULL );
1443 g_return_if_fail( group != NULL );
1445 addrcache_set_dirty( book->addressCache, TRUE );
1447 /* Remember old list */
1448 oldData = group->listEMail;
1449 group->listEMail = listEMail;
1450 mgu_clear_list( oldData );
1455 * Add group and email list to address book.
1456 * Enter: book Address book.
1457 * folder Parent folder, or NULL for root folder.
1458 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1459 * Return: Group object.
1460 * Note: The existing email addresses are replaced with the new addresses. Any references
1461 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1462 * linked to the person are removed.
1464 ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1465 ItemGroup *group = NULL;
1466 ItemFolder *f = folder;
1468 g_return_val_if_fail( book != NULL, NULL );
1470 if( ! f ) f = book->addressCache->rootFolder;
1471 group = addritem_create_item_group();
1472 addrcache_id_group( book->addressCache, group );
1473 addrcache_folder_add_group( book->addressCache, f, group );
1474 group->listEMail = listEMail;
1479 * Add new folder to address book.
1480 * Enter: book Address book.
1481 * parent Parent folder.
1482 * Return: Folder that was added. This should *NOT* be g_free() when done.
1484 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1485 ItemFolder *folder = NULL;
1486 ItemFolder *p = parent;
1488 g_return_val_if_fail( book != NULL, NULL );
1490 if( ! p ) p = book->addressCache->rootFolder;
1491 folder = addritem_create_item_folder();
1492 addrcache_id_folder( book->addressCache, folder );
1493 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1494 p->listFolder = g_list_append( p->listFolder, folder );
1495 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1496 addrcache_set_dirty( book->addressCache, TRUE );
1499 addritem_free_item_folder( folder );
1506 * Update address book attribute list for specified person.
1507 * Enter: book Address book.
1508 * person Person to update.
1509 * listAttrib New list of attributes.
1510 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1511 * linked to the person are removed.
1513 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1517 g_return_if_fail( book != NULL );
1518 g_return_if_fail( person != NULL );
1520 /* Remember old list */
1521 oldData = person->listAttrib;
1523 /* Attach new address list to person. */
1526 UserAttribute *attrib = node->data;
1527 if( attrib->uid == NULL ) {
1528 /* Allocate an ID */
1529 addrcache_id_attribute( book->addressCache, attrib );
1531 node = g_list_next( node );
1533 person->listAttrib = listAttrib;
1534 addrcache_set_dirty( book->addressCache, TRUE );
1536 /* Free up old data */
1537 addritem_free_list_attribute( oldData );
1543 * Add attribute data for person to address book.
1544 * Enter: book Address book.
1545 * person New person object.
1546 * listAttrib New list of attributes.
1547 * Note: Only attributes are inserted into address book.
1549 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1552 g_return_if_fail( book != NULL );
1553 g_return_if_fail( person != NULL );
1557 UserAttribute *attrib = node->data;
1558 if( attrib->uid == NULL ) {
1559 addrcache_id_attribute( book->addressCache, attrib );
1561 addritem_person_add_attribute( person, attrib );
1562 node = g_list_next( node );
1564 addrcache_set_dirty( book->addressCache, TRUE );
1568 * Return address book file for specified object.
1569 * Enter: aio Book item object.
1570 * Return: Address book, or NULL if not found.
1572 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1573 AddressBookFile *book = NULL;
1576 ItemFolder *parent = NULL;
1577 ItemFolder *root = NULL;
1578 if( aio->type == ITEMTYPE_EMAIL ) {
1579 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1581 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1585 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1588 root = addrcache_find_root_folder( parent );
1591 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1598 * Remove folder from address book. Children are re-parented to parent folder.
1599 * param: folder Folder to remove.
1600 * return: Folder, or NULL if not found. Note that object should still be freed.
1602 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1605 g_return_val_if_fail( book != NULL, NULL );
1607 f = addrcache_remove_folder( book->addressCache, folder );
1612 * Remove folder from address book. Children are deleted.
1613 * param: folder Folder to remove.
1614 * return: Folder, or NULL if not found. Note that object should still be freed.
1616 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1619 g_return_val_if_fail( book != NULL, NULL );
1621 f = addrcache_remove_folder_delete( book->addressCache, folder );
1625 #define WORK_BUFLEN 1024
1626 #define ADDRBOOK_DIGITS "0123456789"
1629 * Return list of existing address book files.
1630 * Enter: book Address book file.
1631 * Return: File list.
1633 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1636 struct dirent *entry;
1637 struct stat statbuf;
1638 gchar buf[ WORK_BUFLEN ];
1639 gchar numbuf[ WORK_BUFLEN ];
1640 gint len, lenpre, lensuf, lennum;
1641 long int val, maxval;
1642 GList *fileList = NULL;
1644 g_return_val_if_fail( book != NULL, NULL );
1646 if( book->path == NULL || *book->path == '\0' ) {
1647 book->retVal = MGU_NO_PATH;
1651 strcpy( buf, book->path );
1652 len = strlen( buf );
1654 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1655 buf[ len ] = G_DIR_SEPARATOR;
1656 buf[ ++len ] = '\0';
1660 adbookdir = g_strdup( buf );
1661 strcat( buf, ADDRBOOK_PREFIX );
1663 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1664 book->retVal = MGU_OPEN_DIRECTORY;
1665 g_free( adbookdir );
1669 lenpre = strlen( ADDRBOOK_PREFIX );
1670 lensuf = strlen( ADDRBOOK_SUFFIX );
1671 lennum = FILE_NUMDIGITS + lenpre;
1674 while( ( entry = readdir( dp ) ) != NULL ) {
1675 gchar *endptr = NULL;
1679 strcpy( buf, adbookdir );
1680 strcat( buf, entry->d_name );
1681 stat( buf, &statbuf );
1682 if( S_IFREG & statbuf.st_mode ) {
1683 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1684 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1685 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1686 numbuf[ FILE_NUMDIGITS ] = '\0';
1688 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1689 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1696 val = strtol( numbuf, &endptr, 10 );
1697 if( endptr && val > -1 ) {
1698 if( val > maxval ) maxval = val;
1699 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1707 g_free( adbookdir );
1709 book->maxValue = maxval;
1710 book->retVal = MGU_SUCCESS;
1715 * Return file name for specified file number.
1716 * Enter: fileNum File number.
1717 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1719 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1721 gchar buf[ WORK_BUFLEN ];
1726 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1727 if( fileNum > nmax ) return NULL;
1728 g_snprintf( fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS );
1729 g_snprintf( buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1730 return g_strdup( buf );
1733 /* **********************************************************************
1734 * Address book test functions...
1735 * ***********************************************************************
1739 * Test email address list.
1741 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1746 prev_level = file->level;
1747 if( xml_parse_next_tag( file ) ) {
1748 longjmp( book->jumper, 1 );
1750 if (file->level < prev_level) return;
1751 attr = xml_get_current_tag_attr(file);
1752 /* addrbook_show_attribs( attr ); */
1753 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1754 addrbook_chkparse_addr_list( book, file );
1760 * Test user attributes for person.
1762 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1766 attr = xml_get_current_tag_attr(file);
1767 /* addrbook_show_attribs( attr ); */
1768 element = xml_get_element( file );
1769 /* printf( "\t\tattrib value : %s\n", element ); */
1773 * Test attribute list.
1775 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1779 prev_level = file->level;
1780 if( xml_parse_next_tag( file ) ) {
1781 longjmp( book->jumper, 1 );
1783 if (file->level < prev_level) return;
1784 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1785 addrbook_chkparse_attribute( book, file );
1786 addrbook_chkparse_attr_list( book, file );
1794 static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1797 attr = xml_get_current_tag_attr(file);
1798 /* addrbook_show_attribs( attr ); */
1799 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1800 longjmp( book->jumper, 1 );
1802 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1803 addrbook_chkparse_addr_list( book, file );
1805 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1806 longjmp( book->jumper, 1 );
1808 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1809 addrbook_chkparse_attr_list( book, file );
1814 * Test group member list.
1816 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1821 prev_level = file->level;
1822 if( xml_parse_next_tag( file ) ) {
1823 longjmp( book->jumper, 1 );
1825 if (file->level < prev_level) return;
1826 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1827 attr = xml_get_current_tag_attr(file);
1828 /* addrbook_show_attribs( attr ); */
1829 addrbook_chkparse_member_list( book, file );
1832 attr = xml_get_current_tag_attr( file );
1833 /* addrbook_show_attribs( attr ); */
1841 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1844 attr = xml_get_current_tag_attr(file);
1845 /* addrbook_show_attribs( attr ); */
1846 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1847 longjmp( book->jumper, 1 );
1849 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1850 addrbook_chkparse_member_list( book, file );
1855 * Test folder item list.
1857 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1862 prev_level = file->level;
1863 if( xml_parse_next_tag( file ) ) {
1864 longjmp( book->jumper, 1 );
1866 if (file->level < prev_level) return;
1867 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1868 attr = xml_get_current_tag_attr(file);
1869 /* addrbook_show_attribs( attr ); */
1870 addrbook_chkparse_folder_list( book, file );
1873 attr = xml_get_current_tag_attr( file );
1874 /* addrbook_show_attribs( attr ); */
1882 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1885 attr = xml_get_current_tag_attr(file);
1886 /* addrbook_show_attribs( attr ); */
1887 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1888 longjmp( book->jumper, 1 );
1890 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1891 addrbook_chkparse_folder_list( book, file );
1896 * Test address book.
1898 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1902 if( xml_get_dtd( file ) ) {
1905 if( xml_parse_next_tag( file ) ) {
1909 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1913 attr = xml_get_current_tag_attr(file);
1914 /* addrbook_show_attribs( attr ); */
1918 if (! file->level ) break;
1920 if( xml_parse_next_tag( file ) ) {
1921 longjmp( book->jumper, 1 );
1923 /* Get next tag (person, group or folder) */
1924 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1925 addrbook_chkparse_person( book, file );
1927 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1928 addrbook_chkparse_group( book, file );
1930 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1931 addrbook_chkparse_folder( book, file );
1938 * Test address book file by parsing contents.
1939 * Enter: book Address book file to check.
1940 * fileName File name to check.
1941 * Return: MGU_SUCCESS if file appears to be valid format.
1943 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1944 XMLFile *file = NULL;
1945 gchar *fileSpec = NULL;
1947 g_return_val_if_fail( book != NULL, -1 );
1949 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1950 book->retVal = MGU_OPEN_FILE;
1951 file = xml_open_file( fileSpec );
1954 book->retVal = MGU_BAD_FORMAT;
1955 if( setjmp( book->jumper ) ) {
1956 /* printf( "Caught Ya!!!\n" ); */
1957 xml_close_file( file );
1958 return book->retVal;
1960 if( addrbook_chkread_tree( book, file ) ) {
1961 book->retVal = MGU_SUCCESS;
1963 xml_close_file( file );
1965 return book->retVal;
1969 * Return link list of all persons in address book. Note that the list contains
1970 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1971 * this will destroy the addressbook data!
1972 * Return: List of items, or NULL if none.
1974 GList *addrbook_get_all_persons( AddressBookFile *book ) {
1975 g_return_val_if_fail( book != NULL, NULL );
1976 return addrcache_get_all_persons( book->addressCache );
1980 * Add person and address data to address book.
1981 * Enter: book Address book.
1982 * folder Folder where to add person, or NULL for root folder.
1984 * address EMail address.
1986 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1987 * this will destroy the address book data.
1989 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
1990 const gchar *address, const gchar *remarks )
1992 g_return_val_if_fail( book != NULL, NULL );
1993 return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
1997 * Return file name for next address book file.
1998 * Enter: book Address book.
1999 * Return: File name, or NULL if could not create. This should be g_free()
2002 gchar *addrbook_guess_next_file( AddressBookFile *book ) {
2003 gchar *newFile = NULL;
2004 GList *fileList = NULL;
2006 fileList = addrbook_get_bookfile_list( book );
2008 fileNum = 1 + book->maxValue;
2010 newFile = addrbook_gen_new_file_name( fileNum );
2011 g_list_free( fileList );