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"
37 #include "adbookbase.h"
39 #ifndef DEV_STANDALONE
44 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
45 #define ADDRBOOK_PREFIX "addrbook-"
46 #define ADDRBOOK_SUFFIX ".xml"
47 #define FILE_NUMDIGITS 6
49 #define ID_TIME_OFFSET 998000000
51 * Create new address book.
53 AddressBookFile *addrbook_create_book() {
54 AddressBookFile *book;
56 book = g_new0( AddressBookFile, 1 );
57 book->type = ADBOOKTYPE_BOOK;
58 book->addressCache = addrcache_create();
59 book->accessFlag = FALSE;
60 book->retVal = MGU_SUCCESS;
62 book->fileName = NULL;
64 book->tempList = NULL;
65 book->tempHash = NULL;
66 book->readFlag = FALSE;
67 book->modifyFlag = TRUE;
72 * Specify name to be used.
74 void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
75 g_return_if_fail( book != NULL );
76 addrcache_set_name( book->addressCache, value );
78 gchar *addrbook_get_name( AddressBookFile *book ) {
79 g_return_val_if_fail( book != NULL, NULL );
80 return addrcache_get_name( book->addressCache );
82 void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
83 g_return_if_fail( book != NULL );
84 book->path = mgu_replace_string( book->path, value );
85 addrcache_set_dirty( book->addressCache, TRUE );
87 void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
88 g_return_if_fail( book != NULL );
89 book->fileName = mgu_replace_string( book->fileName, value );
90 addrcache_set_dirty( book->addressCache, TRUE );
92 void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
93 g_return_if_fail( book != NULL );
94 book->accessFlag = value;
96 gboolean addrbook_get_modified( AddressBookFile *book ) {
97 g_return_val_if_fail( book != NULL, FALSE );
98 return book->modifyFlag;
100 gboolean addrbook_get_accessed( AddressBookFile *book ) {
101 g_return_val_if_fail( book != NULL, FALSE );
102 return book->accessFlag;
104 gboolean addrbook_get_read_flag( AddressBookFile *book ) {
105 g_return_val_if_fail( book != NULL, FALSE );
106 return book->readFlag;
108 gint addrbook_get_status( AddressBookFile *book ) {
109 g_return_val_if_fail( book != NULL, -1 );
112 ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
113 g_return_val_if_fail( book != NULL, NULL );
114 return addrcache_get_root_folder( book->addressCache );
116 GList *addrbook_get_list_folder( AddressBookFile *book ) {
117 g_return_val_if_fail( book != NULL, NULL );
118 return addrcache_get_list_folder( book->addressCache );
120 GList *addrbook_get_list_person( AddressBookFile *book ) {
121 g_return_val_if_fail( book != NULL, NULL );
122 return addrcache_get_list_person( book->addressCache );
124 gboolean addrbook_get_dirty( AddressBookFile *book ) {
125 g_return_val_if_fail( book != NULL, FALSE );
126 return addrcache_get_dirty( book->addressCache );
128 void addrbook_set_dirty( AddressBookFile *book, const gboolean value ) {
129 g_return_if_fail( book != NULL );
130 addrcache_set_dirty( book->addressCache, value );
134 * Empty address book.
136 void addrbook_empty_book( AddressBookFile *book ) {
137 g_return_if_fail( book != NULL );
139 /* Free up internal objects */
140 addrcache_clear( book->addressCache );
141 addrcache_set_dirty( book->addressCache, FALSE );
142 g_list_free( book->tempList );
144 /* Reset to initial state */
145 book->tempList = NULL;
146 book->tempHash = NULL;
147 book->readFlag = FALSE;
148 book->modifyFlag = FALSE;
149 book->accessFlag = FALSE;
150 book->retVal = MGU_SUCCESS;
156 void addrbook_free_book( AddressBookFile *book ) {
157 g_return_if_fail( book != NULL );
160 addrcache_clear( book->addressCache );
161 addrcache_free( book->addressCache );
162 addrcache_set_dirty( book->addressCache, FALSE );
164 /* Free up internal objects */
165 g_free( book->path );
166 g_free( book->fileName );
167 g_list_free( book->tempList );
170 book->fileName = NULL;
172 book->tempList = NULL;
173 book->tempHash = NULL;
174 book->readFlag = FALSE;
175 book->modifyFlag = FALSE;
177 book->type = ADBOOKTYPE_NONE;
178 book->addressCache = NULL;
179 book->accessFlag = FALSE;
180 book->retVal = MGU_SUCCESS;
186 * Print list of items.
188 void addrbook_print_item_list( GList *list, FILE *stream ) {
192 AddrItemObject *obj = node->data;
193 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
194 addritem_print_item_person( ( ItemPerson * ) obj, stream );
196 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
197 addritem_print_item_group( ( ItemGroup * ) obj, stream );
199 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
200 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
202 node = g_list_next( node );
204 fprintf( stream, "\t---\n" );
208 * Print address book.
210 void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
211 g_return_if_fail( book != NULL );
213 fprintf( stream, "AddressBook:\n" );
214 fprintf( stream, "\tpath : '%s'\n", book->path );
215 fprintf( stream, "\tfile : '%s'\n", book->fileName );
216 fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
217 addrcache_print( book->addressCache, stream );
221 * Dump entire address book traversing folders.
223 void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
226 g_return_if_fail( book != NULL );
228 addrbook_print_book( book, stream );
229 folder = book->addressCache->rootFolder;
230 addritem_print_item_folder( folder, stream );
234 * Remove group from address book.
235 * param: group Group to remove.
236 * return: Group, or NULL if not found. Note that object should still be freed.
238 ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
239 g_return_val_if_fail( book != NULL, NULL );
240 return addrcache_remove_group( book->addressCache, group );
244 * Remove specified person from address book.
245 * param: person Person to remove.
246 * return: Person, or NULL if not found. Note that object should still be freed.
248 ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
249 g_return_val_if_fail( book != NULL, NULL );
250 return addrcache_remove_person( book->addressCache, person );
254 * Remove email address in address book for specified person.
255 * param: person Person.
256 * email EMail to remove.
257 * return: EMail object, or NULL if not found. Note that object should still be freed.
259 ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
260 g_return_val_if_fail( book != NULL, NULL );
261 return addrcache_person_remove_email( book->addressCache, person, email );
264 /* **********************************************************************
265 * Read/Write XML data file...
266 * ===========================
268 * 1) The address book is structured as follows:
283 * 2) This sequence of elements was chosen so that the most important
284 * elements (person and their email addresses) appear first.
286 * 3) Groups then appear. When groups are loaded, person's email
287 * addresses have already been loaded and can be found.
289 * 4) Finally folders are loaded. Any forward and backward references
290 * to folders, groups and persons in the folders are resolved after
293 * ***********************************************************************
296 /* Element tag names */
297 #define AB_ELTAG_ADDRESS "address"
298 #define AB_ELTAG_ATTRIBUTE "attribute"
299 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
300 #define AB_ELTAG_ADDRESS_LIST "address-list"
301 #define AB_ELTAG_MEMBER "member"
302 #define AB_ELTAG_MEMBER_LIST "member-list"
303 #define AB_ELTAG_ITEM "item"
304 #define AB_ELTAG_ITEM_LIST "item-list"
305 #define AB_ELTAG_ADDRESS_BOOK "address-book"
306 #define AB_ELTAG_PERSON "person"
307 #define AB_ELTAG_GROUP "group"
308 #define AB_ELTAG_FOLDER "folder"
310 /* Attribute tag names */
311 #define AB_ATTAG_TYPE "type"
312 #define AB_ATTAG_UID "uid"
313 #define AB_ATTAG_NAME "name"
314 #define AB_ATTAG_REMARKS "remarks"
315 #define AB_ATTAG_FIRST_NAME "first-name"
316 #define AB_ATTAG_LAST_NAME "last-name"
317 #define AB_ATTAG_NICK_NAME "nick-name"
318 #define AB_ATTAG_COMMON_NAME "cn"
319 #define AB_ATTAG_ALIAS "alias"
320 #define AB_ATTAG_EMAIL "email"
321 #define AB_ATTAG_EID "eid"
322 #define AB_ATTAG_PID "pid"
324 /* Attribute values */
325 #define AB_ATTAG_VAL_PERSON "person"
326 #define AB_ATTAG_VAL_GROUP "group"
327 #define AB_ATTAG_VAL_FOLDER "folder"
330 * Parse address item for person.
332 static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
335 ItemEMail *email = NULL;
337 attr = xml_get_current_tag_attr(file);
339 name = ((XMLAttr *)attr->data)->name;
340 value = ((XMLAttr *)attr->data)->value;
341 if( ! email ) email = addritem_create_item_email();
342 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
343 ADDRITEM_ID(email) = g_strdup( value );
345 else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
346 ADDRITEM_NAME(email) = g_strdup( value );
348 else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
349 email->address = g_strdup( value );
351 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
352 email->remarks = g_strdup( value );
354 attr = g_list_next( attr );
358 addrcache_person_add_email( book->addressCache, person, email );
361 addritem_free_item_email( email );
368 * Parse email address list.
370 static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
375 prev_level = file->level;
376 if( xml_parse_next_tag( file ) ) {
377 longjmp( book->jumper, 1 );
379 if (file->level < prev_level) return;
380 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
381 attr = xml_get_current_tag_attr(file);
382 addrbook_parse_address( book, file, person );
383 addrbook_parse_addr_list( book, file, person );
389 * Parse attibute for person.
391 static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
395 UserAttribute *uAttr = NULL;
397 attr = xml_get_current_tag_attr(file);
399 name = ((XMLAttr *)attr->data)->name;
400 value = ((XMLAttr *)attr->data)->value;
401 if( ! uAttr ) uAttr = addritem_create_attribute();
402 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
403 addritem_attrib_set_id( uAttr, value );
405 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
406 addritem_attrib_set_name( uAttr, value );
408 attr = g_list_next( attr );
411 element = xml_get_element( file );
412 addritem_attrib_set_value( uAttr, element );
416 addritem_person_add_attribute( person, uAttr );
419 addritem_free_attribute( uAttr );
426 * Parse attribute list.
428 static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
433 prev_level = file->level;
434 if( xml_parse_next_tag( file ) ) {
435 longjmp( book->jumper, 1 );
437 if (file->level < prev_level) return;
438 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
439 attr = xml_get_current_tag_attr(file);
440 addrbook_parse_attribute( file, person );
441 addrbook_parse_attr_list( book, file, person );
449 static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
452 ItemPerson *person = NULL;
454 attr = xml_get_current_tag_attr(file);
456 name = ((XMLAttr *)attr->data)->name;
457 value = ((XMLAttr *)attr->data)->value;
458 if( ! person ) person = addritem_create_item_person();
459 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
460 ADDRITEM_ID(person) = g_strdup( value );
462 else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
463 person->firstName = g_strdup( value );
465 else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
466 person->lastName = g_strdup( value );
468 else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
469 person->nickName = g_strdup( value );
471 else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
472 ADDRITEM_NAME(person) = g_strdup( value );
474 attr = g_list_next( attr );
476 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
477 longjmp( book->jumper, 1 );
479 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
480 addrbook_parse_addr_list( book, file, person );
482 addrcache_hash_add_person( book->addressCache, person );
485 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
486 longjmp( book->jumper, 1 );
488 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
489 addrbook_parse_attr_list( book, file, person );
494 * Parse group member.
496 static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
499 gchar *pid = NULL, *eid = NULL;
500 ItemEMail *email = NULL;
502 attr = xml_get_current_tag_attr(file);
504 name = ((XMLAttr *)attr->data)->name;
505 value = ((XMLAttr *)attr->data)->value;
506 if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
507 pid = g_strdup( value );
509 else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
510 eid = g_strdup( value );
512 attr = g_list_next( attr );
514 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
515 email = addrcache_get_email( book->addressCache, eid );
518 addrcache_group_add_email( book->addressCache, group, email );
521 addritem_free_item_email( email );
528 * Parse group member list.
530 static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
535 prev_level = file->level;
536 if( xml_parse_next_tag( file ) ) {
537 longjmp( book->jumper, 1 );
539 if (file->level < prev_level) return;
540 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
541 attr = xml_get_current_tag_attr(file);
542 addrbook_parse_member( book, file, group );
543 addrbook_parse_member_list( book, file, group );
546 attr = xml_get_current_tag_attr( file );
554 static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
557 ItemGroup *group = NULL;
559 attr = xml_get_current_tag_attr(file);
561 name = ((XMLAttr *)attr->data)->name;
562 value = ((XMLAttr *)attr->data)->value;
563 if( ! group ) group = addritem_create_item_group();
564 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
565 ADDRITEM_ID(group) = g_strdup( value );
567 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
568 ADDRITEM_NAME(group) = g_strdup( value );
570 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
571 group->remarks = g_strdup( value );
573 attr = g_list_next( attr );
575 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
576 longjmp( book->jumper, 1 );
578 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
580 addrcache_hash_add_group( book->addressCache, group );
582 addrbook_parse_member_list( book, file, group );
589 static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
594 attr = xml_get_current_tag_attr(file);
596 name = ((XMLAttr *)attr->data)->name;
597 value = ((XMLAttr *)attr->data)->value;
598 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
599 uid = g_strdup( value );
601 attr = g_list_next( attr );
605 folder->listItems = g_list_append( folder->listItems, uid );
611 * Parse folder item list.
613 static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
618 prev_level = file->level;
619 if( xml_parse_next_tag( file ) ) {
620 longjmp( book->jumper, 1 );
622 if (file->level < prev_level) return;
623 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
624 attr = xml_get_current_tag_attr(file);
625 addrbook_parse_folder_item( book, file, folder );
626 addrbook_parse_folder_list( book, file, folder );
629 attr = xml_get_current_tag_attr( file );
637 static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
640 ItemFolder *folder = NULL;
642 attr = xml_get_current_tag_attr(file);
644 name = ((XMLAttr *)attr->data)->name;
645 value = ((XMLAttr *)attr->data)->value;
647 folder = addritem_create_item_folder();
649 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
650 ADDRITEM_ID(folder) = g_strdup( value );
652 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
653 ADDRITEM_NAME(folder) = g_strdup( value );
655 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
656 folder->remarks = g_strdup( value );
658 attr = g_list_next( attr );
660 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
661 longjmp( book->jumper, 1 );
663 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
665 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
666 book->tempList = g_list_append( book->tempList, folder );
667 ADDRITEM_PARENT(folder) = NULL; /* We will resolve folder later */
670 addrbook_parse_folder_list( book, file, folder );
675 * Parse address book.
676 * Return: TRUE if data read successfully, FALSE if error reading data.
678 static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
683 book->retVal = MGU_BAD_FORMAT;
684 if( xml_get_dtd( file ) ) {
687 if( xml_parse_next_tag( file ) ) {
688 longjmp( book->jumper, 1 );
690 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
694 attr = xml_get_current_tag_attr(file);
696 name = ((XMLAttr *)attr->data)->name;
697 value = ((XMLAttr *)attr->data)->value;
698 if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
699 addrbook_set_name( book, value );
701 attr = g_list_next( attr );
706 if (! file->level ) break;
707 /* Get next item tag (person, group or folder) */
708 if( xml_parse_next_tag( file ) ) {
709 longjmp( book->jumper, 1 );
711 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
712 addrbook_parse_person( book, file );
714 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
715 addrbook_parse_group( book, file );
717 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
718 addrbook_parse_folder( book, file );
721 if( retVal ) book->retVal = MGU_SUCCESS;
726 * Resolve folder items visitor function.
728 static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
729 AddressBookFile *book = data;
730 AddrItemObject *obj = ( AddrItemObject * ) value;
731 ItemFolder *rootFolder = book->addressCache->rootFolder;
732 if( obj->parent == NULL ) {
733 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
734 rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
735 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
737 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
738 rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
739 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
745 * Resolve folder items. Lists of UID's are replaced with pointers to data items.
747 static void addrbook_resolve_folder_items( AddressBookFile *book ) {
748 GList *nodeFolder = NULL;
749 GList *listRemove = NULL;
751 ItemFolder *rootFolder = book->addressCache->rootFolder;
752 nodeFolder = book->tempList;
753 while( nodeFolder ) {
754 ItemFolder *folder = nodeFolder->data;
756 node = folder->listItems;
758 gchar *uid = node->data;
759 AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
761 if( aio->type == ITEMTYPE_FOLDER ) {
762 ItemFolder *item = ( ItemFolder * ) aio;
763 folder->listFolder = g_list_append( folder->listFolder, item );
764 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
765 addrcache_hash_add_folder( book->addressCache, folder );
767 else if( aio->type == ITEMTYPE_PERSON ) {
768 ItemPerson *item = ( ItemPerson * ) aio;
769 folder->listPerson = g_list_append( folder->listPerson, item );
770 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
772 else if( aio->type == ITEMTYPE_GROUP ) {
773 ItemGroup *item = ( ItemGroup * ) aio;
774 folder->listGroup = g_list_append( folder->listGroup, item );
775 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
777 /* Replace data with pointer to item */
782 /* Not found, append to remove list. */
783 listRemove = g_list_append( listRemove, uid );
785 node = g_list_next( node );
787 rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
789 /* Process remove list */
792 gchar *uid = node->data;
793 folder->listItems = g_list_remove( folder->listItems, uid );
795 node = g_list_next( node );
797 g_list_free( listRemove );
798 nodeFolder = g_list_next( nodeFolder );
801 /* Remove folders with parents. */
803 node = rootFolder->listFolder;
805 ItemFolder *folder = ( ItemFolder * ) node->data;
806 if( ADDRITEM_PARENT(folder) ) {
807 /* Remove folders with parents */
808 listRemove = g_list_append( listRemove, folder );
811 /* Add to root folder */
812 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
814 node = g_list_next( node );
817 /* Process remove list */
820 rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
821 node = g_list_next( node );
823 g_list_free( listRemove );
825 /* Move all unparented persons and groups into root folder */
826 g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
828 /* Free up some more */
829 nodeFolder = book->tempList;
830 while( nodeFolder ) {
831 ItemFolder *folder = nodeFolder->data;
832 g_list_free( folder->listItems );
833 folder->listItems = NULL;
834 nodeFolder = g_list_next( nodeFolder );
836 g_list_free( book->tempList );
837 book->tempList = NULL;
842 * Read address book file.
844 gint addrbook_read_data( AddressBookFile *book ) {
845 XMLFile *file = NULL;
846 gchar *fileSpec = NULL;
848 g_return_val_if_fail( book != NULL, -1 );
850 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
851 book->retVal = MGU_OPEN_FILE;
852 book->accessFlag = FALSE;
853 book->modifyFlag = FALSE;
854 file = xml_open_file( fileSpec );
857 book->tempList = NULL;
859 /* Trap for parsing errors. */
860 if( setjmp( book->jumper ) ) {
861 xml_close_file( file );
864 addrbook_read_tree( book, file );
865 xml_close_file( file );
867 /* Resolve folder items */
868 addrbook_resolve_folder_items( book );
869 book->tempList = NULL;
870 book->readFlag = TRUE;
871 addrcache_set_dirty( book->addressCache, FALSE );
876 static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
878 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
883 static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
885 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
891 static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
895 xml_file_put_escape_str( fp, value );
900 * Write file hash table visitor function.
902 static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
903 AddrItemObject *obj = ( AddrItemObject * ) value;
904 FILE *fp = ( FILE * ) data;
908 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
909 ItemPerson *person = ( ItemPerson * ) value;
911 addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
912 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
913 addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
914 addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
915 addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
916 addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
919 /* Output email addresses */
920 addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
922 node = person->listEMail;
924 ItemEMail *email = node->data;
925 addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
926 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
927 addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
928 addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
929 addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
931 node = g_list_next( node );
933 addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
935 /* Output user attributes */
936 addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
938 node = person->listAttrib;
940 UserAttribute *attrib = node->data;
941 addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
942 addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
943 addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
945 xml_file_put_escape_str( fp, attrib->value );
946 addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
947 node = g_list_next( node );
949 addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
950 addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
956 * Write file hash table visitor function.
958 static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
959 AddrItemObject *obj = ( AddrItemObject * ) value;
960 FILE *fp = ( FILE * ) data;
964 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
965 ItemGroup *group = ( ItemGroup * ) value;
967 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
968 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
969 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
970 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
973 /* Output email address links */
974 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
976 node = group->listEMail;
978 ItemEMail *email = node->data;
979 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
980 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
981 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
982 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
983 fputs( " />\n", fp );
984 node = g_list_next( node );
986 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
987 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
993 * Write file hash table visitor function.
995 static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
996 AddrItemObject *obj = ( AddrItemObject * ) value;
997 FILE *fp = ( FILE * ) data;
1001 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1002 ItemFolder *folder = ( ItemFolder * ) value;
1004 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1005 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1006 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1007 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1008 fputs( " >\n", fp );
1009 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1012 /* Output persons */
1013 node = folder->listPerson;
1015 ItemPerson *item = node->data;
1016 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1017 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1018 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1019 fputs( " />\n", fp );
1020 node = g_list_next( node );
1024 node = folder->listGroup;
1026 ItemGroup *item = node->data;
1027 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1028 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1029 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1030 fputs( " />\n", fp );
1031 node = g_list_next( node );
1034 /* Output folders */
1035 node = folder->listFolder;
1037 ItemFolder *item = node->data;
1038 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1039 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1040 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1041 fputs( " />\n", fp );
1042 node = g_list_next( node );
1044 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1045 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1051 * Output address book data to specified file.
1052 * return: Status code.
1054 gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1057 #ifndef DEV_STANDALONE
1061 g_return_val_if_fail( book != NULL, -1 );
1062 g_return_val_if_fail( newFile != NULL, -1 );
1064 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1066 book->retVal = MGU_OPEN_FILE;
1067 #ifdef DEV_STANDALONE
1068 fp = fopen( fileSpec, "w" );
1071 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1073 pfile = prefs_write_open( fileSpec );
1077 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1078 conv_get_current_charset_str() );
1080 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1081 addrbook_write_attr( fp, AB_ATTAG_NAME, addrcache_get_name( book->addressCache ) );
1082 fputs( " >\n", fp );
1084 /* Output all persons */
1085 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1087 /* Output all groups */
1088 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1090 /* Output all folders */
1091 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1093 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1094 book->retVal = MGU_SUCCESS;
1095 #ifdef DEV_STANDALONE
1098 if( prefs_write_close( pfile ) < 0 ) {
1099 book->retVal = MGU_ERROR_WRITE;
1105 return book->retVal;
1109 * Output address book data to original file.
1110 * return: Status code.
1112 gint addrbook_save_data( AddressBookFile *book ) {
1113 g_return_val_if_fail( book != NULL, -1 );
1115 book->retVal = MGU_NO_FILE;
1116 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1117 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1119 addrbook_write_to( book, book->fileName );
1120 if( book->retVal == MGU_SUCCESS ) {
1121 addrcache_set_dirty( book->addressCache, FALSE );
1123 return book->retVal;
1126 /* **********************************************************************
1127 * Address book edit interface functions...
1128 * ***********************************************************************
1132 * Move person's email item.
1133 * param: book Address book.
1135 * itemMove Item to move.
1136 * itemTarget Target item before which to move item.
1138 ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1139 ItemEMail *itemMove, ItemEMail *itemTarget )
1141 ItemEMail *email = NULL;
1143 g_return_val_if_fail( book != NULL, NULL );
1145 email = addritem_move_email_before( person, itemMove, itemTarget );
1147 addrcache_set_dirty( book->addressCache, TRUE );
1153 * Move person's email item.
1154 * param: book Address book.
1156 * itemMove Item to move.
1157 * itemTarget Target item after which to move item.
1159 ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1160 ItemEMail *itemMove, ItemEMail *itemTarget )
1162 ItemEMail *email = NULL;
1164 g_return_val_if_fail( book != NULL, NULL );
1166 email = addritem_move_email_after( person, itemMove, itemTarget );
1168 addrcache_set_dirty( book->addressCache, TRUE );
1174 * Hash table visitor function.
1176 static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1184 * Update address book email list for specified person.
1185 * Enter: book Address book.
1186 * person Person to update.
1187 * listEMail New list of email addresses.
1188 * Note: The existing email addresses are replaced with the new addresses. Any references
1189 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1190 * linked to the person are removed.
1192 void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1197 g_return_if_fail( book != NULL );
1198 g_return_if_fail( person != NULL );
1200 /* Remember old list */
1201 oldData = person->listEMail;
1203 /* Attach new address list to person. */
1206 ItemEMail *email = node->data;
1207 if( ADDRITEM_ID(email) == NULL ) {
1208 /* Allocate an ID */
1209 addrcache_id_email( book->addressCache, email );
1211 ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1212 node = g_list_next( node );
1214 person->listEMail = listEMail;
1216 /* Get groups where person's email is listed */
1217 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1219 GHashTable *hashEMail;
1222 /* Load hash table with new address entries */
1223 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1226 ItemEMail *email = node->data;
1227 gchar *addr = g_strdup( email->address );
1229 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1230 g_hash_table_insert( hashEMail, addr, email );
1232 node = g_list_next( node );
1235 /* Re-parent new addresses to existing groups, where email address match. */
1236 nodeGrp = listGroup;
1238 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1239 GList *groupEMail = group->listEMail;
1241 GList *listRemove = NULL;
1243 /* Process each email item linked to group */
1244 nodeGrpEM = groupEMail;
1245 while( nodeGrpEM ) {
1246 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1247 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1248 /* Found an email address for this person */
1249 ItemEMail *emailNew = NULL;
1250 gchar *addr = g_strdup( emailGrp->address );
1252 emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1255 /* Point to this entry */
1256 nodeGrpEM->data = emailNew;
1259 /* Mark for removal */
1260 listRemove = g_list_append( listRemove, emailGrp );
1263 /* Move on to next email link */
1264 nodeGrpEM = g_list_next( nodeGrpEM );
1267 /* Process all removed links in current group */
1268 nodeGrpEM = listRemove;
1269 while( nodeGrpEM ) {
1270 ItemEMail *emailGrp = nodeGrpEM->data;
1271 groupEMail = g_list_remove( groupEMail, emailGrp );
1272 nodeGrpEM = g_list_next( nodeGrpEM );
1275 /* Move on to next group */
1276 nodeGrp = g_list_next( nodeGrp );
1280 /* Clear hash table */
1281 g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1282 g_hash_table_destroy( hashEMail );
1284 g_list_free( listGroup );
1287 addrcache_set_dirty( book->addressCache, TRUE );
1289 /* Free up old data */
1290 addritem_free_list_email( oldData );
1296 * Add person and address data to address book.
1297 * Enter: book Address book.
1298 * folder Folder where to add person, or NULL for root folder.
1299 * listEMail New list of email addresses.
1300 * Return: Person added.
1301 * Note: A new person is created with specified list of email addresses. All objects inserted
1302 * into address book.
1304 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1306 ItemFolder *f = folder;
1309 g_return_val_if_fail( book != NULL, NULL );
1311 if( ! f ) f = book->addressCache->rootFolder;
1312 person = addritem_create_item_person();
1313 addrcache_id_person( book->addressCache, person );
1314 addrcache_folder_add_person( book->addressCache, f, person );
1318 ItemEMail *email = node->data;
1319 if( ADDRITEM_ID(email) == NULL ) {
1320 addrcache_id_email( book->addressCache, email );
1322 addrcache_person_add_email( book->addressCache, person, email );
1323 node = g_list_next( node );
1329 * Load hash table visitor function.
1331 static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1332 AddrItemObject *obj = ( AddrItemObject * ) value;
1334 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1335 GHashTable *table = ( GHashTable * ) data;
1336 gchar *newKey = g_strdup( key );
1337 ItemEMail *email = ( ItemEMail * ) obj;
1338 if( ! g_hash_table_lookup( table, newKey ) ) {
1339 g_hash_table_insert( table, newKey, email );
1345 * Load hash table with links to email addresses.
1347 static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
1348 g_return_if_fail( book != NULL );
1349 g_return_if_fail( table != NULL );
1350 g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
1354 * Build available email list visitor function.
1356 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1357 AddrItemObject *obj = ( AddrItemObject * ) value;
1359 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1360 AddressBookFile *book = data;
1361 ItemPerson *person = ( ItemPerson * ) obj;
1362 GList *node = person->listEMail;
1364 ItemEMail *email = node->data;
1365 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1367 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1368 book->tempList = g_list_append( book->tempList, email );
1370 node = g_list_next( node );
1376 * Return link list of available email items (which have not already been linked to
1377 * groups). Note that the list contains references to items and should be g_free()
1378 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1379 * destroy the addressbook data!
1380 * Return: List of items, or NULL if none.
1382 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1386 g_return_val_if_fail( book != NULL, NULL );
1388 /* Load hash table with group email entries */
1389 table = g_hash_table_new( g_str_hash, g_str_equal );
1391 list = group->listEMail;
1393 ItemEMail *email = list->data;
1394 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1395 list = g_list_next( list );
1399 /* Build list of available email addresses which exclude those already in groups */
1400 book->tempList = NULL;
1401 book->tempHash = table;
1402 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1403 list = book->tempList;
1404 book->tempList = NULL;
1405 book->tempHash = NULL;
1407 /* Clear hash table */
1408 g_hash_table_destroy( table );
1415 * Update address book email list for specified group.
1416 * Enter: book Address book.
1417 * group group to update.
1418 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1419 * Note: The existing email addresses are replaced with the new addresses. Any references
1420 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1421 * linked to the person are removed.
1423 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1426 g_return_if_fail( book != NULL );
1427 g_return_if_fail( group != NULL );
1429 addrcache_set_dirty( book->addressCache, TRUE );
1431 /* Remember old list */
1432 oldData = group->listEMail;
1433 group->listEMail = listEMail;
1434 mgu_clear_list( oldData );
1439 * Add group and email list to address book.
1440 * Enter: book Address book.
1441 * folder Parent folder, or NULL for root folder.
1442 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1443 * Return: Group object.
1444 * Note: The existing email addresses are replaced with the new addresses. Any references
1445 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1446 * linked to the person are removed.
1448 ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1449 ItemGroup *group = NULL;
1450 ItemFolder *f = folder;
1452 g_return_val_if_fail( book != NULL, NULL );
1454 if( ! f ) f = book->addressCache->rootFolder;
1455 group = addritem_create_item_group();
1456 addrcache_id_group( book->addressCache, group );
1457 addrcache_folder_add_group( book->addressCache, f, group );
1458 group->listEMail = listEMail;
1463 * Add new folder to address book.
1464 * Enter: book Address book.
1465 * parent Parent folder.
1466 * Return: Folder that was added. This should *NOT* be g_free() when done.
1468 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1469 ItemFolder *folder = NULL;
1470 ItemFolder *p = parent;
1472 g_return_val_if_fail( book != NULL, NULL );
1474 if( ! p ) p = book->addressCache->rootFolder;
1475 folder = addritem_create_item_folder();
1476 addrcache_id_folder( book->addressCache, folder );
1477 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1478 p->listFolder = g_list_append( p->listFolder, folder );
1479 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1480 addrcache_set_dirty( book->addressCache, TRUE );
1483 addritem_free_item_folder( folder );
1490 * Update address book attribute list for specified person.
1491 * Enter: book Address book.
1492 * person Person to update.
1493 * listAttrib New list of attributes.
1494 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1495 * linked to the person are removed.
1497 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1501 g_return_if_fail( book != NULL );
1502 g_return_if_fail( person != NULL );
1504 /* Remember old list */
1505 oldData = person->listAttrib;
1507 /* Attach new address list to person. */
1510 UserAttribute *attrib = node->data;
1511 if( attrib->uid == NULL ) {
1512 /* Allocate an ID */
1513 addrcache_id_attribute( book->addressCache, attrib );
1515 node = g_list_next( node );
1517 person->listAttrib = listAttrib;
1518 addrcache_set_dirty( book->addressCache, TRUE );
1520 /* Free up old data */
1521 addritem_free_list_attribute( oldData );
1527 * Add attribute data for person to address book.
1528 * Enter: book Address book.
1529 * person New person object.
1530 * listAttrib New list of attributes.
1531 * Note: Only attributes are inserted into address book.
1533 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1536 g_return_if_fail( book != NULL );
1537 g_return_if_fail( person != NULL );
1541 UserAttribute *attrib = node->data;
1542 if( attrib->uid == NULL ) {
1543 addrcache_id_attribute( book->addressCache, attrib );
1545 addritem_person_add_attribute( person, attrib );
1546 node = g_list_next( node );
1548 addrcache_set_dirty( book->addressCache, TRUE );
1552 * Return address book file for specified object.
1553 * Enter: aio Book item object.
1554 * Return: Address book, or NULL if not found.
1556 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1557 AddressBookFile *book = NULL;
1560 ItemFolder *parent = NULL;
1561 ItemFolder *root = NULL;
1562 if( aio->type == ITEMTYPE_EMAIL ) {
1563 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1565 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1569 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1572 root = addrcache_find_root_folder( parent );
1575 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1582 * Remove folder from address book. Children are re-parented to parent folder.
1583 * param: folder Folder to remove.
1584 * return: Folder, or NULL if not found. Note that object should still be freed.
1586 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1589 g_return_val_if_fail( book != NULL, NULL );
1591 f = addrcache_remove_folder( book->addressCache, folder );
1596 * Remove folder from address book. Children are deleted.
1597 * param: folder Folder to remove.
1598 * return: Folder, or NULL if not found. Note that object should still be freed.
1600 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1603 g_return_val_if_fail( book != NULL, NULL );
1605 f = addrcache_remove_folder_delete( book->addressCache, folder );
1609 #define WORK_BUFLEN 1024
1610 #define ADDRBOOK_DIGITS "0123456789"
1613 * Return list of existing address book files.
1614 * Enter: book Address book file.
1615 * Return: File list.
1617 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1620 struct dirent *entry;
1621 struct stat statbuf;
1622 gchar buf[ WORK_BUFLEN ];
1623 gchar numbuf[ WORK_BUFLEN ];
1624 gint len, lenpre, lensuf, lennum;
1625 long int val, maxval;
1626 GList *fileList = NULL;
1628 g_return_val_if_fail( book != NULL, NULL );
1630 if( book->path == NULL || *book->path == '\0' ) {
1631 book->retVal = MGU_NO_PATH;
1635 strcpy( buf, book->path );
1636 len = strlen( buf );
1638 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1639 buf[ len ] = G_DIR_SEPARATOR;
1640 buf[ ++len ] = '\0';
1644 adbookdir = g_strdup( buf );
1645 strcat( buf, ADDRBOOK_PREFIX );
1647 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1648 book->retVal = MGU_OPEN_DIRECTORY;
1649 g_free( adbookdir );
1653 lenpre = strlen( ADDRBOOK_PREFIX );
1654 lensuf = strlen( ADDRBOOK_SUFFIX );
1655 lennum = FILE_NUMDIGITS + lenpre;
1658 while( ( entry = readdir( dp ) ) != NULL ) {
1659 gchar *endptr = NULL;
1663 strcpy( buf, adbookdir );
1664 strcat( buf, entry->d_name );
1665 stat( buf, &statbuf );
1666 if( S_IFREG & statbuf.st_mode ) {
1667 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1668 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1669 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1670 numbuf[ FILE_NUMDIGITS ] = '\0';
1672 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1673 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1680 val = strtol( numbuf, &endptr, 10 );
1681 if( endptr && val > -1 ) {
1682 if( val > maxval ) maxval = val;
1683 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1691 g_free( adbookdir );
1693 book->maxValue = maxval;
1694 book->retVal = MGU_SUCCESS;
1699 * Return file name for specified file number.
1700 * Enter: fileNum File number.
1701 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1703 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1705 gchar buf[ WORK_BUFLEN ];
1710 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1711 if( fileNum > nmax ) return NULL;
1712 sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1713 sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1714 return g_strdup( buf );
1717 /* **********************************************************************
1718 * Address book test functions...
1719 * ***********************************************************************
1722 static void addrbook_show_attribs( GList *attr ) {
1724 gchar *name = ((XMLAttr *)attr->data)->name;
1725 gchar *value = ((XMLAttr *)attr->data)->value;
1726 printf( "\tn/v = %s : %s\n", name, value );
1727 attr = g_list_next( attr );
1729 printf( "\t---\n" );
1733 * Test email address list.
1735 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1740 prev_level = file->level;
1741 if( xml_parse_next_tag( file ) ) {
1742 longjmp( book->jumper, 1 );
1744 if (file->level < prev_level) return;
1745 attr = xml_get_current_tag_attr(file);
1746 /* addrbook_show_attribs( attr ); */
1747 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1748 addrbook_chkparse_addr_list( book, file );
1754 * Test user attributes for person.
1756 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1760 attr = xml_get_current_tag_attr(file);
1761 /* addrbook_show_attribs( attr ); */
1762 element = xml_get_element( file );
1763 /* printf( "\t\tattrib value : %s\n", element ); */
1767 * Test attribute list.
1769 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1773 prev_level = file->level;
1774 if( xml_parse_next_tag( file ) ) {
1775 longjmp( book->jumper, 1 );
1777 if (file->level < prev_level) return;
1778 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1779 addrbook_chkparse_attribute( book, file );
1780 addrbook_chkparse_attr_list( book, file );
1788 static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1791 attr = xml_get_current_tag_attr(file);
1792 /* addrbook_show_attribs( attr ); */
1793 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1794 longjmp( book->jumper, 1 );
1796 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1797 addrbook_chkparse_addr_list( book, file );
1799 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1800 longjmp( book->jumper, 1 );
1802 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1803 addrbook_chkparse_attr_list( book, file );
1808 * Test group member list.
1810 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1815 prev_level = file->level;
1816 if( xml_parse_next_tag( file ) ) {
1817 longjmp( book->jumper, 1 );
1819 if (file->level < prev_level) return;
1820 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1821 attr = xml_get_current_tag_attr(file);
1822 /* addrbook_show_attribs( attr ); */
1823 addrbook_chkparse_member_list( book, file );
1826 attr = xml_get_current_tag_attr( file );
1827 /* addrbook_show_attribs( attr ); */
1835 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1838 attr = xml_get_current_tag_attr(file);
1839 /* addrbook_show_attribs( attr ); */
1840 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1841 longjmp( book->jumper, 1 );
1843 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1844 addrbook_chkparse_member_list( book, file );
1849 * Test folder item list.
1851 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1856 prev_level = file->level;
1857 if( xml_parse_next_tag( file ) ) {
1858 longjmp( book->jumper, 1 );
1860 if (file->level < prev_level) return;
1861 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1862 attr = xml_get_current_tag_attr(file);
1863 /* addrbook_show_attribs( attr ); */
1864 addrbook_chkparse_folder_list( book, file );
1867 attr = xml_get_current_tag_attr( file );
1868 /* addrbook_show_attribs( attr ); */
1876 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1879 attr = xml_get_current_tag_attr(file);
1880 /* addrbook_show_attribs( attr ); */
1881 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1882 longjmp( book->jumper, 1 );
1884 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1885 addrbook_chkparse_folder_list( book, file );
1890 * Test address book.
1892 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1896 if( xml_get_dtd( file ) ) {
1899 if( xml_parse_next_tag( file ) ) {
1903 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1907 attr = xml_get_current_tag_attr(file);
1908 /* addrbook_show_attribs( attr ); */
1912 if (! file->level ) break;
1914 if( xml_parse_next_tag( file ) ) {
1915 longjmp( book->jumper, 1 );
1917 /* Get next tag (person, group or folder) */
1918 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1919 addrbook_chkparse_person( book, file );
1921 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1922 addrbook_chkparse_group( book, file );
1924 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1925 addrbook_chkparse_folder( book, file );
1932 * Test address book file by parsing contents.
1933 * Enter: book Address book file to check.
1934 * fileName File name to check.
1935 * Return: MGU_SUCCESS if file appears to be valid format.
1937 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1938 XMLFile *file = NULL;
1939 gchar *fileSpec = NULL;
1941 g_return_val_if_fail( book != NULL, -1 );
1943 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1944 book->retVal = MGU_OPEN_FILE;
1945 file = xml_open_file( fileSpec );
1948 book->retVal = MGU_BAD_FORMAT;
1949 if( setjmp( book->jumper ) ) {
1950 /* printf( "Caught Ya!!!\n" ); */
1951 xml_close_file( file );
1952 return book->retVal;
1954 if( addrbook_chkread_tree( book, file ) ) {
1955 book->retVal = MGU_SUCCESS;
1957 xml_close_file( file );
1959 return book->retVal;
1963 * Return link list of all persons in address book. Note that the list contains
1964 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1965 * this will destroy the addressbook data!
1966 * Return: List of items, or NULL if none.
1968 GList *addrbook_get_all_persons( AddressBookFile *book ) {
1969 g_return_val_if_fail( book != NULL, NULL );
1970 return addrcache_get_all_persons( book->addressCache );
1974 * Add person and address data to address book.
1975 * Enter: book Address book.
1976 * folder Folder where to add person, or NULL for root folder.
1978 * address EMail address.
1980 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1981 * this will destroy the address book data.
1983 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
1984 const gchar *address, const gchar *remarks )
1986 g_return_val_if_fail( book != NULL, NULL );
1987 return addrcache_add_contact( book->addressCache, folder, name, address, remarks );