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 * Write file hash table visitor function.
992 static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
993 AddrItemObject *obj = ( AddrItemObject * ) value;
994 FILE *fp = ( FILE * ) data;
998 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
999 ItemGroup *group = ( ItemGroup * ) value;
1001 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
1002 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
1003 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
1004 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
1005 fputs( " >\n", fp );
1007 /* Output email address links */
1008 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
1010 node = group->listEMail;
1012 ItemEMail *email = node->data;
1013 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1014 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
1015 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
1016 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
1017 fputs( " />\n", fp );
1018 node = g_list_next( node );
1020 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
1021 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1027 * Write file hash table visitor function.
1029 static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1030 AddrItemObject *obj = ( AddrItemObject * ) value;
1031 FILE *fp = ( FILE * ) data;
1035 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1036 ItemFolder *folder = ( ItemFolder * ) value;
1038 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1039 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1040 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1041 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1042 fputs( " >\n", fp );
1043 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1046 /* Output persons */
1047 node = folder->listPerson;
1049 ItemPerson *item = node->data;
1050 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1051 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1052 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1053 fputs( " />\n", fp );
1054 node = g_list_next( node );
1058 node = folder->listGroup;
1060 ItemGroup *item = node->data;
1061 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1062 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1063 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1064 fputs( " />\n", fp );
1065 node = g_list_next( node );
1068 /* Output folders */
1069 node = folder->listFolder;
1071 ItemFolder *item = node->data;
1072 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1073 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1074 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1075 fputs( " />\n", fp );
1076 node = g_list_next( node );
1078 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1079 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1085 * Output address book data to specified file.
1086 * return: Status code.
1088 gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1091 #ifndef DEV_STANDALONE
1095 g_return_val_if_fail( book != NULL, -1 );
1096 g_return_val_if_fail( newFile != NULL, -1 );
1098 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1100 book->retVal = MGU_OPEN_FILE;
1101 #ifdef DEV_STANDALONE
1102 fp = fopen( fileSpec, "w" );
1105 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1107 pfile = prefs_write_open( fileSpec );
1111 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1112 conv_get_current_charset_str() );
1114 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1115 addrbook_write_attr( fp, AB_ATTAG_NAME, book->name );
1116 fputs( " >\n", fp );
1118 /* Output all persons */
1119 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1121 /* Output all groups */
1122 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1124 /* Output all folders */
1125 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1127 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1128 book->retVal = MGU_SUCCESS;
1129 #ifdef DEV_STANDALONE
1132 if( prefs_write_close( pfile ) < 0 ) {
1133 book->retVal = MGU_ERROR_WRITE;
1139 return book->retVal;
1143 * Output address book data to original file.
1144 * return: Status code.
1146 gint addrbook_save_data( AddressBookFile *book ) {
1147 g_return_val_if_fail( book != NULL, -1 );
1149 book->retVal = MGU_NO_FILE;
1150 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1151 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1153 addrbook_write_to( book, book->fileName );
1154 if( book->retVal == MGU_SUCCESS ) {
1155 book->dirtyFlag = FALSE;
1157 return book->retVal;
1160 /* **********************************************************************
1161 * Address book edit interface functions...
1162 * ***********************************************************************
1166 * Move person's email item.
1167 * param: book Address book.
1169 * itemMove Item to move.
1170 * itemTarget Target item before which to move item.
1172 ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1173 ItemEMail *itemMove, ItemEMail *itemTarget )
1175 ItemEMail *email = NULL;
1177 g_return_val_if_fail( book != NULL, NULL );
1179 email = addritem_move_email_before( person, itemMove, itemTarget );
1181 book->dirtyFlag = TRUE;
1187 * Move person's email item.
1188 * param: book Address book.
1190 * itemMove Item to move.
1191 * itemTarget Target item after which to move item.
1193 ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1194 ItemEMail *itemMove, ItemEMail *itemTarget )
1196 ItemEMail *email = NULL;
1198 g_return_val_if_fail( book != NULL, NULL );
1200 email = addritem_move_email_after( person, itemMove, itemTarget );
1202 book->dirtyFlag = TRUE;
1208 * Hash table visitor function.
1210 static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1218 * Update address book email list for specified person.
1219 * Enter: book Address book.
1220 * person Person to update.
1221 * listEMail New list of email addresses.
1222 * Note: The existing email addresses are replaced with the new addresses. Any references
1223 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1224 * linked to the person are removed.
1226 void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1231 g_return_if_fail( book != NULL );
1232 g_return_if_fail( person != NULL );
1234 /* Remember old list */
1235 oldData = person->listEMail;
1237 /* Attach new address list to person. */
1240 ItemEMail *email = node->data;
1241 if( ADDRITEM_ID(email) == NULL ) {
1242 /* Allocate an ID */
1243 addrcache_id_email( book->addressCache, email );
1245 ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1246 node = g_list_next( node );
1248 person->listEMail = listEMail;
1250 /* Get groups where person's email is listed */
1251 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1253 GHashTable *hashEMail;
1256 /* Load hash table with new address entries */
1257 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1260 ItemEMail *email = node->data;
1261 gchar *addr = g_strdup( email->address );
1263 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1264 g_hash_table_insert( hashEMail, addr, email );
1266 node = g_list_next( node );
1269 /* Re-parent new addresses to existing groups, where email address match. */
1270 nodeGrp = listGroup;
1272 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1273 GList *groupEMail = group->listEMail;
1275 GList *listRemove = NULL;
1277 /* Process each email item linked to group */
1278 nodeGrpEM = groupEMail;
1279 while( nodeGrpEM ) {
1280 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1281 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1282 /* Found an email address for this person */
1283 ItemEMail *emailNew = NULL;
1284 gchar *addr = g_strdup( emailGrp->address );
1286 emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1289 /* Point to this entry */
1290 nodeGrpEM->data = emailNew;
1293 /* Mark for removal */
1294 listRemove = g_list_append( listRemove, emailGrp );
1297 /* Move on to next email link */
1298 nodeGrpEM = g_list_next( nodeGrpEM );
1301 /* Process all removed links in current group */
1302 nodeGrpEM = listRemove;
1303 while( nodeGrpEM ) {
1304 ItemEMail *emailGrp = nodeGrpEM->data;
1305 groupEMail = g_list_remove( groupEMail, emailGrp );
1306 nodeGrpEM = g_list_next( nodeGrpEM );
1309 /* Move on to next group */
1310 nodeGrp = g_list_next( nodeGrp );
1314 /* Clear hash table */
1315 g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1316 g_hash_table_destroy( hashEMail );
1318 g_list_free( listGroup );
1322 /* Free up old data */
1323 addritem_free_list_email( oldData );
1325 book->dirtyFlag = TRUE;
1330 * Add person and address data to address book.
1331 * Enter: book Address book.
1332 * folder Folder where to add person, or NULL for root folder.
1333 * listEMail New list of email addresses.
1334 * Return: Person added.
1335 * Note: A new person is created with specified list of email addresses. All objects inserted
1336 * into address book.
1338 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1340 ItemFolder *f = folder;
1343 g_return_val_if_fail( book != NULL, NULL );
1345 if( ! f ) f = book->addressCache->rootFolder;
1346 person = addritem_create_item_person();
1347 addrcache_id_person( book->addressCache, person );
1348 addrcache_folder_add_person( book->addressCache, f, person );
1352 ItemEMail *email = node->data;
1353 if( ADDRITEM_ID(email) == NULL ) {
1354 addrcache_id_email( book->addressCache, email );
1356 addrcache_person_add_email( book->addressCache, person, email );
1357 node = g_list_next( node );
1359 book->dirtyFlag = TRUE;
1364 * Load hash table visitor function.
1366 static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1367 AddrItemObject *obj = ( AddrItemObject * ) value;
1369 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1370 GHashTable *table = ( GHashTable * ) data;
1371 gchar *newKey = g_strdup( key );
1372 ItemEMail *email = ( ItemEMail * ) obj;
1373 if( ! g_hash_table_lookup( table, newKey ) ) {
1374 g_hash_table_insert( table, newKey, email );
1380 * Load hash table with links to email addresses.
1382 static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
1383 g_return_if_fail( book != NULL );
1384 g_return_if_fail( table != NULL );
1385 g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
1389 * Build available email list visitor function.
1391 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1392 AddrItemObject *obj = ( AddrItemObject * ) value;
1394 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1395 AddressBookFile *book = data;
1396 ItemPerson *person = ( ItemPerson * ) obj;
1397 GList *node = person->listEMail;
1399 ItemEMail *email = node->data;
1400 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1402 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1403 book->tempList = g_list_append( book->tempList, email );
1405 node = g_list_next( node );
1411 * Return link list of available email items (which have not already been linked to
1412 * groups). Note that the list contains references to items and should be g_free()
1413 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1414 * destroy the addressbook data!
1415 * Return: List of items, or NULL if none.
1417 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1421 g_return_val_if_fail( book != NULL, NULL );
1423 /* Load hash table with group email entries */
1424 table = g_hash_table_new( g_str_hash, g_str_equal );
1426 list = group->listEMail;
1428 ItemEMail *email = list->data;
1429 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1430 list = g_list_next( list );
1434 /* Build list of available email addresses which exclude those already in groups */
1435 book->tempList = NULL;
1436 book->tempHash = table;
1437 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1438 list = book->tempList;
1439 book->tempList = NULL;
1440 book->tempHash = NULL;
1442 /* Clear hash table */
1443 g_hash_table_destroy( table );
1450 * Update address book email list for specified group.
1451 * Enter: book Address book.
1452 * group group to update.
1453 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1454 * Note: The existing email addresses are replaced with the new addresses. Any references
1455 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1456 * linked to the person are removed.
1458 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1461 g_return_if_fail( book != NULL );
1462 g_return_if_fail( group != NULL );
1464 /* Remember old list */
1465 oldData = group->listEMail;
1466 group->listEMail = listEMail;
1467 mgu_clear_list( oldData );
1469 book->dirtyFlag = TRUE;
1473 * Add group and email list to address book.
1474 * Enter: book Address book.
1475 * folder Parent folder, or NULL for root folder.
1476 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1477 * Return: Group object.
1478 * Note: The existing email addresses are replaced with the new addresses. Any references
1479 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1480 * linked to the person are removed.
1482 ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1483 ItemGroup *group = NULL;
1484 ItemFolder *f = folder;
1486 g_return_val_if_fail( book != NULL, NULL );
1488 if( ! f ) f = book->addressCache->rootFolder;
1489 group = addritem_create_item_group();
1490 addrcache_id_group( book->addressCache, group );
1491 addrcache_folder_add_group( book->addressCache, f, group );
1492 group->listEMail = listEMail;
1493 book->dirtyFlag = TRUE;
1498 * Add new folder to address book.
1499 * Enter: book Address book.
1500 * parent Parent folder.
1501 * Return: Folder that was added. This should *NOT* be g_free() when done.
1503 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1504 ItemFolder *folder = NULL;
1505 ItemFolder *p = parent;
1507 g_return_val_if_fail( book != NULL, NULL );
1509 if( ! p ) p = book->addressCache->rootFolder;
1510 folder = addritem_create_item_folder();
1511 addrcache_id_folder( book->addressCache, folder );
1512 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1513 p->listFolder = g_list_append( p->listFolder, folder );
1514 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1515 book->dirtyFlag = TRUE;
1518 addritem_free_item_folder( folder );
1525 * Update address book attribute list for specified person.
1526 * Enter: book Address book.
1527 * person Person to update.
1528 * listAttrib New list of attributes.
1529 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1530 * linked to the person are removed.
1532 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1536 g_return_if_fail( book != NULL );
1537 g_return_if_fail( person != NULL );
1539 /* Remember old list */
1540 oldData = person->listAttrib;
1542 /* Attach new address list to person. */
1545 UserAttribute *attrib = node->data;
1546 if( attrib->uid == NULL ) {
1547 /* Allocate an ID */
1548 addrcache_id_attribute( book->addressCache, attrib );
1550 node = g_list_next( node );
1552 person->listAttrib = listAttrib;
1554 /* Free up old data */
1555 addritem_free_list_attribute( oldData );
1557 book->dirtyFlag = TRUE;
1562 * Add attribute data for person to address book.
1563 * Enter: book Address book.
1564 * person New person object.
1565 * listAttrib New list of attributes.
1566 * Note: Only attributes are inserted into address book.
1568 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1571 g_return_if_fail( book != NULL );
1572 g_return_if_fail( person != NULL );
1576 UserAttribute *attrib = node->data;
1577 if( attrib->uid == NULL ) {
1578 addrcache_id_attribute( book->addressCache, attrib );
1580 addritem_person_add_attribute( person, attrib );
1581 node = g_list_next( node );
1583 book->dirtyFlag = TRUE;
1587 * Return address book file for specified object.
1588 * Enter: aio Book item object.
1589 * Return: Address book, or NULL if not found.
1591 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1592 AddressBookFile *book = NULL;
1595 ItemFolder *parent = NULL;
1596 ItemFolder *root = NULL;
1597 if( aio->type == ITEMTYPE_EMAIL ) {
1598 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1600 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1604 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1607 root = addrcache_find_root_folder( parent );
1610 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1617 * Remove folder from address book. Children are re-parented to parent folder.
1618 * param: folder Folder to remove.
1619 * return: Folder, or NULL if not found. Note that object should still be freed.
1621 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1624 g_return_val_if_fail( book != NULL, NULL );
1626 f = addrcache_remove_folder( book->addressCache, folder );
1627 if( f ) book->dirtyFlag = TRUE;
1632 * Remove folder from address book. Children are deleted.
1633 * param: folder Folder to remove.
1634 * return: Folder, or NULL if not found. Note that object should still be freed.
1636 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1639 g_return_val_if_fail( book != NULL, NULL );
1641 f = addrcache_remove_folder_delete( book->addressCache, folder );
1642 if( f ) book->dirtyFlag = TRUE;
1646 #define WORK_BUFLEN 1024
1647 #define ADDRBOOK_DIGITS "0123456789"
1650 * Return list of existing address book files.
1651 * Enter: book Address book file.
1652 * Return: File list.
1654 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1657 struct dirent *entry;
1658 struct stat statbuf;
1659 gchar buf[ WORK_BUFLEN ];
1660 gchar numbuf[ WORK_BUFLEN ];
1661 gint len, lenpre, lensuf, lennum;
1662 long int val, maxval;
1663 GList *fileList = NULL;
1665 g_return_val_if_fail( book != NULL, NULL );
1667 if( book->path == NULL || *book->path == '\0' ) {
1668 book->retVal = MGU_NO_PATH;
1672 strcpy( buf, book->path );
1673 len = strlen( buf );
1675 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1676 buf[ len ] = G_DIR_SEPARATOR;
1677 buf[ ++len ] = '\0';
1681 adbookdir = g_strdup( buf );
1682 strcat( buf, ADDRBOOK_PREFIX );
1684 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1685 book->retVal = MGU_OPEN_DIRECTORY;
1686 g_free( adbookdir );
1690 lenpre = strlen( ADDRBOOK_PREFIX );
1691 lensuf = strlen( ADDRBOOK_SUFFIX );
1692 lennum = FILE_NUMDIGITS + lenpre;
1695 while( ( entry = readdir( dp ) ) != NULL ) {
1696 gchar *endptr = NULL;
1700 strcpy( buf, adbookdir );
1701 strcat( buf, entry->d_name );
1702 stat( buf, &statbuf );
1703 if( S_IFREG & statbuf.st_mode ) {
1704 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1705 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1706 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1707 numbuf[ FILE_NUMDIGITS ] = '\0';
1709 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1710 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1717 val = strtol( numbuf, &endptr, 10 );
1718 if( endptr && val > -1 ) {
1719 if( val > maxval ) maxval = val;
1720 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1728 g_free( adbookdir );
1730 book->maxValue = maxval;
1731 book->retVal = MGU_SUCCESS;
1736 * Return file name for specified file number.
1737 * Enter: fileNum File number.
1738 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1740 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1742 gchar buf[ WORK_BUFLEN ];
1747 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1748 if( fileNum > nmax ) return NULL;
1749 sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1750 sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1751 return g_strdup( buf );
1754 /* **********************************************************************
1755 * Address book test functions...
1756 * ***********************************************************************
1759 static void addrbook_show_attribs( GList *attr ) {
1761 gchar *name = ((XMLAttr *)attr->data)->name;
1762 gchar *value = ((XMLAttr *)attr->data)->value;
1763 printf( "\tn/v = %s : %s\n", name, value );
1764 attr = g_list_next( attr );
1766 printf( "\t---\n" );
1770 * Test email address list.
1772 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1777 prev_level = file->level;
1778 if( xml_parse_next_tag( file ) ) {
1779 longjmp( book->jumper, 1 );
1781 if (file->level < prev_level) return;
1782 attr = xml_get_current_tag_attr(file);
1783 /* addrbook_show_attribs( attr ); */
1784 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1785 addrbook_chkparse_addr_list( book, file );
1791 * Test user attributes for person.
1793 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1797 attr = xml_get_current_tag_attr(file);
1798 /* addrbook_show_attribs( attr ); */
1799 element = xml_get_element( file );
1800 /* printf( "\t\tattrib value : %s\n", element ); */
1804 * Test attribute list.
1806 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1810 prev_level = file->level;
1811 if( xml_parse_next_tag( file ) ) {
1812 longjmp( book->jumper, 1 );
1814 if (file->level < prev_level) return;
1815 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1816 addrbook_chkparse_attribute( book, file );
1817 addrbook_chkparse_attr_list( book, file );
1825 static void addrbook_chkparse_person( 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_ADDRESS_LIST ) ) {
1834 addrbook_chkparse_addr_list( book, file );
1836 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1837 longjmp( book->jumper, 1 );
1839 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1840 addrbook_chkparse_attr_list( book, file );
1845 * Test group member list.
1847 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1852 prev_level = file->level;
1853 if( xml_parse_next_tag( file ) ) {
1854 longjmp( book->jumper, 1 );
1856 if (file->level < prev_level) return;
1857 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1858 attr = xml_get_current_tag_attr(file);
1859 /* addrbook_show_attribs( attr ); */
1860 addrbook_chkparse_member_list( book, file );
1863 attr = xml_get_current_tag_attr( file );
1864 /* addrbook_show_attribs( attr ); */
1872 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1875 attr = xml_get_current_tag_attr(file);
1876 /* addrbook_show_attribs( attr ); */
1877 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1878 longjmp( book->jumper, 1 );
1880 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1881 addrbook_chkparse_member_list( book, file );
1886 * Test folder item list.
1888 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1893 prev_level = file->level;
1894 if( xml_parse_next_tag( file ) ) {
1895 longjmp( book->jumper, 1 );
1897 if (file->level < prev_level) return;
1898 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1899 attr = xml_get_current_tag_attr(file);
1900 /* addrbook_show_attribs( attr ); */
1901 addrbook_chkparse_folder_list( book, file );
1904 attr = xml_get_current_tag_attr( file );
1905 /* addrbook_show_attribs( attr ); */
1913 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1916 attr = xml_get_current_tag_attr(file);
1917 /* addrbook_show_attribs( attr ); */
1918 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1919 longjmp( book->jumper, 1 );
1921 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1922 addrbook_chkparse_folder_list( book, file );
1927 * Test address book.
1929 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1933 if( xml_get_dtd( file ) ) {
1936 if( xml_parse_next_tag( file ) ) {
1940 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1944 attr = xml_get_current_tag_attr(file);
1945 /* addrbook_show_attribs( attr ); */
1949 if (! file->level ) break;
1951 if( xml_parse_next_tag( file ) ) {
1952 longjmp( book->jumper, 1 );
1954 /* Get next tag (person, group or folder) */
1955 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1956 addrbook_chkparse_person( book, file );
1958 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1959 addrbook_chkparse_group( book, file );
1961 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1962 addrbook_chkparse_folder( book, file );
1969 * Test address book file by parsing contents.
1970 * Enter: book Address book file to check.
1971 * fileName File name to check.
1972 * Return: MGU_SUCCESS if file appears to be valid format.
1974 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1975 XMLFile *file = NULL;
1976 gchar *fileSpec = NULL;
1978 g_return_val_if_fail( book != NULL, -1 );
1980 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1981 book->retVal = MGU_OPEN_FILE;
1982 file = xml_open_file( fileSpec );
1985 book->retVal = MGU_BAD_FORMAT;
1986 if( setjmp( book->jumper ) ) {
1987 /* printf( "Caught Ya!!!\n" ); */
1988 xml_close_file( file );
1989 return book->retVal;
1991 if( addrbook_chkread_tree( book, file ) ) {
1992 book->retVal = MGU_SUCCESS;
1994 xml_close_file( file );
1996 return book->retVal;
2000 * Return link list of all persons in address book. Note that the list contains
2001 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
2002 * this will destroy the addressbook data!
2003 * Return: List of items, or NULL if none.
2005 GList *addrbook_get_all_persons( AddressBookFile *book ) {
2006 g_return_val_if_fail( book != NULL, NULL );
2007 return addrcache_get_all_persons( book->addressCache );
2011 * Add person and address data to address book.
2012 * Enter: book Address book.
2013 * folder Folder where to add person, or NULL for root folder.
2015 * address EMail address.
2017 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
2018 * this will destroy the address book data.
2020 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
2021 const gchar *address, const gchar *remarks )
2023 ItemPerson *person = NULL;
2025 g_return_val_if_fail( book != NULL, NULL );
2027 person = addrcache_add_contact( book->addressCache, folder, name, address, remarks );
2028 if( person ) book->dirtyFlag = TRUE;