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