2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * Functions to maintain address cache.
29 #include "addrcache.h"
32 #define ID_TIME_OFFSET 998000000
33 #define ADDRCACHE_MAX_SEARCH_COUNT 1000
35 static int _nextCacheID__ = 0;
38 * Generate next cache ID.
40 static int addrcache_next_cache_id() {
43 if( _nextCacheID__ == 0 ) {
46 retVal = _nextCacheID__;
52 * Create new address cache.
54 AddressCache *addrcache_create() {
58 cache = g_new0( AddressCache, 1 );
59 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
60 cache->cacheID = g_strdup_printf( "%d", addrcache_next_cache_id() );
62 cache->dataRead = FALSE;
63 cache->modified = FALSE;
64 cache->dirtyFlag = FALSE;
65 cache->accessFlag = FALSE;
67 cache->modifyTime = 0;
69 /* Generate the next ID using system time */
73 cache->nextID = t - ID_TIME_OFFSET;
76 cache->tempList = NULL;
77 cache->rootFolder = addritem_create_item_folder();
78 cache->rootFolder->isRoot = TRUE;
79 ADDRITEM_PARENT(cache->rootFolder) = NULL;
86 ItemFolder *addrcache_get_root_folder( AddressCache *cache ) {
87 g_return_val_if_fail( cache != NULL, NULL );
88 return cache->rootFolder;
90 GList *addrcache_get_list_folder( AddressCache *cache ) {
91 g_return_val_if_fail( cache != NULL, NULL );
92 return cache->rootFolder->listFolder;
94 GList *addrcache_get_list_person( AddressCache *cache ) {
95 g_return_val_if_fail( cache != NULL, NULL );
96 return cache->rootFolder->listPerson;
98 gboolean addrcache_get_dirty( AddressCache *cache ) {
99 g_return_val_if_fail( cache != NULL, FALSE );
100 return cache->dirtyFlag;
102 void addrcache_set_dirty( AddressCache *cache, const gboolean value ) {
103 g_return_if_fail( cache != NULL );
104 cache->dirtyFlag = value;
106 gboolean addrcache_get_modified( AddressCache *cache ) {
107 g_return_val_if_fail( cache != NULL, FALSE );
108 return cache->modified;
110 void addrcache_set_modified( AddressCache *cache, const gboolean value ) {
111 g_return_if_fail( cache != NULL );
112 cache->modified = value;
114 gboolean addrcache_get_read_flag( AddressCache *cache ) {
115 g_return_val_if_fail( cache != NULL, FALSE );
116 return cache->dataRead;
118 void addrcache_set_read_flag( AddressCache *cache, const gboolean value ) {
119 g_return_if_fail( cache != NULL );
120 cache->dataRead = value;
122 gboolean addrcache_get_accessed( AddressCache *cache ) {
123 g_return_val_if_fail( cache != NULL, FALSE );
124 return cache->accessFlag;
126 void addrcache_set_accessed( AddressCache *cache, const gboolean value ) {
127 g_return_if_fail( cache != NULL );
128 cache->accessFlag = value;
130 gchar *addrcache_get_name( AddressCache *cache ) {
131 g_return_val_if_fail( cache != NULL, NULL );
134 void addrcache_set_name( AddressCache *cache, const gchar *value ) {
135 g_return_if_fail( cache != NULL );
136 cache->name = mgu_replace_string( cache->name, value );
137 g_strstrip( cache->name );
138 cache->dirtyFlag = TRUE;
144 void addrcache_next_id( AddressCache *cache ) {
145 g_return_if_fail( cache != NULL );
150 * Refresh internal variables. This can be used force a reload.
152 void addrcache_refresh( AddressCache *cache ) {
153 cache->dataRead = FALSE;
154 cache->modified = TRUE;
155 cache->accessFlag = FALSE;
156 cache->modifyTime = 0;
160 * Free hash table visitor function.
162 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
163 AddrItemObject *obj = ( AddrItemObject * ) value;
165 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
166 addritem_free_item_person( ( ItemPerson * ) obj );
168 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
169 addritem_free_item_email( ( ItemEMail * ) obj );
171 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
172 addritem_free_item_group( ( ItemGroup * ) obj );
174 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
175 addritem_free_item_folder( ( ItemFolder * ) obj );
183 * Free hash table of address cache items.
185 static void addrcache_free_item_hash( GHashTable *table ) {
186 g_return_if_fail( table != NULL );
187 g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
191 * Free up folders and groups.
193 static void addrcache_free_all_folders( ItemFolder *parent ) {
196 if( parent == NULL ) return;
198 node = parent->listFolder;
200 ItemFolder *folder = node->data;
201 addrcache_free_all_folders( folder );
203 node = g_list_next( node );
205 g_list_free( parent->listPerson );
206 g_list_free( parent->listGroup );
207 g_list_free( parent->listFolder );
208 parent->listPerson = NULL;
209 parent->listGroup = NULL;
210 parent->listFolder = NULL;
214 * Clear the address cache.
216 void addrcache_clear( AddressCache *cache ) {
217 g_return_if_fail( cache != NULL );
219 /* printf( "...addrcache_clear :%s:\n", cache->name ); */
220 /* Free up folders and hash table */
221 addrcache_free_all_folders( cache->rootFolder );
222 addrcache_free_item_hash( cache->itemHash );
223 g_hash_table_destroy( cache->itemHash );
224 cache->itemHash = NULL;
225 ADDRITEM_PARENT(cache->rootFolder) = NULL;
226 addritem_free_item_folder( cache->rootFolder );
227 cache->rootFolder = NULL;
228 if( cache->tempList ) g_list_free( cache->tempList );
229 cache->tempList = NULL;
231 /* Reset to initial state */
232 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
233 cache->rootFolder = addritem_create_item_folder();
234 cache->rootFolder->isRoot = TRUE;
235 ADDRITEM_PARENT(cache->rootFolder) = NULL;
237 addrcache_refresh( cache );
241 * Free address cache.
243 void addrcache_free( AddressCache *cache ) {
244 g_return_if_fail( cache != NULL );
246 cache->dirtyFlag = FALSE;
247 addrcache_free_all_folders( cache->rootFolder );
248 addrcache_free_item_hash( cache->itemHash );
249 g_hash_table_destroy( cache->itemHash );
250 cache->itemHash = NULL;
251 ADDRITEM_PARENT(cache->rootFolder) = NULL;
252 addritem_free_item_folder( cache->rootFolder );
253 cache->rootFolder = NULL;
254 g_list_free( cache->tempList );
255 cache->tempList = NULL;
256 g_free( cache->cacheID );
257 cache->cacheID = NULL;
258 g_free( cache->name );
264 * Check whether file has changed by comparing with cache.
265 * return: TRUE if file has changed.
267 gboolean addrcache_check_file( AddressCache *cache, gchar *path ) {
269 struct stat filestat;
272 if( 0 == g_stat( path, &filestat ) ) {
273 if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
280 * Save file time to cache.
281 * return: TRUE if time marked.
283 gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) {
284 gboolean retVal = FALSE;
285 struct stat filestat;
287 if( 0 == g_stat( path, &filestat ) ) {
288 cache->modifyTime = filestat.st_mtime;
296 * Print list of items.
298 void addrcache_print_item_list( GList *list, FILE *stream ) {
301 AddrItemObject *obj = node->data;
302 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
303 addritem_print_item_person( ( ItemPerson * ) obj, stream );
305 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
306 addritem_print_item_group( ( ItemGroup * ) obj, stream );
308 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
309 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
311 node = g_list_next( node );
313 fprintf( stream, "\t---\n" );
317 * Print item hash table visitor function.
319 static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) {
320 AddrItemObject *obj = ( AddrItemObject * ) value;
321 FILE *stream = ( FILE * ) data;
322 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
323 addritem_print_item_person( ( ItemPerson * ) obj, stream );
325 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
326 printf( "addrcache: print email\n" );
328 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
329 addritem_print_item_group( ( ItemGroup * ) obj, stream );
331 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
332 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
337 * Dump entire address cache hash table contents.
339 void addrcache_print( AddressCache *cache, FILE *stream ) {
340 g_return_if_fail( cache != NULL );
341 fprintf( stream, "AddressCache:\n" );
342 fprintf( stream, "cache id : %s\n", cache->cacheID );
343 fprintf( stream, "next id : %d\n", cache->nextID );
344 fprintf( stream, "name : %s\n", cache->name );
345 fprintf( stream, "mod time : %ld\n", (long int)cache->modifyTime );
346 fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" );
347 fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" );
351 * Dump entire address cache hash table contents.
353 void addrcache_dump_hash( AddressCache *cache, FILE *stream ) {
354 g_return_if_fail( cache != NULL );
355 addrcache_print( cache, stream );
356 g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream );
360 * Allocate ID for person.
362 void addrcache_id_person( AddressCache *cache, ItemPerson *person ) {
363 g_return_if_fail( cache != NULL );
364 g_return_if_fail( person != NULL );
365 if( ADDRITEM_ID(person) ) return;
366 addrcache_next_id( cache );
367 ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID );
371 * Allocate ID for group.
373 void addrcache_id_group( AddressCache *cache, ItemGroup *group ) {
374 g_return_if_fail( cache != NULL );
375 g_return_if_fail( group != NULL );
376 if( ADDRITEM_ID(group) ) return;
377 addrcache_next_id( cache );
378 ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID );
382 * Allocate ID for folder.
384 void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) {
385 g_return_if_fail( cache != NULL );
386 g_return_if_fail( folder != NULL );
387 if( ADDRITEM_ID(folder) ) return;
388 addrcache_next_id( cache );
389 ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID );
393 * Allocate ID for email address.
395 void addrcache_id_email( AddressCache *cache, ItemEMail *email ) {
396 g_return_if_fail( cache != NULL );
397 g_return_if_fail( email != NULL );
398 if( ADDRITEM_ID(email) ) return;
399 addrcache_next_id( cache );
400 ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID );
404 * Allocate ID for user attribute.
406 void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) {
407 g_return_if_fail( cache != NULL );
408 g_return_if_fail( attrib != NULL );
409 if( attrib->uid ) return;
410 addrcache_next_id( cache );
411 attrib->uid = g_strdup_printf( "%d", cache->nextID );
415 * Add person to hash table.
416 * return: TRUE if item added.
418 gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
419 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) {
422 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person );
427 * Add email to hash table.
428 * return: TRUE if item added.
430 gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
431 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
434 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
439 * Add group to hash table.
440 * return: TRUE if item added.
442 gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) {
443 g_return_val_if_fail( cache != NULL, FALSE );
444 g_return_val_if_fail( group != NULL, FALSE );
446 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) {
449 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group );
454 * Add folder to hash table.
455 * return: TRUE if item added.
457 gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) {
458 g_return_val_if_fail( cache != NULL, FALSE );
459 g_return_val_if_fail( folder != NULL, FALSE );
461 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) {
464 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder );
469 * Add person to specified folder in cache.
471 gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) {
472 gboolean retVal = FALSE;
474 g_return_val_if_fail( cache != NULL, FALSE );
475 g_return_val_if_fail( folder != NULL, FALSE );
476 g_return_val_if_fail( item != NULL, FALSE );
478 retVal = addrcache_hash_add_person( cache, item );
480 addritem_folder_add_person( folder, item );
481 cache->dirtyFlag = TRUE;
487 * Add folder to specified folder in cache.
489 gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) {
490 gboolean retVal = FALSE;
492 g_return_val_if_fail( cache != NULL, FALSE );
493 g_return_val_if_fail( folder != NULL, FALSE );
494 g_return_val_if_fail( item != NULL, FALSE );
496 retVal = addrcache_hash_add_folder( cache, item );
498 addritem_folder_add_folder( folder, item );
499 cache->dirtyFlag = TRUE;
505 * Add folder to specified folder in cache.
507 gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) {
508 gboolean retVal = FALSE;
510 g_return_val_if_fail( cache != NULL, FALSE );
511 g_return_val_if_fail( folder != NULL, FALSE );
512 g_return_val_if_fail( item != NULL, FALSE );
514 retVal = addrcache_hash_add_group( cache, item );
516 addritem_folder_add_group( folder, item );
517 cache->dirtyFlag = TRUE;
523 * Add person to address cache.
524 * return: TRUE if item added.
526 gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
527 gboolean retVal = FALSE;
529 g_return_val_if_fail( cache != NULL, FALSE );
530 g_return_val_if_fail( person != NULL, FALSE );
532 retVal = addrcache_hash_add_person( cache, person );
534 addritem_folder_add_person( cache->rootFolder, person );
535 cache->dirtyFlag = TRUE;
541 * Add EMail address to person.
542 * return: TRUE if item added.
544 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
545 gboolean retVal = FALSE;
547 g_return_val_if_fail( cache != NULL, FALSE );
548 g_return_val_if_fail( person != NULL, FALSE );
549 g_return_val_if_fail( email != NULL, FALSE );
551 retVal = addrcache_hash_add_email( cache, email );
553 addritem_person_add_email( person, email );
554 cache->dirtyFlag = TRUE;
560 * Add group to address cache.
561 * return: TRUE if item added.
563 gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
564 gboolean retVal = FALSE;
566 g_return_val_if_fail( cache != NULL, FALSE );
567 g_return_val_if_fail( group != NULL, FALSE );
569 retVal = addrcache_hash_add_group( cache, group );
571 addritem_folder_add_group( cache->rootFolder, group );
572 cache->dirtyFlag = TRUE;
578 * Add EMail address to person.
579 * return: TRUE if item added.
581 gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) {
582 g_return_val_if_fail( cache != NULL, FALSE );
583 g_return_val_if_fail( group != NULL, FALSE );
584 g_return_val_if_fail( email != NULL, FALSE );
586 addritem_group_add_email( group, email );
587 cache->dirtyFlag = TRUE;
592 * Add folder to address cache.
593 * return: TRUE if item added.
595 gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
596 gboolean retVal = FALSE;
598 g_return_val_if_fail( cache != NULL, FALSE );
599 g_return_val_if_fail( folder != NULL, FALSE );
601 retVal = addrcache_hash_add_folder( cache, folder );
603 addritem_folder_add_folder( cache->rootFolder, folder );
604 cache->dirtyFlag = TRUE;
610 * Move person to destination folder.
611 * Enter: cache Cache.
612 * person Person to move.
613 * target Target folder.
615 void addrcache_folder_move_person(
616 AddressCache *cache, ItemPerson *person, ItemFolder *target )
620 g_return_if_fail( cache != NULL );
621 g_return_if_fail( person != NULL );
623 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
624 if( ! parent ) parent = cache->rootFolder;
625 parent->listPerson = g_list_remove( parent->listPerson, person );
626 target->listPerson = g_list_append( target->listPerson, person );
627 ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
628 cache->dirtyFlag = TRUE;
632 * Move group to destination folder.
633 * Enter: cache Cache.
634 * group Group to move.
635 * target Target folder.
637 void addrcache_folder_move_group(
638 AddressCache *cache, ItemGroup *group, ItemFolder *target )
642 g_return_if_fail( cache != NULL );
643 g_return_if_fail( group != NULL );
645 parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
646 if( ! parent ) parent = cache->rootFolder;
647 parent->listGroup = g_list_remove( parent->listGroup, group );
648 target->listGroup = g_list_append( target->listGroup, group );
649 ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
650 cache->dirtyFlag = TRUE;
654 * Move folder to destination folder.
655 * Enter: cache Cache.
656 * folder Folder to move.
657 * target Target folder.
659 void addrcache_folder_move_folder(
660 AddressCache *cache, ItemFolder *folder, ItemFolder *target )
664 g_return_if_fail( cache != NULL );
665 g_return_if_fail( folder != NULL );
667 parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
668 if( ! parent ) parent = cache->rootFolder;
669 parent->listFolder = g_list_remove( parent->listFolder, folder );
670 target->listFolder = g_list_append( target->listFolder, folder );
671 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
672 cache->dirtyFlag = TRUE;
676 * Return pointer to object (either person or group) for specified ID.
677 * param: uid Object ID.
678 * return: Object, or NULL if not found.
680 AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) {
681 AddrItemObject *obj = NULL;
684 g_return_val_if_fail( cache != NULL, NULL );
686 if( uid == NULL || *uid == '\0' ) return NULL;
687 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
689 /* Check for matching UID */
690 uidH = ADDRITEM_ID(obj);
692 if( strcmp( uidH, uid ) == 0 ) return obj;
699 * Return pointer for specified object ID.
700 * param: uid Object ID.
701 * return: Person object, or NULL if not found.
703 ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) {
704 ItemPerson *person = NULL;
705 AddrItemObject *obj = addrcache_get_object( cache, uid );
708 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
709 person = ( ItemPerson * ) obj;
716 * Return pointer for specified object ID.
717 * param: uid group ID.
718 * return: Group object, or NULL if not found.
720 ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
721 ItemGroup *group = NULL;
722 AddrItemObject *obj = addrcache_get_object( cache, uid );
725 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
726 group = ( ItemGroup * ) obj;
733 * Find email address in address cache.
734 * param: eid EMail ID.
735 * return: email object for specified object ID and email ID, or NULL if not found.
737 ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
738 ItemEMail *email = NULL;
739 AddrItemObject *obj = addrcache_get_object( cache, eid );
742 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
743 email = ( ItemEMail * ) obj;
750 * Remove attribute from person.
751 * param: uid Object ID for person.
753 * return: UserAttribute object, or NULL if not found. Note that object should still be freed.
755 UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) {
756 UserAttribute *attrib = NULL;
759 if( aid == NULL || *aid == '\0' ) return NULL;
761 person = addrcache_get_person( cache, uid );
763 attrib = addritem_person_remove_attrib_id( person, aid );
764 cache->dirtyFlag = TRUE;
770 * Remove attribute from person.
771 * param: person Person.
772 * attrib Attribute to remove.
773 * return: UserAttribute object. Note that object should still be freed.
775 UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) {
776 UserAttribute *found = NULL;
778 g_return_val_if_fail( cache != NULL, NULL );
780 if( person && attrib ) {
781 found = addritem_person_remove_attribute( person, attrib );
782 cache->dirtyFlag = TRUE;
788 * Remove group from address cache.
789 * param: group Group to remove.
790 * return: Group, or NULL if not found. Note that object should still be freed.
792 ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
793 AddrItemObject *obj = NULL;
795 g_return_val_if_fail( cache != NULL, NULL );
798 gchar *uid = ADDRITEM_ID(group);
799 if( uid == NULL || *uid == '\0' ) return NULL;
800 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
802 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
803 if( ! parent ) parent = cache->rootFolder;
805 /* Remove group from parent's list and hash table */
806 parent->listGroup = g_list_remove( parent->listGroup, obj );
807 g_hash_table_remove( cache->itemHash, uid );
808 cache->dirtyFlag = TRUE;
816 * Remove specified email from address cache. Note that object is only
817 * removed from cache and not parent objects.
818 * param: email EMail to remove.
819 * return: EMail, or NULL if not found. Note that object should still be freed.
821 ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
822 AddrItemObject *obj = NULL;
824 g_return_val_if_fail( cache != NULL, NULL );
827 gchar *eid = ADDRITEM_ID(email);
828 if( eid == NULL || *eid == '\0' ) return NULL;
829 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
831 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
832 /* Remove email addresses from hash table. */
833 g_hash_table_remove( cache->itemHash, eid );
834 cache->dirtyFlag = TRUE;
843 * Hash table visitor function to remove email from group.
845 static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
846 AddrItemObject *obj = ( AddrItemObject * ) value;
847 ItemEMail *email = ( ItemEMail * ) data;
849 if( ! email ) return;
850 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
851 ItemGroup *group = ( ItemGroup * ) value;
853 /* Remove each email address that belongs to the person from the list */
854 group->listEMail = g_list_remove( group->listEMail, email );
860 * Remove specified person from address cache.
861 * param: person Person to remove.
862 * return: Person, or NULL if not found. Note that object should still be freed.
864 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
865 AddrItemObject *obj = NULL;
868 g_return_val_if_fail( cache != NULL, NULL );
871 uid = ADDRITEM_ID(person);
872 if( uid == NULL || *uid == '\0' ) return NULL;
873 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
875 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
879 /* Remove all email addresses for person */
880 /* from groups and from hash table */
881 node = person->listEMail;
887 g_hash_table_foreach( cache->itemHash,
888 addrcache_allgrp_rem_email_vis, email );
889 eid = ADDRITEM_ID( email );
890 g_hash_table_remove( cache->itemHash, eid );
891 node = g_list_next( node );
894 /* Remove person from owning folder */
895 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
896 if( ! parent ) parent = cache->rootFolder;
897 parent->listPerson = g_list_remove( parent->listPerson, person );
898 g_hash_table_remove( cache->itemHash, uid );
899 cache->dirtyFlag = TRUE;
908 * Remove email address in address cache for specified person.
909 * param: person Person.
910 * email EMail to remove.
911 * return: EMail object, or NULL if not found. Note that object should still be freed.
913 ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
914 ItemEMail *found = NULL;
916 g_return_val_if_fail( cache != NULL, NULL );
918 if( person && email ) {
919 found = addritem_person_remove_email( person, email );
921 /* Remove email from all groups. */
922 g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
924 /* Remove email from person's address list */
925 if( person->listEMail ) {
926 person->listEMail = g_list_remove( person->listEMail, email );
928 /* Unlink reference to person. */
929 ADDRITEM_PARENT(email) = NULL;
930 cache->dirtyFlag = TRUE;
937 * Move email address in address cache to new person. If member of group, address
939 * param: cache Cache.
940 * email EMail to remove.
941 * target Target person.
942 * return: EMail object, or NULL if not found. Note that object should still be freed.
944 void addrcache_person_move_email(
945 AddressCache *cache, ItemEMail *email, ItemPerson *target )
949 g_return_if_fail( cache != NULL );
951 if( email == NULL ) return;
952 if( target == NULL ) return;
954 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
957 found = addritem_person_remove_email( person, email );
960 if( person->listEMail ) {
961 person->listEMail = g_list_remove( person->listEMail, found );
962 addritem_person_add_email( target, found );
963 cache->dirtyFlag = TRUE;
966 addritem_person_add_email( target, found );
967 cache->dirtyFlag = TRUE;
973 * Return link list of address items for root level folder. Note that the list contains
974 * references to items and should be g_free() when done. Do *NOT* attempt to use the
975 * addrcache_free_xxx() functions... this will destroy the address cache data!
976 * Return: List of items, or NULL if none.
978 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
981 ItemFolder *f = folder;
983 g_return_val_if_fail( cache != NULL, NULL );
985 if( ! f ) f = cache->rootFolder;
986 node = f->listPerson;
988 list = g_list_append( list, node->data );
989 node = g_list_next( node );
993 list = g_list_append( list, node->data );
994 node = g_list_next( node );
1000 * Return link list of persons for specified folder. Note that the list contains
1001 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1002 * addrcache_free_xxx() functions... this will destroy the address cache data!
1003 * Return: List of items, or NULL if none.
1005 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1006 ItemFolder *f = folder;
1008 g_return_val_if_fail( cache != NULL, NULL );
1010 if( ! f ) f = cache->rootFolder;
1011 return addritem_folder_get_person_list( f );
1015 * Return link list of group items for specified folder. Note that the list contains
1016 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1017 * addrcache_free_xxx() functions... this will destroy the address cache data!
1018 * Return: List of items, or NULL if none.
1020 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1021 ItemFolder *f = folder;
1023 g_return_val_if_fail( cache != NULL, NULL );
1025 if( ! f ) f = cache->rootFolder;
1026 return addritem_folder_get_group_list( f );
1030 * Return link list of folder items for specified folder. Note that the list contains
1031 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1032 * addrcache_free_xxx() functions... this will destroy the address cache data!
1033 * Return: List of items, or NULL if none.
1035 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1038 ItemFolder *f = folder;
1040 g_return_val_if_fail( cache != NULL, NULL );
1042 if( ! f ) f = cache->rootFolder;
1043 node = f->listFolder;
1045 list = g_list_append( list, node->data );
1046 node = g_list_next( node );
1052 * Return link list of address items for root level folder. Note that the list contains
1053 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1054 * addrcache_free_xxx() functions... this will destroy the address cache data!
1055 * Return: List of items, or NULL if none.
1057 GList *addrcache_get_address_list( AddressCache *cache ) {
1058 g_return_val_if_fail( cache != NULL, NULL );
1059 return addrcache_folder_get_address_list( cache, cache->rootFolder );
1063 * Return link list of persons for root level folder. Note that the list contains
1064 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1065 * addrcache_free_xxx() functions... this will destroy the address cache data!
1066 * Return: List of items, or NULL if none.
1068 GList *addrcache_get_person_list( AddressCache *cache ) {
1069 g_return_val_if_fail( cache != NULL, NULL );
1070 return addritem_folder_get_person_list( cache->rootFolder );
1074 * Return link list of group items in root level folder. Note that the list contains
1075 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1076 * addrcache_free_xxx() functions... this will destroy the address cache data!
1077 * Return: List of items, or NULL if none.
1079 GList *addrcache_get_group_list( AddressCache *cache ) {
1080 g_return_val_if_fail( cache != NULL, NULL );
1081 return cache->rootFolder->listGroup;
1085 * Return link list of folder items in root level folder. Note that the list contains
1086 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1087 * addrcache_free_xxx() functions... this will destroy the address cache data!
1088 * Return: List of items, or NULL if none.
1090 GList *addrcache_get_folder_list( AddressCache *cache ) {
1091 g_return_val_if_fail( cache != NULL, NULL );
1092 return cache->rootFolder->listFolder;
1096 * Group visitor function.
1098 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1099 AddrItemObject *obj = ( AddrItemObject * ) value;
1101 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1102 AddressCache *cache = data;
1103 ItemGroup *group = ( ItemGroup * ) obj;
1104 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1105 GList *node = group->listEMail;
1107 ItemEMail *email = ( ItemEMail * ) node->data;
1108 if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1109 if( ! g_list_find( cache->tempList, group ) ) {
1110 cache->tempList = g_list_append( cache->tempList, group );
1113 node = g_list_next( node );
1119 * Return linked list of groups which contain a reference to specified person's email
1122 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1125 g_return_val_if_fail( cache != NULL, NULL );
1127 cache->tempList = NULL;
1128 cache->tempList = g_list_append( cache->tempList, person );
1129 g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1130 cache->tempList = g_list_remove( cache->tempList, person );
1131 list = cache->tempList;
1132 cache->tempList = NULL;
1137 * Find root folder for specified folder.
1138 * Enter: folder Folder to search.
1139 * Return: root folder, or NULL if not found.
1141 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1142 ItemFolder *item = folder;
1146 if( item->isRoot ) break;
1147 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1151 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1157 * Get all person visitor function.
1159 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1160 AddrItemObject *obj = ( AddrItemObject * ) value;
1162 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1163 AddressCache *cache = data;
1164 cache->tempList = g_list_append( cache->tempList, obj );
1169 * Return link list of all persons in address cache. Note that the list contains
1170 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1171 * this will destroy the address cache data!
1172 * Return: List of items, or NULL if none.
1174 GList *addrcache_get_all_persons( AddressCache *cache ) {
1177 g_return_val_if_fail( cache != NULL, NULL );
1179 cache->tempList = NULL;
1180 g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1181 list = cache->tempList;
1182 cache->tempList = NULL;
1187 * Get all groups visitor function.
1189 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1190 AddrItemObject *obj = ( AddrItemObject * ) value;
1192 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1193 AddressCache *cache = data;
1194 cache->tempList = g_list_append( cache->tempList, obj );
1199 * Return link list of all groups in address cache. Note that the list contains
1200 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1201 * this will destroy the address cache data!
1202 * Return: List of items, or NULL if none.
1204 GList *addrcache_get_all_groups( AddressCache *cache ) {
1207 g_return_val_if_fail( cache != NULL, NULL );
1209 cache->tempList = NULL;
1210 g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1211 list = cache->tempList;
1212 cache->tempList = NULL;
1217 * Remove folder from cache. Children are re-parented to parent folder.
1218 * param: folder Folder to remove.
1219 * return: Folder, or NULL if not found. Note that object should still be freed.
1221 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1222 AddrItemObject *obj = NULL;
1224 g_return_val_if_fail( cache != NULL, NULL );
1227 gchar *uid = ADDRITEM_ID(folder);
1228 if( uid == NULL || *uid == '\0' ) return NULL;
1229 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1231 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1233 AddrItemObject *aio;
1234 if( ! parent ) parent = cache->rootFolder;
1236 /* Re-parent children in folder */
1237 node = folder->listFolder;
1239 aio = ( AddrItemObject * ) node->data;
1240 parent->listFolder = g_list_append( parent->listFolder, aio );
1241 aio->parent = ADDRITEM_OBJECT(parent);
1242 node = g_list_next( node );
1244 node = folder->listPerson;
1246 aio = ( AddrItemObject * ) node->data;
1247 parent->listPerson = g_list_append( parent->listPerson, aio );
1248 aio->parent = ADDRITEM_OBJECT(parent);
1249 node = g_list_next( node );
1251 node = folder->listGroup;
1253 aio = ( AddrItemObject * ) node->data;
1254 parent->listGroup = g_list_append( parent->listGroup, aio );
1255 aio->parent = ADDRITEM_OBJECT(parent);
1256 node = g_list_next( node );
1259 /* Remove folder from parent's list and hash table */
1260 parent->listFolder = g_list_remove( parent->listFolder, folder );
1261 ADDRITEM_PARENT(folder) = NULL;
1262 g_hash_table_remove( cache->itemHash, uid );
1263 cache->dirtyFlag = TRUE;
1271 * Remove folder from cache. Children are deleted.
1272 * param: folder Folder to remove.
1273 * return: Folder, or NULL if not found. Note that object should still be freed.
1275 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1276 AddrItemObject *obj = NULL;
1278 g_return_val_if_fail( cache != NULL, NULL );
1281 gchar *uid = ADDRITEM_ID(folder);
1282 if( uid == NULL || *uid == '\0' ) return NULL;
1283 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1285 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1286 if( ! parent ) parent = cache->rootFolder;
1289 while( folder->listGroup ) {
1290 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1291 item = addrcache_remove_group( cache, item );
1293 addritem_free_item_group( item );
1298 while( folder->listPerson ) {
1299 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1300 item = addrcache_remove_person( cache, item );
1302 addritem_free_item_person( item );
1307 /* Recursive deletion of folder */
1308 while( folder->listFolder ) {
1309 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1310 item = addrcache_remove_folder_delete( cache, item );
1312 addritem_free_item_folder( item );
1317 /* Remove folder from parent's list and hash table */
1318 parent->listFolder = g_list_remove( parent->listFolder, folder );
1319 ADDRITEM_PARENT(folder) = NULL;
1320 g_hash_table_remove( cache->itemHash, uid );
1321 cache->dirtyFlag = TRUE;
1329 * Add person and address data to cache.
1330 * \param cache Cache.
1331 * \param folder Folder where to add person, or NULL for root folder.
1332 * \param name Common name.
1333 * \param address EMail address.
1334 * \param remarks Remarks.
1335 * \return Person added. Do not *NOT* to use the
1336 * <code>addrbook_free_xxx()</code> functions...; this will destroy
1337 * the address book data.
1339 ItemPerson *addrcache_add_contact(
1340 AddressCache *cache, ItemFolder *folder, const gchar *name,
1341 const gchar *address, const gchar *remarks )
1343 ItemPerson *person = NULL;
1344 ItemEMail *email = NULL;
1345 ItemFolder *f = folder;
1347 g_return_val_if_fail( cache != NULL, NULL );
1349 if( ! f ) f = cache->rootFolder;
1351 /* Create person object */
1352 person = addritem_create_item_person();
1353 addritem_person_set_common_name( person, name );
1354 addrcache_id_person( cache, person );
1355 addrcache_folder_add_person( cache, f, person );
1357 /* Create email object */
1358 email = addritem_create_item_email();
1359 addritem_email_set_address( email, address );
1360 addritem_email_set_remarks( email, remarks );
1361 addrcache_id_email( cache, email );
1362 addritem_person_add_email( person, email );
1363 cache->dirtyFlag = TRUE;
1369 * Create a new folder and add to address cache.
1370 * \param cache Address cache.
1371 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1373 * \return Folder that was created. This should <b>*NOT*</b> be
1374 * <code>g_free()</code> when done.
1376 ItemFolder *addrcache_add_new_folder( AddressCache *cache, ItemFolder *parent )
1379 ItemFolder *p = parent;
1381 g_return_val_if_fail( cache != NULL, NULL );
1383 if( !p ) p = cache->rootFolder;
1384 folder = addritem_create_item_folder();
1385 addrcache_id_folder( cache, folder );
1386 if( addrcache_hash_add_folder( cache, folder ) ) {
1387 p->listFolder = g_list_append( p->listFolder, folder );
1388 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1389 addrcache_set_dirty( cache, TRUE );
1392 addritem_free_item_folder( folder );