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