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.
1185 static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1193 * Update address book email list for specified person.
1194 * Enter: book Address book.
1195 * person Person to update.
1196 * listEMail New list of email addresses.
1197 * Note: The existing email addresses are replaced with the new addresses. Any references
1198 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1199 * linked to the person are removed.
1201 void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1206 g_return_if_fail( book != NULL );
1207 g_return_if_fail( person != NULL );
1209 /* Remember old list */
1210 oldData = person->listEMail;
1212 /* Attach new address list to person. */
1215 ItemEMail *email = node->data;
1216 if( ADDRITEM_ID(email) == NULL ) {
1217 /* Allocate an ID */
1218 addrcache_id_email( book->addressCache, email );
1220 ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1221 node = g_list_next( node );
1223 person->listEMail = listEMail;
1225 /* Get groups where person's email is listed */
1226 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1228 GHashTable *hashEMail;
1231 /* Load hash table with new address entries */
1232 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1235 ItemEMail *email = node->data;
1236 gchar *addr = g_strdup( email->address );
1238 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1239 g_hash_table_insert( hashEMail, addr, email );
1241 node = g_list_next( node );
1244 /* Re-parent new addresses to existing groups, where email address match. */
1245 nodeGrp = listGroup;
1247 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1248 GList *groupEMail = group->listEMail;
1250 GList *listRemove = NULL;
1252 /* Process each email item linked to group */
1253 nodeGrpEM = groupEMail;
1254 while( nodeGrpEM ) {
1255 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1256 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1257 /* Found an email address for this person */
1258 ItemEMail *emailNew = NULL;
1259 gchar *addr = g_strdup( emailGrp->address );
1261 emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1264 /* Point to this entry */
1265 nodeGrpEM->data = emailNew;
1268 /* Mark for removal */
1269 listRemove = g_list_append( listRemove, emailGrp );
1272 /* Move on to next email link */
1273 nodeGrpEM = g_list_next( nodeGrpEM );
1276 /* Process all removed links in current group */
1277 nodeGrpEM = listRemove;
1278 while( nodeGrpEM ) {
1279 ItemEMail *emailGrp = nodeGrpEM->data;
1280 groupEMail = g_list_remove( groupEMail, emailGrp );
1281 nodeGrpEM = g_list_next( nodeGrpEM );
1284 /* Move on to next group */
1285 nodeGrp = g_list_next( nodeGrp );
1289 /* Clear hash table */
1290 g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1291 g_hash_table_destroy( hashEMail );
1293 g_list_free( listGroup );
1296 addrcache_set_dirty( book->addressCache, TRUE );
1298 /* Free up old data */
1299 addritem_free_list_email( oldData );
1305 * Add person and address data to address book.
1306 * Enter: book Address book.
1307 * folder Folder where to add person, or NULL for root folder.
1308 * listEMail New list of email addresses.
1309 * Return: Person added.
1310 * Note: A new person is created with specified list of email addresses. All objects inserted
1311 * into address book.
1313 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1315 ItemFolder *f = folder;
1318 g_return_val_if_fail( book != NULL, NULL );
1320 if( ! f ) f = book->addressCache->rootFolder;
1321 person = addritem_create_item_person();
1322 addrcache_id_person( book->addressCache, person );
1323 addrcache_folder_add_person( book->addressCache, f, person );
1327 ItemEMail *email = node->data;
1328 if( ADDRITEM_ID(email) == NULL ) {
1329 addrcache_id_email( book->addressCache, email );
1331 addrcache_person_add_email( book->addressCache, person, email );
1332 node = g_list_next( node );
1338 * Load hash table visitor function.
1340 static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1341 AddrItemObject *obj = ( AddrItemObject * ) value;
1343 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1344 GHashTable *table = ( GHashTable * ) data;
1345 gchar *newKey = g_strdup( key );
1346 ItemEMail *email = ( ItemEMail * ) obj;
1347 if( ! g_hash_table_lookup( table, newKey ) ) {
1348 g_hash_table_insert( table, newKey, email );
1354 * Build available email list visitor function.
1356 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1357 AddrItemObject *obj = ( AddrItemObject * ) value;
1359 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1360 AddressBookFile *book = data;
1361 ItemPerson *person = ( ItemPerson * ) obj;
1362 GList *node = person->listEMail;
1364 ItemEMail *email = node->data;
1365 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1367 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1368 book->tempList = g_list_append( book->tempList, email );
1370 node = g_list_next( node );
1376 * Return link list of available email items (which have not already been linked to
1377 * groups). Note that the list contains references to items and should be g_free()
1378 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1379 * destroy the addressbook data!
1380 * Return: List of items, or NULL if none.
1382 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1386 g_return_val_if_fail( book != NULL, NULL );
1388 /* Load hash table with group email entries */
1389 table = g_hash_table_new( g_str_hash, g_str_equal );
1391 list = group->listEMail;
1393 ItemEMail *email = list->data;
1394 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1395 list = g_list_next( list );
1399 /* Build list of available email addresses which exclude those already in groups */
1400 book->tempList = NULL;
1401 book->tempHash = table;
1402 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1403 list = book->tempList;
1404 book->tempList = NULL;
1405 book->tempHash = NULL;
1407 /* Clear hash table */
1408 g_hash_table_destroy( table );
1415 * Update address book email list for specified group.
1416 * Enter: book Address book.
1417 * group group to update.
1418 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1419 * Note: The existing email addresses are replaced with the new addresses. Any references
1420 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1421 * linked to the person are removed.
1423 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1426 g_return_if_fail( book != NULL );
1427 g_return_if_fail( group != NULL );
1429 addrcache_set_dirty( book->addressCache, TRUE );
1431 /* Remember old list */
1432 oldData = group->listEMail;
1433 group->listEMail = listEMail;
1434 mgu_clear_list( oldData );
1439 * Add group and email list to address book.
1440 * Enter: book Address book.
1441 * folder Parent folder, or NULL for root folder.
1442 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1443 * Return: Group object.
1444 * Note: The existing email addresses are replaced with the new addresses. Any references
1445 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1446 * linked to the person are removed.
1448 ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1449 ItemGroup *group = NULL;
1450 ItemFolder *f = folder;
1452 g_return_val_if_fail( book != NULL, NULL );
1454 if( ! f ) f = book->addressCache->rootFolder;
1455 group = addritem_create_item_group();
1456 addrcache_id_group( book->addressCache, group );
1457 addrcache_folder_add_group( book->addressCache, f, group );
1458 group->listEMail = listEMail;
1463 * Add new folder to address book.
1464 * Enter: book Address book.
1465 * parent Parent folder.
1466 * Return: Folder that was added. This should *NOT* be g_free() when done.
1468 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1469 ItemFolder *folder = NULL;
1470 ItemFolder *p = parent;
1472 g_return_val_if_fail( book != NULL, NULL );
1474 if( ! p ) p = book->addressCache->rootFolder;
1475 folder = addritem_create_item_folder();
1476 addrcache_id_folder( book->addressCache, folder );
1477 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1478 p->listFolder = g_list_append( p->listFolder, folder );
1479 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1480 addrcache_set_dirty( book->addressCache, TRUE );
1483 addritem_free_item_folder( folder );
1490 * Update address book attribute list for specified person.
1491 * Enter: book Address book.
1492 * person Person to update.
1493 * listAttrib New list of attributes.
1494 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1495 * linked to the person are removed.
1497 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1501 g_return_if_fail( book != NULL );
1502 g_return_if_fail( person != NULL );
1504 /* Remember old list */
1505 oldData = person->listAttrib;
1507 /* Attach new address list to person. */
1510 UserAttribute *attrib = node->data;
1511 if( attrib->uid == NULL ) {
1512 /* Allocate an ID */
1513 addrcache_id_attribute( book->addressCache, attrib );
1515 node = g_list_next( node );
1517 person->listAttrib = listAttrib;
1518 addrcache_set_dirty( book->addressCache, TRUE );
1520 /* Free up old data */
1521 addritem_free_list_attribute( oldData );
1527 * Add attribute data for person to address book.
1528 * Enter: book Address book.
1529 * person New person object.
1530 * listAttrib New list of attributes.
1531 * Note: Only attributes are inserted into address book.
1533 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1536 g_return_if_fail( book != NULL );
1537 g_return_if_fail( person != NULL );
1541 UserAttribute *attrib = node->data;
1542 if( attrib->uid == NULL ) {
1543 addrcache_id_attribute( book->addressCache, attrib );
1545 addritem_person_add_attribute( person, attrib );
1546 node = g_list_next( node );
1548 addrcache_set_dirty( book->addressCache, TRUE );
1552 * Return address book file for specified object.
1553 * Enter: aio Book item object.
1554 * Return: Address book, or NULL if not found.
1556 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1557 AddressBookFile *book = NULL;
1560 ItemFolder *parent = NULL;
1561 ItemFolder *root = NULL;
1562 if( aio->type == ITEMTYPE_EMAIL ) {
1563 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1565 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1569 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1572 root = addrcache_find_root_folder( parent );
1575 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1582 * Remove folder from address book. Children are re-parented to parent folder.
1583 * param: folder Folder to remove.
1584 * return: Folder, or NULL if not found. Note that object should still be freed.
1586 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1589 g_return_val_if_fail( book != NULL, NULL );
1591 f = addrcache_remove_folder( book->addressCache, folder );
1596 * Remove folder from address book. Children are deleted.
1597 * param: folder Folder to remove.
1598 * return: Folder, or NULL if not found. Note that object should still be freed.
1600 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1603 g_return_val_if_fail( book != NULL, NULL );
1605 f = addrcache_remove_folder_delete( book->addressCache, folder );
1609 #define WORK_BUFLEN 1024
1610 #define ADDRBOOK_DIGITS "0123456789"
1613 * Return list of existing address book files.
1614 * Enter: book Address book file.
1615 * Return: File list.
1617 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1620 struct dirent *entry;
1621 struct stat statbuf;
1622 gchar buf[ WORK_BUFLEN ];
1623 gchar numbuf[ WORK_BUFLEN ];
1624 gint len, lenpre, lensuf, lennum;
1625 long int val, maxval;
1626 GList *fileList = NULL;
1628 g_return_val_if_fail( book != NULL, NULL );
1630 if( book->path == NULL || *book->path == '\0' ) {
1631 book->retVal = MGU_NO_PATH;
1635 strcpy( buf, book->path );
1636 len = strlen( buf );
1638 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1639 buf[ len ] = G_DIR_SEPARATOR;
1640 buf[ ++len ] = '\0';
1644 adbookdir = g_strdup( buf );
1645 strcat( buf, ADDRBOOK_PREFIX );
1647 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1648 book->retVal = MGU_OPEN_DIRECTORY;
1649 g_free( adbookdir );
1653 lenpre = strlen( ADDRBOOK_PREFIX );
1654 lensuf = strlen( ADDRBOOK_SUFFIX );
1655 lennum = FILE_NUMDIGITS + lenpre;
1658 while( ( entry = readdir( dp ) ) != NULL ) {
1659 gchar *endptr = NULL;
1663 strcpy( buf, adbookdir );
1664 strcat( buf, entry->d_name );
1665 stat( buf, &statbuf );
1666 if( S_IFREG & statbuf.st_mode ) {
1667 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1668 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1669 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1670 numbuf[ FILE_NUMDIGITS ] = '\0';
1672 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1673 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1680 val = strtol( numbuf, &endptr, 10 );
1681 if( endptr && val > -1 ) {
1682 if( val > maxval ) maxval = val;
1683 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1691 g_free( adbookdir );
1693 book->maxValue = maxval;
1694 book->retVal = MGU_SUCCESS;
1699 * Return file name for specified file number.
1700 * Enter: fileNum File number.
1701 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1703 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1705 gchar buf[ WORK_BUFLEN ];
1710 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1711 if( fileNum > nmax ) return NULL;
1712 sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1713 sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1714 return g_strdup( buf );
1717 /* **********************************************************************
1718 * Address book test functions...
1719 * ***********************************************************************
1723 * Test email address list.
1725 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1730 prev_level = file->level;
1731 if( xml_parse_next_tag( file ) ) {
1732 longjmp( book->jumper, 1 );
1734 if (file->level < prev_level) return;
1735 attr = xml_get_current_tag_attr(file);
1736 /* addrbook_show_attribs( attr ); */
1737 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1738 addrbook_chkparse_addr_list( book, file );
1744 * Test user attributes for person.
1746 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1750 attr = xml_get_current_tag_attr(file);
1751 /* addrbook_show_attribs( attr ); */
1752 element = xml_get_element( file );
1753 /* printf( "\t\tattrib value : %s\n", element ); */
1757 * Test attribute list.
1759 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1763 prev_level = file->level;
1764 if( xml_parse_next_tag( file ) ) {
1765 longjmp( book->jumper, 1 );
1767 if (file->level < prev_level) return;
1768 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1769 addrbook_chkparse_attribute( book, file );
1770 addrbook_chkparse_attr_list( book, file );
1778 static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1781 attr = xml_get_current_tag_attr(file);
1782 /* addrbook_show_attribs( attr ); */
1783 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1784 longjmp( book->jumper, 1 );
1786 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1787 addrbook_chkparse_addr_list( book, file );
1789 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1790 longjmp( book->jumper, 1 );
1792 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1793 addrbook_chkparse_attr_list( book, file );
1798 * Test group member list.
1800 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1805 prev_level = file->level;
1806 if( xml_parse_next_tag( file ) ) {
1807 longjmp( book->jumper, 1 );
1809 if (file->level < prev_level) return;
1810 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1811 attr = xml_get_current_tag_attr(file);
1812 /* addrbook_show_attribs( attr ); */
1813 addrbook_chkparse_member_list( book, file );
1816 attr = xml_get_current_tag_attr( file );
1817 /* addrbook_show_attribs( attr ); */
1825 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1828 attr = xml_get_current_tag_attr(file);
1829 /* addrbook_show_attribs( attr ); */
1830 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1831 longjmp( book->jumper, 1 );
1833 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1834 addrbook_chkparse_member_list( book, file );
1839 * Test folder item list.
1841 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1846 prev_level = file->level;
1847 if( xml_parse_next_tag( file ) ) {
1848 longjmp( book->jumper, 1 );
1850 if (file->level < prev_level) return;
1851 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1852 attr = xml_get_current_tag_attr(file);
1853 /* addrbook_show_attribs( attr ); */
1854 addrbook_chkparse_folder_list( book, file );
1857 attr = xml_get_current_tag_attr( file );
1858 /* addrbook_show_attribs( attr ); */
1866 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1869 attr = xml_get_current_tag_attr(file);
1870 /* addrbook_show_attribs( attr ); */
1871 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1872 longjmp( book->jumper, 1 );
1874 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1875 addrbook_chkparse_folder_list( book, file );
1880 * Test address book.
1882 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1886 if( xml_get_dtd( file ) ) {
1889 if( xml_parse_next_tag( file ) ) {
1893 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1897 attr = xml_get_current_tag_attr(file);
1898 /* addrbook_show_attribs( attr ); */
1902 if (! file->level ) break;
1904 if( xml_parse_next_tag( file ) ) {
1905 longjmp( book->jumper, 1 );
1907 /* Get next tag (person, group or folder) */
1908 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1909 addrbook_chkparse_person( book, file );
1911 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1912 addrbook_chkparse_group( book, file );
1914 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1915 addrbook_chkparse_folder( book, file );
1922 * Test address book file by parsing contents.
1923 * Enter: book Address book file to check.
1924 * fileName File name to check.
1925 * Return: MGU_SUCCESS if file appears to be valid format.
1927 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1928 XMLFile *file = NULL;
1929 gchar *fileSpec = NULL;
1931 g_return_val_if_fail( book != NULL, -1 );
1933 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1934 book->retVal = MGU_OPEN_FILE;
1935 file = xml_open_file( fileSpec );
1938 book->retVal = MGU_BAD_FORMAT;
1939 if( setjmp( book->jumper ) ) {
1940 /* printf( "Caught Ya!!!\n" ); */
1941 xml_close_file( file );
1942 return book->retVal;
1944 if( addrbook_chkread_tree( book, file ) ) {
1945 book->retVal = MGU_SUCCESS;
1947 xml_close_file( file );
1949 return book->retVal;
1953 * Return link list of all persons in address book. Note that the list contains
1954 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1955 * this will destroy the addressbook data!
1956 * Return: List of items, or NULL if none.
1958 GList *addrbook_get_all_persons( AddressBookFile *book ) {
1959 g_return_val_if_fail( book != NULL, NULL );
1960 return addrcache_get_all_persons( book->addressCache );
1964 * Add person and address data to address book.
1965 * Enter: book Address book.
1966 * folder Folder where to add person, or NULL for root folder.
1968 * address EMail address.
1970 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1971 * this will destroy the address book data.
1973 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
1974 const gchar *address, const gchar *remarks )
1976 g_return_val_if_fail( book != NULL, NULL );
1977 return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
1981 * Return file name for next address book file.
1982 * Enter: book Address book.
1983 * Return: File name, or NULL if could not create. This should be g_free()
1986 gchar *addrbook_guess_next_file( AddressBookFile *book ) {
1987 gchar *newFile = NULL;
1988 GList *fileList = NULL;
1990 fileList = addrbook_get_bookfile_list( book );
1992 fileNum = 1 + book->maxValue;
1994 newFile = addrbook_gen_new_file_name( fileNum );
1995 g_list_free( fileList );