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 external address book files.
35 #include "addrcache.h"
38 #ifndef DEV_STANDALONE
43 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
44 #define ADDRBOOK_PREFIX "addrbook-"
45 #define ADDRBOOK_SUFFIX ".xml"
46 #define FILE_NUMDIGITS 6
48 #define ID_TIME_OFFSET 998000000
50 * Create new address book.
52 AddressBookFile *addrbook_create_book() {
53 AddressBookFile *book;
55 book = g_new0( AddressBookFile, 1 );
58 book->fileName = NULL;
59 book->retVal = MGU_SUCCESS;
60 book->addressCache = addrcache_create();
62 book->tempList = NULL;
63 book->readFlag = FALSE;
64 book->dirtyFlag = FALSE;
65 book->modifyFlag = TRUE;
66 book->accessFlag = FALSE;
67 book->tempHash = NULL;
72 * Specify name to be used.
74 void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
75 g_return_if_fail( book != NULL );
76 book->name = mgu_replace_string( book->name, value );
78 void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
79 g_return_if_fail( book != NULL );
80 book->path = mgu_replace_string( book->path, value );
81 book->dirtyFlag = TRUE;
83 void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
84 g_return_if_fail( book != NULL );
85 book->fileName = mgu_replace_string( book->fileName, value );
86 book->dirtyFlag = TRUE;
88 void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
89 g_return_if_fail( book != NULL );
90 book->accessFlag = value;
92 gboolean addrbook_get_modified( AddressBookFile *book ) {
93 g_return_val_if_fail( book != NULL, FALSE );
94 return book->modifyFlag;
96 gboolean addrbook_get_accessed( AddressBookFile *book ) {
97 g_return_val_if_fail( book != NULL, FALSE );
98 return book->accessFlag;
100 gboolean addrbook_get_read_flag( AddressBookFile *book ) {
101 g_return_val_if_fail( book != NULL, FALSE );
102 return book->readFlag;
104 gint addrbook_get_status( AddressBookFile *book ) {
105 g_return_val_if_fail( book != NULL, -1 );
108 ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
109 g_return_val_if_fail( book != NULL, NULL );
110 return addrcache_get_root_folder( book->addressCache );
112 GList *addrbook_get_list_folder( AddressBookFile *book ) {
113 g_return_val_if_fail( book != NULL, NULL );
114 return addrcache_get_list_folder( book->addressCache );
116 GList *addrbook_get_list_person( AddressBookFile *book ) {
117 g_return_val_if_fail( book != NULL, NULL );
118 return addrcache_get_list_person( book->addressCache );
120 gchar *addrbook_get_name( AddressBookFile *book ) {
121 g_return_val_if_fail( book != NULL, NULL );
125 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
126 AddrItemObject *obj = ( AddrItemObject * ) value;
128 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
129 addritem_free_item_person( ( ItemPerson * ) obj );
131 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
132 addritem_free_item_group( ( ItemGroup * ) obj );
134 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
135 addritem_free_item_folder( ( ItemFolder * ) obj );
143 * Free hash table of address book items.
145 static void addrcache_free_item_hash( GHashTable *table ) {
146 g_return_if_fail( table != NULL );
147 g_hash_table_freeze( table );
148 g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
149 g_hash_table_thaw( table );
150 g_hash_table_destroy( table );
154 * Empty address book.
156 void addrbook_empty_book( AddressBookFile *book ) {
157 g_return_if_fail( book != NULL );
159 /* Free up folders and hash table */
160 addrcache_clear( book->addressCache );
162 g_list_free( book->tempList );
163 book->tempList = NULL;
165 /* Reset to initial state */
166 book->retVal = MGU_SUCCESS;
167 book->tempHash = NULL;
168 book->readFlag = FALSE;
169 book->dirtyFlag = FALSE;
170 book->modifyFlag = FALSE;
171 book->accessFlag = FALSE;
177 void addrbook_free_book( AddressBookFile *book ) {
178 g_return_if_fail( book != NULL );
180 g_free( book->name );
181 g_free( book->path );
182 g_free( book->fileName );
185 book->fileName = NULL;
187 /* Free up folders and hash table */
188 addrcache_free( book->addressCache );
189 book->addressCache = NULL;
191 g_list_free( book->tempList );
192 book->tempList = NULL;
194 book->retVal = MGU_SUCCESS;
195 book->tempHash = NULL;
196 book->readFlag = FALSE;
197 book->dirtyFlag = FALSE;
198 book->modifyFlag = FALSE;
199 book->accessFlag = FALSE;
205 * Print list of items.
207 void addrbook_print_item_list( GList *list, FILE *stream ) {
211 AddrItemObject *obj = node->data;
212 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
213 addritem_print_item_person( ( ItemPerson * ) obj, stream );
215 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
216 addritem_print_item_group( ( ItemGroup * ) obj, stream );
218 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
219 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
221 node = g_list_next( node );
223 fprintf( stream, "\t---\n" );
227 * Print address book.
229 void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
230 g_return_if_fail( book != NULL );
232 fprintf( stream, "AddressBook:\n" );
233 fprintf( stream, "\tname : '%s'\n", book->name );
234 fprintf( stream, "\tpath : '%s'\n", book->path );
235 fprintf( stream, "\tfile : '%s'\n", book->fileName );
236 fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
237 addrcache_print( book->addressCache, stream );
241 * Dump entire address book traversing folders.
243 void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
246 g_return_if_fail( book != NULL );
248 addrbook_print_book( book, stream );
249 folder = book->addressCache->rootFolder;
250 addritem_print_item_folder( folder, stream );
254 * Remove group from address book.
255 * param: group Group to remove.
256 * return: Group, or NULL if not found. Note that object should still be freed.
258 ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
261 g_return_val_if_fail( book != NULL, NULL );
263 item = addrcache_remove_group( book->addressCache, group );
264 if( item ) book->dirtyFlag = TRUE;
269 * Remove specified person from address book.
270 * param: person Person to remove.
271 * return: Person, or NULL if not found. Note that object should still be freed.
273 ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
276 g_return_val_if_fail( book != NULL, NULL );
278 item = addrcache_remove_person( book->addressCache, person );
279 if( item ) book->dirtyFlag = TRUE;
284 * Remove email address in address book for specified person.
285 * param: person Person.
286 * email EMail to remove.
287 * return: EMail object, or NULL if not found. Note that object should still be freed.
289 ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
292 g_return_val_if_fail( book != NULL, NULL );
294 item = addrcache_person_remove_email( book->addressCache, person, email );
295 if( item ); book->dirtyFlag = TRUE;
299 /* **********************************************************************
300 * Read/Write XML data file...
301 * ===========================
303 * 1) The address book is structured as follows:
318 * 2) This sequence of elements was chosen so that the most important
319 * elements (person and their email addresses) appear first.
321 * 3) Groups then appear. When groups are loaded, person's email
322 * addresses have already been loaded and can be found.
324 * 4) Finally folders are loaded. Any forward and backward references
325 * to folders, groups and persons in the folders are resolved after
328 * ***********************************************************************
331 /* Element tag names */
332 #define AB_ELTAG_ADDRESS "address"
333 #define AB_ELTAG_ATTRIBUTE "attribute"
334 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
335 #define AB_ELTAG_ADDRESS_LIST "address-list"
336 #define AB_ELTAG_MEMBER "member"
337 #define AB_ELTAG_MEMBER_LIST "member-list"
338 #define AB_ELTAG_ITEM "item"
339 #define AB_ELTAG_ITEM_LIST "item-list"
340 #define AB_ELTAG_ADDRESS_BOOK "address-book"
341 #define AB_ELTAG_PERSON "person"
342 #define AB_ELTAG_GROUP "group"
343 #define AB_ELTAG_FOLDER "folder"
345 /* Attribute tag names */
346 #define AB_ATTAG_TYPE "type"
347 #define AB_ATTAG_UID "uid"
348 #define AB_ATTAG_NAME "name"
349 #define AB_ATTAG_REMARKS "remarks"
350 #define AB_ATTAG_FIRST_NAME "first-name"
351 #define AB_ATTAG_LAST_NAME "last-name"
352 #define AB_ATTAG_NICK_NAME "nick-name"
353 #define AB_ATTAG_COMMON_NAME "cn"
354 #define AB_ATTAG_ALIAS "alias"
355 #define AB_ATTAG_EMAIL "email"
356 #define AB_ATTAG_EID "eid"
357 #define AB_ATTAG_PID "pid"
359 /* Attribute values */
360 #define AB_ATTAG_VAL_PERSON "person"
361 #define AB_ATTAG_VAL_GROUP "group"
362 #define AB_ATTAG_VAL_FOLDER "folder"
365 * Parse address item for person.
367 static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
370 ItemEMail *email = NULL;
372 attr = xml_get_current_tag_attr(file);
374 name = ((XMLAttr *)attr->data)->name;
375 value = ((XMLAttr *)attr->data)->value;
376 if( ! email ) email = addritem_create_item_email();
377 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
378 ADDRITEM_ID(email) = g_strdup( value );
380 else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
381 ADDRITEM_NAME(email) = g_strdup( value );
383 else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
384 email->address = g_strdup( value );
386 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
387 email->remarks = g_strdup( value );
389 attr = g_list_next( attr );
393 addrcache_person_add_email( book->addressCache, person, email );
396 addritem_free_item_email( email );
403 * Parse email address list.
405 static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
410 prev_level = file->level;
411 if( xml_parse_next_tag( file ) ) {
412 longjmp( book->jumper, 1 );
414 if (file->level < prev_level) return;
415 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
416 attr = xml_get_current_tag_attr(file);
417 addrbook_parse_address( book, file, person );
418 addrbook_parse_addr_list( book, file, person );
424 * Parse attibute for person.
426 static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
430 UserAttribute *uAttr = NULL;
432 attr = xml_get_current_tag_attr(file);
434 name = ((XMLAttr *)attr->data)->name;
435 value = ((XMLAttr *)attr->data)->value;
436 if( ! uAttr ) uAttr = addritem_create_attribute();
437 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
438 addritem_attrib_set_id( uAttr, value );
440 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
441 addritem_attrib_set_name( uAttr, value );
443 attr = g_list_next( attr );
446 element = xml_get_element( file );
447 addritem_attrib_set_value( uAttr, element );
451 addritem_person_add_attribute( person, uAttr );
454 addritem_free_attribute( uAttr );
461 * Parse attribute list.
463 static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
468 prev_level = file->level;
469 if( xml_parse_next_tag( file ) ) {
470 longjmp( book->jumper, 1 );
472 if (file->level < prev_level) return;
473 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
474 attr = xml_get_current_tag_attr(file);
475 addrbook_parse_attribute( file, person );
476 addrbook_parse_attr_list( book, file, person );
484 static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
487 ItemPerson *person = NULL;
489 attr = xml_get_current_tag_attr(file);
491 name = ((XMLAttr *)attr->data)->name;
492 value = ((XMLAttr *)attr->data)->value;
493 if( ! person ) person = addritem_create_item_person();
494 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
495 ADDRITEM_ID(person) = g_strdup( value );
497 else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
498 person->firstName = g_strdup( value );
500 else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
501 person->lastName = g_strdup( value );
503 else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
504 person->nickName = g_strdup( value );
506 else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
507 ADDRITEM_NAME(person) = g_strdup( value );
509 attr = g_list_next( attr );
511 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
512 longjmp( book->jumper, 1 );
514 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
515 addrbook_parse_addr_list( book, file, person );
517 addrcache_hash_add_person( book->addressCache, person );
520 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
521 longjmp( book->jumper, 1 );
523 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
524 addrbook_parse_attr_list( book, file, person );
529 * Parse group member.
531 static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
534 gchar *pid = NULL, *eid = NULL;
535 ItemEMail *email = NULL;
537 attr = xml_get_current_tag_attr(file);
539 name = ((XMLAttr *)attr->data)->name;
540 value = ((XMLAttr *)attr->data)->value;
541 if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
542 pid = g_strdup( value );
544 else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
545 eid = g_strdup( value );
547 attr = g_list_next( attr );
549 email = addrcache_get_email( book->addressCache, pid, eid );
552 addrcache_group_add_email( book->addressCache, group, email );
555 addritem_free_item_email( email );
562 * Parse group member list.
564 static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
569 prev_level = file->level;
570 if( xml_parse_next_tag( file ) ) {
571 longjmp( book->jumper, 1 );
573 if (file->level < prev_level) return;
574 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
575 attr = xml_get_current_tag_attr(file);
576 addrbook_parse_member( book, file, group );
577 addrbook_parse_member_list( book, file, group );
580 attr = xml_get_current_tag_attr( file );
588 static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
591 ItemGroup *group = NULL;
593 attr = xml_get_current_tag_attr(file);
595 name = ((XMLAttr *)attr->data)->name;
596 value = ((XMLAttr *)attr->data)->value;
597 if( ! group ) group = addritem_create_item_group();
598 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
599 ADDRITEM_ID(group) = g_strdup( value );
601 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
602 ADDRITEM_NAME(group) = g_strdup( value );
604 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
605 group->remarks = g_strdup( value );
607 attr = g_list_next( attr );
609 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
610 longjmp( book->jumper, 1 );
612 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
614 addrcache_hash_add_group( book->addressCache, group );
616 addrbook_parse_member_list( book, file, group );
623 static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
628 attr = xml_get_current_tag_attr(file);
630 name = ((XMLAttr *)attr->data)->name;
631 value = ((XMLAttr *)attr->data)->value;
632 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
633 uid = g_strdup( value );
635 attr = g_list_next( attr );
639 folder->listItems = g_list_append( folder->listItems, uid );
645 * Parse folder item list.
647 static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
652 prev_level = file->level;
653 if( xml_parse_next_tag( file ) ) {
654 longjmp( book->jumper, 1 );
656 if (file->level < prev_level) return;
657 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
658 attr = xml_get_current_tag_attr(file);
659 addrbook_parse_folder_item( book, file, folder );
660 addrbook_parse_folder_list( book, file, folder );
663 attr = xml_get_current_tag_attr( file );
671 static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
674 ItemFolder *folder = NULL;
676 attr = xml_get_current_tag_attr(file);
678 name = ((XMLAttr *)attr->data)->name;
679 value = ((XMLAttr *)attr->data)->value;
681 folder = addritem_create_item_folder();
683 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
684 ADDRITEM_ID(folder) = g_strdup( value );
686 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
687 ADDRITEM_NAME(folder) = g_strdup( value );
689 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
690 folder->remarks = g_strdup( value );
692 attr = g_list_next( attr );
694 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
695 longjmp( book->jumper, 1 );
697 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
699 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
700 book->tempList = g_list_append( book->tempList, folder );
701 ADDRITEM_PARENT(folder) = NULL; /* We will resolve folder later */
704 addrbook_parse_folder_list( book, file, folder );
709 * Parse address book.
710 * Return: TRUE if data read successfully, FALSE if error reading data.
712 static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
717 book->retVal = MGU_BAD_FORMAT;
718 if( xml_get_dtd( file ) ) {
721 if( xml_parse_next_tag( file ) ) {
722 longjmp( book->jumper, 1 );
724 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
728 attr = xml_get_current_tag_attr(file);
730 name = ((XMLAttr *)attr->data)->name;
731 value = ((XMLAttr *)attr->data)->value;
732 if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
733 addrbook_set_name( book, value );
735 attr = g_list_next( attr );
740 if (! file->level ) break;
741 /* Get next item tag (person, group or folder) */
742 if( xml_parse_next_tag( file ) ) {
743 longjmp( book->jumper, 1 );
745 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
746 addrbook_parse_person( book, file );
748 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
749 addrbook_parse_group( book, file );
751 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
752 addrbook_parse_folder( book, file );
755 if( retVal ) book->retVal = MGU_SUCCESS;
760 * Resolve folder items visitor function.
762 static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
763 AddressBookFile *book = data;
764 AddrItemObject *obj = ( AddrItemObject * ) value;
765 ItemFolder *rootFolder = book->addressCache->rootFolder;
766 if( obj->parent == NULL ) {
767 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
768 rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
769 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
771 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
772 rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
773 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
779 * Resolve folder items. Lists of UID's are replaced with pointers to data items.
781 static void addrbook_resolve_folder_items( AddressBookFile *book ) {
782 GList *nodeFolder = NULL;
783 GList *listRemove = NULL;
785 ItemFolder *rootFolder = book->addressCache->rootFolder;
786 nodeFolder = book->tempList;
787 while( nodeFolder ) {
788 ItemFolder *folder = nodeFolder->data;
790 node = folder->listItems;
792 gchar *uid = node->data;
793 AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
795 if( aio->type == ITEMTYPE_FOLDER ) {
796 ItemFolder *item = ( ItemFolder * ) aio;
797 folder->listFolder = g_list_append( folder->listFolder, item );
798 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
799 addrcache_hash_add_folder( book->addressCache, folder );
801 else if( aio->type == ITEMTYPE_PERSON ) {
802 ItemPerson *item = ( ItemPerson * ) aio;
803 folder->listPerson = g_list_append( folder->listPerson, item );
804 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
806 else if( aio->type == ITEMTYPE_GROUP ) {
807 ItemGroup *item = ( ItemGroup * ) aio;
808 folder->listGroup = g_list_append( folder->listGroup, item );
809 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
811 /* Replace data with pointer to item */
816 /* Not found, append to remove list. */
817 listRemove = g_list_append( listRemove, uid );
819 node = g_list_next( node );
821 rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
823 /* Process remove list */
826 gchar *uid = node->data;
827 folder->listItems = g_list_remove( folder->listItems, uid );
829 node = g_list_next( node );
831 g_list_free( listRemove );
832 nodeFolder = g_list_next( nodeFolder );
835 /* Remove folders with parents. */
837 node = rootFolder->listFolder;
839 ItemFolder *folder = ( ItemFolder * ) node->data;
840 if( ADDRITEM_PARENT(folder) ) {
841 /* Remove folders with parents */
842 listRemove = g_list_append( listRemove, folder );
845 /* Add to root folder */
846 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
848 node = g_list_next( node );
851 /* Process remove list */
854 rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
855 node = g_list_next( node );
857 g_list_free( listRemove );
859 /* Move all unparented persons and groups into root folder */
860 g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
862 /* Free up some more */
863 nodeFolder = book->tempList;
864 while( nodeFolder ) {
865 ItemFolder *folder = nodeFolder->data;
866 g_list_free( folder->listItems );
867 folder->listItems = NULL;
868 nodeFolder = g_list_next( nodeFolder );
870 g_list_free( book->tempList );
871 book->tempList = NULL;
876 * Read address book file.
878 gint addrbook_read_data( AddressBookFile *book ) {
879 XMLFile *file = NULL;
880 gchar *fileSpec = NULL;
882 g_return_val_if_fail( book != NULL, -1 );
884 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
885 book->retVal = MGU_OPEN_FILE;
886 book->accessFlag = FALSE;
887 book->modifyFlag = FALSE;
888 file = xml_open_file( fileSpec );
891 book->tempList = NULL;
893 /* Trap for parsing errors. */
894 if( setjmp( book->jumper ) ) {
895 xml_close_file( file );
898 addrbook_read_tree( book, file );
899 xml_close_file( file );
901 /* Resolve folder items */
902 addrbook_resolve_folder_items( book );
903 book->tempList = NULL;
904 book->readFlag = TRUE;
905 book->dirtyFlag = FALSE;
910 static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
912 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
917 static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
919 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
925 static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
929 xml_file_put_escape_str( fp, value );
934 * Write file hash table visitor function.
936 static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
937 AddrItemObject *obj = ( AddrItemObject * ) value;
938 FILE *fp = ( FILE * ) data;
942 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
943 ItemPerson *person = ( ItemPerson * ) value;
945 addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
946 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
947 addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
948 addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
949 addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
950 addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
953 /* Output email addresses */
954 addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
956 node = person->listEMail;
958 ItemEMail *email = node->data;
959 addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
960 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
961 addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
962 addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
963 addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
965 node = g_list_next( node );
967 addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
969 /* Output user attributes */
970 addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
972 node = person->listAttrib;
974 UserAttribute *attrib = node->data;
975 addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
976 addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
977 addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
979 xml_file_put_escape_str( fp, attrib->value );
980 addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
981 node = g_list_next( node );
983 addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
984 addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
990 * Output all groups in folder.
992 static void addrbook_write_folder_group( ItemFolder *parent, FILE *fp ) {
993 GList *nodeGrp = parent->listGroup;
997 ItemGroup *group = nodeGrp->data;
999 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
1000 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
1001 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
1002 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
1003 fputs( " >\n", fp );
1005 /* Output email address links */
1006 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
1008 node = group->listEMail;
1010 ItemEMail *email = node->data;
1011 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1012 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
1013 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
1014 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
1015 fputs( " />\n", fp );
1016 node = g_list_next( node );
1018 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
1019 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1021 nodeGrp = g_list_next( nodeGrp );
1023 node = parent->listFolder;
1025 ItemFolder *folder = node->data;
1026 addrbook_write_folder_group( folder, fp );
1027 node = g_list_next( node );
1032 * Write file hash table visitor function.
1034 static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
1035 AddrItemObject *obj = ( AddrItemObject * ) value;
1036 FILE *fp = ( FILE * ) data;
1040 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1041 ItemGroup *group = ( ItemGroup * ) value;
1043 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
1044 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
1045 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
1046 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
1047 fputs( " >\n", fp );
1049 /* Output email address links */
1050 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
1052 node = group->listEMail;
1054 ItemEMail *email = node->data;
1055 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1056 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
1057 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
1058 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
1059 fputs( " />\n", fp );
1060 node = g_list_next( node );
1062 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
1063 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1069 * Output all folders in folder.
1071 static void addrbook_write_folder_folder( ItemFolder *parent, FILE *fp ) {
1072 GList *nodeFold = parent->listFolder;
1076 ItemFolder *folder = nodeFold->data;
1077 addrbook_write_folder_folder( folder, fp );
1079 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1080 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1081 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1082 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1083 fputs( " >\n", fp );
1084 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1087 /* Output persons */
1088 node = folder->listPerson;
1090 ItemPerson *item = node->data;
1091 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM );
1092 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1093 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1094 fputs( " />\n", fp );
1095 node = g_list_next( node );
1099 node = folder->listGroup;
1101 ItemGroup *item = node->data;
1102 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM );
1103 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1104 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1105 fputs( " />\n", fp );
1106 node = g_list_next( node );
1109 /* Output folders */
1110 node = folder->listFolder;
1112 ItemFolder *item = node->data;
1113 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM );
1114 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1115 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1116 fputs( " />\n", fp );
1117 node = g_list_next( node );
1119 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1120 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1122 nodeFold = g_list_next( nodeFold );
1127 * Write file hash table visitor function.
1129 static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1130 AddrItemObject *obj = ( AddrItemObject * ) value;
1131 FILE *fp = ( FILE * ) data;
1135 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1136 ItemFolder *folder = ( ItemFolder * ) value;
1138 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1139 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1140 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1141 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1142 fputs( " >\n", fp );
1143 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1146 /* Output persons */
1147 node = folder->listPerson;
1149 ItemPerson *item = node->data;
1150 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1151 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1152 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1153 fputs( " />\n", fp );
1154 node = g_list_next( node );
1158 node = folder->listGroup;
1160 ItemGroup *item = node->data;
1161 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1162 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1163 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1164 fputs( " />\n", fp );
1165 node = g_list_next( node );
1168 /* Output folders */
1169 node = folder->listFolder;
1171 ItemFolder *item = node->data;
1172 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1173 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1174 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1175 fputs( " />\n", fp );
1176 node = g_list_next( node );
1178 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1179 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1185 * Output address book data to specified file.
1186 * return: Status code.
1188 gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1191 #ifndef DEV_STANDALONE
1195 g_return_val_if_fail( book != NULL, -1 );
1196 g_return_val_if_fail( newFile != NULL, -1 );
1198 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1200 book->retVal = MGU_OPEN_FILE;
1201 #ifdef DEV_STANDALONE
1202 fp = fopen( fileSpec, "w" );
1205 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1207 pfile = prefs_write_open( fileSpec );
1211 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1212 conv_get_current_charset_str() );
1214 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1215 addrbook_write_attr( fp, AB_ATTAG_NAME, book->name );
1216 fputs( " >\n", fp );
1218 /* Output all persons */
1219 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1221 /* Output all groups */
1222 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1223 /* addrbook_write_folder_group( book->rootFolder, fp ); */
1225 /* Output all folders */
1226 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1227 /* addrbook_write_folder_folder( book->rootFolder, fp ); */
1229 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1230 book->retVal = MGU_SUCCESS;
1231 #ifdef DEV_STANDALONE
1234 if( prefs_write_close( pfile ) < 0 ) {
1235 book->retVal = MGU_ERROR_WRITE;
1241 return book->retVal;
1245 * Output address book data to original file.
1246 * return: Status code.
1248 gint addrbook_save_data( AddressBookFile *book ) {
1249 g_return_val_if_fail( book != NULL, -1 );
1251 book->retVal = MGU_NO_FILE;
1252 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1253 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1255 addrbook_write_to( book, book->fileName );
1256 if( book->retVal == MGU_SUCCESS ) {
1257 book->dirtyFlag = FALSE;
1259 return book->retVal;
1262 /* **********************************************************************
1263 * Address book edit interface functions...
1264 * ***********************************************************************
1268 * Move person's email item.
1269 * param: book Address book.
1271 * itemMove Item to move.
1272 * itemTarget Target item before which to move item.
1274 ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1275 ItemEMail *itemMove, ItemEMail *itemTarget )
1277 ItemEMail *email = NULL;
1279 g_return_val_if_fail( book != NULL, NULL );
1281 email = addritem_move_email_before( person, itemMove, itemTarget );
1283 book->dirtyFlag = TRUE;
1289 * Move person's email item.
1290 * param: book Address book.
1292 * itemMove Item to move.
1293 * itemTarget Target item after which to move item.
1295 ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1296 ItemEMail *itemMove, ItemEMail *itemTarget )
1298 ItemEMail *email = NULL;
1300 g_return_val_if_fail( book != NULL, NULL );
1302 email = addritem_move_email_after( person, itemMove, itemTarget );
1304 book->dirtyFlag = TRUE;
1310 * Hash table visitor function.
1312 static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1320 * Update address book email list for specified person.
1321 * Enter: book Address book.
1322 * person Person to update.
1323 * listEMail New list of email addresses.
1324 * Note: The existing email addresses are replaced with the new addresses. Any references
1325 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1326 * linked to the person are removed.
1328 void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1333 g_return_if_fail( book != NULL );
1334 g_return_if_fail( person != NULL );
1336 /* Remember old list */
1337 oldData = person->listEMail;
1339 /* Attach new address list to person. */
1342 ItemEMail *email = node->data;
1343 if( ADDRITEM_ID(email) == NULL ) {
1344 /* Allocate an ID */
1345 addrcache_id_email( book->addressCache, email );
1347 ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1348 node = g_list_next( node );
1350 person->listEMail = listEMail;
1352 /* Get groups where person's email is listed */
1353 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1355 GHashTable *hashEMail;
1358 /* Load hash table with new address entries */
1359 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1362 ItemEMail *email = node->data;
1363 gchar *addr = g_strdup( email->address );
1365 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1366 g_hash_table_insert( hashEMail, addr, email );
1368 node = g_list_next( node );
1371 /* Re-parent new addresses to existing groups, where email address match. */
1372 nodeGrp = listGroup;
1374 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1375 GList *groupEMail = group->listEMail;
1377 GList *listRemove = NULL;
1379 /* Process each email item linked to group */
1380 nodeGrpEM = groupEMail;
1381 while( nodeGrpEM ) {
1382 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1383 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1384 /* Found an email address for this person */
1385 ItemEMail *emailNew = NULL;
1386 gchar *addr = g_strdup( emailGrp->address );
1388 emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1391 /* Point to this entry */
1392 nodeGrpEM->data = emailNew;
1395 /* Mark for removal */
1396 listRemove = g_list_append( listRemove, emailGrp );
1399 /* Move on to next email link */
1400 nodeGrpEM = g_list_next( nodeGrpEM );
1403 /* Process all removed links in current group */
1404 nodeGrpEM = listRemove;
1405 while( nodeGrpEM ) {
1406 ItemEMail *emailGrp = nodeGrpEM->data;
1407 groupEMail = g_list_remove( groupEMail, emailGrp );
1408 nodeGrpEM = g_list_next( nodeGrpEM );
1411 /* Move on to next group */
1412 nodeGrp = g_list_next( nodeGrp );
1416 /* Clear hash table */
1417 g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1418 g_hash_table_destroy( hashEMail );
1420 g_list_free( listGroup );
1424 /* Free up old data */
1425 addritem_free_list_email( oldData );
1427 book->dirtyFlag = TRUE;
1432 * Add person and address data to address book.
1433 * Enter: book Address book.
1434 * folder Folder where to add person, or NULL for root folder.
1435 * listEMail New list of email addresses.
1436 * Return: Person added.
1437 * Note: A new person is created with specified list of email addresses. All objects inserted
1438 * into address book.
1440 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1442 ItemFolder *f = folder;
1445 g_return_val_if_fail( book != NULL, NULL );
1447 if( ! f ) f = book->addressCache->rootFolder;
1448 person = addritem_create_item_person();
1449 addrcache_id_person( book->addressCache, person );
1450 addrcache_folder_add_person( book->addressCache, f, person );
1454 ItemEMail *email = node->data;
1455 if( ADDRITEM_ID(email) == NULL ) {
1456 addrcache_id_email( book->addressCache, email );
1458 addrcache_person_add_email( book->addressCache, person, email );
1459 node = g_list_next( node );
1461 book->dirtyFlag = TRUE;
1466 * Load hash table visitor function.
1468 static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1469 AddrItemObject *obj = ( AddrItemObject * ) value;
1471 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1472 GHashTable *table = ( GHashTable * ) data;
1473 gchar *newKey = g_strdup( key );
1474 ItemEMail *email = ( ItemEMail * ) obj;
1475 if( ! g_hash_table_lookup( table, newKey ) ) {
1476 g_hash_table_insert( table, newKey, email );
1482 * Load hash table with links to email addresses.
1484 static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
1485 g_return_if_fail( book != NULL );
1486 g_return_if_fail( table != NULL );
1487 g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
1491 * Build available email list visitor function.
1493 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1494 AddrItemObject *obj = ( AddrItemObject * ) value;
1496 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1497 AddressBookFile *book = data;
1498 ItemPerson *person = ( ItemPerson * ) obj;
1499 GList *node = person->listEMail;
1501 ItemEMail *email = node->data;
1502 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1504 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1505 book->tempList = g_list_append( book->tempList, email );
1507 node = g_list_next( node );
1513 * Return link list of available email items (which have not already been linked to
1514 * groups). Note that the list contains references to items and should be g_free()
1515 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1516 * destroy the addressbook data!
1517 * Return: List of items, or NULL if none.
1519 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1523 g_return_val_if_fail( book != NULL, NULL );
1525 /* Load hash table with group email entries */
1526 table = g_hash_table_new( g_str_hash, g_str_equal );
1528 list = group->listEMail;
1530 ItemEMail *email = list->data;
1531 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1532 list = g_list_next( list );
1536 /* Build list of available email addresses which exclude those already in groups */
1537 book->tempList = NULL;
1538 book->tempHash = table;
1539 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1540 list = book->tempList;
1541 book->tempList = NULL;
1542 book->tempHash = NULL;
1544 /* Clear hash table */
1545 g_hash_table_destroy( table );
1552 * Update address book email list for specified group.
1553 * Enter: book Address book.
1554 * group group to update.
1555 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1556 * Note: The existing email addresses are replaced with the new addresses. Any references
1557 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1558 * linked to the person are removed.
1560 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1563 g_return_if_fail( book != NULL );
1564 g_return_if_fail( group != NULL );
1566 /* Remember old list */
1567 oldData = group->listEMail;
1568 group->listEMail = listEMail;
1569 mgu_clear_list( oldData );
1571 book->dirtyFlag = TRUE;
1575 * Add group and email list to address book.
1576 * Enter: book Address book.
1577 * folder Parent folder, or NULL for root folder.
1578 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1579 * Return: Group object.
1580 * Note: The existing email addresses are replaced with the new addresses. Any references
1581 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1582 * linked to the person are removed.
1584 ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1585 ItemGroup *group = NULL;
1586 ItemFolder *f = folder;
1588 g_return_val_if_fail( book != NULL, NULL );
1590 if( ! f ) f = book->addressCache->rootFolder;
1591 group = addritem_create_item_group();
1592 addrcache_id_group( book->addressCache, group );
1593 addrcache_folder_add_group( book->addressCache, f, group );
1594 group->listEMail = listEMail;
1595 book->dirtyFlag = TRUE;
1600 * Add new folder to address book.
1601 * Enter: book Address book.
1602 * parent Parent folder.
1603 * Return: Folder that was added. This should *NOT* be g_free() when done.
1605 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1606 ItemFolder *folder = NULL;
1607 ItemFolder *p = parent;
1609 g_return_val_if_fail( book != NULL, NULL );
1611 if( ! p ) p = book->addressCache->rootFolder;
1612 folder = addritem_create_item_folder();
1613 addrcache_id_folder( book->addressCache, folder );
1614 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1615 p->listFolder = g_list_append( p->listFolder, folder );
1616 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1617 book->dirtyFlag = TRUE;
1620 addritem_free_item_folder( folder );
1627 * Update address book attribute list for specified person.
1628 * Enter: book Address book.
1629 * person Person to update.
1630 * listAttrib New list of attributes.
1631 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1632 * linked to the person are removed.
1634 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1638 g_return_if_fail( book != NULL );
1639 g_return_if_fail( person != NULL );
1641 /* Remember old list */
1642 oldData = person->listAttrib;
1644 /* Attach new address list to person. */
1647 UserAttribute *attrib = node->data;
1648 if( attrib->uid == NULL ) {
1649 /* Allocate an ID */
1650 addrcache_id_attribute( book->addressCache, attrib );
1652 node = g_list_next( node );
1654 person->listAttrib = listAttrib;
1656 /* Free up old data */
1657 addritem_free_list_attribute( oldData );
1659 book->dirtyFlag = TRUE;
1664 * Add attribute data for person to address book.
1665 * Enter: book Address book.
1666 * person New person object.
1667 * listAttrib New list of attributes.
1668 * Note: Only attributes are inserted into address book.
1670 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1673 g_return_if_fail( book != NULL );
1674 g_return_if_fail( person != NULL );
1678 UserAttribute *attrib = node->data;
1679 if( attrib->uid == NULL ) {
1680 addrcache_id_attribute( book->addressCache, attrib );
1682 addritem_person_add_attribute( person, attrib );
1683 node = g_list_next( node );
1685 book->dirtyFlag = TRUE;
1689 * Return address book file for specified object.
1690 * Enter: aio Book item object.
1691 * Return: Address book, or NULL if not found.
1693 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1694 AddressBookFile *book = NULL;
1697 ItemFolder *parent = NULL;
1698 ItemFolder *root = NULL;
1699 if( aio->type == ITEMTYPE_EMAIL ) {
1700 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1702 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1706 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1709 root = addrcache_find_root_folder( parent );
1712 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1719 * Remove folder from address book. Children are re-parented to parent folder.
1720 * param: folder Folder to remove.
1721 * return: Folder, or NULL if not found. Note that object should still be freed.
1723 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1726 g_return_val_if_fail( book != NULL, NULL );
1728 f = addrcache_remove_folder( book->addressCache, folder );
1729 if( f ) book->dirtyFlag = TRUE;
1734 * Remove folder from address book. Children are deleted.
1735 * param: folder Folder to remove.
1736 * return: Folder, or NULL if not found. Note that object should still be freed.
1738 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1741 g_return_val_if_fail( book != NULL, NULL );
1743 f = addrcache_remove_folder_delete( book->addressCache, folder );
1744 if( f ) book->dirtyFlag = TRUE;
1748 #define WORK_BUFLEN 1024
1749 #define ADDRBOOK_DIGITS "0123456789"
1752 * Return list of existing address book files.
1753 * Enter: book Address book file.
1754 * Return: File list.
1756 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1759 struct dirent *entry;
1760 struct stat statbuf;
1761 gchar buf[ WORK_BUFLEN ];
1762 gchar numbuf[ WORK_BUFLEN ];
1763 gint len, lenpre, lensuf, lennum;
1764 long int val, maxval;
1765 GList *fileList = NULL;
1767 g_return_val_if_fail( book != NULL, NULL );
1769 if( book->path == NULL || *book->path == '\0' ) {
1770 book->retVal = MGU_NO_PATH;
1774 strcpy( buf, book->path );
1775 len = strlen( buf );
1777 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1778 buf[ len ] = G_DIR_SEPARATOR;
1779 buf[ ++len ] = '\0';
1783 adbookdir = g_strdup( buf );
1784 strcat( buf, ADDRBOOK_PREFIX );
1786 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1787 book->retVal = MGU_OPEN_DIRECTORY;
1788 g_free( adbookdir );
1792 lenpre = strlen( ADDRBOOK_PREFIX );
1793 lensuf = strlen( ADDRBOOK_SUFFIX );
1794 lennum = FILE_NUMDIGITS + lenpre;
1797 while( ( entry = readdir( dp ) ) != NULL ) {
1798 gchar *endptr = NULL;
1802 strcpy( buf, adbookdir );
1803 strcat( buf, entry->d_name );
1804 stat( buf, &statbuf );
1805 if( S_IFREG & statbuf.st_mode ) {
1806 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1807 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1808 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1810 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1811 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1818 val = strtol( numbuf, &endptr, 10 );
1819 if( endptr && val > -1 ) {
1820 if( val > maxval ) maxval = val;
1821 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1829 g_free( adbookdir );
1831 book->maxValue = maxval;
1832 book->retVal = MGU_SUCCESS;
1837 * Return file name for specified file number.
1838 * Enter: fileNum File number.
1839 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1841 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1843 gchar buf[ WORK_BUFLEN ];
1848 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1849 if( fileNum > nmax ) return NULL;
1850 sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1851 sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1852 return g_strdup( buf );
1855 /* **********************************************************************
1856 * Address book test functions...
1857 * ***********************************************************************
1860 static void addrbook_show_attribs( GList *attr ) {
1862 gchar *name = ((XMLAttr *)attr->data)->name;
1863 gchar *value = ((XMLAttr *)attr->data)->value;
1864 printf( "\tn/v = %s : %s\n", name, value );
1865 attr = g_list_next( attr );
1867 printf( "\t---\n" );
1871 * Test email address list.
1873 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1878 prev_level = file->level;
1879 if( xml_parse_next_tag( file ) ) {
1880 longjmp( book->jumper, 1 );
1882 if (file->level < prev_level) return;
1883 attr = xml_get_current_tag_attr(file);
1884 /* addrbook_show_attribs( attr ); */
1885 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1886 addrbook_chkparse_addr_list( book, file );
1892 * Test user attributes for person.
1894 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1898 attr = xml_get_current_tag_attr(file);
1899 /* addrbook_show_attribs( attr ); */
1900 element = xml_get_element( file );
1901 /* printf( "\t\tattrib value : %s\n", element ); */
1905 * Test attribute list.
1907 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1911 prev_level = file->level;
1912 if( xml_parse_next_tag( file ) ) {
1913 longjmp( book->jumper, 1 );
1915 if (file->level < prev_level) return;
1916 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1917 addrbook_chkparse_attribute( book, file );
1918 addrbook_chkparse_attr_list( book, file );
1926 static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1929 attr = xml_get_current_tag_attr(file);
1930 /* addrbook_show_attribs( attr ); */
1931 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1932 longjmp( book->jumper, 1 );
1934 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1935 addrbook_chkparse_addr_list( book, file );
1937 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1938 longjmp( book->jumper, 1 );
1940 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1941 addrbook_chkparse_attr_list( book, file );
1946 * Test group member list.
1948 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1953 prev_level = file->level;
1954 if( xml_parse_next_tag( file ) ) {
1955 longjmp( book->jumper, 1 );
1957 if (file->level < prev_level) return;
1958 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1959 attr = xml_get_current_tag_attr(file);
1960 /* addrbook_show_attribs( attr ); */
1961 addrbook_chkparse_member_list( book, file );
1964 attr = xml_get_current_tag_attr( file );
1965 /* addrbook_show_attribs( attr ); */
1973 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1976 attr = xml_get_current_tag_attr(file);
1977 /* addrbook_show_attribs( attr ); */
1978 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1979 longjmp( book->jumper, 1 );
1981 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1982 addrbook_chkparse_member_list( book, file );
1987 * Test folder item list.
1989 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1994 prev_level = file->level;
1995 if( xml_parse_next_tag( file ) ) {
1996 longjmp( book->jumper, 1 );
1998 if (file->level < prev_level) return;
1999 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
2000 attr = xml_get_current_tag_attr(file);
2001 /* addrbook_show_attribs( attr ); */
2002 addrbook_chkparse_folder_list( book, file );
2005 attr = xml_get_current_tag_attr( file );
2006 /* addrbook_show_attribs( attr ); */
2014 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
2017 attr = xml_get_current_tag_attr(file);
2018 /* addrbook_show_attribs( attr ); */
2019 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
2020 longjmp( book->jumper, 1 );
2022 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
2023 addrbook_chkparse_folder_list( book, file );
2028 * Test address book.
2030 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
2034 if( xml_get_dtd( file ) ) {
2037 if( xml_parse_next_tag( file ) ) {
2041 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
2045 attr = xml_get_current_tag_attr(file);
2046 /* addrbook_show_attribs( attr ); */
2050 if (! file->level ) break;
2052 if( xml_parse_next_tag( file ) ) {
2053 longjmp( book->jumper, 1 );
2055 /* Get next tag (person, group or folder) */
2056 if( xml_parse_next_tag( file ) ) {
2057 longjmp( book->jumper, 1 );
2059 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
2060 addrbook_chkparse_person( book, file );
2062 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
2063 addrbook_chkparse_group( book, file );
2065 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
2066 addrbook_chkparse_folder( book, file );
2069 /* Item not recognized */
2077 * Test address book file by parsing contents.
2078 * Enter: book Address book file to check.
2079 * fileName File name to check.
2080 * Return: MGU_SUCCESS if file appears to be valid format.
2082 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
2083 XMLFile *file = NULL;
2084 gchar *fileSpec = NULL;
2086 g_return_val_if_fail( book != NULL, -1 );
2088 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
2089 book->retVal = MGU_OPEN_FILE;
2090 file = xml_open_file( fileSpec );
2093 book->retVal = MGU_BAD_FORMAT;
2094 if( setjmp( book->jumper ) ) {
2095 /* printf( "Caught Ya!!!\n" ); */
2096 xml_close_file( file );
2097 return book->retVal;
2099 if( addrbook_chkread_tree( book, file ) ) {
2100 book->retVal = MGU_SUCCESS;
2102 xml_close_file( file );
2104 return book->retVal;
2108 * Return link list of all persons in address book. Note that the list contains
2109 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
2110 * this will destroy the addressbook data!
2111 * Return: List of items, or NULL if none.
2113 GList *addrbook_get_all_persons( AddressBookFile *book ) {
2114 g_return_val_if_fail( book != NULL, NULL );
2115 return addrcache_get_all_persons( book->addressCache );
2119 * Add person and address data to address book.
2120 * Enter: book Address book.
2121 * folder Folder where to add person, or NULL for root folder.
2123 * address EMail address.
2125 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
2126 * this will destroy the address book data.
2128 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
2129 const gchar *address, const gchar *remarks )
2131 ItemPerson *person = NULL;
2133 g_return_val_if_fail( book != NULL, NULL );
2135 person = addrcache_add_contact( book->addressCache, folder, name, address, remarks );
2136 if( person ) book->dirtyFlag = TRUE;