2005-09-14 [paul] 1.9.14cvs26
[claws.git] / src / addrcache.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2002 Match Grun
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 /*
21  * Functions to maintain address cache.
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/stat.h>
27
28 #include "mgutils.h"
29 #include "addrcache.h"
30 #include "utils.h"
31
32 #define ID_TIME_OFFSET             998000000
33 #define ADDRCACHE_MAX_SEARCH_COUNT 1000
34
35 static int _nextCacheID__ = 0;
36
37 /*
38  * Generate next cache ID.
39  */
40 static int addrcache_next_cache_id() {
41         int retVal;
42
43         if( _nextCacheID__ == 0 ) {
44                 _nextCacheID__ = 1;
45         }
46         retVal = _nextCacheID__;
47         ++_nextCacheID__;
48         return retVal;
49 }
50
51 /*
52 * Create new address cache.
53 */
54 AddressCache *addrcache_create() {
55         AddressCache *cache;
56         gint t;
57
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() );
61
62         cache->dataRead = FALSE;
63         cache->modified = FALSE;
64         cache->dirtyFlag = FALSE;
65         cache->accessFlag = FALSE;
66         cache->name = NULL;
67         cache->modifyTime = 0;
68
69         /* Generate the next ID using system time */
70         cache->nextID = 1;
71         t = time( NULL );
72         if( t > 0 ) {
73                 cache->nextID = t - ID_TIME_OFFSET;
74         }
75
76         cache->tempList = NULL;
77         cache->rootFolder = addritem_create_item_folder();
78         cache->rootFolder->isRoot = TRUE;
79         ADDRITEM_PARENT(cache->rootFolder) = NULL;
80         return cache;
81 }
82
83 /*
84 * Properties.
85 */
86 ItemFolder *addrcache_get_root_folder( AddressCache *cache ) {
87         g_return_val_if_fail( cache != NULL, NULL );
88         return cache->rootFolder;
89 }
90 GList *addrcache_get_list_folder( AddressCache *cache ) {
91         g_return_val_if_fail( cache != NULL, NULL );
92         return cache->rootFolder->listFolder;
93 }
94 GList *addrcache_get_list_person( AddressCache *cache ) {
95         g_return_val_if_fail( cache != NULL, NULL );
96         return cache->rootFolder->listPerson;
97 }
98 gboolean addrcache_get_dirty( AddressCache *cache ) {
99         g_return_val_if_fail( cache != NULL, FALSE );
100         return cache->dirtyFlag;
101 }
102 void addrcache_set_dirty( AddressCache *cache, const gboolean value ) {
103         g_return_if_fail( cache != NULL );
104         cache->dirtyFlag = value;
105 }
106 gboolean addrcache_get_modified( AddressCache *cache ) {
107         g_return_val_if_fail( cache != NULL, FALSE );
108         return cache->modified;
109 }
110 void addrcache_set_modified( AddressCache *cache, const gboolean value ) {
111         g_return_if_fail( cache != NULL );
112         cache->modified = value;
113 }
114 gboolean addrcache_get_read_flag( AddressCache *cache ) {
115         g_return_val_if_fail( cache != NULL, FALSE );
116         return cache->dataRead;
117 }
118 void addrcache_set_read_flag( AddressCache *cache, const gboolean value ) {
119         g_return_if_fail( cache != NULL );
120         cache->dataRead = value;
121 }
122 gboolean addrcache_get_accessed( AddressCache *cache ) {
123         g_return_val_if_fail( cache != NULL, FALSE );
124         return cache->accessFlag;
125 }
126 void addrcache_set_accessed( AddressCache *cache, const gboolean value ) {
127         g_return_if_fail( cache != NULL );
128         cache->accessFlag = value;
129 }
130 gchar *addrcache_get_name( AddressCache *cache ) {
131         g_return_val_if_fail( cache != NULL, NULL );
132         return cache->name;
133 }
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;
139 }
140
141 /*
142 * Generate next ID.
143 */
144 void addrcache_next_id( AddressCache *cache ) {
145         g_return_if_fail( cache != NULL );
146         cache->nextID++;
147 }
148
149 /*
150 * Refresh internal variables. This can be used force a reload.
151 */
152 void addrcache_refresh( AddressCache *cache ) {
153         cache->dataRead = FALSE;
154         cache->modified = TRUE;
155         cache->accessFlag = FALSE;
156         cache->modifyTime = 0;
157 }
158
159 /*
160 * Free hash table visitor function.
161 */
162 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
163         AddrItemObject *obj = ( AddrItemObject * ) value;
164
165         if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
166                 addritem_free_item_person( ( ItemPerson * ) obj );
167         }
168         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
169                 addritem_free_item_email( ( ItemEMail * ) obj );
170         }
171         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
172                 addritem_free_item_group( ( ItemGroup * ) obj );
173         }
174         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
175                 addritem_free_item_folder( ( ItemFolder * ) obj );
176         }
177         key = NULL;
178         value = NULL;
179         return TRUE;
180 }
181
182 /*
183 * Free hash table of address cache items.
184 */
185 static void addrcache_free_item_hash( GHashTable *table ) {
186         g_return_if_fail( table != NULL );
187         g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
188 }
189
190 /*
191 * Free up folders and groups.
192 */
193 static void addrcache_free_all_folders( ItemFolder *parent ) {
194         GList *node;
195
196         if( parent == NULL ) return;
197
198         node = parent->listFolder;
199         while( node ) {
200                 ItemFolder *folder = node->data;
201                 addrcache_free_all_folders( folder );
202                 node->data = NULL;
203                 node = g_list_next( node );
204         }
205         g_list_free( parent->listPerson );
206         g_list_free( parent->listGroup );
207         g_list_free( parent->listFolder );
208         parent->listPerson = NULL;
209         parent->listGroup = NULL;
210         parent->listFolder = NULL;
211 }
212
213 /*
214 * Clear the address cache.
215 */
216 void addrcache_clear( AddressCache *cache ) {
217         g_return_if_fail( cache != NULL );
218
219         /* printf( "...addrcache_clear :%s:\n", cache->name ); */
220         /* Free up folders and hash table */
221         addrcache_free_all_folders( cache->rootFolder );
222         addrcache_free_item_hash( cache->itemHash );
223         g_hash_table_destroy( cache->itemHash );
224         cache->itemHash = NULL;
225         ADDRITEM_PARENT(cache->rootFolder) = NULL;
226         addritem_free_item_folder( cache->rootFolder );
227         cache->rootFolder = NULL;
228         if( cache->tempList ) g_list_free( cache->tempList );
229         cache->tempList = NULL;
230
231         /* Reset to initial state */
232         cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
233         cache->rootFolder = addritem_create_item_folder();
234         cache->rootFolder->isRoot = TRUE;
235         ADDRITEM_PARENT(cache->rootFolder) = NULL;
236
237         addrcache_refresh( cache );
238 }
239
240 /*
241 * Free address cache.
242 */
243 void addrcache_free( AddressCache *cache ) {
244         g_return_if_fail( cache != NULL );
245
246         cache->dirtyFlag = FALSE;
247         addrcache_free_all_folders( cache->rootFolder );
248         addrcache_free_item_hash( cache->itemHash );
249         g_hash_table_destroy( cache->itemHash );
250         cache->itemHash = NULL;
251         ADDRITEM_PARENT(cache->rootFolder) = NULL;
252         addritem_free_item_folder( cache->rootFolder );
253         cache->rootFolder = NULL;
254         g_list_free( cache->tempList );
255         cache->tempList = NULL;
256         g_free( cache->cacheID );
257         cache->cacheID = NULL;
258         g_free( cache->name );
259         cache->name = NULL;
260         g_free( cache );
261 }
262
263 /*
264 * Check whether file has changed by comparing with cache.
265 * return: TRUE if file has changed.
266 */
267 gboolean addrcache_check_file( AddressCache *cache, gchar *path ) {
268         gboolean retVal;
269         struct stat filestat;
270         retVal = TRUE;
271         if( path ) {
272                 if( 0 == g_stat( path, &filestat ) ) {
273                         if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
274                 }
275         }
276         return retVal;
277 }
278
279 /*
280 * Save file time to cache.
281 * return: TRUE if time marked.
282 */
283 gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) {
284         gboolean retVal = FALSE;
285         struct stat filestat;
286         if( path ) {
287                 if( 0 == g_stat( path, &filestat ) ) {
288                         cache->modifyTime = filestat.st_mtime;
289                         retVal = TRUE;
290                 }
291         }
292         return retVal;
293 }
294
295 /*
296 * Print list of items.
297 */
298 void addrcache_print_item_list( GList *list, FILE *stream ) {
299         GList *node = list;
300         while( node ) {
301                 AddrItemObject *obj = node->data;
302                 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
303                         addritem_print_item_person( ( ItemPerson * ) obj, stream );
304                 }
305                 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
306                         addritem_print_item_group( ( ItemGroup * ) obj, stream );
307                 }
308                 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
309                         addritem_print_item_folder( ( ItemFolder * ) obj, stream );
310                 }
311                 node = g_list_next( node );
312         }
313         fprintf( stream, "\t---\n" );
314 }
315
316 /*
317 * Print item hash table visitor function.
318 */
319 static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) {
320         AddrItemObject *obj = ( AddrItemObject * ) value;
321         FILE *stream = ( FILE * ) data;
322         if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
323                 addritem_print_item_person( ( ItemPerson * ) obj, stream );
324         }
325         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
326                 printf( "addrcache: print email\n" );
327         }
328         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
329                 addritem_print_item_group( ( ItemGroup * ) obj, stream );
330         }
331         else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
332                 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
333         }
334 }
335
336 /*
337 * Dump entire address cache hash table contents.
338 */
339 void addrcache_print( AddressCache *cache, FILE *stream ) {
340         g_return_if_fail( cache != NULL );
341         fprintf( stream, "AddressCache:\n" );
342         fprintf( stream, "cache id : %s\n",  cache->cacheID );
343         fprintf( stream, "next id  : %d\n",  cache->nextID );
344         fprintf( stream, "name     : %s\n",  cache->name );
345         fprintf( stream, "mod time : %ld\n", (long int)cache->modifyTime );
346         fprintf( stream, "modified : %s\n",  cache->modified ? "yes" : "no" );
347         fprintf( stream, "data read: %s\n",  cache->dataRead ? "yes" : "no" );
348 }
349
350 /*
351 * Dump entire address cache hash table contents.
352 */
353 void addrcache_dump_hash( AddressCache *cache, FILE *stream ) {
354         g_return_if_fail( cache != NULL );
355         addrcache_print( cache, stream );
356         g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream );
357 }
358
359 /*
360  * Allocate ID for person.
361  */
362 void addrcache_id_person( AddressCache *cache, ItemPerson *person ) {
363         g_return_if_fail( cache != NULL );
364         g_return_if_fail( person != NULL );
365         if( ADDRITEM_ID(person) ) return;
366         addrcache_next_id( cache );
367         ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID );
368 }
369
370 /*
371  * Allocate ID for group.
372  */
373 void addrcache_id_group( AddressCache *cache, ItemGroup *group ) {
374         g_return_if_fail( cache != NULL );
375         g_return_if_fail( group != NULL );
376         if( ADDRITEM_ID(group) ) return;
377         addrcache_next_id( cache );
378         ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID );
379 }
380
381 /*
382  * Allocate ID for folder.
383  */
384 void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) {
385         g_return_if_fail( cache != NULL );
386         g_return_if_fail( folder != NULL );
387         if( ADDRITEM_ID(folder) ) return;
388         addrcache_next_id( cache );
389         ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID );
390 }
391
392 /*
393  * Allocate ID for email address.
394  */
395 void addrcache_id_email( AddressCache *cache, ItemEMail *email ) {
396         g_return_if_fail( cache != NULL );
397         g_return_if_fail( email != NULL );
398         if( ADDRITEM_ID(email) ) return;
399         addrcache_next_id( cache );
400         ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID );
401 }
402
403 /*
404  * Allocate ID for user attribute.
405  */
406 void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) {
407         g_return_if_fail( cache != NULL );
408         g_return_if_fail( attrib != NULL );
409         if( attrib->uid ) return;
410         addrcache_next_id( cache );
411         attrib->uid = g_strdup_printf( "%d", cache->nextID );
412 }
413
414 /*
415 * Add person to hash table.
416 * return: TRUE if item added.
417 */
418 gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
419         if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) {
420                 return FALSE;
421         }
422         g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person );
423         return TRUE;
424 }
425
426 /*
427 * Add email to hash table.
428 * return: TRUE if item added.
429 */
430 gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
431         if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
432                 return FALSE;
433         }
434         g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
435         return TRUE;
436 }
437
438 /*
439 * Add group to hash table.
440 * return: TRUE if item added.
441 */
442 gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) {
443         g_return_val_if_fail( cache != NULL, FALSE );
444         g_return_val_if_fail( group != NULL, FALSE );
445
446         if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) {
447                 return FALSE;
448         }
449         g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group );
450         return TRUE;
451 }
452
453 /*
454 * Add folder to hash table.
455 * return: TRUE if item added.
456 */
457 gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) {
458         g_return_val_if_fail( cache != NULL, FALSE );
459         g_return_val_if_fail( folder != NULL, FALSE );
460
461         if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) {
462                 return FALSE;
463         }
464         g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder );
465         return TRUE;
466 }
467
468 /*
469 * Add person to specified folder in cache.
470 */
471 gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) {
472         gboolean retVal = FALSE;
473
474         g_return_val_if_fail( cache != NULL, FALSE );
475         g_return_val_if_fail( folder != NULL, FALSE );
476         g_return_val_if_fail( item != NULL, FALSE );
477
478         retVal = addrcache_hash_add_person( cache, item );
479         if( retVal ) {
480                 addritem_folder_add_person( folder, item );
481                 cache->dirtyFlag = TRUE;
482         }
483         return retVal;
484 }
485
486 /*
487 * Add folder to specified folder in cache.
488 */
489 gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) {
490         gboolean retVal = FALSE;
491
492         g_return_val_if_fail( cache != NULL, FALSE );
493         g_return_val_if_fail( folder != NULL, FALSE );
494         g_return_val_if_fail( item != NULL, FALSE );
495
496         retVal = addrcache_hash_add_folder( cache, item );
497         if( retVal ) {
498                 addritem_folder_add_folder( folder, item );
499                 cache->dirtyFlag = TRUE;
500         }
501         return TRUE;
502 }
503
504 /*
505 * Add folder to specified folder in cache.
506 */
507 gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) {
508         gboolean retVal = FALSE;
509
510         g_return_val_if_fail( cache != NULL, FALSE );
511         g_return_val_if_fail( folder != NULL, FALSE );
512         g_return_val_if_fail( item != NULL, FALSE );
513
514         retVal = addrcache_hash_add_group( cache, item );
515         if( retVal ) {
516                 addritem_folder_add_group( folder, item );
517                 cache->dirtyFlag = TRUE;
518         }
519         return retVal;
520 }
521
522 /*
523 * Add person to address cache.
524 * return: TRUE if item added.
525 */
526 gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
527         gboolean retVal = FALSE;
528
529         g_return_val_if_fail( cache != NULL, FALSE );
530         g_return_val_if_fail( person != NULL, FALSE );
531
532         retVal = addrcache_hash_add_person( cache, person );
533         if( retVal ) {
534                 addritem_folder_add_person( cache->rootFolder, person );
535                 cache->dirtyFlag = TRUE;
536         }
537         return retVal;
538 }
539
540 /*
541 * Add EMail address to person.
542 * return: TRUE if item added.
543 */
544 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
545         gboolean retVal = FALSE;
546
547         g_return_val_if_fail( cache != NULL, FALSE );
548         g_return_val_if_fail( person != NULL, FALSE );
549         g_return_val_if_fail( email != NULL, FALSE );
550
551         retVal = addrcache_hash_add_email( cache, email );
552         if( retVal ) {
553                 addritem_person_add_email( person, email );
554                 cache->dirtyFlag = TRUE;
555         }
556         return retVal;
557 }
558
559 /*
560 * Add group to address cache.
561 * return: TRUE if item added.
562 */
563 gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
564         gboolean retVal = FALSE;
565
566         g_return_val_if_fail( cache != NULL, FALSE );
567         g_return_val_if_fail( group != NULL, FALSE );
568
569         retVal = addrcache_hash_add_group( cache, group );
570         if( retVal ) {
571                 addritem_folder_add_group( cache->rootFolder, group );
572                 cache->dirtyFlag = TRUE;
573         }
574         return retVal;
575 }
576
577 /*
578 * Add EMail address to person.
579 * return: TRUE if item added.
580 */
581 gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) {
582         g_return_val_if_fail( cache != NULL, FALSE );
583         g_return_val_if_fail( group != NULL, FALSE );
584         g_return_val_if_fail( email != NULL, FALSE );
585
586         addritem_group_add_email( group, email );
587         cache->dirtyFlag = TRUE;
588         return TRUE;
589 }
590
591 /*
592 * Add folder to address cache.
593 * return: TRUE if item added.
594 */
595 gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
596         gboolean retVal = FALSE;
597
598         g_return_val_if_fail( cache != NULL, FALSE );
599         g_return_val_if_fail( folder != NULL, FALSE );
600
601         retVal = addrcache_hash_add_folder( cache, folder );
602         if( retVal ) {
603                 addritem_folder_add_folder( cache->rootFolder, folder );
604                 cache->dirtyFlag = TRUE;
605         }
606         return retVal;
607 }
608
609 /*
610 * Move person to destination folder.
611 * Enter: cache  Cache.
612 *        person Person to move.
613 *        target Target folder.
614 */
615 void addrcache_folder_move_person(
616         AddressCache *cache, ItemPerson *person, ItemFolder *target )
617 {
618         ItemFolder *parent;
619
620         g_return_if_fail( cache != NULL );
621         g_return_if_fail( person != NULL );
622
623         parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
624         if( ! parent ) parent = cache->rootFolder;
625         parent->listPerson = g_list_remove( parent->listPerson, person );
626         target->listPerson = g_list_append( target->listPerson, person );
627         ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
628         cache->dirtyFlag = TRUE;
629 }
630
631 /*
632 * Move group to destination folder.
633 * Enter: cache  Cache.
634 *        group  Group to move.
635 *        target Target folder.
636 */
637 void addrcache_folder_move_group(
638         AddressCache *cache, ItemGroup *group, ItemFolder *target )
639 {
640         ItemFolder *parent;
641
642         g_return_if_fail( cache != NULL );
643         g_return_if_fail( group != NULL );
644
645         parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
646         if( ! parent ) parent = cache->rootFolder;
647         parent->listGroup = g_list_remove( parent->listGroup, group );
648         target->listGroup = g_list_append( target->listGroup, group );
649         ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
650         cache->dirtyFlag = TRUE;
651 }
652
653 /*
654 * Move folder to destination folder.
655 * Enter: cache  Cache.
656 *        folder Folder to move.
657 *        target Target folder.
658 */
659 void addrcache_folder_move_folder(
660         AddressCache *cache, ItemFolder *folder, ItemFolder *target )
661 {
662         ItemFolder *parent;
663
664         g_return_if_fail( cache != NULL );
665         g_return_if_fail( folder != NULL );
666
667         parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
668         if( ! parent ) parent = cache->rootFolder;
669         parent->listFolder = g_list_remove( parent->listFolder, folder );
670         target->listFolder = g_list_append( target->listFolder, folder );
671         ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
672         cache->dirtyFlag = TRUE;
673 }
674
675 /*
676 * Return pointer to object (either person or group) for specified ID.
677 * param: uid Object ID.
678 * return: Object, or NULL if not found.
679 */
680 AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) {
681         AddrItemObject *obj = NULL;
682         gchar *uidH;
683
684         g_return_val_if_fail( cache != NULL, NULL );
685
686         if( uid == NULL || *uid == '\0' ) return NULL;
687         obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
688         if( obj ) {
689                 /* Check for matching UID */
690                 uidH = ADDRITEM_ID(obj);
691                 if( uidH ) {
692                         if( strcmp( uidH, uid ) == 0 ) return obj;
693                 }
694         }
695         return NULL;
696 }
697
698 /*
699 * Return pointer for specified object ID.
700 * param: uid Object ID.
701 * return: Person object, or NULL if not found.
702 */
703 ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) {
704         ItemPerson *person = NULL;
705         AddrItemObject *obj = addrcache_get_object( cache, uid );
706
707         if( obj ) {
708                 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
709                         person = ( ItemPerson * ) obj;
710                 }
711         }
712         return person;
713 }
714
715 /*
716 * Return pointer for specified object ID.
717 * param: uid group ID.
718 * return: Group object, or NULL if not found.
719 */
720 ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
721         ItemGroup *group = NULL;
722         AddrItemObject *obj = addrcache_get_object( cache, uid );
723
724         if( obj ) {
725                 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
726                         group = ( ItemGroup * ) obj;
727                 }
728         }
729         return group;
730 }
731
732 /*
733 * Find email address in address cache.
734 * param: eid    EMail ID.
735 * return: email object for specified object ID and email ID, or NULL if not found.
736 */
737 ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
738         ItemEMail *email = NULL;
739         AddrItemObject *obj = addrcache_get_object( cache, eid );
740
741         if( obj ) {
742                 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
743                         email = ( ItemEMail * ) obj;
744                 }
745         }
746         return email;
747 }
748
749 /*
750 * Remove attribute from person.
751 * param: uid    Object ID for person.
752 *        aid    Attribute ID.
753 * return: UserAttribute object, or NULL if not found. Note that object should still be freed.
754 */
755 UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) {
756         UserAttribute *attrib = NULL;
757         ItemPerson *person;
758
759         if( aid == NULL || *aid == '\0' ) return NULL;
760
761         person = addrcache_get_person( cache, uid );
762         if( person ) {
763                 attrib = addritem_person_remove_attrib_id( person, aid );
764                 cache->dirtyFlag = TRUE;
765         }
766         return attrib;
767 }
768
769 /*
770 * Remove attribute from person.
771 * param: person Person.
772 *        attrib Attribute to remove.
773 * return: UserAttribute object. Note that object should still be freed.
774 */
775 UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) {
776         UserAttribute *found = NULL;
777
778         g_return_val_if_fail( cache != NULL, NULL );
779
780         if( person && attrib ) {
781                 found = addritem_person_remove_attribute( person, attrib );
782                 cache->dirtyFlag = TRUE;
783         }
784         return found;
785 }
786
787 /*
788 * Remove group from address cache.
789 * param: group  Group to remove.
790 * return: Group, or NULL if not found. Note that object should still be freed.
791 */
792 ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
793         AddrItemObject *obj = NULL;
794
795         g_return_val_if_fail( cache != NULL, NULL );
796
797         if( group ) {
798                 gchar *uid = ADDRITEM_ID(group);
799                 if( uid == NULL || *uid == '\0' ) return NULL;
800                 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
801                 if( obj ) {
802                         ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
803                         if( ! parent ) parent = cache->rootFolder;
804
805                         /* Remove group from parent's list and hash table */
806                         parent->listGroup = g_list_remove( parent->listGroup, obj );
807                         g_hash_table_remove( cache->itemHash, uid );
808                         cache->dirtyFlag = TRUE;
809                         return group;
810                 }
811         }
812         return NULL;
813 }
814
815 /*
816 * Remove specified email from address cache. Note that object is only
817 * removed from cache and not parent objects.
818 * param: email  EMail to remove.
819 * return: EMail, or NULL if not found. Note that object should still be freed.
820 */
821 ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
822         AddrItemObject *obj = NULL;
823
824         g_return_val_if_fail( cache != NULL, NULL );
825
826         if( email ) {
827                 gchar *eid = ADDRITEM_ID(email);
828                 if( eid == NULL || *eid == '\0' ) return NULL;
829                 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
830                 if( obj ) {
831                         if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
832                                 /* Remove email addresses from hash table. */
833                                 g_hash_table_remove( cache->itemHash, eid );
834                                 cache->dirtyFlag = TRUE;
835                                 return email;
836                         }
837                 }
838         }
839         return NULL;
840 }
841
842 /*
843 * Hash table visitor function to remove email from group.
844 */
845 static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
846         AddrItemObject *obj = ( AddrItemObject * ) value;
847         ItemEMail *email = ( ItemEMail * ) data;
848
849         if( ! email ) return;
850         if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
851                 ItemGroup *group = ( ItemGroup * ) value;
852                 if( group ) {
853                         /* Remove each email address that belongs to the person from the list */
854                         group->listEMail = g_list_remove( group->listEMail, email );
855                 }
856         }
857 }
858
859 /*
860 * Remove specified person from address cache.
861 * param: person Person to remove.
862 * return: Person, or NULL if not found. Note that object should still be freed.
863 */
864 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
865         AddrItemObject *obj = NULL;
866         gchar *uid;
867
868         g_return_val_if_fail( cache != NULL, NULL );
869
870         if( person ) {
871                 uid = ADDRITEM_ID(person);
872                 if( uid == NULL || *uid == '\0' ) return NULL;
873                 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
874                 if( obj ) {
875                         if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
876                                 ItemFolder *parent;
877                                 GList *node;
878
879                                 /* Remove all email addresses for person */
880                                 /* from groups and from hash table */
881                                 node = person->listEMail;
882                                 while( node ) {
883                                         ItemEMail *email;
884                                         gchar *eid;
885
886                                         email = node->data;
887                                         g_hash_table_foreach( cache->itemHash,
888                                                 addrcache_allgrp_rem_email_vis, email );
889                                         eid = ADDRITEM_ID( email );
890                                         g_hash_table_remove( cache->itemHash, eid );
891                                         node = g_list_next( node );
892                                 }
893
894                                 /* Remove person from owning folder */
895                                 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
896                                 if( ! parent ) parent = cache->rootFolder;
897                                 parent->listPerson = g_list_remove( parent->listPerson, person );
898                                 g_hash_table_remove( cache->itemHash, uid );
899                                 cache->dirtyFlag = TRUE;
900                                 return person;
901                         }
902                 }
903         }
904         return NULL;
905 }
906
907 /*
908 * Remove email address in address cache for specified person.
909 * param: person Person.
910 *        email  EMail to remove.
911 * return: EMail object, or NULL if not found. Note that object should still be freed.
912 */
913 ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
914         ItemEMail *found = NULL;
915
916         g_return_val_if_fail( cache != NULL, NULL );
917
918         if( person && email ) {
919                 found = addritem_person_remove_email( person, email );
920                 if( found ) {
921                         /* Remove email from all groups. */
922                         g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
923
924                         /* Remove email from person's address list */
925                         if( person->listEMail ) {
926                                 person->listEMail = g_list_remove( person->listEMail, email );
927                         }
928                         /* Unlink reference to person. */
929                         ADDRITEM_PARENT(email) = NULL;
930                         cache->dirtyFlag = TRUE;
931                 }
932         }
933         return found;
934 }
935
936 /*
937 * Move email address in address cache to new person. If member of group, address
938 * remains in group.
939 * param: cache  Cache.
940 *        email  EMail to remove.
941 *        target Target person.
942 * return: EMail object, or NULL if not found. Note that object should still be freed.
943 */
944 void addrcache_person_move_email(
945         AddressCache *cache, ItemEMail *email, ItemPerson *target )
946 {
947         ItemPerson *person;
948
949         g_return_if_fail( cache != NULL );
950
951         if( email == NULL ) return;
952         if( target == NULL ) return;
953
954         person = ( ItemPerson * ) ADDRITEM_PARENT(email);
955         if( person ) {
956                 ItemEMail *found;
957                 found = addritem_person_remove_email( person, email );
958                 if( found ) {
959                         /*
960                         if( person->listEMail ) {
961                                 person->listEMail = g_list_remove( person->listEMail, found );
962                                 addritem_person_add_email( target, found );
963                                 cache->dirtyFlag = TRUE;
964                         }
965                         */
966                         addritem_person_add_email( target, found );
967                         cache->dirtyFlag = TRUE;
968                 }
969         }
970 }
971
972 /*
973 * Return link list of address items for root level folder. Note that the list contains
974 * references to items and should be g_free() when done. Do *NOT* attempt to use the
975 * addrcache_free_xxx() functions... this will destroy the address cache data!
976 * Return: List of items, or NULL if none.
977 */
978 GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) {
979         GList *list = NULL;
980         GList *node = NULL;
981         ItemFolder *f = folder;
982
983         g_return_val_if_fail( cache != NULL, NULL );
984
985         if( ! f ) f = cache->rootFolder;
986         node = f->listPerson;
987         while( node ) {
988                 list = g_list_append( list, node->data );
989                 node = g_list_next( node );
990         }
991         node = f->listGroup;
992         while( node ) {
993                 list = g_list_append( list, node->data );
994                 node = g_list_next( node );
995         }
996         return list;
997 }
998
999 /*
1000 * Return link list of persons for specified folder. Note that the list contains
1001 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1002 * addrcache_free_xxx() functions... this will destroy the address cache data!
1003 * Return: List of items, or NULL if none.
1004 */
1005 GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) {
1006         ItemFolder *f = folder;
1007
1008         g_return_val_if_fail( cache != NULL, NULL );
1009
1010         if( ! f ) f = cache->rootFolder;
1011         return addritem_folder_get_person_list( f );
1012 }
1013
1014 /*
1015 * Return link list of group items for specified folder. Note that the list contains
1016 * references to items and should be g_free() when done. Do *NOT* attempt to use the
1017 * addrcache_free_xxx() functions... this will destroy the address cache data!
1018 * Return: List of items, or NULL if none.
1019 */
1020 GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) {
1021         ItemFolder *f = folder;
1022
1023         g_return_val_if_fail( cache != NULL, NULL );
1024
1025         if( ! f ) f = cache->rootFolder;
1026         return addritem_folder_get_group_list( f );
1027 }
1028
1029 /*
1030 * Return link list of folder items for specified folder. Note that the list contains
1031 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1032 * addrcache_free_xxx() functions... this will destroy the address cache data!
1033 * Return: List of items, or NULL if none.
1034 */
1035 GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) {
1036         GList *node = NULL;
1037         GList *list = NULL;
1038         ItemFolder *f = folder;
1039
1040         g_return_val_if_fail( cache != NULL, NULL );
1041
1042         if( ! f ) f = cache->rootFolder;
1043         node = f->listFolder;
1044         while( node ) {
1045                 list = g_list_append( list, node->data );
1046                 node = g_list_next( node );
1047         }
1048         return list;
1049 }
1050
1051 /*
1052 * Return link list of address items for root level folder. Note that the list contains
1053 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1054 * addrcache_free_xxx() functions... this will destroy the address cache data!
1055 * Return: List of items, or NULL if none.
1056 */
1057 GList *addrcache_get_address_list( AddressCache *cache ) {
1058         g_return_val_if_fail( cache != NULL, NULL );
1059         return addrcache_folder_get_address_list( cache, cache->rootFolder );
1060 }
1061
1062 /*
1063 * Return link list of persons for root level folder. Note that the list contains
1064 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1065 * addrcache_free_xxx() functions... this will destroy the address cache data!
1066 * Return: List of items, or NULL if none.
1067 */
1068 GList *addrcache_get_person_list( AddressCache *cache ) {
1069         g_return_val_if_fail( cache != NULL, NULL );
1070         return addritem_folder_get_person_list( cache->rootFolder );
1071 }
1072
1073 /*
1074 * Return link list of group items in root level folder. Note that the list contains
1075 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1076 * addrcache_free_xxx() functions... this will destroy the address cache data!
1077 * Return: List of items, or NULL if none.
1078 */
1079 GList *addrcache_get_group_list( AddressCache *cache ) {
1080         g_return_val_if_fail( cache != NULL, NULL );
1081         return cache->rootFolder->listGroup;
1082 }
1083
1084 /*
1085 * Return link list of folder items in root level folder. Note that the list contains
1086 * references to items and should be g_free() when done. Do *NOT* attempt to used the
1087 * addrcache_free_xxx() functions... this will destroy the address cache data!
1088 * Return: List of items, or NULL if none.
1089 */
1090 GList *addrcache_get_folder_list( AddressCache *cache ) {
1091         g_return_val_if_fail( cache != NULL, NULL );
1092         return cache->rootFolder->listFolder;
1093 }
1094
1095 /*
1096 * Group visitor function.
1097 */
1098 static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) {
1099         AddrItemObject *obj = ( AddrItemObject * ) value;
1100
1101         if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1102                 AddressCache *cache = data;
1103                 ItemGroup *group = ( ItemGroup * ) obj;
1104                 ItemPerson *person = ( ItemPerson * ) cache->tempList->data;
1105                 GList *node = group->listEMail;
1106                 while( node ) {
1107                         ItemEMail *email = ( ItemEMail * ) node->data;
1108                         if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) {
1109                                 if( ! g_list_find( cache->tempList, group ) ) {
1110                                         cache->tempList = g_list_append( cache->tempList, group );
1111                                 }
1112                         }
1113                         node = g_list_next( node );
1114                 }
1115         }
1116 }
1117
1118 /*
1119 * Return linked list of groups which contain a reference to specified person's email
1120 * address.
1121 */
1122 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
1123         GList *list = NULL;
1124
1125         g_return_val_if_fail( cache != NULL, NULL );
1126
1127         cache->tempList = NULL;
1128         cache->tempList = g_list_append( cache->tempList, person );
1129         g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache );
1130         cache->tempList = g_list_remove( cache->tempList, person );
1131         list = cache->tempList;
1132         cache->tempList = NULL;
1133         return list;
1134 }
1135
1136 /*
1137 * Find root folder for specified folder.
1138 * Enter: folder Folder to search.
1139 * Return: root folder, or NULL if not found.
1140 */
1141 ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) {
1142         ItemFolder *item = folder;
1143         gint count = 0;
1144
1145         while( item ) {
1146                 if( item->isRoot ) break;
1147                 if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) {
1148                         item = NULL;
1149                         break;
1150                 }
1151                 item = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1152         }
1153         return item;
1154 }
1155
1156 /*
1157 * Get all person visitor function.
1158 */
1159 static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) {
1160         AddrItemObject *obj = ( AddrItemObject * ) value;
1161
1162         if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1163                 AddressCache *cache = data;
1164                 cache->tempList = g_list_append( cache->tempList, obj );
1165         }
1166 }
1167
1168 /*
1169 * Return link list of all persons in address cache.  Note that the list contains
1170 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1171 * this will destroy the address cache data!
1172 * Return: List of items, or NULL if none.
1173 */
1174 GList *addrcache_get_all_persons( AddressCache *cache ) {
1175         GList *list = NULL;
1176
1177         g_return_val_if_fail( cache != NULL, NULL );
1178
1179         cache->tempList = NULL;
1180         g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache );
1181         list = cache->tempList;
1182         cache->tempList = NULL;
1183         return list;
1184 }
1185
1186 /*
1187 * Get all groups visitor function.
1188 */
1189 static void addrcache_get_all_groups_vis( gpointer key, gpointer value, gpointer data ) {
1190         AddrItemObject *obj = ( AddrItemObject * ) value;
1191
1192         if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
1193                 AddressCache *cache = data;
1194                 cache->tempList = g_list_append( cache->tempList, obj );
1195         }
1196 }
1197
1198 /*
1199 * Return link list of all groups in address cache.  Note that the list contains
1200 * references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions...
1201 * this will destroy the address cache data!
1202 * Return: List of items, or NULL if none.
1203 */
1204 GList *addrcache_get_all_groups( AddressCache *cache ) {
1205         GList *list = NULL;
1206
1207         g_return_val_if_fail( cache != NULL, NULL );
1208
1209         cache->tempList = NULL;
1210         g_hash_table_foreach( cache->itemHash, addrcache_get_all_groups_vis, cache );
1211         list = cache->tempList;
1212         cache->tempList = NULL;
1213         return list;
1214 }
1215
1216 /*
1217 * Remove folder from cache. Children are re-parented to parent folder.
1218 * param: folder Folder to remove.
1219 * return: Folder, or NULL if not found. Note that object should still be freed.
1220 */
1221 ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
1222         AddrItemObject *obj = NULL;
1223
1224         g_return_val_if_fail( cache != NULL, NULL );
1225
1226         if( folder ) {
1227                 gchar *uid = ADDRITEM_ID(folder);
1228                 if( uid == NULL || *uid == '\0' ) return NULL;
1229                 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1230                 if( obj ) {
1231                         ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1232                         GList *node;
1233                         AddrItemObject *aio;
1234                         if( ! parent ) parent = cache->rootFolder;
1235
1236                         /* Re-parent children in folder */
1237                         node = folder->listFolder;
1238                         while( node ) {
1239                                 aio = ( AddrItemObject * ) node->data;
1240                                 parent->listFolder = g_list_append( parent->listFolder, aio );
1241                                 aio->parent = ADDRITEM_OBJECT(parent);
1242                                 node = g_list_next( node );
1243                         }
1244                         node = folder->listPerson;
1245                         while( node ) {
1246                                 aio = ( AddrItemObject * ) node->data;
1247                                 parent->listPerson = g_list_append( parent->listPerson, aio );
1248                                 aio->parent = ADDRITEM_OBJECT(parent);
1249                                 node = g_list_next( node );
1250                         }
1251                         node = folder->listGroup;
1252                         while( node ) {
1253                                 aio = ( AddrItemObject * ) node->data;
1254                                 parent->listGroup = g_list_append( parent->listGroup, aio );
1255                                 aio->parent = ADDRITEM_OBJECT(parent);
1256                                 node = g_list_next( node );
1257                         }
1258
1259                         /* Remove folder from parent's list and hash table */
1260                         parent->listFolder = g_list_remove( parent->listFolder, folder );
1261                         ADDRITEM_PARENT(folder) = NULL;
1262                         g_hash_table_remove( cache->itemHash, uid );
1263                         cache->dirtyFlag = TRUE;
1264                         return folder;
1265                 }
1266         }
1267         return NULL;
1268 }
1269
1270 /*
1271 * Remove folder from cache. Children are deleted.
1272 * param: folder Folder to remove.
1273 * return: Folder, or NULL if not found. Note that object should still be freed.
1274 */
1275 ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) {
1276         AddrItemObject *obj = NULL;
1277
1278         g_return_val_if_fail( cache != NULL, NULL );
1279
1280         if( folder ) {
1281                 gchar *uid = ADDRITEM_ID(folder);
1282                 if( uid == NULL || *uid == '\0' ) return NULL;
1283                 obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
1284                 if( obj ) {
1285                         ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1286                         if( ! parent ) parent = cache->rootFolder;
1287
1288                         /* Remove groups */
1289                         while( folder->listGroup ) {
1290                                 ItemGroup *item = ( ItemGroup * ) folder->listGroup->data;
1291                                 item = addrcache_remove_group( cache, item );
1292                                 if( item ) {
1293                                         addritem_free_item_group( item );
1294                                         item = NULL;
1295                                 }
1296                         }
1297
1298                         while( folder->listPerson ) {
1299                                 ItemPerson *item = ( ItemPerson * ) folder->listPerson->data;
1300                                 item = addrcache_remove_person( cache, item );
1301                                 if( item ) {
1302                                         addritem_free_item_person( item );
1303                                         item = NULL;
1304                                 }
1305                         }
1306
1307                         /* Recursive deletion of folder */
1308                         while( folder->listFolder ) {
1309                                 ItemFolder *item = ( ItemFolder * ) folder->listFolder->data;
1310                                 item = addrcache_remove_folder_delete( cache, item );
1311                                 if( item ) {
1312                                         addritem_free_item_folder( item );
1313                                         item = NULL;
1314                                 }
1315                         }
1316
1317                         /* Remove folder from parent's list and hash table */
1318                         parent->listFolder = g_list_remove( parent->listFolder, folder );
1319                         ADDRITEM_PARENT(folder) = NULL;
1320                         g_hash_table_remove( cache->itemHash, uid );
1321                         cache->dirtyFlag = TRUE;
1322                         return folder;
1323                 }
1324         }
1325         return NULL;
1326 }
1327
1328 /**
1329  * Add person and address data to cache.
1330  * \param cache     Cache.
1331  * \param folder    Folder where to add person, or NULL for root folder.
1332  * \param name      Common name.
1333  * \param address   EMail address.
1334  * \param remarks   Remarks.
1335  * \return Person added. Do not *NOT* to use the 
1336  *         <code>addrbook_free_xxx()</code> functions...; this will destroy
1337  *         the address book data.
1338  */
1339 ItemPerson *addrcache_add_contact(
1340                 AddressCache *cache, ItemFolder *folder, const gchar *name,
1341                 const gchar *address, const gchar *remarks )
1342 {
1343         ItemPerson *person = NULL;
1344         ItemEMail *email = NULL;
1345         ItemFolder *f = folder;
1346
1347         g_return_val_if_fail( cache != NULL, NULL );
1348
1349         if( ! f ) f = cache->rootFolder;
1350
1351         /* Create person object */
1352         person = addritem_create_item_person();
1353         addritem_person_set_common_name( person, name );
1354         addrcache_id_person( cache, person );
1355         addrcache_folder_add_person( cache, f, person );
1356
1357         /* Create email object */
1358         email = addritem_create_item_email();
1359         addritem_email_set_address( email, address );
1360         addritem_email_set_remarks( email, remarks );
1361         addrcache_id_email( cache, email );
1362         addritem_person_add_email( person, email );
1363         cache->dirtyFlag = TRUE;
1364
1365         return person;
1366 }
1367
1368 /**
1369  * Create a new folder and add to address cache.
1370  * \param  cache  Address cache.
1371  * \param  folder Parent folder where to add folder, or <i>NULL</i> for
1372  *                root folder.
1373  * \return Folder that was created. This should <b>*NOT*</b> be
1374  *         <code>g_free()</code> when done.
1375  */
1376 ItemFolder *addrcache_add_new_folder( AddressCache *cache, ItemFolder *parent )
1377 {
1378         ItemFolder *folder;
1379         ItemFolder *p = parent;
1380
1381         g_return_val_if_fail( cache != NULL, NULL );
1382
1383         if( !p ) p = cache->rootFolder;
1384         folder = addritem_create_item_folder();
1385         addrcache_id_folder( cache, folder );
1386         if( addrcache_hash_add_folder( cache, folder ) ) {
1387                 p->listFolder = g_list_append( p->listFolder, folder );
1388                 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1389                 addrcache_set_dirty( cache, TRUE );
1390         }
1391         else {
1392                 addritem_free_item_folder( folder );
1393                 folder = NULL;
1394         }
1395         return folder;
1396 }
1397
1398 /*
1399 * End of Source.
1400 */