2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Match Grun
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * General functions for accessing address book files.
35 #include "addrcache.h"
37 #include "adbookbase.h"
39 #ifndef DEV_STANDALONE
44 #define ADDRBOOK_MAX_SEARCH_COUNT 1000
45 #define ADDRBOOK_PREFIX "addrbook-"
46 #define ADDRBOOK_SUFFIX ".xml"
47 #define FILE_NUMDIGITS 6
49 #define ID_TIME_OFFSET 998000000
51 * Create new address book.
53 AddressBookFile *addrbook_create_book() {
54 AddressBookFile *book;
56 book = g_new0( AddressBookFile, 1 );
57 book->type = ADBOOKTYPE_BOOK;
58 book->addressCache = addrcache_create();
59 book->retVal = MGU_SUCCESS;
61 book->fileName = NULL;
63 book->tempList = NULL;
64 book->tempHash = NULL;
65 book->addressCache->modified = TRUE;
70 * Specify name to be used.
72 void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
73 g_return_if_fail( book != NULL );
74 addrcache_set_name( book->addressCache, value );
76 gchar *addrbook_get_name( AddressBookFile *book ) {
77 g_return_val_if_fail( book != NULL, NULL );
78 return addrcache_get_name( book->addressCache );
80 void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
81 g_return_if_fail( book != NULL );
82 book->path = mgu_replace_string( book->path, value );
83 addrcache_set_dirty( book->addressCache, TRUE );
85 void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
86 g_return_if_fail( book != NULL );
87 book->fileName = mgu_replace_string( book->fileName, value );
88 addrcache_set_dirty( book->addressCache, TRUE );
90 gboolean addrbook_get_modified( AddressBookFile *book ) {
91 g_return_val_if_fail( book != NULL, FALSE );
92 return book->addressCache->modified;
94 void addrbook_set_modified( AddressBookFile *book, const gboolean value ) {
95 g_return_if_fail( book != NULL );
96 book->addressCache->modified = value;
98 gboolean addrbook_get_accessed( AddressBookFile *book ) {
99 g_return_val_if_fail( book != NULL, FALSE );
100 return book->addressCache->accessFlag;
102 void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
103 g_return_if_fail( book != NULL );
104 book->addressCache->accessFlag = value;
106 gboolean addrbook_get_read_flag( AddressBookFile *book ) {
107 g_return_val_if_fail( book != NULL, FALSE );
108 return book->addressCache->dataRead;
110 void addrbook_set_read_flag( AddressBookFile *book, const gboolean value ) {
111 g_return_if_fail( book != NULL );
112 book->addressCache->dataRead = value;
114 gint addrbook_get_status( AddressBookFile *book ) {
115 g_return_val_if_fail( book != NULL, -1 );
118 ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
119 g_return_val_if_fail( book != NULL, NULL );
120 return addrcache_get_root_folder( book->addressCache );
122 GList *addrbook_get_list_folder( AddressBookFile *book ) {
123 g_return_val_if_fail( book != NULL, NULL );
124 return addrcache_get_list_folder( book->addressCache );
126 GList *addrbook_get_list_person( AddressBookFile *book ) {
127 g_return_val_if_fail( book != NULL, NULL );
128 return addrcache_get_list_person( book->addressCache );
130 gboolean addrbook_get_dirty( AddressBookFile *book ) {
131 g_return_val_if_fail( book != NULL, FALSE );
132 return addrcache_get_dirty( book->addressCache );
134 void addrbook_set_dirty( AddressBookFile *book, const gboolean value ) {
135 g_return_if_fail( book != NULL );
136 addrcache_set_dirty( book->addressCache, value );
140 * Empty address book.
142 void addrbook_empty_book( AddressBookFile *book ) {
143 g_return_if_fail( book != NULL );
145 /* Free up internal objects */
146 addrcache_clear( book->addressCache );
147 addrcache_set_dirty( book->addressCache, FALSE );
148 g_list_free( book->tempList );
150 /* Reset to initial state */
151 book->tempList = NULL;
152 book->tempHash = NULL;
153 book->addressCache->dataRead = FALSE;
154 book->addressCache->modified = FALSE;
155 book->addressCache->accessFlag = FALSE;
156 book->retVal = MGU_SUCCESS;
162 void addrbook_free_book( AddressBookFile *book ) {
163 g_return_if_fail( book != NULL );
166 addrcache_clear( book->addressCache );
167 addrcache_free( book->addressCache );
169 /* Free up internal objects */
170 g_free( book->path );
171 g_free( book->fileName );
172 g_list_free( book->tempList );
175 book->fileName = NULL;
177 book->tempList = NULL;
178 book->tempHash = NULL;
180 book->type = ADBOOKTYPE_NONE;
181 book->addressCache = NULL;
182 book->retVal = MGU_SUCCESS;
188 * Print list of items.
190 void addrbook_print_item_list( GList *list, FILE *stream ) {
194 AddrItemObject *obj = node->data;
195 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
196 addritem_print_item_person( ( ItemPerson * ) obj, stream );
198 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
199 addritem_print_item_group( ( ItemGroup * ) obj, stream );
201 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
202 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
204 node = g_list_next( node );
206 fprintf( stream, "\t---\n" );
210 * Print address book.
212 void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
213 g_return_if_fail( book != NULL );
215 fprintf( stream, "AddressBook:\n" );
216 fprintf( stream, "\tpath : '%s'\n", book->path );
217 fprintf( stream, "\tfile : '%s'\n", book->fileName );
218 fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
219 addrcache_print( book->addressCache, stream );
223 * Dump entire address book traversing folders.
225 void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
228 g_return_if_fail( book != NULL );
230 addrbook_print_book( book, stream );
231 folder = book->addressCache->rootFolder;
232 addritem_print_item_folder( folder, stream );
236 * Remove group from address book.
237 * param: group Group to remove.
238 * return: Group, or NULL if not found. Note that object should still be freed.
240 ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
241 g_return_val_if_fail( book != NULL, NULL );
242 return addrcache_remove_group( book->addressCache, group );
246 * Remove specified person from address book.
247 * param: person Person to remove.
248 * return: Person, or NULL if not found. Note that object should still be freed.
250 ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
251 g_return_val_if_fail( book != NULL, NULL );
252 return addrcache_remove_person( book->addressCache, person );
256 * Remove email address in address book for specified person.
257 * param: person Person.
258 * email EMail to remove.
259 * return: EMail object, or NULL if not found. Note that object should still be freed.
261 ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
262 g_return_val_if_fail( book != NULL, NULL );
263 return addrcache_person_remove_email( book->addressCache, person, email );
266 /* **********************************************************************
267 * Read/Write XML data file...
268 * ===========================
270 * 1) The address book is structured as follows:
285 * 2) This sequence of elements was chosen so that the most important
286 * elements (person and their email addresses) appear first.
288 * 3) Groups then appear. When groups are loaded, person's email
289 * addresses have already been loaded and can be found.
291 * 4) Finally folders are loaded. Any forward and backward references
292 * to folders, groups and persons in the folders are resolved after
295 * ***********************************************************************
298 /* Element tag names */
299 #define AB_ELTAG_ADDRESS "address"
300 #define AB_ELTAG_ATTRIBUTE "attribute"
301 #define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
302 #define AB_ELTAG_ADDRESS_LIST "address-list"
303 #define AB_ELTAG_MEMBER "member"
304 #define AB_ELTAG_MEMBER_LIST "member-list"
305 #define AB_ELTAG_ITEM "item"
306 #define AB_ELTAG_ITEM_LIST "item-list"
307 #define AB_ELTAG_ADDRESS_BOOK "address-book"
308 #define AB_ELTAG_PERSON "person"
309 #define AB_ELTAG_GROUP "group"
310 #define AB_ELTAG_FOLDER "folder"
312 /* Attribute tag names */
313 #define AB_ATTAG_TYPE "type"
314 #define AB_ATTAG_UID "uid"
315 #define AB_ATTAG_NAME "name"
316 #define AB_ATTAG_REMARKS "remarks"
317 #define AB_ATTAG_FIRST_NAME "first-name"
318 #define AB_ATTAG_LAST_NAME "last-name"
319 #define AB_ATTAG_NICK_NAME "nick-name"
320 #define AB_ATTAG_COMMON_NAME "cn"
321 #define AB_ATTAG_ALIAS "alias"
322 #define AB_ATTAG_EMAIL "email"
323 #define AB_ATTAG_EID "eid"
324 #define AB_ATTAG_PID "pid"
326 /* Attribute values */
327 #define AB_ATTAG_VAL_PERSON "person"
328 #define AB_ATTAG_VAL_GROUP "group"
329 #define AB_ATTAG_VAL_FOLDER "folder"
332 * Parse address item for person.
334 static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
337 ItemEMail *email = NULL;
339 attr = xml_get_current_tag_attr(file);
341 name = ((XMLAttr *)attr->data)->name;
342 value = ((XMLAttr *)attr->data)->value;
343 if( ! email ) email = addritem_create_item_email();
344 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
345 ADDRITEM_ID(email) = g_strdup( value );
347 else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
348 ADDRITEM_NAME(email) = g_strdup( value );
350 else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
351 email->address = g_strdup( value );
353 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
354 email->remarks = g_strdup( value );
356 attr = g_list_next( attr );
360 addrcache_person_add_email( book->addressCache, person, email );
363 addritem_free_item_email( email );
370 * Parse email address list.
372 static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
377 prev_level = file->level;
378 if( xml_parse_next_tag( file ) ) {
379 longjmp( book->jumper, 1 );
381 if (file->level < prev_level) return;
382 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
383 attr = xml_get_current_tag_attr(file);
384 addrbook_parse_address( book, file, person );
385 addrbook_parse_addr_list( book, file, person );
391 * Parse attibute for person.
393 static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
397 UserAttribute *uAttr = NULL;
399 attr = xml_get_current_tag_attr(file);
401 name = ((XMLAttr *)attr->data)->name;
402 value = ((XMLAttr *)attr->data)->value;
403 if( ! uAttr ) uAttr = addritem_create_attribute();
404 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
405 addritem_attrib_set_id( uAttr, value );
407 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
408 addritem_attrib_set_name( uAttr, value );
410 attr = g_list_next( attr );
413 element = xml_get_element( file );
414 addritem_attrib_set_value( uAttr, element );
418 addritem_person_add_attribute( person, uAttr );
421 addritem_free_attribute( uAttr );
428 * Parse attribute list.
430 static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
435 prev_level = file->level;
436 if( xml_parse_next_tag( file ) ) {
437 longjmp( book->jumper, 1 );
439 if (file->level < prev_level) return;
440 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
441 attr = xml_get_current_tag_attr(file);
442 addrbook_parse_attribute( file, person );
443 addrbook_parse_attr_list( book, file, person );
451 static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
454 ItemPerson *person = NULL;
456 attr = xml_get_current_tag_attr(file);
458 name = ((XMLAttr *)attr->data)->name;
459 value = ((XMLAttr *)attr->data)->value;
460 if( ! person ) person = addritem_create_item_person();
461 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
462 ADDRITEM_ID(person) = g_strdup( value );
464 else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
465 person->firstName = g_strdup( value );
467 else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
468 person->lastName = g_strdup( value );
470 else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
471 person->nickName = g_strdup( value );
473 else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
474 ADDRITEM_NAME(person) = g_strdup( value );
476 attr = g_list_next( attr );
478 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
479 longjmp( book->jumper, 1 );
481 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
482 addrbook_parse_addr_list( book, file, person );
484 addrcache_hash_add_person( book->addressCache, person );
487 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
488 longjmp( book->jumper, 1 );
490 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
491 addrbook_parse_attr_list( book, file, person );
496 * Parse group member.
498 static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
501 gchar *pid = NULL, *eid = NULL;
502 ItemEMail *email = NULL;
504 attr = xml_get_current_tag_attr(file);
506 name = ((XMLAttr *)attr->data)->name;
507 value = ((XMLAttr *)attr->data)->value;
508 if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
509 pid = g_strdup( value );
511 else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
512 eid = g_strdup( value );
514 attr = g_list_next( attr );
516 /* email = addrcache_get_email( book->addressCache, pid, eid ); */
517 email = addrcache_get_email( book->addressCache, eid );
520 addrcache_group_add_email( book->addressCache, group, email );
523 addritem_free_item_email( email );
530 * Parse group member list.
532 static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
537 prev_level = file->level;
538 if( xml_parse_next_tag( file ) ) {
539 longjmp( book->jumper, 1 );
541 if (file->level < prev_level) return;
542 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
543 attr = xml_get_current_tag_attr(file);
544 addrbook_parse_member( book, file, group );
545 addrbook_parse_member_list( book, file, group );
548 attr = xml_get_current_tag_attr( file );
556 static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
559 ItemGroup *group = NULL;
561 attr = xml_get_current_tag_attr(file);
563 name = ((XMLAttr *)attr->data)->name;
564 value = ((XMLAttr *)attr->data)->value;
565 if( ! group ) group = addritem_create_item_group();
566 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
567 ADDRITEM_ID(group) = g_strdup( value );
569 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
570 ADDRITEM_NAME(group) = g_strdup( value );
572 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
573 group->remarks = g_strdup( value );
575 attr = g_list_next( attr );
577 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
578 longjmp( book->jumper, 1 );
580 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
582 addrcache_hash_add_group( book->addressCache, group );
584 addrbook_parse_member_list( book, file, group );
591 static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
596 attr = xml_get_current_tag_attr(file);
598 name = ((XMLAttr *)attr->data)->name;
599 value = ((XMLAttr *)attr->data)->value;
600 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
601 uid = g_strdup( value );
603 attr = g_list_next( attr );
607 folder->listItems = g_list_append( folder->listItems, uid );
613 * Parse folder item list.
615 static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
620 prev_level = file->level;
621 if( xml_parse_next_tag( file ) ) {
622 longjmp( book->jumper, 1 );
624 if (file->level < prev_level) return;
625 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
626 attr = xml_get_current_tag_attr(file);
627 addrbook_parse_folder_item( book, file, folder );
628 addrbook_parse_folder_list( book, file, folder );
631 attr = xml_get_current_tag_attr( file );
639 static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
642 ItemFolder *folder = NULL;
644 attr = xml_get_current_tag_attr(file);
646 name = ((XMLAttr *)attr->data)->name;
647 value = ((XMLAttr *)attr->data)->value;
649 folder = addritem_create_item_folder();
651 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
652 ADDRITEM_ID(folder) = g_strdup( value );
654 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
655 ADDRITEM_NAME(folder) = g_strdup( value );
657 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
658 folder->remarks = g_strdup( value );
660 attr = g_list_next( attr );
662 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
663 longjmp( book->jumper, 1 );
665 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
667 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
668 book->tempList = g_list_append( book->tempList, folder );
669 ADDRITEM_PARENT(folder) = NULL; /* We will resolve folder later */
672 addrbook_parse_folder_list( book, file, folder );
677 * Parse address book.
678 * Return: TRUE if data read successfully, FALSE if error reading data.
680 static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
685 book->retVal = MGU_BAD_FORMAT;
686 if( xml_get_dtd( file ) ) {
689 if( xml_parse_next_tag( file ) ) {
690 longjmp( book->jumper, 1 );
692 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
696 attr = xml_get_current_tag_attr(file);
698 name = ((XMLAttr *)attr->data)->name;
699 value = ((XMLAttr *)attr->data)->value;
700 if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
701 addrbook_set_name( book, value );
703 attr = g_list_next( attr );
708 if (! file->level ) break;
709 /* Get next item tag (person, group or folder) */
710 if( xml_parse_next_tag( file ) ) {
711 longjmp( book->jumper, 1 );
713 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
714 addrbook_parse_person( book, file );
716 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
717 addrbook_parse_group( book, file );
719 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
720 addrbook_parse_folder( book, file );
723 if( retVal ) book->retVal = MGU_SUCCESS;
728 * Resolve folder items visitor function.
730 static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
731 AddressBookFile *book = data;
732 AddrItemObject *obj = ( AddrItemObject * ) value;
733 ItemFolder *rootFolder = book->addressCache->rootFolder;
734 if( obj->parent == NULL ) {
735 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
736 rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
737 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
739 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
740 rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
741 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
747 * Resolve folder items. Lists of UID's are replaced with pointers to data items.
749 static void addrbook_resolve_folder_items( AddressBookFile *book ) {
750 GList *nodeFolder = NULL;
751 GList *listRemove = NULL;
753 ItemFolder *rootFolder = book->addressCache->rootFolder;
754 nodeFolder = book->tempList;
755 while( nodeFolder ) {
756 ItemFolder *folder = nodeFolder->data;
758 node = folder->listItems;
760 gchar *uid = node->data;
761 AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
763 if( aio->type == ITEMTYPE_FOLDER ) {
764 ItemFolder *item = ( ItemFolder * ) aio;
765 folder->listFolder = g_list_append( folder->listFolder, item );
766 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
767 addrcache_hash_add_folder( book->addressCache, folder );
769 else if( aio->type == ITEMTYPE_PERSON ) {
770 ItemPerson *item = ( ItemPerson * ) aio;
771 folder->listPerson = g_list_append( folder->listPerson, item );
772 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
774 else if( aio->type == ITEMTYPE_GROUP ) {
775 ItemGroup *item = ( ItemGroup * ) aio;
776 folder->listGroup = g_list_append( folder->listGroup, item );
777 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
779 /* Replace data with pointer to item */
784 /* Not found, append to remove list. */
785 listRemove = g_list_append( listRemove, uid );
787 node = g_list_next( node );
789 rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
791 /* Process remove list */
794 gchar *uid = node->data;
795 folder->listItems = g_list_remove( folder->listItems, uid );
797 node = g_list_next( node );
799 g_list_free( listRemove );
800 nodeFolder = g_list_next( nodeFolder );
803 /* Remove folders with parents. */
805 node = rootFolder->listFolder;
807 ItemFolder *folder = ( ItemFolder * ) node->data;
808 if( ADDRITEM_PARENT(folder) ) {
809 /* Remove folders with parents */
810 listRemove = g_list_append( listRemove, folder );
813 /* Add to root folder */
814 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
816 node = g_list_next( node );
819 /* Process remove list */
822 rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
823 node = g_list_next( node );
825 g_list_free( listRemove );
827 /* Move all unparented persons and groups into root folder */
828 g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
830 /* Free up some more */
831 nodeFolder = book->tempList;
832 while( nodeFolder ) {
833 ItemFolder *folder = nodeFolder->data;
834 g_list_free( folder->listItems );
835 folder->listItems = NULL;
836 nodeFolder = g_list_next( nodeFolder );
838 g_list_free( book->tempList );
839 book->tempList = NULL;
844 * Read address book file.
846 gint addrbook_read_data( AddressBookFile *book ) {
847 XMLFile *file = NULL;
848 gchar *fileSpec = NULL;
850 g_return_val_if_fail( book != NULL, -1 );
853 printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
854 addrcache_get_name( book->addressCache ) );
857 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
858 book->retVal = MGU_OPEN_FILE;
859 addrcache_clear( book->addressCache );
860 book->addressCache->modified = FALSE;
861 book->addressCache->accessFlag = FALSE;
862 file = xml_open_file( fileSpec );
865 book->tempList = NULL;
867 /* Trap for parsing errors. */
868 if( setjmp( book->jumper ) ) {
869 xml_close_file( file );
872 addrbook_read_tree( book, file );
873 xml_close_file( file );
875 /* Resolve folder items */
876 addrbook_resolve_folder_items( book );
877 book->tempList = NULL;
878 book->addressCache->modified = FALSE;
879 book->addressCache->dataRead = TRUE;
880 addrcache_set_dirty( book->addressCache, FALSE );
885 static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
887 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
892 static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
894 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
900 static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
904 xml_file_put_escape_str( fp, value );
909 * Write file hash table visitor function.
911 static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
912 AddrItemObject *obj = ( AddrItemObject * ) value;
913 FILE *fp = ( FILE * ) data;
917 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
918 ItemPerson *person = ( ItemPerson * ) value;
920 addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
921 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
922 addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
923 addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
924 addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
925 addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
928 /* Output email addresses */
929 addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
931 node = person->listEMail;
933 ItemEMail *email = node->data;
934 addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
935 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
936 addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
937 addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
938 addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
940 node = g_list_next( node );
942 addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
944 /* Output user attributes */
945 addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
947 node = person->listAttrib;
949 UserAttribute *attrib = node->data;
950 addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
951 addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
952 addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
954 xml_file_put_escape_str( fp, attrib->value );
955 addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
956 node = g_list_next( node );
958 addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
959 addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
965 * Write file hash table visitor function.
967 static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
968 AddrItemObject *obj = ( AddrItemObject * ) value;
969 FILE *fp = ( FILE * ) data;
973 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
974 ItemGroup *group = ( ItemGroup * ) value;
976 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
977 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
978 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
979 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
982 /* Output email address links */
983 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
985 node = group->listEMail;
987 ItemEMail *email = node->data;
988 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
989 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
990 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
991 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
992 fputs( " />\n", fp );
993 node = g_list_next( node );
995 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
996 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1002 * Write file hash table visitor function.
1004 static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1005 AddrItemObject *obj = ( AddrItemObject * ) value;
1006 FILE *fp = ( FILE * ) data;
1010 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1011 ItemFolder *folder = ( ItemFolder * ) value;
1013 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1014 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1015 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1016 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1017 fputs( " >\n", fp );
1018 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1021 /* Output persons */
1022 node = folder->listPerson;
1024 ItemPerson *item = node->data;
1025 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1026 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1027 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1028 fputs( " />\n", fp );
1029 node = g_list_next( node );
1033 node = folder->listGroup;
1035 ItemGroup *item = node->data;
1036 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1037 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1038 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1039 fputs( " />\n", fp );
1040 node = g_list_next( node );
1043 /* Output folders */
1044 node = folder->listFolder;
1046 ItemFolder *item = node->data;
1047 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1048 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1049 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1050 fputs( " />\n", fp );
1051 node = g_list_next( node );
1053 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1054 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1060 * Output address book data to specified file.
1061 * return: Status code.
1063 gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1066 #ifndef DEV_STANDALONE
1070 g_return_val_if_fail( book != NULL, -1 );
1071 g_return_val_if_fail( newFile != NULL, -1 );
1073 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1075 book->retVal = MGU_OPEN_FILE;
1076 #ifdef DEV_STANDALONE
1077 fp = fopen( fileSpec, "wb" );
1080 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1082 pfile = prefs_write_open( fileSpec );
1086 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1087 conv_get_current_charset_str() );
1089 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1090 addrbook_write_attr( fp, AB_ATTAG_NAME, addrcache_get_name( book->addressCache ) );
1091 fputs( " >\n", fp );
1093 /* Output all persons */
1094 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1096 /* Output all groups */
1097 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1099 /* Output all folders */
1100 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1102 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1103 book->retVal = MGU_SUCCESS;
1104 #ifdef DEV_STANDALONE
1107 if( prefs_write_close( pfile ) < 0 ) {
1108 book->retVal = MGU_ERROR_WRITE;
1114 return book->retVal;
1118 * Output address book data to original file.
1119 * return: Status code.
1121 gint addrbook_save_data( AddressBookFile *book ) {
1122 g_return_val_if_fail( book != NULL, -1 );
1124 book->retVal = MGU_NO_FILE;
1125 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1126 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1128 addrbook_write_to( book, book->fileName );
1129 if( book->retVal == MGU_SUCCESS ) {
1130 addrcache_set_dirty( book->addressCache, FALSE );
1132 return book->retVal;
1135 /* **********************************************************************
1136 * Address book edit interface functions...
1137 * ***********************************************************************
1141 * Move person's email item.
1142 * param: book Address book.
1144 * itemMove Item to move.
1145 * itemTarget Target item before which to move item.
1147 ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1148 ItemEMail *itemMove, ItemEMail *itemTarget )
1150 ItemEMail *email = NULL;
1152 g_return_val_if_fail( book != NULL, NULL );
1154 email = addritem_move_email_before( person, itemMove, itemTarget );
1156 addrcache_set_dirty( book->addressCache, TRUE );
1162 * Move person's email item.
1163 * param: book Address book.
1165 * itemMove Item to move.
1166 * itemTarget Target item after which to move item.
1168 ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1169 ItemEMail *itemMove, ItemEMail *itemTarget )
1171 ItemEMail *email = NULL;
1173 g_return_val_if_fail( book != NULL, NULL );
1175 email = addritem_move_email_after( person, itemMove, itemTarget );
1177 addrcache_set_dirty( book->addressCache, TRUE );
1183 * Hash table visitor function for deletion of hashtable entries.
1185 static gboolean addrbook_free_simple_hash_vis(
1186 gpointer *key, gpointer *value, gpointer *data )
1195 * Update address book email list for specified person.
1196 * Enter: book Address book.
1197 * person Person to update.
1198 * listEMail List of new email addresses.
1199 * Note: The existing email addresses are replaced with the new addresses. Any references
1200 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1201 * linked to the person are removed.
1203 void addrbook_update_address_list(
1204 AddressBookFile *book, ItemPerson *person, GList *listEMail )
1210 g_return_if_fail( book != NULL );
1211 g_return_if_fail( person != NULL );
1213 /* Get groups where person's existing email addresses are listed */
1214 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1216 GHashTable *hashEMail;
1217 GHashTable *hashEMailAlias;
1220 /* Load hash table with new address entries */
1221 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1222 hashEMailAlias = g_hash_table_new( g_str_hash, g_str_equal );
1225 ItemEMail *email = node->data;
1226 gchar *addr = g_strdup( email->address );
1227 gchar *alias = email->obj.name ;
1229 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1230 g_hash_table_insert( hashEMail, addr, email );
1232 if ( *alias != '\0' && ! g_hash_table_lookup( hashEMailAlias, alias ) ) {
1233 g_hash_table_insert( hashEMailAlias, alias, email );
1235 node = g_list_next( node );
1238 /* Re-parent new addresses to existing groups, where email address match. */
1239 nodeGrp = listGroup;
1241 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1242 GList *groupEMail = group->listEMail;
1244 GList *listRemove = NULL;
1246 /* Process each email item linked to group */
1247 nodeGrpEM = groupEMail;
1248 while( nodeGrpEM ) {
1249 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1251 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1252 /* Found an email address for this person */
1253 ItemEMail *emailNew = NULL;
1254 gchar *addr = g_strdup( emailGrp->address );
1255 gchar *alias = emailGrp->obj.name;
1257 emailNew = ( ItemEMail * )
1258 g_hash_table_lookup( hashEMail, addr );
1260 /* If no match by e-mail, try to match by e-mail alias */
1261 if( ! emailNew && *alias != '\0' ) {
1262 emailNew = ( ItemEMail * )
1263 g_hash_table_lookup( hashEMailAlias, alias);
1267 /* Point to this entry */
1268 nodeGrpEM->data = emailNew;
1270 else if(g_hash_table_size(hashEMail)==1) {
1271 /* If the person has just one e-mail address, then
1272 change e-mail address in group list */
1273 nodeGrpEM->data = listEMail->data;
1276 /* Mark for removal */
1277 listRemove = g_list_append( listRemove, emailGrp );
1280 /* Move on to next email link */
1281 nodeGrpEM = g_list_next( nodeGrpEM );
1284 /* Process all removed links in current group */
1285 nodeGrpEM = listRemove;
1286 while( nodeGrpEM ) {
1287 ItemEMail *emailGrp = nodeGrpEM->data;
1288 groupEMail = g_list_remove( groupEMail, emailGrp );
1289 nodeGrpEM = g_list_next( nodeGrpEM );
1292 g_list_free( listRemove );
1294 /* Move on to next group */
1295 nodeGrp = g_list_next( nodeGrp );
1299 /* Clear hash table */
1300 g_hash_table_foreach_remove(
1301 hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1302 g_hash_table_destroy( hashEMail );
1304 g_hash_table_destroy( hashEMailAlias );
1305 hashEMailAlias = NULL;
1306 g_list_free( listGroup );
1310 /* Remove old addresses from person and cache */
1312 node = person->listEMail;
1314 ItemEMail *email = node->data;
1316 if( addrcache_person_remove_email( book->addressCache, person, email ) ) {
1317 addrcache_remove_email( book->addressCache, email );
1319 listDelete = g_list_append( listDelete, email );
1320 node = person->listEMail;
1323 /* Add new address entries */
1326 ItemEMail *email = node->data;
1328 if( ADDRITEM_ID(email) == NULL ) {
1329 /* Allocate an ID for new address */
1330 addrcache_id_email( book->addressCache, email );
1332 addrcache_person_add_email( book->addressCache, person, email );
1333 node = g_list_next( node );
1336 addrcache_set_dirty( book->addressCache, TRUE );
1338 /* Free up memory */
1339 g_list_free( listEMail );
1344 ItemEMail *email = node->data;
1346 addritem_free_item_email( email );
1347 node = g_list_next( node );
1349 g_list_free( listDelete );
1355 * Add person and address data to address book.
1356 * Enter: book Address book.
1357 * folder Folder where to add person, or NULL for root folder.
1358 * listEMail New list of email addresses.
1359 * Return: Person added.
1360 * Note: A new person is created with specified list of email addresses. All objects inserted
1361 * into address book.
1363 ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1365 ItemFolder *f = folder;
1368 g_return_val_if_fail( book != NULL, NULL );
1370 if( ! f ) f = book->addressCache->rootFolder;
1371 person = addritem_create_item_person();
1372 addrcache_id_person( book->addressCache, person );
1373 addrcache_folder_add_person( book->addressCache, f, person );
1377 ItemEMail *email = node->data;
1378 if( ADDRITEM_ID(email) == NULL ) {
1379 addrcache_id_email( book->addressCache, email );
1381 addrcache_person_add_email( book->addressCache, person, email );
1382 node = g_list_next( node );
1388 * Build available email list visitor function.
1390 static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1391 AddrItemObject *obj = ( AddrItemObject * ) value;
1393 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1394 AddressBookFile *book = data;
1395 ItemPerson *person = ( ItemPerson * ) obj;
1396 GList *node = person->listEMail;
1398 ItemEMail *email = node->data;
1399 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1401 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1402 book->tempList = g_list_append( book->tempList, email );
1404 node = g_list_next( node );
1410 * Return link list of available email items (which have not already been linked to
1411 * groups). Note that the list contains references to items and should be g_free()
1412 * when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1413 * destroy the addressbook data!
1414 * Return: List of items, or NULL if none.
1416 GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1420 g_return_val_if_fail( book != NULL, NULL );
1422 /* Load hash table with group email entries */
1423 table = g_hash_table_new( g_str_hash, g_str_equal );
1425 list = group->listEMail;
1427 ItemEMail *email = list->data;
1428 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1429 list = g_list_next( list );
1433 /* Build list of available email addresses which exclude those already in groups */
1434 book->tempList = NULL;
1435 book->tempHash = table;
1436 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1437 list = book->tempList;
1438 book->tempList = NULL;
1439 book->tempHash = NULL;
1441 /* Clear hash table */
1442 g_hash_table_destroy( table );
1449 * Update address book email list for specified group.
1450 * Enter: book Address book.
1451 * group group to update.
1452 * listEMail New list of email addresses. This should *NOT* be g_free() when done.
1453 * Note: The existing email addresses are replaced with the new addresses. Any references
1454 * to old addresses in the groups are re-linked to the new addresses. All old addresses
1455 * linked to the person are removed.
1457 void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1460 g_return_if_fail( book != NULL );
1461 g_return_if_fail( group != NULL );
1463 addrcache_set_dirty( book->addressCache, TRUE );
1465 /* Remember old list */
1466 oldData = group->listEMail;
1467 group->listEMail = listEMail;
1468 mgu_clear_list( oldData );
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;
1497 * Add new folder to address book.
1498 * Enter: book Address book.
1499 * parent Parent folder.
1500 * Return: Folder that was added. This should *NOT* be g_free() when done.
1502 ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1503 ItemFolder *folder = NULL;
1504 ItemFolder *p = parent;
1506 g_return_val_if_fail( book != NULL, NULL );
1508 if( ! p ) p = book->addressCache->rootFolder;
1509 folder = addritem_create_item_folder();
1510 addrcache_id_folder( book->addressCache, folder );
1511 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1512 p->listFolder = g_list_append( p->listFolder, folder );
1513 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1514 addrcache_set_dirty( book->addressCache, TRUE );
1517 addritem_free_item_folder( folder );
1524 * Update address book attribute list for specified person.
1525 * Enter: book Address book.
1526 * person Person to update.
1527 * listAttrib New list of attributes.
1528 * Note: The existing email addresses are replaced with the new addresses. All old attributes
1529 * linked to the person are removed.
1531 void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1535 g_return_if_fail( book != NULL );
1536 g_return_if_fail( person != NULL );
1538 /* Remember old list */
1539 oldData = person->listAttrib;
1541 /* Attach new address list to person. */
1544 UserAttribute *attrib = node->data;
1545 if( attrib->uid == NULL ) {
1546 /* Allocate an ID */
1547 addrcache_id_attribute( book->addressCache, attrib );
1549 node = g_list_next( node );
1551 person->listAttrib = listAttrib;
1552 addrcache_set_dirty( book->addressCache, TRUE );
1554 /* Free up old data */
1555 addritem_free_list_attribute( oldData );
1561 * Add attribute data for person to address book.
1562 * Enter: book Address book.
1563 * person New person object.
1564 * listAttrib New list of attributes.
1565 * Note: Only attributes are inserted into address book.
1567 void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1570 g_return_if_fail( book != NULL );
1571 g_return_if_fail( person != NULL );
1575 UserAttribute *attrib = node->data;
1576 if( attrib->uid == NULL ) {
1577 addrcache_id_attribute( book->addressCache, attrib );
1579 addritem_person_add_attribute( person, attrib );
1580 node = g_list_next( node );
1582 addrcache_set_dirty( book->addressCache, TRUE );
1586 * Return address book file for specified object.
1587 * Enter: aio Book item object.
1588 * Return: Address book, or NULL if not found.
1590 AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1591 AddressBookFile *book = NULL;
1594 ItemFolder *parent = NULL;
1595 ItemFolder *root = NULL;
1596 if( aio->type == ITEMTYPE_EMAIL ) {
1597 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1599 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1603 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1606 root = addrcache_find_root_folder( parent );
1609 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1616 * Remove folder from address book. Children are re-parented to parent folder.
1617 * param: folder Folder to remove.
1618 * return: Folder, or NULL if not found. Note that object should still be freed.
1620 ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1623 g_return_val_if_fail( book != NULL, NULL );
1625 f = addrcache_remove_folder( book->addressCache, folder );
1630 * Remove folder from address book. Children are deleted.
1631 * param: folder Folder to remove.
1632 * return: Folder, or NULL if not found. Note that object should still be freed.
1634 ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1637 g_return_val_if_fail( book != NULL, NULL );
1639 f = addrcache_remove_folder_delete( book->addressCache, folder );
1643 #define WORK_BUFLEN 1024
1644 #define ADDRBOOK_DIGITS "0123456789"
1647 * Return list of existing address book files.
1648 * Enter: book Address book file.
1649 * Return: File list.
1651 GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1654 struct dirent *entry;
1655 struct stat statbuf;
1656 gchar buf[ WORK_BUFLEN ];
1657 gchar numbuf[ WORK_BUFLEN ];
1658 gint len, lenpre, lensuf, lennum;
1659 long int val, maxval;
1660 GList *fileList = NULL;
1662 g_return_val_if_fail( book != NULL, NULL );
1664 if( book->path == NULL || *book->path == '\0' ) {
1665 book->retVal = MGU_NO_PATH;
1669 strcpy( buf, book->path );
1670 len = strlen( buf );
1672 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1673 buf[ len ] = G_DIR_SEPARATOR;
1674 buf[ ++len ] = '\0';
1678 adbookdir = g_strdup( buf );
1679 strcat( buf, ADDRBOOK_PREFIX );
1681 if( ( dp = opendir( adbookdir ) ) == NULL ) {
1682 book->retVal = MGU_OPEN_DIRECTORY;
1683 g_free( adbookdir );
1687 lenpre = strlen( ADDRBOOK_PREFIX );
1688 lensuf = strlen( ADDRBOOK_SUFFIX );
1689 lennum = FILE_NUMDIGITS + lenpre;
1692 while( ( entry = readdir( dp ) ) != NULL ) {
1693 gchar *endptr = NULL;
1697 strcpy( buf, adbookdir );
1698 strcat( buf, entry->d_name );
1699 stat( buf, &statbuf );
1700 if( S_IFREG & statbuf.st_mode ) {
1701 if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1702 if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1703 strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1704 numbuf[ FILE_NUMDIGITS ] = '\0';
1706 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1707 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1714 val = strtol( numbuf, &endptr, 10 );
1715 if( endptr && val > -1 ) {
1716 if( val > maxval ) maxval = val;
1717 fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1725 g_free( adbookdir );
1727 book->maxValue = maxval;
1728 book->retVal = MGU_SUCCESS;
1733 * Return file name for specified file number.
1734 * Enter: fileNum File number.
1735 * Return: File name, or NULL if file number too large. Should be g_free() when done.
1737 gchar *addrbook_gen_new_file_name( gint fileNum ) {
1739 gchar buf[ WORK_BUFLEN ];
1744 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1745 if( fileNum > nmax ) return NULL;
1746 g_snprintf( fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS );
1747 g_snprintf( buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1748 return g_strdup( buf );
1751 /* **********************************************************************
1752 * Address book test functions...
1753 * ***********************************************************************
1757 * Test email address list.
1759 static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1764 prev_level = file->level;
1765 if( xml_parse_next_tag( file ) ) {
1766 longjmp( book->jumper, 1 );
1768 if (file->level < prev_level) return;
1769 attr = xml_get_current_tag_attr(file);
1770 /* addrbook_show_attribs( attr ); */
1771 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1772 addrbook_chkparse_addr_list( book, file );
1778 * Test user attributes for person.
1780 static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1784 attr = xml_get_current_tag_attr(file);
1785 /* addrbook_show_attribs( attr ); */
1786 element = xml_get_element( file );
1787 /* printf( "\t\tattrib value : %s\n", element ); */
1791 * Test attribute list.
1793 static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1797 prev_level = file->level;
1798 if( xml_parse_next_tag( file ) ) {
1799 longjmp( book->jumper, 1 );
1801 if (file->level < prev_level) return;
1802 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1803 addrbook_chkparse_attribute( book, file );
1804 addrbook_chkparse_attr_list( book, file );
1812 static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1815 attr = xml_get_current_tag_attr(file);
1816 /* addrbook_show_attribs( attr ); */
1817 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1818 longjmp( book->jumper, 1 );
1820 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1821 addrbook_chkparse_addr_list( book, file );
1823 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1824 longjmp( book->jumper, 1 );
1826 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1827 addrbook_chkparse_attr_list( book, file );
1832 * Test group member list.
1834 static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1839 prev_level = file->level;
1840 if( xml_parse_next_tag( file ) ) {
1841 longjmp( book->jumper, 1 );
1843 if (file->level < prev_level) return;
1844 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1845 attr = xml_get_current_tag_attr(file);
1846 /* addrbook_show_attribs( attr ); */
1847 addrbook_chkparse_member_list( book, file );
1850 attr = xml_get_current_tag_attr( file );
1851 /* addrbook_show_attribs( attr ); */
1859 static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1862 attr = xml_get_current_tag_attr(file);
1863 /* addrbook_show_attribs( attr ); */
1864 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1865 longjmp( book->jumper, 1 );
1867 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1868 addrbook_chkparse_member_list( book, file );
1873 * Test folder item list.
1875 static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1880 prev_level = file->level;
1881 if( xml_parse_next_tag( file ) ) {
1882 longjmp( book->jumper, 1 );
1884 if (file->level < prev_level) return;
1885 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1886 attr = xml_get_current_tag_attr(file);
1887 /* addrbook_show_attribs( attr ); */
1888 addrbook_chkparse_folder_list( book, file );
1891 attr = xml_get_current_tag_attr( file );
1892 /* addrbook_show_attribs( attr ); */
1900 static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1903 attr = xml_get_current_tag_attr(file);
1904 /* addrbook_show_attribs( attr ); */
1905 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1906 longjmp( book->jumper, 1 );
1908 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1909 addrbook_chkparse_folder_list( book, file );
1914 * Test address book.
1916 static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1920 if( xml_get_dtd( file ) ) {
1923 if( xml_parse_next_tag( file ) ) {
1927 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1931 attr = xml_get_current_tag_attr(file);
1932 /* addrbook_show_attribs( attr ); */
1936 if (! file->level ) break;
1938 if( xml_parse_next_tag( file ) ) {
1939 longjmp( book->jumper, 1 );
1941 /* Get next tag (person, group or folder) */
1942 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1943 addrbook_chkparse_person( book, file );
1945 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1946 addrbook_chkparse_group( book, file );
1948 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1949 addrbook_chkparse_folder( book, file );
1956 * Test address book file by parsing contents.
1957 * Enter: book Address book file to check.
1958 * fileName File name to check.
1959 * Return: MGU_SUCCESS if file appears to be valid format.
1961 gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1962 XMLFile *file = NULL;
1963 gchar *fileSpec = NULL;
1965 g_return_val_if_fail( book != NULL, -1 );
1967 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1968 book->retVal = MGU_OPEN_FILE;
1969 file = xml_open_file( fileSpec );
1972 book->retVal = MGU_BAD_FORMAT;
1973 if( setjmp( book->jumper ) ) {
1974 /* printf( "Caught Ya!!!\n" ); */
1975 xml_close_file( file );
1976 return book->retVal;
1978 if( addrbook_chkread_tree( book, file ) ) {
1979 book->retVal = MGU_SUCCESS;
1981 xml_close_file( file );
1983 return book->retVal;
1987 * Return link list of all persons in address book. Note that the list contains
1988 * references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1989 * this will destroy the addressbook data!
1990 * Return: List of items, or NULL if none.
1992 GList *addrbook_get_all_persons( AddressBookFile *book ) {
1993 g_return_val_if_fail( book != NULL, NULL );
1994 return addrcache_get_all_persons( book->addressCache );
1998 * Add person and address data to address book.
1999 * Enter: book Address book.
2000 * folder Folder where to add person, or NULL for root folder.
2002 * address EMail address.
2004 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
2005 * this will destroy the address book data.
2007 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
2008 const gchar *address, const gchar *remarks )
2010 g_return_val_if_fail( book != NULL, NULL );
2011 return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
2015 * Return file name for next address book file.
2016 * Enter: book Address book.
2017 * Return: File name, or NULL if could not create. This should be g_free()
2020 gchar *addrbook_guess_next_file( AddressBookFile *book ) {
2021 gchar *newFile = NULL;
2022 GList *fileList = NULL;
2024 fileList = addrbook_get_bookfile_list( book );
2026 fileNum = 1 + book->maxValue;
2028 newFile = addrbook_gen_new_file_name( fileNum );
2029 g_list_free( fileList );