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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Functions to maintain address cache.
29 #include "addrcache.h"
31 #define ID_TIME_OFFSET 998000000
32 #define ADDRCACHE_MAX_SEARCH_COUNT 1000
34 static int _nextCacheID__ = 0;
37 * Generate next cache ID.
39 static int addrcache_next_cache_id() {
42 if( _nextCacheID__ == 0 ) {
45 retVal = _nextCacheID__;
51 * Create new address cache.
53 AddressCache *addrcache_create() {
57 cache = g_new0( AddressCache, 1 );
58 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
59 cache->cacheID = g_strdup_printf( "%d", addrcache_next_cache_id() );
61 cache->dataRead = FALSE;
62 cache->modified = FALSE;
63 cache->dirtyFlag = FALSE;
64 cache->accessFlag = FALSE;
66 cache->modifyTime = 0;
68 /* Generate the next ID using system time */
72 cache->nextID = t - ID_TIME_OFFSET;
75 cache->tempList = NULL;
76 cache->rootFolder = addritem_create_item_folder();
77 cache->rootFolder->isRoot = TRUE;
78 ADDRITEM_PARENT(cache->rootFolder) = NULL;
85 ItemFolder *addrcache_get_root_folder( AddressCache *cache ) {
86 g_return_val_if_fail( cache != NULL, NULL );
87 return cache->rootFolder;
89 GList *addrcache_get_list_folder( AddressCache *cache ) {
90 g_return_val_if_fail( cache != NULL, NULL );
91 return cache->rootFolder->listFolder;
93 GList *addrcache_get_list_person( AddressCache *cache ) {
94 g_return_val_if_fail( cache != NULL, NULL );
95 return cache->rootFolder->listPerson;
97 gboolean addrcache_get_dirty( AddressCache *cache ) {
98 g_return_val_if_fail( cache != NULL, FALSE );
99 return cache->dirtyFlag;
101 void addrcache_set_dirty( AddressCache *cache, const gboolean value ) {
102 g_return_if_fail( cache != NULL );
103 cache->dirtyFlag = value;
105 gboolean addrcache_get_modified( AddressCache *cache ) {
106 g_return_val_if_fail( cache != NULL, FALSE );
107 return cache->modified;
109 void addrcache_set_modified( AddressCache *cache, const gboolean value ) {
110 g_return_if_fail( cache != NULL );
111 cache->modified = value;
113 gboolean addrcache_get_read_flag( AddressCache *cache ) {
114 g_return_val_if_fail( cache != NULL, FALSE );
115 return cache->dataRead;
117 void addrcache_set_read_flag( AddressCache *cache, const gboolean value ) {
118 g_return_if_fail( cache != NULL );
119 cache->dataRead = value;
121 gboolean addrcache_get_accessed( AddressCache *cache ) {
122 g_return_val_if_fail( cache != NULL, FALSE );
123 return cache->accessFlag;
125 void addrcache_set_accessed( AddressCache *cache, const gboolean value ) {
126 g_return_if_fail( cache != NULL );
127 cache->accessFlag = value;
129 gchar *addrcache_get_name( AddressCache *cache ) {
130 g_return_val_if_fail( cache != NULL, NULL );
133 void addrcache_set_name( AddressCache *cache, const gchar *value ) {
134 g_return_if_fail( cache != NULL );
135 cache->name = mgu_replace_string( cache->name, value );
136 g_strstrip( cache->name );
137 cache->dirtyFlag = TRUE;
143 void addrcache_next_id( AddressCache *cache ) {
144 g_return_if_fail( cache != NULL );
149 * Refresh internal variables. This can be used force a reload.
151 void addrcache_refresh( AddressCache *cache ) {
152 cache->dataRead = FALSE;
153 cache->modified = TRUE;
154 cache->accessFlag = FALSE;
155 cache->modifyTime = 0;
159 * Free hash table visitor function.
161 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
162 AddrItemObject *obj = ( AddrItemObject * ) value;
164 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
165 addritem_free_item_person( ( ItemPerson * ) obj );
167 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
168 addritem_free_item_email( ( ItemEMail * ) obj );
170 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
171 addritem_free_item_group( ( ItemGroup * ) obj );
173 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
174 addritem_free_item_folder( ( ItemFolder * ) obj );
182 * Free hash table of address cache items.
184 static void addrcache_free_item_hash( GHashTable *table ) {
185 g_return_if_fail( table != NULL );
186 g_hash_table_freeze( table );
187 g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
188 g_hash_table_thaw( table );
192 * Free up folders and groups.
194 static void addrcache_free_all_folders( ItemFolder *parent ) {
197 if( parent == NULL ) return;
199 node = parent->listFolder;
201 ItemFolder *folder = node->data;
202 addrcache_free_all_folders( folder );
204 node = g_list_next( node );
206 g_list_free( parent->listPerson );
207 g_list_free( parent->listGroup );
208 g_list_free( parent->listFolder );
209 parent->listPerson = NULL;
210 parent->listGroup = NULL;
211 parent->listFolder = NULL;
215 * Clear the address cache.
217 void addrcache_clear( AddressCache *cache ) {
218 g_return_if_fail( cache != NULL );
220 /* printf( "...addrcache_clear :%s:\n", cache->name ); */
221 /* Free up folders and hash table */
222 addrcache_free_all_folders( cache->rootFolder );
223 addrcache_free_item_hash( cache->itemHash );
224 g_hash_table_destroy( cache->itemHash );
225 cache->itemHash = NULL;
226 ADDRITEM_PARENT(cache->rootFolder) = NULL;
227 addritem_free_item_folder( cache->rootFolder );
228 cache->rootFolder = NULL;
229 if( cache->tempList ) g_list_free( cache->tempList );
230 cache->tempList = NULL;
232 /* Reset to initial state */
233 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
234 cache->rootFolder = addritem_create_item_folder();
235 cache->rootFolder->isRoot = TRUE;
236 ADDRITEM_PARENT(cache->rootFolder) = NULL;
238 addrcache_refresh( cache );
242 * Free address cache.
244 void addrcache_free( AddressCache *cache ) {
245 g_return_if_fail( cache != NULL );
247 cache->dirtyFlag = FALSE;
248 addrcache_free_all_folders( cache->rootFolder );
249 addrcache_free_item_hash( cache->itemHash );
250 g_hash_table_destroy( cache->itemHash );
251 cache->itemHash = NULL;
252 ADDRITEM_PARENT(cache->rootFolder) = NULL;
253 addritem_free_item_folder( cache->rootFolder );
254 cache->rootFolder = NULL;
255 g_list_free( cache->tempList );
256 cache->tempList = NULL;
257 g_free( cache->cacheID );
258 cache->cacheID = NULL;
259 g_free( cache->name );
265 * Check whether file has changed by comparing with cache.
266 * return: TRUE if file has changed.
268 gboolean addrcache_check_file( AddressCache *cache, gchar *path ) {
270 struct stat filestat;
273 if( 0 == lstat( path, &filestat ) ) {
274 if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
281 * Save file time to cache.
282 * return: TRUE if time marked.
284 gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) {
285 gboolean retVal = FALSE;
286 struct stat filestat;
288 if( 0 == lstat( path, &filestat ) ) {
289 cache->modifyTime = filestat.st_mtime;
297 * Print list of items.
299 void addrcache_print_item_list( GList *list, FILE *stream ) {
302 AddrItemObject *obj = node->data;
303 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
304 addritem_print_item_person( ( ItemPerson * ) obj, stream );
306 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
307 addritem_print_item_group( ( ItemGroup * ) obj, stream );
309 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
310 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
312 node = g_list_next( node );
314 fprintf( stream, "\t---\n" );
318 * Print item hash table visitor function.
320 static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) {
321 AddrItemObject *obj = ( AddrItemObject * ) value;
322 FILE *stream = ( FILE * ) data;
323 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
324 addritem_print_item_person( ( ItemPerson * ) obj, stream );
326 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
327 printf( "addrcache: print email\n" );
329 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
330 addritem_print_item_group( ( ItemGroup * ) obj, stream );
332 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
333 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
338 * Dump entire address cache hash table contents.
340 void addrcache_print( AddressCache *cache, FILE *stream ) {
341 g_return_if_fail( cache != NULL );
342 fprintf( stream, "AddressCache:\n" );
343 fprintf( stream, "cache id : %s\n", cache->cacheID );
344 fprintf( stream, "next id : %d\n", cache->nextID );
345 fprintf( stream, "name : %s\n", cache->name );
346 fprintf( stream, "mod time : %ld\n", cache->modifyTime );
347 fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" );
348 fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" );
352 * Dump entire address cache hash table contents.
354 void addrcache_dump_hash( AddressCache *cache, FILE *stream ) {
355 g_return_if_fail( cache != NULL );
356 addrcache_print( cache, stream );
357 g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream );
361 * Allocate ID for person.
363 void addrcache_id_person( AddressCache *cache, ItemPerson *person ) {
364 g_return_if_fail( cache != NULL );
365 g_return_if_fail( person != NULL );
366 if( ADDRITEM_ID(person) ) return;
367 addrcache_next_id( cache );
368 ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID );
372 * Allocate ID for group.
374 void addrcache_id_group( AddressCache *cache, ItemGroup *group ) {
375 g_return_if_fail( cache != NULL );
376 g_return_if_fail( group != NULL );
377 if( ADDRITEM_ID(group) ) return;
378 addrcache_next_id( cache );
379 ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID );
383 * Allocate ID for folder.
385 void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) {
386 g_return_if_fail( cache != NULL );
387 g_return_if_fail( folder != NULL );
388 if( ADDRITEM_ID(folder) ) return;
389 addrcache_next_id( cache );
390 ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID );
394 * Allocate ID for email address.
396 void addrcache_id_email( AddressCache *cache, ItemEMail *email ) {
397 g_return_if_fail( cache != NULL );
398 g_return_if_fail( email != NULL );
399 if( ADDRITEM_ID(email) ) return;
400 addrcache_next_id( cache );
401 ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID );
405 * Allocate ID for user attribute.
407 void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) {
408 g_return_if_fail( cache != NULL );
409 g_return_if_fail( attrib != NULL );
410 if( attrib->uid ) return;
411 addrcache_next_id( cache );
412 attrib->uid = g_strdup_printf( "%d", cache->nextID );
416 * Add person to hash table.
417 * return: TRUE if item added.
419 gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
420 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) {
423 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person );
428 * Add email to hash table.
429 * return: TRUE if item added.
431 gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
432 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
435 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
440 * Add group to hash table.
441 * return: TRUE if item added.
443 gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) {
444 g_return_val_if_fail( cache != NULL, FALSE );
445 g_return_val_if_fail( group != NULL, FALSE );
447 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) {
450 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group );
455 * Add folder to hash table.
456 * return: TRUE if item added.
458 gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) {
459 g_return_val_if_fail( cache != NULL, FALSE );
460 g_return_val_if_fail( folder != NULL, FALSE );
462 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) {
465 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder );
470 * Add person to specified folder in cache.
472 gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) {
473 gboolean retVal = FALSE;
475 g_return_val_if_fail( cache != NULL, FALSE );
476 g_return_val_if_fail( folder != NULL, FALSE );
477 g_return_val_if_fail( item != NULL, FALSE );
479 retVal = addrcache_hash_add_person( cache, item );
481 addritem_folder_add_person( folder, item );
482 cache->dirtyFlag = TRUE;
488 * Add folder to specified folder in cache.
490 gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) {
491 gboolean retVal = FALSE;
493 g_return_val_if_fail( cache != NULL, FALSE );
494 g_return_val_if_fail( folder != NULL, FALSE );
495 g_return_val_if_fail( item != NULL, FALSE );
497 retVal = addrcache_hash_add_folder( cache, item );
499 addritem_folder_add_folder( folder, item );
500 cache->dirtyFlag = TRUE;
506 * Add folder to specified folder in cache.
508 gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) {
509 gboolean retVal = FALSE;
511 g_return_val_if_fail( cache != NULL, FALSE );
512 g_return_val_if_fail( folder != NULL, FALSE );
513 g_return_val_if_fail( item != NULL, FALSE );
515 retVal = addrcache_hash_add_group( cache, item );
517 addritem_folder_add_group( folder, item );
518 cache->dirtyFlag = TRUE;
524 * Add person to address cache.
525 * return: TRUE if item added.
527 gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
528 gboolean retVal = FALSE;
530 g_return_val_if_fail( cache != NULL, FALSE );
531 g_return_val_if_fail( person != NULL, FALSE );
533 retVal = addrcache_hash_add_person( cache, person );
535 addritem_folder_add_person( cache->rootFolder, person );
536 cache->dirtyFlag = TRUE;
542 * Add EMail address to person.
543 * return: TRUE if item added.
545 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
546 gboolean retVal = FALSE;
548 g_return_val_if_fail( cache != NULL, FALSE );
549 g_return_val_if_fail( person != NULL, FALSE );
550 g_return_val_if_fail( email != NULL, FALSE );
552 retVal = addrcache_hash_add_email( cache, email );
554 addritem_person_add_email( person, email );
555 cache->dirtyFlag = TRUE;
561 * Add group to address cache.
562 * return: TRUE if item added.
564 gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
565 gboolean retVal = FALSE;
567 g_return_val_if_fail( cache != NULL, FALSE );
568 g_return_val_if_fail( group != NULL, FALSE );
570 retVal = addrcache_hash_add_group( cache, group );
572 addritem_folder_add_group( cache->rootFolder, group );
573 cache->dirtyFlag = TRUE;
579 * Add EMail address to person.
580 * return: TRUE if item added.
582 gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) {
583 g_return_val_if_fail( cache != NULL, FALSE );
584 g_return_val_if_fail( group != NULL, FALSE );
585 g_return_val_if_fail( email != NULL, FALSE );
587 addritem_group_add_email( group, email );
588 cache->dirtyFlag = TRUE;
593 * Add folder to address cache.
594 * return: TRUE if item added.
596 gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
597 gboolean retVal = FALSE;
599 g_return_val_if_fail( cache != NULL, FALSE );
600 g_return_val_if_fail( folder != NULL, FALSE );
602 retVal = addrcache_hash_add_folder( cache, folder );
604 addritem_folder_add_folder( cache->rootFolder, folder );
605 cache->dirtyFlag = TRUE;
611 * Move person to destination folder.
612 * Enter: cache Cache.
613 * person Person to move.
614 * target Target folder.
616 void addrcache_folder_move_person(
617 AddressCache *cache, ItemPerson *person, ItemFolder *target )
621 g_return_if_fail( cache != NULL );
622 g_return_if_fail( person != NULL );
624 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
625 if( ! parent ) parent = cache->rootFolder;
626 parent->listPerson = g_list_remove( parent->listPerson, person );
627 target->listPerson = g_list_append( target->listPerson, person );
628 ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
629 cache->dirtyFlag = TRUE;
633 * Move group to destination folder.
634 * Enter: cache Cache.
635 * group Group to move.
636 * target Target folder.
638 void addrcache_folder_move_group(
639 AddressCache *cache, ItemGroup *group, ItemFolder *target )
643 g_return_if_fail( cache != NULL );
644 g_return_if_fail( group != NULL );
646 parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
647 if( ! parent ) parent = cache->rootFolder;
648 parent->listGroup = g_list_remove( parent->listGroup, group );
649 target->listGroup = g_list_append( target->listGroup, group );
650 ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
651 cache->dirtyFlag = TRUE;
655 * Move folder to destination folder.
656 * Enter: cache Cache.
657 * folder Folder to move.
658 * target Target folder.
660 void addrcache_folder_move_folder(
661 AddressCache *cache, ItemFolder *folder, ItemFolder *target )
665 g_return_if_fail( cache != NULL );
666 g_return_if_fail( folder != NULL );
668 parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
669 if( ! parent ) parent = cache->rootFolder;
670 parent->listFolder = g_list_remove( parent->listFolder, folder );
671 target->listFolder = g_list_append( target->listFolder, folder );
672 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
673 cache->dirtyFlag = TRUE;
677 * Return pointer to object (either person or group) for specified ID.
678 * param: uid Object ID.
679 * return: Object, or NULL if not found.
681 AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) {
682 AddrItemObject *obj = NULL;
685 g_return_val_if_fail( cache != NULL, NULL );
687 if( uid == NULL || *uid == '\0' ) return NULL;
688 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
690 /* Check for matching UID */
691 uidH = ADDRITEM_ID(obj);
693 if( strcmp( uidH, uid ) == 0 ) return obj;
700 * Return pointer for specified object ID.
701 * param: uid Object ID.
702 * return: Person object, or NULL if not found.
704 ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) {
705 ItemPerson *person = NULL;
706 AddrItemObject *obj = addrcache_get_object( cache, uid );
709 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
710 person = ( ItemPerson * ) obj;
717 * Return pointer for specified object ID.
718 * param: uid group ID.
719 * return: Group object, or NULL if not found.
721 ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
722 ItemGroup *group = NULL;
723 AddrItemObject *obj = addrcache_get_object( cache, uid );
726 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
727 group = ( ItemGroup * ) obj;
734 * Find email address in address cache.
735 * param: eid EMail ID.
736 * return: email object for specified object ID and email ID, or NULL if not found.
738 ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
739 ItemEMail *email = NULL;
740 AddrItemObject *obj = addrcache_get_object( cache, eid );
743 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
744 email = ( ItemEMail * ) obj;
751 * Remove attribute from person.
752 * param: uid Object ID for person.
754 * return: UserAttribute object, or NULL if not found. Note that object should still be freed.
756 UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) {
757 UserAttribute *attrib = NULL;
760 if( aid == NULL || *aid == '\0' ) return NULL;
762 person = addrcache_get_person( cache, uid );
764 attrib = addritem_person_remove_attrib_id( person, aid );
765 cache->dirtyFlag = TRUE;
771 * Remove attribute from person.
772 * param: person Person.
773 * attrib Attribute to remove.
774 * return: UserAttribute object. Note that object should still be freed.
776 UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) {
777 UserAttribute *found = NULL;
779 g_return_val_if_fail( cache != NULL, NULL );
781 if( person && attrib ) {
782 found = addritem_person_remove_attribute( person, attrib );
783 cache->dirtyFlag = TRUE;
789 * Remove group from address cache.
790 * param: group Group to remove.
791 * return: Group, or NULL if not found. Note that object should still be freed.
793 ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
794 AddrItemObject *obj = NULL;
796 g_return_val_if_fail( cache != NULL, NULL );
799 gchar *uid = ADDRITEM_ID(group);
800 if( uid == NULL || *uid == '\0' ) return NULL;
801 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
803 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
804 if( ! parent ) parent = cache->rootFolder;
806 /* Remove group from parent's list and hash table */
807 parent->listGroup = g_list_remove( parent->listGroup, obj );
808 g_hash_table_remove( cache->itemHash, uid );
809 cache->dirtyFlag = TRUE;
817 * Remove specified email from address cache. Note that object is only
818 * removed from cache and not parent objects.
819 * param: email EMail to remove.
820 * return: EMail, or NULL if not found. Note that object should still be freed.
822 ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
823 AddrItemObject *obj = NULL;
825 g_return_val_if_fail( cache != NULL, NULL );
828 gchar *eid = ADDRITEM_ID(email);
829 if( eid == NULL || *eid == '\0' ) return NULL;
830 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
832 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
833 /* Remove email addresses from hash table. */
834 g_hash_table_remove( cache->itemHash, eid );
835 cache->dirtyFlag = TRUE;
844 * Hash table visitor function to remove email from group.
846 static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
847 AddrItemObject *obj = ( AddrItemObject * ) value;
848 ItemEMail *email = ( ItemEMail * ) data;
850 if( ! email ) return;
851 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
852 ItemGroup *group = ( ItemGroup * ) value;
854 /* Remove each email address that belongs to the person from the list */
855 group->listEMail = g_list_remove( group->listEMail, email );
861 * Remove specified person from address cache.
862 * param: person Person to remove.
863 * return: Person, or NULL if not found. Note that object should still be freed.
865 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
866 AddrItemObject *obj = NULL;
869 g_return_val_if_fail( cache != NULL, NULL );
872 uid = ADDRITEM_ID(person);
873 if( uid == NULL || *uid == '\0' ) return NULL;
874 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
876 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
880 /* Remove all email addresses for person */
881 /* from groups and from hash table */
882 node = person->listEMail;
888 g_hash_table_foreach( cache->itemHash,
889 addrcache_allgrp_rem_email_vis, email );
890 eid = ADDRITEM_ID( email );
891 g_hash_table_remove( cache->itemHash, eid );
892 node = g_list_next( node );
895 /* Remove person from owning folder */
896 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
897 if( ! parent ) parent = cache->rootFolder;
898 parent->listPerson = g_list_remove( parent->listPerson, person );
899 g_hash_table_remove( cache->itemHash, uid );
900 cache->dirtyFlag = TRUE;
909 * Remove email address in address cache for specified person.
910 * param: person Person.
911 * email EMail to remove.
912 * return: EMail object, or NULL if not found. Note that object should still be freed.
914 ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
915 ItemEMail *found = NULL;
917 g_return_val_if_fail( cache != NULL, NULL );
919 if( person && email ) {
920 found = addritem_person_remove_email( person, email );
922 /* Remove email from all groups. */
923 g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
925 /* Remove email from person's address list */
926 if( person->listEMail ) {
927 person->listEMail = g_list_remove( person->listEMail, email );
929 /* Unlink reference to person. */
930 ADDRITEM_PARENT(email) = NULL;
931 cache->dirtyFlag = TRUE;
938 * Move email address in address cache to new person. If member of group, address
940 * param: cache Cache.
941 * email EMail to remove.
942 * target Target person.
943 * return: EMail object, or NULL if not found. Note that object should still be freed.
945 void addrcache_person_move_email(
946 AddressCache *cache, ItemEMail *email, ItemPerson *target )
950 g_return_if_fail( cache != NULL );
952 if( email == NULL ) return;
953 if( target == NULL ) return;
955 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
958 found = addritem_person_remove_email( person, email );
961 if( person->listEMail ) {
962 person->listEMail = g_list_remove( person->listEMail, found );
963 addritem_person_add_email( target, found );
964 cache->dirtyFlag = TRUE;
967 addritem_person_add_email( target, found );
968 cache->dirtyFlag = TRUE;
974 * Return link list of address items for root level folder. Note that the list contains
975 * references to items and should be g_free() when done. Do *NOT* attempt to use the
976 * addrcache_free_xxx() functions... this will destroy the address cache data!
977 * Return: List of items, or NULL if none.
979 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
982 ItemFolder *f = folder;
984 g_return_val_if_fail( cache != NULL, NULL );
986 if( ! f ) f = cache->rootFolder;
987 node = f->listPerson;
989 list = g_list_append( list, node->data );
990 node = g_list_next( node );
994 list = g_list_append( list, node->data );
995 node = g_list_next( node );
1001 * Return link list of persons for specified folder. Note that the list contains
1002 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1003 * addrcache_free_xxx() functions... this will destroy the address cache data!
1004 * Return: List of items, or NULL if none.
1006 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1007 ItemFolder *f = folder;
1009 g_return_val_if_fail( cache != NULL, NULL );
1011 if( ! f ) f = cache->rootFolder;
1012 return addritem_folder_get_person_list( f );
1016 * Return link list of group items for specified folder. Note that the list contains
1017 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1018 * addrcache_free_xxx() functions... this will destroy the address cache data!
1019 * Return: List of items, or NULL if none.
1021 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1022 ItemFolder *f = folder;
1024 g_return_val_if_fail( cache != NULL, NULL );
1026 if( ! f ) f = cache->rootFolder;
1027 return addritem_folder_get_group_list( f );
1031 * Return link list of folder items for specified folder. Note that the list contains
1032 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1033 * addrcache_free_xxx() functions... this will destroy the address cache data!
1034 * Return: List of items, or NULL if none.
1036 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1039 ItemFolder *f = folder;
1041 g_return_val_if_fail( cache != NULL, NULL );
1043 if( ! f ) f = cache->rootFolder;
1044 node = f->listFolder;
1046 list = g_list_append( list, node->data );
1047 node = g_list_next( node );
1053 * Return link list of address items for root level folder. Note that the list contains
1054 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1055 * addrcache_free_xxx() functions... this will destroy the address cache data!
1056 * Return: List of items, or NULL if none.
1058 GList *addrcache_get_address_list( AddressCache *cache ) {
1059 g_return_val_if_fail( cache != NULL, NULL );
1060 return addrcache_folder_get_address_list( cache, cache->rootFolder );
1064 * Return link list of persons for root level folder. Note that the list contains
1065 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1066 * addrcache_free_xxx() functions... this will destroy the address cache data!
1067 * Return: List of items, or NULL if none.
1069 GList *addrcache_get_person_list( AddressCache *cache ) {
1070 g_return_val_if_fail( cache != NULL, NULL );
1071 return addritem_folder_get_person_list( cache->rootFolder );
1075 * Return link list of group items in root level folder. Note that the list contains
1076 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1077 * addrcache_free_xxx() functions... this will destroy the address cache data!
1078 * Return: List of items, or NULL if none.
1080 GList *addrcache_get_group_list( AddressCache *cache ) {
1081 g_return_val_if_fail( cache != NULL, NULL );
1082 return cache->rootFolder->listGroup;
1086 * Return link list of folder items in root level folder. Note that the list contains
1087 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1088 * addrcache_free_xxx() functions... this will destroy the address cache data!
1089 * Return: List of items, or NULL if none.
1091 GList *addrcache_get_folder_list( AddressCache *cache ) {
1092 g_return_val_if_fail( cache != NULL, NULL );
1093 return cache->rootFolder->listFolder;
1097 * Group visitor function.
1099 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1100 AddrItemObject *obj = ( AddrItemObject * ) value;
1102 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1103 AddressCache *cache = data;
1104 ItemGroup *group = ( ItemGroup * ) obj;
1105 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1106 GList *node = group->listEMail;
1108 ItemEMail *email = ( ItemEMail * ) node->data;
1109 if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1110 if( ! g_list_find( cache->tempList, group ) ) {
1111 cache->tempList = g_list_append( cache->tempList, group );
1114 node = g_list_next( node );
1120 * Return linked list of groups which contain a reference to specified person's email
1123 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1126 g_return_val_if_fail( cache != NULL, NULL );
1128 cache->tempList = NULL;
1129 cache->tempList = g_list_append( cache->tempList, person );
1130 g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1131 cache->tempList = g_list_remove( cache->tempList, person );
1132 list = cache->tempList;
1133 cache->tempList = NULL;
1138 * Find root folder for specified folder.
1139 * Enter: folder Folder to search.
1140 * Return: root folder, or NULL if not found.
1142 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1143 ItemFolder *item = folder;
1147 if( item->isRoot ) break;
1148 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1152 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1158 * Get all person visitor function.
1160 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1161 AddrItemObject *obj = ( AddrItemObject * ) value;
1163 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1164 AddressCache *cache = data;
1165 cache->tempList = g_list_append( cache->tempList, obj );
1170 * Return link list of all persons in address cache. Note that the list contains
1171 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1172 * this will destroy the address cache data!
1173 * Return: List of items, or NULL if none.
1175 GList *addrcache_get_all_persons( AddressCache *cache ) {
1178 g_return_val_if_fail( cache != NULL, NULL );
1180 cache->tempList = NULL;
1181 g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1182 list = cache->tempList;
1183 cache->tempList = NULL;
1188 * Get all groups visitor function.
1190 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1191 AddrItemObject *obj = ( AddrItemObject * ) value;
1193 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1194 AddressCache *cache = data;
1195 cache->tempList = g_list_append( cache->tempList, obj );
1200 * Return link list of all groups in address cache. Note that the list contains
1201 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1202 * this will destroy the address cache data!
1203 * Return: List of items, or NULL if none.
1205 GList *addrcache_get_all_groups( AddressCache *cache ) {
1208 g_return_val_if_fail( cache != NULL, NULL );
1210 cache->tempList = NULL;
1211 g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1212 list = cache->tempList;
1213 cache->tempList = NULL;
1218 * Remove folder from cache. Children are re-parented to parent folder.
1219 * param: folder Folder to remove.
1220 * return: Folder, or NULL if not found. Note that object should still be freed.
1222 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1223 AddrItemObject *obj = NULL;
1225 g_return_val_if_fail( cache != NULL, NULL );
1228 gchar *uid = ADDRITEM_ID(folder);
1229 if( uid == NULL || *uid == '\0' ) return NULL;
1230 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1232 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1234 AddrItemObject *aio;
1235 if( ! parent ) parent = cache->rootFolder;
1237 /* Re-parent children in folder */
1238 node = folder->listFolder;
1240 aio = ( AddrItemObject * ) node->data;
1241 parent->listFolder = g_list_append( parent->listFolder, aio );
1242 aio->parent = ADDRITEM_OBJECT(parent);
1243 node = g_list_next( node );
1245 node = folder->listPerson;
1247 aio = ( AddrItemObject * ) node->data;
1248 parent->listPerson = g_list_append( parent->listPerson, aio );
1249 aio->parent = ADDRITEM_OBJECT(parent);
1250 node = g_list_next( node );
1252 node = folder->listGroup;
1254 aio = ( AddrItemObject * ) node->data;
1255 parent->listGroup = g_list_append( parent->listGroup, aio );
1256 aio->parent = ADDRITEM_OBJECT(parent);
1257 node = g_list_next( node );
1260 /* Remove folder from parent's list and hash table */
1261 parent->listFolder = g_list_remove( parent->listFolder, folder );
1262 ADDRITEM_PARENT(folder) = NULL;
1263 g_hash_table_remove( cache->itemHash, uid );
1264 cache->dirtyFlag = TRUE;
1272 * Remove folder from cache. Children are deleted.
1273 * param: folder Folder to remove.
1274 * return: Folder, or NULL if not found. Note that object should still be freed.
1276 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1277 AddrItemObject *obj = NULL;
1279 g_return_val_if_fail( cache != NULL, NULL );
1282 gchar *uid = ADDRITEM_ID(folder);
1283 if( uid == NULL || *uid == '\0' ) return NULL;
1284 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1286 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1287 if( ! parent ) parent = cache->rootFolder;
1290 while( folder->listGroup ) {
1291 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1292 item = addrcache_remove_group( cache, item );
1294 addritem_free_item_group( item );
1299 while( folder->listPerson ) {
1300 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1301 item = addrcache_remove_person( cache, item );
1303 addritem_free_item_person( item );
1308 /* Recursive deletion of folder */
1309 while( folder->listFolder ) {
1310 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1311 item = addrcache_remove_folder_delete( cache, item );
1313 addritem_free_item_folder( item );
1318 /* Remove folder from parent's list and hash table */
1319 parent->listFolder = g_list_remove( parent->listFolder, folder );
1320 ADDRITEM_PARENT(folder) = NULL;
1321 g_hash_table_remove( cache->itemHash, uid );
1322 cache->dirtyFlag = TRUE;
1330 * Add person and address data to cache.
1331 * \param cache Cache.
1332 * \param folder Folder where to add person, or NULL for root folder.
1333 * \param name Common name.
1334 * \param address EMail address.
1335 * \param remarks Remarks.
1336 * \return Person added. Do not *NOT* to use the
1337 * <code>addrbook_free_xxx()</code> functions...; this will destroy
1338 * the address book data.
1340 ItemPerson *addrcache_add_contact(
1341 AddressCache *cache, ItemFolder *folder, const gchar *name,
1342 const gchar *address, const gchar *remarks )
1344 ItemPerson *person = NULL;
1345 ItemEMail *email = NULL;
1346 ItemFolder *f = folder;
1348 g_return_val_if_fail( cache != NULL, NULL );
1350 if( ! f ) f = cache->rootFolder;
1352 /* Create person object */
1353 person = addritem_create_item_person();
1354 addritem_person_set_common_name( person, name );
1355 addrcache_id_person( cache, person );
1356 addrcache_folder_add_person( cache, f, person );
1358 /* Create email object */
1359 email = addritem_create_item_email();
1360 addritem_email_set_address( email, address );
1361 addritem_email_set_remarks( email, remarks );
1362 addrcache_id_email( cache, email );
1363 addritem_person_add_email( person, email );
1364 cache->dirtyFlag = TRUE;
1370 * Create a new folder and add to address cache.
1371 * \param cache Address cache.
1372 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1374 * \return Folder that was created. This should <b>*NOT*</b> be
1375 * <code>g_free()</code> when done.
1377 ItemFolder *addrcache_add_new_folder( AddressCache *cache, ItemFolder *parent )
1380 ItemFolder *p = parent;
1382 g_return_val_if_fail( cache != NULL, NULL );
1384 if( !p ) p = cache->rootFolder;
1385 folder = addritem_create_item_folder();
1386 addrcache_id_folder( cache, folder );
1387 if( addrcache_hash_add_folder( cache, folder ) ) {
1388 p->listFolder = g_list_append( p->listFolder, folder );
1389 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1390 addrcache_set_dirty( cache, TRUE );
1393 addritem_free_item_folder( folder );