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_foreach_remove( table, addrcache_free_item_vis, NULL );
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 == stat( 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 == stat( 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 );
959 if( person->listEMail ) {
960 person->listEMail = g_list_remove( person->listEMail, found );
961 addritem_person_add_email( target, found );
962 cache->dirtyFlag = TRUE;
965 addritem_person_add_email( target, found );
966 cache->dirtyFlag = TRUE;
972 * Return link list of address items for root level folder. Note that the list contains
973 * references to items and should be g_free() when done. Do *NOT* attempt to use the
974 * addrcache_free_xxx() functions... this will destroy the address cache data!
975 * Return: List of items, or NULL if none.
977 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
980 ItemFolder *f = folder;
982 g_return_val_if_fail( cache != NULL, NULL );
984 if( ! f ) f = cache->rootFolder;
985 node = f->listPerson;
987 list = g_list_append( list, node->data );
988 node = g_list_next( node );
992 list = g_list_append( list, node->data );
993 node = g_list_next( node );
999 * Return link list of persons for specified folder. Note that the list contains
1000 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1001 * addrcache_free_xxx() functions... this will destroy the address cache data!
1002 * Return: List of items, or NULL if none.
1004 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1005 ItemFolder *f = folder;
1007 g_return_val_if_fail( cache != NULL, NULL );
1009 if( ! f ) f = cache->rootFolder;
1010 return addritem_folder_get_person_list( f );
1014 * Return link list of group items for specified folder. Note that the list contains
1015 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1016 * addrcache_free_xxx() functions... this will destroy the address cache data!
1017 * Return: List of items, or NULL if none.
1019 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1020 ItemFolder *f = folder;
1022 g_return_val_if_fail( cache != NULL, NULL );
1024 if( ! f ) f = cache->rootFolder;
1025 return addritem_folder_get_group_list( f );
1029 * Return link list of folder items for specified folder. Note that the list contains
1030 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1031 * addrcache_free_xxx() functions... this will destroy the address cache data!
1032 * Return: List of items, or NULL if none.
1034 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1037 ItemFolder *f = folder;
1039 g_return_val_if_fail( cache != NULL, NULL );
1041 if( ! f ) f = cache->rootFolder;
1042 node = f->listFolder;
1044 list = g_list_append( list, node->data );
1045 node = g_list_next( node );
1051 * Return link list of address items for root level folder. Note that the list contains
1052 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1053 * addrcache_free_xxx() functions... this will destroy the address cache data!
1054 * Return: List of items, or NULL if none.
1056 GList *addrcache_get_address_list( AddressCache *cache ) {
1057 g_return_val_if_fail( cache != NULL, NULL );
1058 return addrcache_folder_get_address_list( cache, cache->rootFolder );
1062 * Return link list of persons for root level folder. Note that the list contains
1063 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1064 * addrcache_free_xxx() functions... this will destroy the address cache data!
1065 * Return: List of items, or NULL if none.
1067 GList *addrcache_get_person_list( AddressCache *cache ) {
1068 g_return_val_if_fail( cache != NULL, NULL );
1069 return addritem_folder_get_person_list( cache->rootFolder );
1073 * Return link list of group items in root level folder. Note that the list contains
1074 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1075 * addrcache_free_xxx() functions... this will destroy the address cache data!
1076 * Return: List of items, or NULL if none.
1078 GList *addrcache_get_group_list( AddressCache *cache ) {
1079 g_return_val_if_fail( cache != NULL, NULL );
1080 return cache->rootFolder->listGroup;
1084 * Return link list of folder items in root level folder. Note that the list contains
1085 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1086 * addrcache_free_xxx() functions... this will destroy the address cache data!
1087 * Return: List of items, or NULL if none.
1089 GList *addrcache_get_folder_list( AddressCache *cache ) {
1090 g_return_val_if_fail( cache != NULL, NULL );
1091 return cache->rootFolder->listFolder;
1095 * Group visitor function.
1097 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1098 AddrItemObject *obj = ( AddrItemObject * ) value;
1100 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1101 AddressCache *cache = data;
1102 ItemGroup *group = ( ItemGroup * ) obj;
1103 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1104 GList *node = group->listEMail;
1106 ItemEMail *email = ( ItemEMail * ) node->data;
1107 if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1108 if( ! g_list_find( cache->tempList, group ) ) {
1109 cache->tempList = g_list_append( cache->tempList, group );
1112 node = g_list_next( node );
1118 * Return linked list of groups which contain a reference to specified person's email
1121 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1124 g_return_val_if_fail( cache != NULL, NULL );
1126 cache->tempList = NULL;
1127 cache->tempList = g_list_append( cache->tempList, person );
1128 g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1129 cache->tempList = g_list_remove( cache->tempList, person );
1130 list = cache->tempList;
1131 cache->tempList = NULL;
1136 * Find root folder for specified folder.
1137 * Enter: folder Folder to search.
1138 * Return: root folder, or NULL if not found.
1140 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1141 ItemFolder *item = folder;
1145 if( item->isRoot ) break;
1146 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1150 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1156 * Get all person visitor function.
1158 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1159 AddrItemObject *obj = ( AddrItemObject * ) value;
1161 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1162 AddressCache *cache = data;
1163 cache->tempList = g_list_append( cache->tempList, obj );
1168 * Return link list of all persons in address cache. Note that the list contains
1169 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1170 * this will destroy the address cache data!
1171 * Return: List of items, or NULL if none.
1173 GList *addrcache_get_all_persons( AddressCache *cache ) {
1176 g_return_val_if_fail( cache != NULL, NULL );
1178 cache->tempList = NULL;
1179 g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1180 list = cache->tempList;
1181 cache->tempList = NULL;
1186 * Get all groups visitor function.
1188 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1189 AddrItemObject *obj = ( AddrItemObject * ) value;
1191 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1192 AddressCache *cache = data;
1193 cache->tempList = g_list_append( cache->tempList, obj );
1198 * Return link list of all groups in address cache. Note that the list contains
1199 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1200 * this will destroy the address cache data!
1201 * Return: List of items, or NULL if none.
1203 GList *addrcache_get_all_groups( AddressCache *cache ) {
1206 g_return_val_if_fail( cache != NULL, NULL );
1208 cache->tempList = NULL;
1209 g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1210 list = cache->tempList;
1211 cache->tempList = NULL;
1216 * Remove folder from cache. Children are re-parented to parent folder.
1217 * param: folder Folder to remove.
1218 * return: Folder, or NULL if not found. Note that object should still be freed.
1220 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1221 AddrItemObject *obj = NULL;
1223 g_return_val_if_fail( cache != NULL, NULL );
1226 gchar *uid = ADDRITEM_ID(folder);
1227 if( uid == NULL || *uid == '\0' ) return NULL;
1228 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1230 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1232 AddrItemObject *aio;
1233 if( ! parent ) parent = cache->rootFolder;
1235 /* Re-parent children in folder */
1236 node = folder->listFolder;
1238 aio = ( AddrItemObject * ) node->data;
1239 parent->listFolder = g_list_append( parent->listFolder, aio );
1240 aio->parent = ADDRITEM_OBJECT(parent);
1241 node = g_list_next( node );
1243 node = folder->listPerson;
1245 aio = ( AddrItemObject * ) node->data;
1246 parent->listPerson = g_list_append( parent->listPerson, aio );
1247 aio->parent = ADDRITEM_OBJECT(parent);
1248 node = g_list_next( node );
1250 node = folder->listGroup;
1252 aio = ( AddrItemObject * ) node->data;
1253 parent->listGroup = g_list_append( parent->listGroup, aio );
1254 aio->parent = ADDRITEM_OBJECT(parent);
1255 node = g_list_next( node );
1258 /* Remove folder from parent's list and hash table */
1259 parent->listFolder = g_list_remove( parent->listFolder, folder );
1260 ADDRITEM_PARENT(folder) = NULL;
1261 g_hash_table_remove( cache->itemHash, uid );
1262 cache->dirtyFlag = TRUE;
1270 * Remove folder from cache. Children are deleted.
1271 * param: folder Folder to remove.
1272 * return: Folder, or NULL if not found. Note that object should still be freed.
1274 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1275 AddrItemObject *obj = NULL;
1277 g_return_val_if_fail( cache != NULL, NULL );
1280 gchar *uid = ADDRITEM_ID(folder);
1281 if( uid == NULL || *uid == '\0' ) return NULL;
1282 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1284 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1285 if( ! parent ) parent = cache->rootFolder;
1288 while( folder->listGroup ) {
1289 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1290 item = addrcache_remove_group( cache, item );
1292 addritem_free_item_group( item );
1297 while( folder->listPerson ) {
1298 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1299 item = addrcache_remove_person( cache, item );
1301 addritem_free_item_person( item );
1306 /* Recursive deletion of folder */
1307 while( folder->listFolder ) {
1308 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1309 item = addrcache_remove_folder_delete( cache, item );
1311 addritem_free_item_folder( item );
1316 /* Remove folder from parent's list and hash table */
1317 parent->listFolder = g_list_remove( parent->listFolder, folder );
1318 ADDRITEM_PARENT(folder) = NULL;
1319 g_hash_table_remove( cache->itemHash, uid );
1320 cache->dirtyFlag = TRUE;
1328 * Add person and address data to cache.
1329 * \param cache Cache.
1330 * \param folder Folder where to add person, or NULL for root folder.
1331 * \param name Common name.
1332 * \param address EMail address.
1333 * \param remarks Remarks.
1334 * \return Person added. Do not *NOT* to use the
1335 * <code>addrbook_free_xxx()</code> functions...; this will destroy
1336 * the address book data.
1338 ItemPerson *addrcache_add_contact(
1339 AddressCache *cache, ItemFolder *folder, const gchar *name,
1340 const gchar *address, const gchar *remarks )
1342 ItemPerson *person = NULL;
1343 ItemEMail *email = NULL;
1344 ItemFolder *f = folder;
1346 g_return_val_if_fail( cache != NULL, NULL );
1348 if( ! f ) f = cache->rootFolder;
1350 /* Create person object */
1351 person = addritem_create_item_person();
1352 addritem_person_set_common_name( person, name );
1353 addrcache_id_person( cache, person );
1354 addrcache_folder_add_person( cache, f, person );
1356 /* Create email object */
1357 email = addritem_create_item_email();
1358 addritem_email_set_address( email, address );
1359 addritem_email_set_remarks( email, remarks );
1360 addrcache_id_email( cache, email );
1361 addritem_person_add_email( person, email );
1362 cache->dirtyFlag = TRUE;
1368 * Create a new folder and add to address cache.
1369 * \param cache Address cache.
1370 * \param folder Parent folder where to add folder, or <i>NULL</i> for
1372 * \return Folder that was created. This should <b>*NOT*</b> be
1373 * <code>g_free()</code> when done.
1375 ItemFolder *addrcache_add_new_folder( AddressCache *cache, ItemFolder *parent )
1378 ItemFolder *p = parent;
1380 g_return_val_if_fail( cache != NULL, NULL );
1382 if( !p ) p = cache->rootFolder;
1383 folder = addritem_create_item_folder();
1384 addrcache_id_folder( cache, folder );
1385 if( addrcache_hash_add_folder( cache, folder ) ) {
1386 p->listFolder = g_list_append( p->listFolder, folder );
1387 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1388 addrcache_set_dirty( cache, TRUE );
1391 addritem_free_item_folder( folder );