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.
30 #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;
164 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
165 /* Free person and their email */
166 addritem_free_item_person( ( ItemPerson * ) obj );
168 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
169 addritem_free_item_group( ( ItemGroup * ) obj );
171 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
172 addritem_free_item_folder( ( ItemFolder * ) obj );
180 * Free hash table of address cache items.
182 static void addrcache_free_item_hash( GHashTable *table ) {
183 g_return_if_fail( table != NULL );
184 g_hash_table_freeze( table );
185 g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
186 g_hash_table_thaw( table );
190 * Free up folders and groups.
192 static void addrcache_free_all_folders( ItemFolder *parent ) {
195 if( parent == NULL ) return;
197 node = parent->listFolder;
199 ItemFolder *folder = node->data;
200 addrcache_free_all_folders( folder );
202 node = g_list_next( node );
204 g_list_free( parent->listPerson );
205 g_list_free( parent->listGroup );
206 g_list_free( parent->listFolder );
207 parent->listPerson = NULL;
208 parent->listGroup = NULL;
209 parent->listFolder = NULL;
213 * Clear the address cache.
215 void addrcache_clear( AddressCache *cache ) {
216 g_return_if_fail( cache != NULL );
218 /* printf( "...addrcache_clear :%s:\n", cache->name ); */
219 /* Free up folders and hash table */
220 addrcache_free_all_folders( cache->rootFolder );
221 addrcache_free_item_hash( cache->itemHash );
222 g_hash_table_destroy( cache->itemHash );
223 cache->itemHash = NULL;
224 ADDRITEM_PARENT(cache->rootFolder) = NULL;
225 addritem_free_item_folder( cache->rootFolder );
226 cache->rootFolder = NULL;
227 if( cache->tempList ) g_list_free( cache->tempList );
228 cache->tempList = NULL;
230 /* Reset to initial state */
231 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
232 cache->rootFolder = addritem_create_item_folder();
233 cache->rootFolder->isRoot = TRUE;
234 ADDRITEM_PARENT(cache->rootFolder) = NULL;
236 addrcache_refresh( cache );
240 * Free address cache.
242 void addrcache_free( AddressCache *cache ) {
243 g_return_if_fail( cache != NULL );
245 cache->dirtyFlag = FALSE;
246 addrcache_free_all_folders( cache->rootFolder );
247 addrcache_free_item_hash( cache->itemHash );
248 g_hash_table_destroy( cache->itemHash );
249 cache->itemHash = NULL;
250 ADDRITEM_PARENT(cache->rootFolder) = NULL;
251 addritem_free_item_folder( cache->rootFolder );
252 cache->rootFolder = NULL;
253 g_list_free( cache->tempList );
254 cache->tempList = NULL;
255 g_free( cache->cacheID );
256 cache->cacheID = NULL;
257 g_free( cache->name );
263 * Check whether file has changed by comparing with cache.
264 * return: TRUE if file has changed.
266 gboolean addrcache_check_file( AddressCache *cache, gchar *path ) {
268 struct stat filestat;
271 if( 0 == lstat( path, &filestat ) ) {
272 if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
279 * Save file time to cache.
280 * return: TRUE if time marked.
282 gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) {
283 gboolean retVal = FALSE;
284 struct stat filestat;
286 if( 0 == lstat( path, &filestat ) ) {
287 cache->modifyTime = filestat.st_mtime;
295 * Print list of items.
297 void addrcache_print_item_list( GList *list, FILE *stream ) {
300 AddrItemObject *obj = node->data;
301 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
302 addritem_print_item_person( ( ItemPerson * ) obj, stream );
304 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
305 addritem_print_item_group( ( ItemGroup * ) obj, stream );
307 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
308 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
310 node = g_list_next( node );
312 fprintf( stream, "\t---\n" );
316 * Print item hash table visitor function.
318 static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) {
319 AddrItemObject *obj = ( AddrItemObject * ) value;
320 FILE *stream = ( FILE * ) data;
321 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
322 addritem_print_item_person( ( ItemPerson * ) obj, stream );
324 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
325 printf( "addrcache: print email\n" );
327 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
328 addritem_print_item_group( ( ItemGroup * ) obj, stream );
330 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
331 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
336 * Dump entire address cache hash table contents.
338 void addrcache_print( AddressCache *cache, FILE *stream ) {
339 g_return_if_fail( cache != NULL );
340 fprintf( stream, "AddressCache:\n" );
341 fprintf( stream, "cache id : %s\n", cache->cacheID );
342 fprintf( stream, "next id : %d\n", cache->nextID );
343 fprintf( stream, "name : %s\n", cache->name );
344 fprintf( stream, "mod time : %ld\n", cache->modifyTime );
345 fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" );
346 fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" );
350 * Dump entire address cache hash table contents.
352 void addrcache_dump_hash( AddressCache *cache, FILE *stream ) {
353 g_return_if_fail( cache != NULL );
354 addrcache_print( cache, stream );
355 g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream );
359 * Allocate ID for person.
361 void addrcache_id_person( AddressCache *cache, ItemPerson *person ) {
362 g_return_if_fail( cache != NULL );
363 g_return_if_fail( person != NULL );
364 if( ADDRITEM_ID(person) ) return;
365 addrcache_next_id( cache );
366 ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID );
370 * Allocate ID for group.
372 void addrcache_id_group( AddressCache *cache, ItemGroup *group ) {
373 g_return_if_fail( cache != NULL );
374 g_return_if_fail( group != NULL );
375 if( ADDRITEM_ID(group) ) return;
376 addrcache_next_id( cache );
377 ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID );
381 * Allocate ID for folder.
383 void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) {
384 g_return_if_fail( cache != NULL );
385 g_return_if_fail( folder != NULL );
386 if( ADDRITEM_ID(folder) ) return;
387 addrcache_next_id( cache );
388 ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID );
392 * Allocate ID for email address.
394 void addrcache_id_email( AddressCache *cache, ItemEMail *email ) {
395 g_return_if_fail( cache != NULL );
396 g_return_if_fail( email != NULL );
397 if( ADDRITEM_ID(email) ) return;
398 addrcache_next_id( cache );
399 ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID );
403 * Allocate ID for user attribute.
405 void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) {
406 g_return_if_fail( cache != NULL );
407 g_return_if_fail( attrib != NULL );
408 if( attrib->uid ) return;
409 addrcache_next_id( cache );
410 attrib->uid = g_strdup_printf( "%d", cache->nextID );
414 * Add person to hash table.
415 * return: TRUE if item added.
417 gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
418 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) {
421 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person );
426 * Add email to hash table.
427 * return: TRUE if item added.
429 gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
430 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
433 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
438 * Add group to hash table.
439 * return: TRUE if item added.
441 gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) {
442 g_return_val_if_fail( cache != NULL, FALSE );
443 g_return_val_if_fail( group != NULL, FALSE );
445 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) {
448 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group );
453 * Add folder to hash table.
454 * return: TRUE if item added.
456 gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) {
457 g_return_val_if_fail( cache != NULL, FALSE );
458 g_return_val_if_fail( folder != NULL, FALSE );
460 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) {
463 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder );
468 * Add person to specified folder in cache.
470 gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) {
471 gboolean retVal = FALSE;
473 g_return_val_if_fail( cache != NULL, FALSE );
474 g_return_val_if_fail( folder != NULL, FALSE );
475 g_return_val_if_fail( item != NULL, FALSE );
477 retVal = addrcache_hash_add_person( cache, item );
479 addritem_folder_add_person( folder, item );
480 cache->dirtyFlag = TRUE;
486 * Add folder to specified folder in cache.
488 gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) {
489 gboolean retVal = FALSE;
491 g_return_val_if_fail( cache != NULL, FALSE );
492 g_return_val_if_fail( folder != NULL, FALSE );
493 g_return_val_if_fail( item != NULL, FALSE );
495 retVal = addrcache_hash_add_folder( cache, item );
497 addritem_folder_add_folder( folder, item );
498 cache->dirtyFlag = TRUE;
504 * Add folder to specified folder in cache.
506 gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) {
507 gboolean retVal = FALSE;
509 g_return_val_if_fail( cache != NULL, FALSE );
510 g_return_val_if_fail( folder != NULL, FALSE );
511 g_return_val_if_fail( item != NULL, FALSE );
513 retVal = addrcache_hash_add_group( cache, item );
515 addritem_folder_add_group( folder, item );
516 cache->dirtyFlag = TRUE;
522 * Add person to address cache.
523 * return: TRUE if item added.
525 gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
526 gboolean retVal = FALSE;
528 g_return_val_if_fail( cache != NULL, FALSE );
529 g_return_val_if_fail( person != NULL, FALSE );
531 retVal = addrcache_hash_add_person( cache, person );
533 addritem_folder_add_person( cache->rootFolder, person );
534 cache->dirtyFlag = TRUE;
540 * Add EMail address to person.
541 * return: TRUE if item added.
543 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
544 gboolean retVal = FALSE;
546 g_return_val_if_fail( cache != NULL, FALSE );
547 g_return_val_if_fail( person != NULL, FALSE );
548 g_return_val_if_fail( email != NULL, FALSE );
550 retVal = addrcache_hash_add_email( cache, email );
552 addritem_person_add_email( person, email );
553 cache->dirtyFlag = TRUE;
559 * Add group to address cache.
560 * return: TRUE if item added.
562 gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
563 gboolean retVal = FALSE;
565 g_return_val_if_fail( cache != NULL, FALSE );
566 g_return_val_if_fail( group != NULL, FALSE );
568 retVal = addrcache_hash_add_group( cache, group );
570 addritem_folder_add_group( cache->rootFolder, group );
571 cache->dirtyFlag = TRUE;
577 * Add EMail address to person.
578 * return: TRUE if item added.
580 gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) {
581 g_return_val_if_fail( cache != NULL, FALSE );
582 g_return_val_if_fail( group != NULL, FALSE );
583 g_return_val_if_fail( email != NULL, FALSE );
585 addritem_group_add_email( group, email );
586 cache->dirtyFlag = TRUE;
591 * Add folder to address cache.
592 * return: TRUE if item added.
594 gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
595 gboolean retVal = FALSE;
597 g_return_val_if_fail( cache != NULL, FALSE );
598 g_return_val_if_fail( folder != NULL, FALSE );
600 retVal = addrcache_hash_add_folder( cache, folder );
602 addritem_folder_add_folder( cache->rootFolder, folder );
603 cache->dirtyFlag = TRUE;
609 * Move person to destination folder.
610 * Enter: cache Cache.
611 * person Person to move.
612 * target Target folder.
614 void addrcache_folder_move_person(
615 AddressCache *cache, ItemPerson *person, ItemFolder *target )
619 g_return_if_fail( cache != NULL );
620 g_return_if_fail( person != NULL );
622 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
623 if( ! parent ) parent = cache->rootFolder;
624 parent->listPerson = g_list_remove( parent->listPerson, person );
625 target->listPerson = g_list_append( target->listPerson, person );
626 ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
627 cache->dirtyFlag = TRUE;
631 * Move group to destination folder.
632 * Enter: cache Cache.
633 * group Group to move.
634 * target Target folder.
636 void addrcache_folder_move_group(
637 AddressCache *cache, ItemGroup *group, ItemFolder *target )
641 g_return_if_fail( cache != NULL );
642 g_return_if_fail( group != NULL );
644 parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
645 if( ! parent ) parent = cache->rootFolder;
646 parent->listGroup = g_list_remove( parent->listGroup, group );
647 target->listGroup = g_list_append( target->listGroup, group );
648 ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
649 cache->dirtyFlag = TRUE;
653 * Move folder to destination folder.
654 * Enter: cache Cache.
655 * folder Folder to move.
656 * target Target folder.
658 void addrcache_folder_move_folder(
659 AddressCache *cache, ItemFolder *folder, ItemFolder *target )
663 g_return_if_fail( cache != NULL );
664 g_return_if_fail( folder != NULL );
666 parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
667 if( ! parent ) parent = cache->rootFolder;
668 parent->listFolder = g_list_remove( parent->listFolder, folder );
669 target->listFolder = g_list_append( target->listFolder, folder );
670 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
671 cache->dirtyFlag = TRUE;
675 * Return pointer to object (either person or group) for specified ID.
676 * param: uid Object ID.
677 * return: Object, or NULL if not found.
679 AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) {
680 AddrItemObject *obj = NULL;
683 g_return_val_if_fail( cache != NULL, NULL );
685 if( uid == NULL || *uid == '\0' ) return NULL;
686 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
688 /* Check for matching UID */
689 uidH = ADDRITEM_ID(obj);
691 if( strcmp( uidH, uid ) == 0 ) return obj;
698 * Return pointer for specified object ID.
699 * param: uid Object ID.
700 * return: Person object, or NULL if not found.
702 ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) {
703 ItemPerson *person = NULL;
704 AddrItemObject *obj = addrcache_get_object( cache, uid );
707 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
708 person = ( ItemPerson * ) obj;
715 * Return pointer for specified object ID.
716 * param: uid group ID.
717 * return: Group object, or NULL if not found.
719 ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
720 ItemGroup *group = NULL;
721 AddrItemObject *obj = addrcache_get_object( cache, uid );
724 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
725 group = ( ItemGroup * ) obj;
732 * Find email address in address cache.
733 * param: eid EMail ID.
734 * return: email object for specified object ID and email ID, or NULL if not found.
736 ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
737 ItemEMail *email = NULL;
738 AddrItemObject *obj = addrcache_get_object( cache, eid );
741 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
742 email = ( ItemEMail * ) obj;
749 * Remove attribute from person.
750 * param: uid Object ID for person.
752 * return: UserAttribute object, or NULL if not found. Note that object should still be freed.
754 UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) {
755 UserAttribute *attrib = NULL;
758 if( aid == NULL || *aid == '\0' ) return NULL;
760 person = addrcache_get_person( cache, uid );
762 attrib = addritem_person_remove_attrib_id( person, aid );
763 cache->dirtyFlag = TRUE;
769 * Remove attribute from person.
770 * param: person Person.
771 * attrib Attribute to remove.
772 * return: UserAttribute object. Note that object should still be freed.
774 UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) {
775 UserAttribute *found = NULL;
777 g_return_val_if_fail( cache != NULL, NULL );
779 if( person && attrib ) {
780 found = addritem_person_remove_attribute( person, attrib );
781 cache->dirtyFlag = TRUE;
787 * Remove group from address cache.
788 * param: group Group to remove.
789 * return: Group, or NULL if not found. Note that object should still be freed.
791 ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
792 AddrItemObject *obj = NULL;
794 g_return_val_if_fail( cache != NULL, NULL );
797 gchar *uid = ADDRITEM_ID(group);
798 if( uid == NULL || *uid == '\0' ) return NULL;
799 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
801 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
802 if( ! parent ) parent = cache->rootFolder;
804 /* Remove group from parent's list and hash table */
805 parent->listGroup = g_list_remove( parent->listGroup, obj );
806 g_hash_table_remove( cache->itemHash, uid );
807 cache->dirtyFlag = TRUE;
815 * Remove specified email from address cache. Note that object is only
816 * removed from cache and not parent objects.
817 * param: email EMail to remove.
818 * return: EMail, or NULL if not found. Note that object should still be freed.
820 ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
821 AddrItemObject *obj = NULL;
823 g_return_val_if_fail( cache != NULL, NULL );
826 gchar *eid = ADDRITEM_ID(email);
827 if( eid == NULL || *eid == '\0' ) return NULL;
828 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
830 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
831 /* Remove email addresses from hash table. */
832 g_hash_table_remove( cache->itemHash, eid );
833 cache->dirtyFlag = TRUE;
842 * Hash table visitor function to remove email from group.
844 static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
845 AddrItemObject *obj = ( AddrItemObject * ) value;
846 ItemEMail *email = ( ItemEMail * ) data;
848 if( ! email ) return;
849 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
850 ItemGroup *group = ( ItemGroup * ) value;
852 /* Remove each email address that belongs to the person from the list */
853 group->listEMail = g_list_remove( group->listEMail, email );
859 * Remove specified person from address cache.
860 * param: person Person to remove.
861 * return: Person, or NULL if not found. Note that object should still be freed.
863 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
864 AddrItemObject *obj = NULL;
867 g_return_val_if_fail( cache != NULL, NULL );
870 uid = ADDRITEM_ID(person);
871 if( uid == NULL || *uid == '\0' ) return NULL;
872 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
874 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
878 /* Remove all email addresses for person */
879 /* from groups and from hash table */
880 node = person->listEMail;
886 g_hash_table_foreach( cache->itemHash,
887 addrcache_allgrp_rem_email_vis, email );
888 eid = ADDRITEM_ID( email );
889 g_hash_table_remove( cache->itemHash, eid );
890 node = g_list_next( node );
893 /* Remove person from owning folder */
894 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
895 if( ! parent ) parent = cache->rootFolder;
896 parent->listPerson = g_list_remove( parent->listPerson, person );
897 g_hash_table_remove( cache->itemHash, uid );
898 cache->dirtyFlag = TRUE;
907 * Remove email address in address cache for specified person.
908 * param: person Person.
909 * email EMail to remove.
910 * return: EMail object, or NULL if not found. Note that object should still be freed.
912 ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
913 ItemEMail *found = NULL;
915 g_return_val_if_fail( cache != NULL, NULL );
917 if( person && email ) {
918 found = addritem_person_remove_email( person, email );
920 /* Remove email from all groups. */
921 g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
923 /* Remove email from person's address list */
924 if( person->listEMail ) {
925 person->listEMail = g_list_remove( person->listEMail, email );
927 /* Unlink reference to person. */
928 ADDRITEM_PARENT(email) = NULL;
929 cache->dirtyFlag = TRUE;
936 * Move email address in address cache to new person. If member of group, address
938 * param: cache Cache.
939 * email EMail to remove.
940 * target Target person.
941 * return: EMail object, or NULL if not found. Note that object should still be freed.
943 void addrcache_person_move_email(
944 AddressCache *cache, ItemEMail *email, ItemPerson *target )
948 g_return_if_fail( cache != NULL );
950 if( email == NULL ) return;
951 if( target == NULL ) return;
953 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
956 found = addritem_person_remove_email( person, email );
958 if( person->listEMail ) {
959 person->listEMail = g_list_remove( person->listEMail, found );
960 addritem_person_add_email( target, found );
961 cache->dirtyFlag = TRUE;
968 * Return link list of address items for root level folder. Note that the list contains
969 * references to items and should be g_free() when done. Do *NOT* attempt to use the
970 * addrcache_free_xxx() functions... this will destroy the address cache data!
971 * Return: List of items, or NULL if none.
973 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
976 ItemFolder *f = folder;
978 g_return_val_if_fail( cache != NULL, NULL );
980 if( ! f ) f = cache->rootFolder;
981 node = f->listPerson;
983 list = g_list_append( list, node->data );
984 node = g_list_next( node );
988 list = g_list_append( list, node->data );
989 node = g_list_next( node );
995 * Return link list of persons for specified folder. Note that the list contains
996 * references to items and should be g_free() when done. Do *NOT* attempt to use the
997 * addrcache_free_xxx() functions... this will destroy the address cache data!
998 * Return: List of items, or NULL if none.
1000 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1001 ItemFolder *f = folder;
1003 g_return_val_if_fail( cache != NULL, NULL );
1005 if( ! f ) f = cache->rootFolder;
1006 return addritem_folder_get_person_list( f );
1010 * Return link list of group items for specified folder. Note that the list contains
1011 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1012 * addrcache_free_xxx() functions... this will destroy the address cache data!
1013 * Return: List of items, or NULL if none.
1015 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1016 ItemFolder *f = folder;
1018 g_return_val_if_fail( cache != NULL, NULL );
1020 if( ! f ) f = cache->rootFolder;
1021 return addritem_folder_get_group_list( f );
1025 * Return link list of folder items for specified folder. Note that the list contains
1026 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1027 * addrcache_free_xxx() functions... this will destroy the address cache data!
1028 * Return: List of items, or NULL if none.
1030 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1033 ItemFolder *f = folder;
1035 g_return_val_if_fail( cache != NULL, NULL );
1037 if( ! f ) f = cache->rootFolder;
1038 node = f->listFolder;
1040 list = g_list_append( list, node->data );
1041 node = g_list_next( node );
1047 * Return link list of address items for root level folder. Note that the list contains
1048 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1049 * addrcache_free_xxx() functions... this will destroy the address cache data!
1050 * Return: List of items, or NULL if none.
1052 GList *addrcache_get_address_list( AddressCache *cache ) {
1053 g_return_val_if_fail( cache != NULL, NULL );
1054 return addrcache_folder_get_address_list( cache, cache->rootFolder );
1058 * Return link list of persons for root level folder. Note that the list contains
1059 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1060 * addrcache_free_xxx() functions... this will destroy the address cache data!
1061 * Return: List of items, or NULL if none.
1063 GList *addrcache_get_person_list( AddressCache *cache ) {
1064 g_return_val_if_fail( cache != NULL, NULL );
1065 return addritem_folder_get_person_list( cache->rootFolder );
1069 * Return link list of group items in root level folder. Note that the list contains
1070 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1071 * addrcache_free_xxx() functions... this will destroy the address cache data!
1072 * Return: List of items, or NULL if none.
1074 GList *addrcache_get_group_list( AddressCache *cache ) {
1075 g_return_val_if_fail( cache != NULL, NULL );
1076 return cache->rootFolder->listGroup;
1080 * Return link list of folder items in root level folder. Note that the list contains
1081 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1082 * addrcache_free_xxx() functions... this will destroy the address cache data!
1083 * Return: List of items, or NULL if none.
1085 GList *addrcache_get_folder_list( AddressCache *cache ) {
1086 g_return_val_if_fail( cache != NULL, NULL );
1087 return cache->rootFolder->listFolder;
1091 * Group visitor function.
1093 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1094 AddrItemObject *obj = ( AddrItemObject * ) value;
1096 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1097 AddressCache *cache = data;
1098 ItemGroup *group = ( ItemGroup * ) obj;
1099 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1100 GList *node = group->listEMail;
1102 ItemEMail *email = ( ItemEMail * ) node->data;
1103 if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1104 if( ! g_list_find( cache->tempList, group ) ) {
1105 cache->tempList = g_list_append( cache->tempList, group );
1108 node = g_list_next( node );
1114 * Return linked list of groups which contain a reference to specified person's email
1117 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1120 g_return_val_if_fail( cache != NULL, NULL );
1122 cache->tempList = NULL;
1123 cache->tempList = g_list_append( cache->tempList, person );
1124 g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1125 cache->tempList = g_list_remove( cache->tempList, person );
1126 list = cache->tempList;
1127 cache->tempList = NULL;
1132 * Find root folder for specified folder.
1133 * Enter: folder Folder to search.
1134 * Return: root folder, or NULL if not found.
1136 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1137 ItemFolder *item = folder;
1141 if( item->isRoot ) break;
1142 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1146 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1152 * Get all person visitor function.
1154 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1155 AddrItemObject *obj = ( AddrItemObject * ) value;
1157 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1158 AddressCache *cache = data;
1159 cache->tempList = g_list_append( cache->tempList, obj );
1164 * Return link list of all persons in address cache. Note that the list contains
1165 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1166 * this will destroy the address cache data!
1167 * Return: List of items, or NULL if none.
1169 GList *addrcache_get_all_persons( AddressCache *cache ) {
1172 g_return_val_if_fail( cache != NULL, NULL );
1174 cache->tempList = NULL;
1175 g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1176 list = cache->tempList;
1177 cache->tempList = NULL;
1182 * Get all groups visitor function.
1184 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1185 AddrItemObject *obj = ( AddrItemObject * ) value;
1187 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1188 AddressCache *cache = data;
1189 cache->tempList = g_list_append( cache->tempList, obj );
1194 * Return link list of all groups in address cache. Note that the list contains
1195 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1196 * this will destroy the address cache data!
1197 * Return: List of items, or NULL if none.
1199 GList *addrcache_get_all_groups( AddressCache *cache ) {
1202 g_return_val_if_fail( cache != NULL, NULL );
1204 cache->tempList = NULL;
1205 g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1206 list = cache->tempList;
1207 cache->tempList = NULL;
1212 * Remove folder from cache. Children are re-parented to parent folder.
1213 * param: folder Folder to remove.
1214 * return: Folder, or NULL if not found. Note that object should still be freed.
1216 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1217 AddrItemObject *obj = NULL;
1219 g_return_val_if_fail( cache != NULL, NULL );
1222 gchar *uid = ADDRITEM_ID(folder);
1223 if( uid == NULL || *uid == '\0' ) return NULL;
1224 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1226 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1228 AddrItemObject *aio;
1229 if( ! parent ) parent = cache->rootFolder;
1231 /* Re-parent children in folder */
1232 node = folder->listFolder;
1234 aio = ( AddrItemObject * ) node->data;
1235 parent->listFolder = g_list_append( parent->listFolder, aio );
1236 aio->parent = ADDRITEM_OBJECT(parent);
1237 node = g_list_next( node );
1239 node = folder->listPerson;
1241 aio = ( AddrItemObject * ) node->data;
1242 parent->listPerson = g_list_append( parent->listPerson, aio );
1243 aio->parent = ADDRITEM_OBJECT(parent);
1244 node = g_list_next( node );
1246 node = folder->listGroup;
1248 aio = ( AddrItemObject * ) node->data;
1249 parent->listGroup = g_list_append( parent->listGroup, aio );
1250 aio->parent = ADDRITEM_OBJECT(parent);
1251 node = g_list_next( node );
1254 /* Remove folder from parent's list and hash table */
1255 parent->listFolder = g_list_remove( parent->listFolder, folder );
1256 ADDRITEM_PARENT(folder) = NULL;
1257 g_hash_table_remove( cache->itemHash, uid );
1258 cache->dirtyFlag = TRUE;
1266 * Remove folder from cache. Children are deleted.
1267 * param: folder Folder to remove.
1268 * return: Folder, or NULL if not found. Note that object should still be freed.
1270 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1271 AddrItemObject *obj = NULL;
1273 g_return_val_if_fail( cache != NULL, NULL );
1276 gchar *uid = ADDRITEM_ID(folder);
1277 if( uid == NULL || *uid == '\0' ) return NULL;
1278 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1280 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1281 if( ! parent ) parent = cache->rootFolder;
1284 while( folder->listGroup ) {
1285 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1286 item = addrcache_remove_group( cache, item );
1288 addritem_free_item_group( item );
1293 while( folder->listPerson ) {
1294 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1295 item = addrcache_remove_person( cache, item );
1297 addritem_free_item_person( item );
1302 /* Recursive deletion of folder */
1303 while( folder->listFolder ) {
1304 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1305 item = addrcache_remove_folder_delete( cache, item );
1307 addritem_free_item_folder( item );
1312 /* Remove folder from parent's list and hash table */
1313 parent->listFolder = g_list_remove( parent->listFolder, folder );
1314 ADDRITEM_PARENT(folder) = NULL;
1315 g_hash_table_remove( cache->itemHash, uid );
1316 cache->dirtyFlag = TRUE;
1324 * Add person and address data to cache.
1325 * Enter: cache Cache.
1326 * folder Folder where to add person, or NULL for root folder.
1328 * address EMail address.
1330 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1331 * this will destroy the address book data.
1333 ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, const gchar *name,
1334 const gchar *address, const gchar *remarks )
1336 ItemPerson *person = NULL;
1337 ItemEMail *email = NULL;
1338 ItemFolder *f = folder;
1340 g_return_val_if_fail( cache != NULL, NULL );
1342 if( ! f ) f = cache->rootFolder;
1344 /* Create person object */
1345 person = addritem_create_item_person();
1346 addritem_person_set_common_name( person, name );
1347 addrcache_id_person( cache, person );
1348 addrcache_folder_add_person( cache, f, person );
1350 /* Create email object */
1351 email = addritem_create_item_email();
1352 addritem_email_set_address( email, address );
1353 addritem_email_set_remarks( email, remarks );
1354 addrcache_id_email( cache, email );
1355 addritem_person_add_email( person, email );
1356 cache->dirtyFlag = TRUE;