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