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;
80 cache->searchIndex = NULL;
88 ItemFolder *addrcache_get_root_folder( AddressCache *cache ) {
89 g_return_val_if_fail( cache != NULL, NULL );
90 return cache->rootFolder;
92 GList *addrcache_get_list_folder( AddressCache *cache ) {
93 g_return_val_if_fail( cache != NULL, NULL );
94 return cache->rootFolder->listFolder;
96 GList *addrcache_get_list_person( AddressCache *cache ) {
97 g_return_val_if_fail( cache != NULL, NULL );
98 return cache->rootFolder->listPerson;
100 gboolean addrcache_get_dirty( AddressCache *cache ) {
101 g_return_val_if_fail( cache != NULL, FALSE );
102 return cache->dirtyFlag;
104 void addrcache_set_dirty( AddressCache *cache, const gboolean value ) {
105 g_return_if_fail( cache != NULL );
106 cache->dirtyFlag = value;
108 gboolean addrcache_get_modified( AddressCache *cache ) {
109 g_return_val_if_fail( cache != NULL, FALSE );
110 return cache->modified;
112 void addrcache_set_modified( AddressCache *cache, const gboolean value ) {
113 g_return_if_fail( cache != NULL );
114 cache->modified = value;
116 gboolean addrcache_get_read_flag( AddressCache *cache ) {
117 g_return_val_if_fail( cache != NULL, FALSE );
118 return cache->dataRead;
120 void addrcache_set_read_flag( AddressCache *cache, const gboolean value ) {
121 g_return_if_fail( cache != NULL );
122 cache->dataRead = value;
124 gboolean addrcache_get_accessed( AddressCache *cache ) {
125 g_return_val_if_fail( cache != NULL, FALSE );
126 return cache->accessFlag;
128 void addrcache_set_accessed( AddressCache *cache, const gboolean value ) {
129 g_return_if_fail( cache != NULL );
130 cache->accessFlag = value;
132 gchar *addrcache_get_name( AddressCache *cache ) {
133 g_return_val_if_fail( cache != NULL, NULL );
136 void addrcache_set_name( AddressCache *cache, const gchar *value ) {
137 g_return_if_fail( cache != NULL );
138 cache->name = mgu_replace_string( cache->name, value );
139 g_strstrip( cache->name );
140 cache->dirtyFlag = TRUE;
146 void addrcache_next_id( AddressCache *cache ) {
147 g_return_if_fail( cache != NULL );
152 * Refresh internal variables. This can be used force a reload.
154 void addrcache_refresh( AddressCache *cache ) {
155 cache->dataRead = FALSE;
156 cache->modified = TRUE;
157 cache->accessFlag = FALSE;
158 cache->modifyTime = 0;
162 * Free hash table visitor function.
164 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
165 AddrItemObject *obj = ( AddrItemObject * ) value;
167 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
168 addritem_free_item_person( ( ItemPerson * ) obj );
170 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
171 addritem_free_item_email( ( ItemEMail * ) obj );
173 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
174 addritem_free_item_group( ( ItemGroup * ) obj );
176 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
177 addritem_free_item_folder( ( ItemFolder * ) obj );
185 * Free hash table of address cache items.
187 static void addrcache_free_item_hash( GHashTable *table ) {
188 g_return_if_fail( table != NULL );
189 g_hash_table_freeze( table );
190 g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
191 g_hash_table_thaw( table );
195 * Free up folders and groups.
197 static void addrcache_free_all_folders( ItemFolder *parent ) {
200 if( parent == NULL ) return;
202 node = parent->listFolder;
204 ItemFolder *folder = node->data;
205 addrcache_free_all_folders( folder );
207 node = g_list_next( node );
209 g_list_free( parent->listPerson );
210 g_list_free( parent->listGroup );
211 g_list_free( parent->listFolder );
212 parent->listPerson = NULL;
213 parent->listGroup = NULL;
214 parent->listFolder = NULL;
218 * Clear the address cache.
220 void addrcache_clear( AddressCache *cache ) {
221 g_return_if_fail( cache != NULL );
223 /* Clear completion index */
224 addrcindex_clear( cache->searchIndex );
226 /* Free up folders and hash table */
227 addrcache_free_all_folders( cache->rootFolder );
228 addrcache_free_item_hash( cache->itemHash );
229 g_hash_table_destroy( cache->itemHash );
230 cache->itemHash = NULL;
231 ADDRITEM_PARENT(cache->rootFolder) = NULL;
232 addritem_free_item_folder( cache->rootFolder );
233 cache->rootFolder = NULL;
234 if( cache->tempList ) g_list_free( cache->tempList );
235 cache->tempList = NULL;
237 /* Reset to initial state */
238 cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
239 cache->rootFolder = addritem_create_item_folder();
240 cache->rootFolder->isRoot = TRUE;
241 ADDRITEM_PARENT(cache->rootFolder) = NULL;
243 addrcache_refresh( cache );
247 * Free address cache.
249 void addrcache_free( AddressCache *cache ) {
250 g_return_if_fail( cache != NULL );
252 /* Free completion index */
253 addrcindex_free( cache->searchIndex );
254 cache->searchIndex = NULL;
256 cache->dirtyFlag = FALSE;
257 addrcache_free_all_folders( cache->rootFolder );
258 addrcache_free_item_hash( cache->itemHash );
259 g_hash_table_destroy( cache->itemHash );
260 cache->itemHash = NULL;
261 ADDRITEM_PARENT(cache->rootFolder) = NULL;
262 addritem_free_item_folder( cache->rootFolder );
263 cache->rootFolder = NULL;
264 g_list_free( cache->tempList );
265 cache->tempList = NULL;
266 g_free( cache->cacheID );
267 cache->cacheID = NULL;
268 g_free( cache->name );
275 * Check whether file has changed by comparing with cache.
276 * return: TRUE if file has changed.
278 gboolean addrcache_check_file( AddressCache *cache, gchar *path ) {
280 struct stat filestat;
283 if( 0 == lstat( path, &filestat ) ) {
284 if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
291 * Save file time to cache.
292 * return: TRUE if time marked.
294 gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) {
295 gboolean retVal = FALSE;
296 struct stat filestat;
298 if( 0 == lstat( path, &filestat ) ) {
299 cache->modifyTime = filestat.st_mtime;
307 * Print list of items.
309 void addrcache_print_item_list( GList *list, FILE *stream ) {
312 AddrItemObject *obj = node->data;
313 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
314 addritem_print_item_person( ( ItemPerson * ) obj, stream );
316 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
317 addritem_print_item_group( ( ItemGroup * ) obj, stream );
319 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
320 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
322 node = g_list_next( node );
324 fprintf( stream, "\t---\n" );
328 * Print item hash table visitor function.
330 static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) {
331 AddrItemObject *obj = ( AddrItemObject * ) value;
332 FILE *stream = ( FILE * ) data;
333 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
334 addritem_print_item_person( ( ItemPerson * ) obj, stream );
336 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
337 printf( "addrcache: print email\n" );
339 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
340 addritem_print_item_group( ( ItemGroup * ) obj, stream );
342 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
343 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
348 * Dump entire address cache hash table contents.
350 void addrcache_print( AddressCache *cache, FILE *stream ) {
351 g_return_if_fail( cache != NULL );
352 fprintf( stream, "AddressCache:\n" );
353 fprintf( stream, "cache id : %s\n", cache->cacheID );
354 fprintf( stream, "next id : %d\n", cache->nextID );
355 fprintf( stream, "name : %s\n", cache->name );
356 fprintf( stream, "mod time : %ld\n", cache->modifyTime );
357 fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" );
358 fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" );
362 * Dump entire address cache hash table contents.
364 void addrcache_dump_hash( AddressCache *cache, FILE *stream ) {
365 g_return_if_fail( cache != NULL );
366 addrcache_print( cache, stream );
367 g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream );
371 * Allocate ID for person.
373 void addrcache_id_person( AddressCache *cache, ItemPerson *person ) {
374 g_return_if_fail( cache != NULL );
375 g_return_if_fail( person != NULL );
376 if( ADDRITEM_ID(person) ) return;
377 addrcache_next_id( cache );
378 ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID );
382 * Allocate ID for group.
384 void addrcache_id_group( AddressCache *cache, ItemGroup *group ) {
385 g_return_if_fail( cache != NULL );
386 g_return_if_fail( group != NULL );
387 if( ADDRITEM_ID(group) ) return;
388 addrcache_next_id( cache );
389 ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID );
393 * Allocate ID for folder.
395 void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) {
396 g_return_if_fail( cache != NULL );
397 g_return_if_fail( folder != NULL );
398 if( ADDRITEM_ID(folder) ) return;
399 addrcache_next_id( cache );
400 ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID );
404 * Allocate ID for email address.
406 void addrcache_id_email( AddressCache *cache, ItemEMail *email ) {
407 g_return_if_fail( cache != NULL );
408 g_return_if_fail( email != NULL );
409 if( ADDRITEM_ID(email) ) return;
410 addrcache_next_id( cache );
411 ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID );
415 * Allocate ID for user attribute.
417 void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) {
418 g_return_if_fail( cache != NULL );
419 g_return_if_fail( attrib != NULL );
420 if( attrib->uid ) return;
421 addrcache_next_id( cache );
422 attrib->uid = g_strdup_printf( "%d", cache->nextID );
426 * Add person to hash table.
427 * return: TRUE if item added.
429 gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
430 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) {
433 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person );
438 * Add email to hash table.
439 * return: TRUE if item added.
441 gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
442 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
445 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
450 * Add group to hash table.
451 * return: TRUE if item added.
453 gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) {
454 g_return_val_if_fail( cache != NULL, FALSE );
455 g_return_val_if_fail( group != NULL, FALSE );
457 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) {
460 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group );
465 * Add folder to hash table.
466 * return: TRUE if item added.
468 gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) {
469 g_return_val_if_fail( cache != NULL, FALSE );
470 g_return_val_if_fail( folder != NULL, FALSE );
472 if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) {
475 g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder );
480 * Add person to specified folder in cache.
482 gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) {
483 gboolean retVal = FALSE;
485 g_return_val_if_fail( cache != NULL, FALSE );
486 g_return_val_if_fail( folder != NULL, FALSE );
487 g_return_val_if_fail( item != NULL, FALSE );
489 retVal = addrcache_hash_add_person( cache, item );
491 addritem_folder_add_person( folder, item );
492 cache->dirtyFlag = TRUE;
498 * Add folder to specified folder in cache.
500 gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) {
501 gboolean retVal = FALSE;
503 g_return_val_if_fail( cache != NULL, FALSE );
504 g_return_val_if_fail( folder != NULL, FALSE );
505 g_return_val_if_fail( item != NULL, FALSE );
507 retVal = addrcache_hash_add_folder( cache, item );
509 addritem_folder_add_folder( folder, item );
510 cache->dirtyFlag = TRUE;
516 * Add folder to specified folder in cache.
518 gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) {
519 gboolean retVal = FALSE;
521 g_return_val_if_fail( cache != NULL, FALSE );
522 g_return_val_if_fail( folder != NULL, FALSE );
523 g_return_val_if_fail( item != NULL, FALSE );
525 retVal = addrcache_hash_add_group( cache, item );
527 addritem_folder_add_group( folder, item );
528 cache->dirtyFlag = TRUE;
534 * Add person to address cache.
535 * return: TRUE if item added.
537 gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
538 gboolean retVal = FALSE;
540 g_return_val_if_fail( cache != NULL, FALSE );
541 g_return_val_if_fail( person != NULL, FALSE );
543 retVal = addrcache_hash_add_person( cache, person );
545 addritem_folder_add_person( cache->rootFolder, person );
546 cache->dirtyFlag = TRUE;
552 * Add EMail address to person.
553 * return: TRUE if item added.
555 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
556 gboolean retVal = FALSE;
558 g_return_val_if_fail( cache != NULL, FALSE );
559 g_return_val_if_fail( person != NULL, FALSE );
560 g_return_val_if_fail( email != NULL, FALSE );
562 retVal = addrcache_hash_add_email( cache, email );
564 addritem_person_add_email( person, email );
565 cache->dirtyFlag = TRUE;
571 * Add group to address cache.
572 * return: TRUE if item added.
574 gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
575 gboolean retVal = FALSE;
577 g_return_val_if_fail( cache != NULL, FALSE );
578 g_return_val_if_fail( group != NULL, FALSE );
580 retVal = addrcache_hash_add_group( cache, group );
582 addritem_folder_add_group( cache->rootFolder, group );
583 cache->dirtyFlag = TRUE;
589 * Add EMail address to person.
590 * return: TRUE if item added.
592 gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) {
593 g_return_val_if_fail( cache != NULL, FALSE );
594 g_return_val_if_fail( group != NULL, FALSE );
595 g_return_val_if_fail( email != NULL, FALSE );
597 addritem_group_add_email( group, email );
598 cache->dirtyFlag = TRUE;
603 * Add folder to address cache.
604 * return: TRUE if item added.
606 gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
607 gboolean retVal = FALSE;
609 g_return_val_if_fail( cache != NULL, FALSE );
610 g_return_val_if_fail( folder != NULL, FALSE );
612 retVal = addrcache_hash_add_folder( cache, folder );
614 addritem_folder_add_folder( cache->rootFolder, folder );
615 cache->dirtyFlag = TRUE;
621 * Move person to destination folder.
622 * Enter: cache Cache.
623 * person Person to move.
624 * target Target folder.
626 void addrcache_folder_move_person(
627 AddressCache *cache, ItemPerson *person, ItemFolder *target )
631 g_return_if_fail( cache != NULL );
632 g_return_if_fail( person != NULL );
634 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
635 if( ! parent ) parent = cache->rootFolder;
636 parent->listPerson = g_list_remove( parent->listPerson, person );
637 target->listPerson = g_list_append( target->listPerson, person );
638 ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
639 cache->dirtyFlag = TRUE;
643 * Move group to destination folder.
644 * Enter: cache Cache.
645 * group Group to move.
646 * target Target folder.
648 void addrcache_folder_move_group(
649 AddressCache *cache, ItemGroup *group, ItemFolder *target )
653 g_return_if_fail( cache != NULL );
654 g_return_if_fail( group != NULL );
656 parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
657 if( ! parent ) parent = cache->rootFolder;
658 parent->listGroup = g_list_remove( parent->listGroup, group );
659 target->listGroup = g_list_append( target->listGroup, group );
660 ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
661 cache->dirtyFlag = TRUE;
665 * Move folder to destination folder.
666 * Enter: cache Cache.
667 * folder Folder to move.
668 * target Target folder.
670 void addrcache_folder_move_folder(
671 AddressCache *cache, ItemFolder *folder, ItemFolder *target )
675 g_return_if_fail( cache != NULL );
676 g_return_if_fail( folder != NULL );
678 parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
679 if( ! parent ) parent = cache->rootFolder;
680 parent->listFolder = g_list_remove( parent->listFolder, folder );
681 target->listFolder = g_list_append( target->listFolder, folder );
682 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
683 cache->dirtyFlag = TRUE;
687 * Return pointer to object (either person or group) for specified ID.
688 * param: uid Object ID.
689 * return: Object, or NULL if not found.
691 AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) {
692 AddrItemObject *obj = NULL;
695 g_return_val_if_fail( cache != NULL, NULL );
697 if( uid == NULL || *uid == '\0' ) return NULL;
698 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
700 /* Check for matching UID */
701 uidH = ADDRITEM_ID(obj);
703 if( strcmp( uidH, uid ) == 0 ) return obj;
710 * Return pointer for specified object ID.
711 * param: uid Object ID.
712 * return: Person object, or NULL if not found.
714 ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) {
715 ItemPerson *person = NULL;
716 AddrItemObject *obj = addrcache_get_object( cache, uid );
719 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
720 person = ( ItemPerson * ) obj;
727 * Return pointer for specified object ID.
728 * param: uid group ID.
729 * return: Group object, or NULL if not found.
731 ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
732 ItemGroup *group = NULL;
733 AddrItemObject *obj = addrcache_get_object( cache, uid );
736 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
737 group = ( ItemGroup * ) obj;
744 * Find email address in address cache.
745 * param: eid EMail ID.
746 * return: email object for specified object ID and email ID, or NULL if not found.
748 ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
749 ItemEMail *email = NULL;
750 AddrItemObject *obj = addrcache_get_object( cache, eid );
753 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
754 email = ( ItemEMail * ) obj;
761 * Remove attribute from person.
762 * param: uid Object ID for person.
764 * return: UserAttribute object, or NULL if not found. Note that object should still be freed.
766 UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) {
767 UserAttribute *attrib = NULL;
770 if( aid == NULL || *aid == '\0' ) return NULL;
772 person = addrcache_get_person( cache, uid );
774 attrib = addritem_person_remove_attrib_id( person, aid );
775 cache->dirtyFlag = TRUE;
781 * Remove attribute from person.
782 * param: person Person.
783 * attrib Attribute to remove.
784 * return: UserAttribute object. Note that object should still be freed.
786 UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) {
787 UserAttribute *found = NULL;
789 g_return_val_if_fail( cache != NULL, NULL );
791 if( person && attrib ) {
792 found = addritem_person_remove_attribute( person, attrib );
793 cache->dirtyFlag = TRUE;
799 * Remove group from address cache.
800 * param: group Group to remove.
801 * return: Group, or NULL if not found. Note that object should still be freed.
803 ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
804 AddrItemObject *obj = NULL;
806 g_return_val_if_fail( cache != NULL, NULL );
809 gchar *uid = ADDRITEM_ID(group);
810 if( uid == NULL || *uid == '\0' ) return NULL;
811 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
813 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
814 if( ! parent ) parent = cache->rootFolder;
816 /* Remove group from parent's list and hash table */
817 parent->listGroup = g_list_remove( parent->listGroup, obj );
818 g_hash_table_remove( cache->itemHash, uid );
819 cache->dirtyFlag = TRUE;
827 * Remove specified email from address cache. Note that object is only
828 * removed from cache and not parent objects.
829 * param: email EMail to remove.
830 * return: EMail, or NULL if not found. Note that object should still be freed.
832 ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
833 AddrItemObject *obj = NULL;
835 g_return_val_if_fail( cache != NULL, NULL );
838 gchar *eid = ADDRITEM_ID(email);
839 if( eid == NULL || *eid == '\0' ) return NULL;
840 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
842 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
843 /* Remove email addresses from hash table. */
844 g_hash_table_remove( cache->itemHash, eid );
845 cache->dirtyFlag = TRUE;
854 * Hash table visitor function to remove email from group.
856 static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
857 AddrItemObject *obj = ( AddrItemObject * ) value;
858 ItemEMail *email = ( ItemEMail * ) data;
860 if( ! email ) return;
861 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
862 ItemGroup *group = ( ItemGroup * ) value;
864 /* Remove each email address that belongs to the person from the list */
865 group->listEMail = g_list_remove( group->listEMail, email );
871 * Remove specified person from address cache.
872 * param: person Person to remove.
873 * return: Person, or NULL if not found. Note that object should still be freed.
875 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
876 AddrItemObject *obj = NULL;
879 g_return_val_if_fail( cache != NULL, NULL );
882 uid = ADDRITEM_ID(person);
883 if( uid == NULL || *uid == '\0' ) return NULL;
884 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
886 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
890 /* Remove all email addresses for person */
891 /* from groups and from hash table */
892 node = person->listEMail;
898 g_hash_table_foreach( cache->itemHash,
899 addrcache_allgrp_rem_email_vis, email );
900 eid = ADDRITEM_ID( email );
901 g_hash_table_remove( cache->itemHash, eid );
902 node = g_list_next( node );
905 /* Remove person from owning folder */
906 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
907 if( ! parent ) parent = cache->rootFolder;
908 parent->listPerson = g_list_remove( parent->listPerson, person );
909 g_hash_table_remove( cache->itemHash, uid );
910 cache->dirtyFlag = TRUE;
919 * Remove email address in address cache for specified person.
920 * param: person Person.
921 * email EMail to remove.
922 * return: EMail object, or NULL if not found. Note that object should still be freed.
924 ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
925 ItemEMail *found = NULL;
927 g_return_val_if_fail( cache != NULL, NULL );
929 if( person && email ) {
930 found = addritem_person_remove_email( person, email );
932 /* Remove email from all groups. */
933 g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
935 /* Remove email from person's address list */
936 if( person->listEMail ) {
937 person->listEMail = g_list_remove( person->listEMail, email );
939 /* Unlink reference to person. */
940 ADDRITEM_PARENT(email) = NULL;
941 cache->dirtyFlag = TRUE;
948 * Move email address in address cache to new person. If member of group, address
950 * param: cache Cache.
951 * email EMail to remove.
952 * target Target person.
953 * return: EMail object, or NULL if not found. Note that object should still be freed.
955 void addrcache_person_move_email(
956 AddressCache *cache, ItemEMail *email, ItemPerson *target )
960 g_return_if_fail( cache != NULL );
962 if( email == NULL ) return;
963 if( target == NULL ) return;
965 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
968 found = addritem_person_remove_email( person, email );
971 if( person->listEMail ) {
972 person->listEMail = g_list_remove( person->listEMail, found );
973 addritem_person_add_email( target, found );
974 cache->dirtyFlag = TRUE;
977 addritem_person_add_email( target, found );
978 cache->dirtyFlag = TRUE;
984 * Return link list of address items for root level folder. Note that the list contains
985 * references to items and should be g_free() when done. Do *NOT* attempt to use the
986 * addrcache_free_xxx() functions... this will destroy the address cache data!
987 * Return: List of items, or NULL if none.
989 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
992 ItemFolder *f = folder;
994 g_return_val_if_fail( cache != NULL, NULL );
996 if( ! f ) f = cache->rootFolder;
997 node = f->listPerson;
999 list = g_list_append( list, node->data );
1000 node = g_list_next( node );
1002 node = f->listGroup;
1004 list = g_list_append( list, node->data );
1005 node = g_list_next( node );
1011 * Return link list of persons for specified folder. Note that the list contains
1012 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1013 * addrcache_free_xxx() functions... this will destroy the address cache data!
1014 * Return: List of items, or NULL if none.
1016 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1017 ItemFolder *f = folder;
1019 g_return_val_if_fail( cache != NULL, NULL );
1021 if( ! f ) f = cache->rootFolder;
1022 return addritem_folder_get_person_list( f );
1026 * Return link list of group items for specified folder. Note that the list contains
1027 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1028 * addrcache_free_xxx() functions... this will destroy the address cache data!
1029 * Return: List of items, or NULL if none.
1031 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1032 ItemFolder *f = folder;
1034 g_return_val_if_fail( cache != NULL, NULL );
1036 if( ! f ) f = cache->rootFolder;
1037 return addritem_folder_get_group_list( f );
1041 * Return link list of folder items for specified folder. Note that the list contains
1042 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1043 * addrcache_free_xxx() functions... this will destroy the address cache data!
1044 * Return: List of items, or NULL if none.
1046 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1049 ItemFolder *f = folder;
1051 g_return_val_if_fail( cache != NULL, NULL );
1053 if( ! f ) f = cache->rootFolder;
1054 node = f->listFolder;
1056 list = g_list_append( list, node->data );
1057 node = g_list_next( node );
1063 * Return link list of address items for root level folder. Note that the list contains
1064 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1065 * addrcache_free_xxx() functions... this will destroy the address cache data!
1066 * Return: List of items, or NULL if none.
1068 GList *addrcache_get_address_list( AddressCache *cache ) {
1069 g_return_val_if_fail( cache != NULL, NULL );
1070 return addrcache_folder_get_address_list( cache, cache->rootFolder );
1074 * Return link list of persons for root level folder. Note that the list contains
1075 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1076 * addrcache_free_xxx() functions... this will destroy the address cache data!
1077 * Return: List of items, or NULL if none.
1079 GList *addrcache_get_person_list( AddressCache *cache ) {
1080 g_return_val_if_fail( cache != NULL, NULL );
1081 return addritem_folder_get_person_list( cache->rootFolder );
1085 * Return link list of group items in root level folder. Note that the list contains
1086 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1087 * addrcache_free_xxx() functions... this will destroy the address cache data!
1088 * Return: List of items, or NULL if none.
1090 GList *addrcache_get_group_list( AddressCache *cache ) {
1091 g_return_val_if_fail( cache != NULL, NULL );
1092 return cache->rootFolder->listGroup;
1096 * Return link list of folder items in root level folder. Note that the list contains
1097 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1098 * addrcache_free_xxx() functions... this will destroy the address cache data!
1099 * Return: List of items, or NULL if none.
1101 GList *addrcache_get_folder_list( AddressCache *cache ) {
1102 g_return_val_if_fail( cache != NULL, NULL );
1103 return cache->rootFolder->listFolder;
1107 * Group visitor function.
1109 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1110 AddrItemObject *obj = ( AddrItemObject * ) value;
1112 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1113 AddressCache *cache = data;
1114 ItemGroup *group = ( ItemGroup * ) obj;
1115 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1116 GList *node = group->listEMail;
1118 ItemEMail *email = ( ItemEMail * ) node->data;
1119 if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1120 if( ! g_list_find( cache->tempList, group ) ) {
1121 cache->tempList = g_list_append( cache->tempList, group );
1124 node = g_list_next( node );
1130 * Return linked list of groups which contain a reference to specified person's email
1133 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1136 g_return_val_if_fail( cache != NULL, NULL );
1138 cache->tempList = NULL;
1139 cache->tempList = g_list_append( cache->tempList, person );
1140 g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1141 cache->tempList = g_list_remove( cache->tempList, person );
1142 list = cache->tempList;
1143 cache->tempList = NULL;
1148 * Find root folder for specified folder.
1149 * Enter: folder Folder to search.
1150 * Return: root folder, or NULL if not found.
1152 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1153 ItemFolder *item = folder;
1157 if( item->isRoot ) break;
1158 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1162 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1168 * Get all person visitor function.
1170 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1171 AddrItemObject *obj = ( AddrItemObject * ) value;
1173 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1174 AddressCache *cache = data;
1175 cache->tempList = g_list_append( cache->tempList, obj );
1180 * Return link list of all persons in address cache. Note that the list contains
1181 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1182 * this will destroy the address cache data!
1183 * Return: List of items, or NULL if none.
1185 GList *addrcache_get_all_persons( AddressCache *cache ) {
1188 g_return_val_if_fail( cache != NULL, NULL );
1190 cache->tempList = NULL;
1191 g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1192 list = cache->tempList;
1193 cache->tempList = NULL;
1198 * Get all groups visitor function.
1200 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1201 AddrItemObject *obj = ( AddrItemObject * ) value;
1203 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1204 AddressCache *cache = data;
1205 cache->tempList = g_list_append( cache->tempList, obj );
1210 * Return link list of all groups in address cache. Note that the list contains
1211 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1212 * this will destroy the address cache data!
1213 * Return: List of items, or NULL if none.
1215 GList *addrcache_get_all_groups( AddressCache *cache ) {
1218 g_return_val_if_fail( cache != NULL, NULL );
1220 cache->tempList = NULL;
1221 g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1222 list = cache->tempList;
1223 cache->tempList = NULL;
1228 * Remove folder from cache. Children are re-parented to parent folder.
1229 * param: folder Folder to remove.
1230 * return: Folder, or NULL if not found. Note that object should still be freed.
1232 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1233 AddrItemObject *obj = NULL;
1235 g_return_val_if_fail( cache != NULL, NULL );
1238 gchar *uid = ADDRITEM_ID(folder);
1239 if( uid == NULL || *uid == '\0' ) return NULL;
1240 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1242 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1244 AddrItemObject *aio;
1245 if( ! parent ) parent = cache->rootFolder;
1247 /* Re-parent children in folder */
1248 node = folder->listFolder;
1250 aio = ( AddrItemObject * ) node->data;
1251 parent->listFolder = g_list_append( parent->listFolder, aio );
1252 aio->parent = ADDRITEM_OBJECT(parent);
1253 node = g_list_next( node );
1255 node = folder->listPerson;
1257 aio = ( AddrItemObject * ) node->data;
1258 parent->listPerson = g_list_append( parent->listPerson, aio );
1259 aio->parent = ADDRITEM_OBJECT(parent);
1260 node = g_list_next( node );
1262 node = folder->listGroup;
1264 aio = ( AddrItemObject * ) node->data;
1265 parent->listGroup = g_list_append( parent->listGroup, aio );
1266 aio->parent = ADDRITEM_OBJECT(parent);
1267 node = g_list_next( node );
1270 /* Remove folder from parent's list and hash table */
1271 parent->listFolder = g_list_remove( parent->listFolder, folder );
1272 ADDRITEM_PARENT(folder) = NULL;
1273 g_hash_table_remove( cache->itemHash, uid );
1274 cache->dirtyFlag = TRUE;
1282 * Remove folder from cache. Children are deleted.
1283 * param: folder Folder to remove.
1284 * return: Folder, or NULL if not found. Note that object should still be freed.
1286 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1287 AddrItemObject *obj = NULL;
1289 g_return_val_if_fail( cache != NULL, NULL );
1292 gchar *uid = ADDRITEM_ID(folder);
1293 if( uid == NULL || *uid == '\0' ) return NULL;
1294 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1296 ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1297 if( ! parent ) parent = cache->rootFolder;
1300 while( folder->listGroup ) {
1301 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1302 item = addrcache_remove_group( cache, item );
1304 addritem_free_item_group( item );
1309 while( folder->listPerson ) {
1310 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1311 item = addrcache_remove_person( cache, item );
1313 addritem_free_item_person( item );
1318 /* Recursive deletion of folder */
1319 while( folder->listFolder ) {
1320 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1321 item = addrcache_remove_folder_delete( cache, item );
1323 addritem_free_item_folder( item );
1328 /* Remove folder from parent's list and hash table */
1329 parent->listFolder = g_list_remove( parent->listFolder, folder );
1330 ADDRITEM_PARENT(folder) = NULL;
1331 g_hash_table_remove( cache->itemHash, uid );
1332 cache->dirtyFlag = TRUE;
1340 * Add person and address data to cache.
1341 * Enter: cache Cache.
1342 * folder Folder where to add person, or NULL for root folder.
1344 * address EMail address.
1346 * Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1347 * this will destroy the address book data.
1349 ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, const gchar *name,
1350 const gchar *address, const gchar *remarks )
1352 ItemPerson *person = NULL;
1353 ItemEMail *email = NULL;
1354 ItemFolder *f = folder;
1356 g_return_val_if_fail( cache != NULL, NULL );
1358 if( ! f ) f = cache->rootFolder;
1360 /* Create person object */
1361 person = addritem_create_item_person();
1362 addritem_person_set_common_name( person, name );
1363 addrcache_id_person( cache, person );
1364 addrcache_folder_add_person( cache, f, person );
1366 /* Create email object */
1367 email = addritem_create_item_email();
1368 addritem_email_set_address( email, address );
1369 addritem_email_set_remarks( email, remarks );
1370 addrcache_id_email( cache, email );
1371 addritem_person_add_email( person, email );
1372 cache->dirtyFlag = TRUE;
1378 * Clear address completion index.
1379 * \param cache Cache.
1381 void addrcache_clear_index( AddressCache *cache ) {
1382 g_return_if_fail( cache != NULL );
1383 addrcindex_clear( cache->searchIndex );
1387 * Control creation of an address completion index.
1388 * \param cache Cache.
1389 * \param value Set to <i>TRUE</i> to create an index, or <i>FALSE</i> to
1392 void addrcache_use_index( AddressCache *cache, gboolean value ) {
1393 g_return_if_fail( cache != NULL );
1396 if( cache->searchIndex ) {
1397 addrcindex_clear( cache->searchIndex );
1400 cache->searchIndex = addrcindex_create();
1404 addrcindex_free( cache->searchIndex );
1405 cache->searchIndex = NULL;
1410 * Load completion callback function.
1412 static void addrcache_load_index_cb( gpointer key, gpointer value, gpointer data ) {
1413 AddrItemObject *obj = ( AddrItemObject * ) value;
1415 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1416 ItemPerson *person = ( ItemPerson * ) obj;
1417 AddrCacheIndex *index = data;
1418 addrcindex_add_person( index, person );
1423 * Rebuild address completion index with all persons in cache.
1424 * \param cache Cache.
1426 void addrcache_build_index( AddressCache *cache ) {
1427 g_return_if_fail( cache != NULL );
1429 if( cache->searchIndex == NULL ) return;
1432 addrcindex_clear( cache->searchIndex );
1435 g_hash_table_foreach(
1436 cache->itemHash, addrcache_load_index_cb, cache->searchIndex );
1437 addrcindex_validate( cache->searchIndex );
1439 /* addrcindex_print( cache->searchIndex, stdout ); */
1443 * Invalidate the address cache. This will cause index to be rebuilt.
1444 * \param cache Cache.
1446 void addrcache_invalidate( AddressCache *cache ) {
1447 g_return_if_fail( cache != NULL );
1449 if( cache->searchIndex == NULL ) return;
1450 addrcindex_invalidate( cache->searchIndex );