summaryrefslogtreecommitdiff
path: root/src/addrbook.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/addrbook.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'src/addrbook.c')
-rw-r--r--src/addrbook.c2020
1 files changed, 2020 insertions, 0 deletions
diff --git a/src/addrbook.c b/src/addrbook.c
new file mode 100644
index 0000000..bcc4cab
--- /dev/null
+++ b/src/addrbook.c
@@ -0,0 +1,2020 @@
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 * General functions for accessing external address book files.
22 */
23
24#include <glib.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <sys/stat.h>
28#include <math.h>
29#include <setjmp.h>
30
31#include "xml.h"
32#include "mgutils.h"
33#include "addritem.h"
34#include "addrcache.h"
35#include "addrbook.h"
36#include "utils.h"
37
38#ifndef DEV_STANDALONE
39#include "prefs.h"
40#include "codeconv.h"
41#endif
42
43#define ADDRBOOK_MAX_SEARCH_COUNT 1000
44#define ADDRBOOK_PREFIX "addrbook-"
45#define ADDRBOOK_SUFFIX ".xml"
46#define FILE_NUMDIGITS 6
47
48#define ID_TIME_OFFSET 998000000
49/*
50* Create new address book.
51*/
52AddressBookFile *addrbook_create_book() {
53 AddressBookFile *book;
54
55 book = g_new0( AddressBookFile, 1 );
56 book->name = NULL;
57 book->path = NULL;
58 book->fileName = NULL;
59 book->retVal = MGU_SUCCESS;
60 book->addressCache = addrcache_create();
61
62 book->tempList = NULL;
63 book->readFlag = FALSE;
64 book->dirtyFlag = FALSE;
65 book->modifyFlag = TRUE;
66 book->accessFlag = FALSE;
67 book->tempHash = NULL;
68 return book;
69}
70
71/*
72* Specify name to be used.
73*/
74void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
75 g_return_if_fail( book != NULL );
76 book->name = mgu_replace_string( book->name, value );
77}
78void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
79 g_return_if_fail( book != NULL );
80 book->path = mgu_replace_string( book->path, value );
81 book->dirtyFlag = TRUE;
82}
83void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
84 g_return_if_fail( book != NULL );
85 book->fileName = mgu_replace_string( book->fileName, value );
86 book->dirtyFlag = TRUE;
87}
88void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
89 g_return_if_fail( book != NULL );
90 book->accessFlag = value;
91}
92gboolean addrbook_get_modified( AddressBookFile *book ) {
93 g_return_val_if_fail( book != NULL, FALSE );
94 return book->modifyFlag;
95}
96gboolean addrbook_get_accessed( AddressBookFile *book ) {
97 g_return_val_if_fail( book != NULL, FALSE );
98 return book->accessFlag;
99}
100gboolean addrbook_get_read_flag( AddressBookFile *book ) {
101 g_return_val_if_fail( book != NULL, FALSE );
102 return book->readFlag;
103}
104gint addrbook_get_status( AddressBookFile *book ) {
105 g_return_val_if_fail( book != NULL, -1 );
106 return book->retVal;
107}
108ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
109 g_return_val_if_fail( book != NULL, NULL );
110 return addrcache_get_root_folder( book->addressCache );
111}
112GList *addrbook_get_list_folder( AddressBookFile *book ) {
113 g_return_val_if_fail( book != NULL, NULL );
114 return addrcache_get_list_folder( book->addressCache );
115}
116GList *addrbook_get_list_person( AddressBookFile *book ) {
117 g_return_val_if_fail( book != NULL, NULL );
118 return addrcache_get_list_person( book->addressCache );
119}
120gchar *addrbook_get_name( AddressBookFile *book ) {
121 g_return_val_if_fail( book != NULL, NULL );
122 return book->name;
123}
124
125/*
126* Empty address book.
127*/
128void addrbook_empty_book( AddressBookFile *book ) {
129 g_return_if_fail( book != NULL );
130
131 /* Free up folders and hash table */
132 addrcache_clear( book->addressCache );
133
134 g_list_free( book->tempList );
135 book->tempList = NULL;
136
137 /* Reset to initial state */
138 book->retVal = MGU_SUCCESS;
139 book->tempHash = NULL;
140 book->readFlag = FALSE;
141 book->dirtyFlag = FALSE;
142 book->modifyFlag = FALSE;
143 book->accessFlag = FALSE;
144}
145
146/*
147* Free address book.
148*/
149void addrbook_free_book( AddressBookFile *book ) {
150 g_return_if_fail( book != NULL );
151
152 g_free( book->name );
153 g_free( book->path );
154 g_free( book->fileName );
155 book->name = NULL;
156 book->path = NULL;
157 book->fileName = NULL;
158
159 /* Free up folders and hash table */
160 addrcache_free( book->addressCache );
161 book->addressCache = NULL;
162
163 g_list_free( book->tempList );
164 book->tempList = NULL;
165
166 book->retVal = MGU_SUCCESS;
167 book->tempHash = NULL;
168 book->readFlag = FALSE;
169 book->dirtyFlag = FALSE;
170 book->modifyFlag = FALSE;
171 book->accessFlag = FALSE;
172
173 g_free( book );
174}
175
176/*
177* Print list of items.
178*/
179void addrbook_print_item_list( GList *list, FILE *stream ) {
180 GList *node = list;
181
182 while( node ) {
183 AddrItemObject *obj = node->data;
184 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
185 addritem_print_item_person( ( ItemPerson * ) obj, stream );
186 }
187 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
188 addritem_print_item_group( ( ItemGroup * ) obj, stream );
189 }
190 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
191 addritem_print_item_folder( ( ItemFolder * ) obj, stream );
192 }
193 node = g_list_next( node );
194 }
195 fprintf( stream, "\t---\n" );
196}
197
198/*
199* Print address book.
200*/
201void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
202 g_return_if_fail( book != NULL );
203
204 fprintf( stream, "AddressBook:\n" );
205 fprintf( stream, "\tname : '%s'\n", book->name );
206 fprintf( stream, "\tpath : '%s'\n", book->path );
207 fprintf( stream, "\tfile : '%s'\n", book->fileName );
208 fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
209 addrcache_print( book->addressCache, stream );
210}
211
212/*
213* Dump entire address book traversing folders.
214*/
215void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
216 ItemFolder *folder;
217
218 g_return_if_fail( book != NULL );
219
220 addrbook_print_book( book, stream );
221 folder = book->addressCache->rootFolder;
222 addritem_print_item_folder( folder, stream );
223}
224
225/*
226* Remove group from address book.
227* param: group Group to remove.
228* return: Group, or NULL if not found. Note that object should still be freed.
229*/
230ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
231 ItemGroup *item;
232
233 g_return_val_if_fail( book != NULL, NULL );
234
235 item = addrcache_remove_group( book->addressCache, group );
236 if( item ) book->dirtyFlag = TRUE;
237 return item;
238}
239
240/*
241* Remove specified person from address book.
242* param: person Person to remove.
243* return: Person, or NULL if not found. Note that object should still be freed.
244*/
245ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
246 ItemPerson *item;
247
248 g_return_val_if_fail( book != NULL, NULL );
249
250 item = addrcache_remove_person( book->addressCache, person );
251 if( item ) book->dirtyFlag = TRUE;
252 return item;
253}
254
255/*
256* Remove email address in address book for specified person.
257* param: person Person.
258* email EMail to remove.
259* return: EMail object, or NULL if not found. Note that object should still be freed.
260*/
261ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
262 ItemEMail *item;
263
264 g_return_val_if_fail( book != NULL, NULL );
265
266 item = addrcache_person_remove_email( book->addressCache, person, email );
267 if( item ) book->dirtyFlag = TRUE;
268 return item;
269}
270
271ItemEMail *addrbook_group_remove_email( AddressBookFile *book, ItemGroup *group, ItemEMail *email ) {
272 ItemEMail *item;
273
274 g_return_val_if_fail( book != NULL, NULL );
275
276 item = addritem_group_remove_email( group, email );
277 if( item ) book->dirtyFlag = TRUE;
278 return item;
279}
280
281/* **********************************************************************
282* Read/Write XML data file...
283* ===========================
284* Notes:
285* 1) The address book is structured as follows:
286*
287* address-book
288* person
289* address-list
290* address
291* attribute-list
292* attribute
293* group
294* member-list
295* member
296* folder
297* item-list
298* item
299*
300* 2) This sequence of elements was chosen so that the most important
301* elements (person and their email addresses) appear first.
302*
303* 3) Groups then appear. When groups are loaded, person's email
304* addresses have already been loaded and can be found.
305*
306* 4) Finally folders are loaded. Any forward and backward references
307* to folders, groups and persons in the folders are resolved after
308* loading.
309*
310* ***********************************************************************
311*/
312
313/* Element tag names */
314#define AB_ELTAG_ADDRESS "address"
315#define AB_ELTAG_ATTRIBUTE "attribute"
316#define AB_ELTAG_ATTRIBUTE_LIST "attribute-list"
317#define AB_ELTAG_ADDRESS_LIST "address-list"
318#define AB_ELTAG_MEMBER "member"
319#define AB_ELTAG_MEMBER_LIST "member-list"
320#define AB_ELTAG_ITEM "item"
321#define AB_ELTAG_ITEM_LIST "item-list"
322#define AB_ELTAG_ADDRESS_BOOK "address-book"
323#define AB_ELTAG_PERSON "person"
324#define AB_ELTAG_GROUP "group"
325#define AB_ELTAG_FOLDER "folder"
326
327/* Attribute tag names */
328#define AB_ATTAG_TYPE "type"
329#define AB_ATTAG_UID "uid"
330#define AB_ATTAG_NAME "name"
331#define AB_ATTAG_REMARKS "remarks"
332#define AB_ATTAG_FIRST_NAME "first-name"
333#define AB_ATTAG_LAST_NAME "last-name"
334#define AB_ATTAG_NICK_NAME "nick-name"
335#define AB_ATTAG_COMMON_NAME "cn"
336#define AB_ATTAG_ALIAS "alias"
337#define AB_ATTAG_EMAIL "email"
338#define AB_ATTAG_EID "eid"
339#define AB_ATTAG_PID "pid"
340
341/* Attribute values */
342#define AB_ATTAG_VAL_PERSON "person"
343#define AB_ATTAG_VAL_GROUP "group"
344#define AB_ATTAG_VAL_FOLDER "folder"
345
346/*
347* Parse address item for person.
348*/
349static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
350 GList *attr;
351 gchar *name, *value;
352 ItemEMail *email = NULL;
353
354 attr = xml_get_current_tag_attr(file);
355 while( attr ) {
356 name = ((XMLAttr *)attr->data)->name;
357 value = ((XMLAttr *)attr->data)->value;
358 if( ! email ) email = addritem_create_item_email();
359 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
360 ADDRITEM_ID(email) = g_strdup( value );
361 }
362 else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
363 ADDRITEM_NAME(email) = g_strdup( value );
364 }
365 else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
366 email->address = g_strdup( value );
367 }
368 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
369 email->remarks = g_strdup( value );
370 }
371 attr = g_list_next( attr );
372 }
373 if( email ) {
374 if( person ) {
375 addrcache_person_add_email( book->addressCache, person, email );
376 }
377 else {
378 addritem_free_item_email( email );
379 email = NULL;
380 }
381 }
382}
383
384/*
385* Parse email address list.
386*/
387static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
388 GList *attr;
389 guint prev_level;
390
391 for (;;) {
392 prev_level = file->level;
393 if( xml_parse_next_tag( file ) ) {
394 longjmp( book->jumper, 1 );
395 }
396 if (file->level < prev_level) return;
397 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
398 attr = xml_get_current_tag_attr(file);
399 addrbook_parse_address( book, file, person );
400 addrbook_parse_addr_list( book, file, person );
401 }
402 }
403}
404
405/*
406* Parse attibute for person.
407*/
408static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
409 GList *attr;
410 gchar *name, *value;
411 gchar *element;
412 UserAttribute *uAttr = NULL;
413
414 attr = xml_get_current_tag_attr(file);
415 while( attr ) {
416 name = ((XMLAttr *)attr->data)->name;
417 value = ((XMLAttr *)attr->data)->value;
418 if( ! uAttr ) uAttr = addritem_create_attribute();
419 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
420 addritem_attrib_set_id( uAttr, value );
421 }
422 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
423 addritem_attrib_set_name( uAttr, value );
424 }
425 attr = g_list_next( attr );
426 }
427
428 element = xml_get_element( file );
429 addritem_attrib_set_value( uAttr, element );
430
431 if( uAttr ) {
432 if( person ) {
433 addritem_person_add_attribute( person, uAttr );
434 }
435 else {
436 addritem_free_attribute( uAttr );
437 uAttr = NULL;
438 }
439 }
440}
441
442/*
443* Parse attribute list.
444*/
445static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
446 GList *attr;
447 guint prev_level;
448
449 for (;;) {
450 prev_level = file->level;
451 if( xml_parse_next_tag( file ) ) {
452 longjmp( book->jumper, 1 );
453 }
454 if (file->level < prev_level) return;
455 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
456 attr = xml_get_current_tag_attr(file);
457 addrbook_parse_attribute( file, person );
458 addrbook_parse_attr_list( book, file, person );
459 }
460 }
461}
462
463/*
464* Parse person.
465*/
466static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
467 GList *attr;
468 gchar *name, *value;
469 ItemPerson *person = NULL;
470
471 attr = xml_get_current_tag_attr(file);
472 while( attr ) {
473 name = ((XMLAttr *)attr->data)->name;
474 value = ((XMLAttr *)attr->data)->value;
475 if( ! person ) person = addritem_create_item_person();
476 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
477 ADDRITEM_ID(person) = g_strdup( value );
478 }
479 else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
480 person->firstName = g_strdup( value );
481 }
482 else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
483 person->lastName = g_strdup( value );
484 }
485 else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
486 person->nickName = g_strdup( value );
487 }
488 else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
489 ADDRITEM_NAME(person) = g_strdup( value );
490 }
491 attr = g_list_next( attr );
492 }
493 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
494 longjmp( book->jumper, 1 );
495 }
496 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
497 addrbook_parse_addr_list( book, file, person );
498 if( person ) {
499 addrcache_hash_add_person( book->addressCache, person );
500 }
501 }
502 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
503 longjmp( book->jumper, 1 );
504 }
505 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
506 addrbook_parse_attr_list( book, file, person );
507 }
508}
509
510/*
511* Parse group member.
512*/
513static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
514 GList *attr;
515 gchar *name, *value;
516 gchar *pid = NULL, *eid = NULL;
517 ItemEMail *email = NULL;
518
519 attr = xml_get_current_tag_attr(file);
520 while( attr ) {
521 name = ((XMLAttr *)attr->data)->name;
522 value = ((XMLAttr *)attr->data)->value;
523 if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
524 pid = g_strdup( value );
525 }
526 else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
527 eid = g_strdup( value );
528 }
529 attr = g_list_next( attr );
530 }
531 email = addrcache_get_email( book->addressCache, pid, eid );
532 if( email ) {
533 if( group ) {
534 addrcache_group_add_email( book->addressCache, group, email );
535 }
536 else {
537 addritem_free_item_email( email );
538 email = NULL;
539 }
540 }
541}
542
543/*
544* Parse group member list.
545*/
546static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
547 GList *attr;
548 guint prev_level;
549
550 for (;;) {
551 prev_level = file->level;
552 if( xml_parse_next_tag( file ) ) {
553 longjmp( book->jumper, 1 );
554 }
555 if (file->level < prev_level) return;
556 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
557 attr = xml_get_current_tag_attr(file);
558 addrbook_parse_member( book, file, group );
559 addrbook_parse_member_list( book, file, group );
560 }
561 else {
562 attr = xml_get_current_tag_attr( file );
563 }
564 }
565}
566
567/*
568* Parse group.
569*/
570static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
571 GList *attr;
572 gchar *name, *value;
573 ItemGroup *group = NULL;
574
575 attr = xml_get_current_tag_attr(file);
576 while( attr ) {
577 name = ((XMLAttr *)attr->data)->name;
578 value = ((XMLAttr *)attr->data)->value;
579 if( ! group ) group = addritem_create_item_group();
580 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
581 ADDRITEM_ID(group) = g_strdup( value );
582 }
583 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
584 ADDRITEM_NAME(group) = g_strdup( value );
585 }
586 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
587 group->remarks = g_strdup( value );
588 }
589 attr = g_list_next( attr );
590 }
591 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
592 longjmp( book->jumper, 1 );
593 }
594 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
595 if( group ) {
596 addrcache_hash_add_group( book->addressCache, group );
597 }
598 addrbook_parse_member_list( book, file, group );
599 }
600}
601
602/*
603* Parse folder item.
604*/
605static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
606 GList *attr;
607 gchar *name, *value;
608 gchar *uid = NULL;
609
610 attr = xml_get_current_tag_attr(file);
611 while( attr ) {
612 name = ((XMLAttr *)attr->data)->name;
613 value = ((XMLAttr *)attr->data)->value;
614 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
615 uid = g_strdup( value );
616 }
617 attr = g_list_next( attr );
618 }
619 if( folder ) {
620 if( uid ) {
621 folder->listItems = g_list_append( folder->listItems, uid );
622 }
623 }
624}
625
626/*
627* Parse folder item list.
628*/
629static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
630 GList *attr;
631 guint prev_level;
632
633 for (;;) {
634 prev_level = file->level;
635 if( xml_parse_next_tag( file ) ) {
636 longjmp( book->jumper, 1 );
637 }
638 if (file->level < prev_level) return;
639 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
640 attr = xml_get_current_tag_attr(file);
641 addrbook_parse_folder_item( book, file, folder );
642 addrbook_parse_folder_list( book, file, folder );
643 }
644 else {
645 attr = xml_get_current_tag_attr( file );
646 }
647 }
648}
649
650/*
651* Parse folder.
652*/
653static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
654 GList *attr;
655 gchar *name, *value;
656 ItemFolder *folder = NULL;
657
658 attr = xml_get_current_tag_attr(file);
659 while( attr ) {
660 name = ((XMLAttr *)attr->data)->name;
661 value = ((XMLAttr *)attr->data)->value;
662 if( ! folder ) {
663 folder = addritem_create_item_folder();
664 }
665 if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
666 ADDRITEM_ID(folder) = g_strdup( value );
667 }
668 else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
669 ADDRITEM_NAME(folder) = g_strdup( value );
670 }
671 else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
672 folder->remarks = g_strdup( value );
673 }
674 attr = g_list_next( attr );
675 }
676 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
677 longjmp( book->jumper, 1 );
678 }
679 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
680 if( folder ) {
681 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
682 book->tempList = g_list_append( book->tempList, folder );
683 ADDRITEM_PARENT(folder) = NULL; /* We will resolve folder later */
684 }
685 }
686 addrbook_parse_folder_list( book, file, folder );
687 }
688}
689
690/*
691* Parse address book.
692* Return: TRUE if data read successfully, FALSE if error reading data.
693*/
694static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
695 gboolean retVal;
696 GList *attr;
697 gchar *name, *value;
698
699 book->retVal = MGU_BAD_FORMAT;
700 if( xml_get_dtd( file ) ) {
701 return FALSE;
702 }
703 if( xml_parse_next_tag( file ) ) {
704 longjmp( book->jumper, 1 );
705 }
706 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
707 return FALSE;
708 }
709
710 attr = xml_get_current_tag_attr(file);
711 while( attr ) {
712 name = ((XMLAttr *)attr->data)->name;
713 value = ((XMLAttr *)attr->data)->value;
714 if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
715 addrbook_set_name( book, value );
716 }
717 attr = g_list_next( attr );
718 }
719
720 retVal = TRUE;
721 for (;;) {
722 if (! file->level ) break;
723 /* Get next item tag (person, group or folder) */
724 if( xml_parse_next_tag( file ) ) {
725 longjmp( book->jumper, 1 );
726 }
727 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
728 addrbook_parse_person( book, file );
729 }
730 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
731 addrbook_parse_group( book, file );
732 }
733 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
734 addrbook_parse_folder( book, file );
735 }
736 }
737 if( retVal ) book->retVal = MGU_SUCCESS;
738 return retVal;
739}
740
741/*
742* Resolve folder items visitor function.
743*/
744static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
745 AddressBookFile *book = data;
746 AddrItemObject *obj = ( AddrItemObject * ) value;
747 ItemFolder *rootFolder = book->addressCache->rootFolder;
748 if( obj->parent == NULL ) {
749 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
750 rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
751 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
752 }
753 else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
754 rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
755 ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
756 }
757 }
758}
759
760/*
761* Resolve folder items. Lists of UID's are replaced with pointers to data items.
762*/
763static void addrbook_resolve_folder_items( AddressBookFile *book ) {
764 GList *nodeFolder = NULL;
765 GList *listRemove = NULL;
766 GList *node = NULL;
767 ItemFolder *rootFolder = book->addressCache->rootFolder;
768 nodeFolder = book->tempList;
769 while( nodeFolder ) {
770 ItemFolder *folder = nodeFolder->data;
771 listRemove = NULL;
772 node = folder->listItems;
773 while( node ) {
774 gchar *uid = node->data;
775 AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
776 if( aio ) {
777 if( aio->type == ITEMTYPE_FOLDER ) {
778 ItemFolder *item = ( ItemFolder * ) aio;
779 folder->listFolder = g_list_append( folder->listFolder, item );
780 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
781 addrcache_hash_add_folder( book->addressCache, folder );
782 }
783 else if( aio->type == ITEMTYPE_PERSON ) {
784 ItemPerson *item = ( ItemPerson * ) aio;
785 folder->listPerson = g_list_append( folder->listPerson, item );
786 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
787 }
788 else if( aio->type == ITEMTYPE_GROUP ) {
789 ItemGroup *item = ( ItemGroup * ) aio;
790 folder->listGroup = g_list_append( folder->listGroup, item );
791 ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
792 }
793 /* Replace data with pointer to item */
794 g_free( uid );
795 node->data = aio;
796 }
797 else {
798 /* Not found, append to remove list. */
799 listRemove = g_list_append( listRemove, uid );
800 }
801 node = g_list_next( node );
802 }
803 rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
804
805 /* Process remove list */
806 node = listRemove;
807 while( node ) {
808 gchar *uid = node->data;
809 folder->listItems = g_list_remove( folder->listItems, uid );
810 g_free( uid );
811 node = g_list_next( node );
812 }
813 g_list_free( listRemove );
814 nodeFolder = g_list_next( nodeFolder );
815 }
816
817 /* Remove folders with parents. */
818 listRemove = NULL;
819 node = rootFolder->listFolder;
820 while( node ) {
821 ItemFolder *folder = ( ItemFolder * ) node->data;
822 if( ADDRITEM_PARENT(folder) ) {
823 /* Remove folders with parents */
824 listRemove = g_list_append( listRemove, folder );
825 }
826 else {
827 /* Add to root folder */
828 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
829 }
830 node = g_list_next( node );
831 }
832
833 /* Process remove list */
834 node = listRemove;
835 while( node ) {
836 rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
837 node = g_list_next( node );
838 }
839 g_list_free( listRemove );
840
841 /* Move all unparented persons and groups into root folder */
842 g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
843
844 /* Free up some more */
845 nodeFolder = book->tempList;
846 while( nodeFolder ) {
847 ItemFolder *folder = nodeFolder->data;
848 g_list_free( folder->listItems );
849 folder->listItems = NULL;
850 nodeFolder = g_list_next( nodeFolder );
851 }
852 g_list_free( book->tempList );
853 book->tempList = NULL;
854
855}
856
857/*
858* Read address book file.
859*/
860gint addrbook_read_data( AddressBookFile *book ) {
861 XMLFile *file = NULL;
862 gchar *fileSpec = NULL;
863
864 g_return_val_if_fail( book != NULL, -1 );
865
866 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
867 book->retVal = MGU_OPEN_FILE;
868 book->accessFlag = FALSE;
869 book->modifyFlag = FALSE;
870 file = xml_open_file( fileSpec );
871 g_free( fileSpec );
872 if( file ) {
873 book->tempList = NULL;
874
875 /* Trap for parsing errors. */
876 if( setjmp( book->jumper ) ) {
877 xml_close_file( file );
878 return book->retVal;
879 }
880 addrbook_read_tree( book, file );
881 xml_close_file( file );
882
883 /* Resolve folder items */
884 addrbook_resolve_folder_items( book );
885 book->tempList = NULL;
886 book->readFlag = TRUE;
887 book->dirtyFlag = FALSE;
888 }
889 return book->retVal;
890}
891
892static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
893 gint i;
894 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
895 fputs( "<", fp );
896 fputs( name, fp );
897}
898
899static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
900 gint i;
901 for( i = 0; i < lvl; i++ ) fputs( " ", fp );
902 fputs( "</", fp );
903 fputs( name, fp );
904 fputs( ">\n", fp );
905}
906
907static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
908 fputs( " ", fp );
909 fputs( name, fp );
910 fputs( "=\"", fp );
911 xml_file_put_escape_str( fp, value );
912 fputs( "\"", fp );
913}
914
915/*
916* Write file hash table visitor function.
917*/
918static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
919 AddrItemObject *obj = ( AddrItemObject * ) value;
920 FILE *fp = ( FILE * ) data;
921 GList *node;
922
923 if( ! obj ) return;
924 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
925 ItemPerson *person = ( ItemPerson * ) value;
926 if( person ) {
927 addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
928 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
929 addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
930 addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
931 addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
932 addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
933 fputs( " >\n", fp);
934
935 /* Output email addresses */
936 addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
937 fputs( ">\n", fp );
938 node = person->listEMail;
939 while ( node ) {
940 ItemEMail *email = node->data;
941 addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
942 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
943 addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
944 addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
945 addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
946 fputs( " />\n", fp);
947 node = g_list_next( node );
948 }
949 addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
950
951 /* Output user attributes */
952 addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
953 fputs( ">\n", fp );
954 node = person->listAttrib;
955 while ( node ) {
956 UserAttribute *attrib = node->data;
957 addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
958 addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
959 addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
960 fputs( " >", fp);
961 xml_file_put_escape_str( fp, attrib->value );
962 addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
963 node = g_list_next( node );
964 }
965 addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
966 addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
967 }
968 }
969}
970
971/*
972* Write file hash table visitor function.
973*/
974static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
975 AddrItemObject *obj = ( AddrItemObject * ) value;
976 FILE *fp = ( FILE * ) data;
977 GList *node;
978
979 if( ! obj ) return;
980 if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
981 ItemGroup *group = ( ItemGroup * ) value;
982 if( group ) {
983 addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
984 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
985 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
986 addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
987 fputs( " >\n", fp );
988
989 /* Output email address links */
990 addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
991 fputs( ">\n", fp );
992 node = group->listEMail;
993 while ( node ) {
994 ItemEMail *email = node->data;
995 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
996 addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
997 addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
998 addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
999 fputs( " />\n", fp );
1000 node = g_list_next( node );
1001 }
1002 addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
1003 addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
1004 }
1005 }
1006}
1007
1008/*
1009* Write file hash table visitor function.
1010*/
1011static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1012 AddrItemObject *obj = ( AddrItemObject * ) value;
1013 FILE *fp = ( FILE * ) data;
1014 GList *node;
1015
1016 if( ! obj ) return;
1017 if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1018 ItemFolder *folder = ( ItemFolder * ) value;
1019 if( folder ) {
1020 addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1021 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1022 addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1023 addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1024 fputs( " >\n", fp );
1025 addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1026 fputs( ">\n", fp );
1027
1028 /* Output persons */
1029 node = folder->listPerson;
1030 while ( node ) {
1031 ItemPerson *item = node->data;
1032 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1033 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON );
1034 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1035 fputs( " />\n", fp );
1036 node = g_list_next( node );
1037 }
1038
1039 /* Output groups */
1040 node = folder->listGroup;
1041 while ( node ) {
1042 ItemGroup *item = node->data;
1043 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1044 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1045 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1046 fputs( " />\n", fp );
1047 node = g_list_next( node );
1048 }
1049
1050 /* Output folders */
1051 node = folder->listFolder;
1052 while ( node ) {
1053 ItemFolder *item = node->data;
1054 addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1055 addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1056 addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1057 fputs( " />\n", fp );
1058 node = g_list_next( node );
1059 }
1060 addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1061 addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1062 }
1063 }
1064}
1065
1066/*
1067* Output address book data to specified file.
1068* return: Status code.
1069*/
1070gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1071 FILE *fp;
1072 gchar *fileSpec;
1073#ifndef DEV_STANDALONE
1074 PrefFile *pfile;
1075#endif
1076
1077 g_return_val_if_fail( book != NULL, -1 );
1078 g_return_val_if_fail( newFile != NULL, -1 );
1079
1080 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1081
1082 book->retVal = MGU_OPEN_FILE;
1083#ifdef DEV_STANDALONE
1084 fp = g_fopen( fileSpec, "wb" );
1085 g_free( fileSpec );
1086 if( fp ) {
1087 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1088#else
1089 pfile = prefs_file_open( fileSpec );
1090 g_free( fileSpec );
1091 if( pfile ) {
1092 fp = pfile->fp;
1093 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n", CS_INTERNAL );
1094#endif
1095 addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1096 addrbook_write_attr( fp, AB_ATTAG_NAME, book->name );
1097 fputs( " >\n", fp );
1098
1099 /* Output all persons */
1100 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1101
1102 /* Output all groups */
1103 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1104
1105 /* Output all folders */
1106 g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1107
1108 addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1109 book->retVal = MGU_SUCCESS;
1110#ifdef DEV_STANDALONE
1111 fclose( fp );
1112#else
1113 if( prefs_file_close( pfile ) < 0 ) {
1114 book->retVal = MGU_ERROR_WRITE;
1115 }
1116#endif
1117 }
1118
1119 fileSpec = NULL;
1120 return book->retVal;
1121}
1122
1123/*
1124* Output address book data to original file.
1125* return: Status code.
1126*/
1127gint addrbook_save_data( AddressBookFile *book ) {
1128 g_return_val_if_fail( book != NULL, -1 );
1129
1130 book->retVal = MGU_NO_FILE;
1131 if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1132 if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1133
1134 addrbook_write_to( book, book->fileName );
1135 if( book->retVal == MGU_SUCCESS ) {
1136 book->dirtyFlag = FALSE;
1137 }
1138 return book->retVal;
1139}
1140
1141/* **********************************************************************
1142* Address book edit interface functions...
1143* ***********************************************************************
1144*/
1145
1146/*
1147* Move person's email item.
1148* param: book Address book.
1149* person Person.
1150* itemMove Item to move.
1151* itemTarget Target item before which to move item.
1152*/
1153ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1154 ItemEMail *itemMove, ItemEMail *itemTarget )
1155{
1156 ItemEMail *email = NULL;
1157
1158 g_return_val_if_fail( book != NULL, NULL );
1159
1160 email = addritem_move_email_before( person, itemMove, itemTarget );
1161 if( email ) {
1162 book->dirtyFlag = TRUE;
1163 }
1164 return email;
1165}
1166
1167/*
1168* Move person's email item.
1169* param: book Address book.
1170* person Person.
1171* itemMove Item to move.
1172* itemTarget Target item after which to move item.
1173*/
1174ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1175 ItemEMail *itemMove, ItemEMail *itemTarget )
1176{
1177 ItemEMail *email = NULL;
1178
1179 g_return_val_if_fail( book != NULL, NULL );
1180
1181 email = addritem_move_email_after( person, itemMove, itemTarget );
1182 if( email ) {
1183 book->dirtyFlag = TRUE;
1184 }
1185 return email;
1186}
1187
1188/*
1189* Hash table visitor function.
1190*/
1191static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1192 g_free( key );
1193 key = NULL;
1194 value = NULL;
1195 return TRUE;
1196}
1197
1198/*
1199* Update address book email list for specified person.
1200* Enter: book Address book.
1201* person Person to update.
1202* listEMail New list of email addresses.
1203* Note: The existing email addresses are replaced with the new addresses. Any references
1204* to old addresses in the groups are re-linked to the new addresses. All old addresses
1205* linked to the person are removed.
1206*/
1207void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1208 GList *node;
1209 GList *oldData;
1210 GList *listGroup;
1211
1212 g_return_if_fail( book != NULL );
1213 g_return_if_fail( person != NULL );
1214
1215 /* Remember old list */
1216 oldData = person->listEMail;
1217
1218 /* Attach new address list to person. */
1219 node = listEMail;
1220 while( node ) {
1221 ItemEMail *email = node->data;
1222 if( ADDRITEM_ID(email) == NULL ) {
1223 /* Allocate an ID */
1224 addrcache_id_email( book->addressCache, email );
1225 }
1226 ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1227 node = g_list_next( node );
1228 }
1229 person->listEMail = listEMail;
1230
1231 /* Get groups where person's email is listed */
1232 listGroup = addrcache_get_group_for_person( book->addressCache, person );
1233 if( listGroup ) {
1234 GHashTable *hashEMail;
1235 GList *nodeGrp;
1236
1237 /* Load hash table with new address entries */
1238 hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1239 node = listEMail;
1240 while( node ) {
1241 ItemEMail *email = node->data;
1242 gchar *addr = g_strdup( email->address );
1243 g_strdown( addr );
1244 if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1245 g_hash_table_insert( hashEMail, addr, email );
1246 }
1247 node = g_list_next( node );
1248 }
1249
1250 /* Re-parent new addresses to existing groups, where email address match. */
1251 nodeGrp = listGroup;
1252 while( nodeGrp ) {
1253 ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1254 GList *groupEMail = group->listEMail;
1255 GList *nodeGrpEM;
1256 GList *listRemove = NULL;
1257
1258 /* Process each email item linked to group */
1259 nodeGrpEM = groupEMail;
1260 while( nodeGrpEM ) {
1261 ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1262 if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1263 /* Found an email address for this person */
1264 ItemEMail *emailNew = NULL;
1265 gchar *addr = g_strdup( emailGrp->address );
1266 g_strdown( addr );
1267 emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1268 g_free( addr );
1269 if( emailNew ) {
1270 /* Point to this entry */
1271 nodeGrpEM->data = emailNew;
1272 }
1273 else {
1274 /* Mark for removal */
1275 listRemove = g_list_append( listRemove, emailGrp );
1276 }
1277 }
1278 /* Move on to next email link */
1279 nodeGrpEM = g_list_next( nodeGrpEM );
1280 }
1281
1282 /* Process all removed links in current group */
1283 nodeGrpEM = listRemove;
1284 while( nodeGrpEM ) {
1285 ItemEMail *emailGrp = nodeGrpEM->data;
1286 groupEMail = g_list_remove( groupEMail, emailGrp );
1287 nodeGrpEM = g_list_next( nodeGrpEM );
1288 }
1289 group->listEMail = groupEMail;
1290
1291 /* Move on to next group */
1292 nodeGrp = g_list_next( nodeGrp );
1293
1294 }
1295
1296 /* Clear hash table */
1297 g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1298 g_hash_table_destroy( hashEMail );
1299 hashEMail = NULL;
1300 g_list_free( listGroup );
1301 listGroup = NULL;
1302 }
1303
1304 /* Free up old data */
1305 addritem_free_list_email( oldData );
1306 oldData = NULL;
1307 book->dirtyFlag = TRUE;
1308
1309}
1310
1311/*
1312* Add person and address data to address book.
1313* Enter: book Address book.
1314* folder Folder where to add person, or NULL for root folder.
1315* listEMail New list of email addresses.
1316* Return: Person added.
1317* Note: A new person is created with specified list of email addresses. All objects inserted
1318* into address book.
1319*/
1320ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1321 ItemPerson *person;
1322 ItemFolder *f = folder;
1323 GList *node;
1324
1325 g_return_val_if_fail( book != NULL, NULL );
1326
1327 if( ! f ) f = book->addressCache->rootFolder;
1328 person = addritem_create_item_person();
1329 addrcache_id_person( book->addressCache, person );
1330 addrcache_folder_add_person( book->addressCache, f, person );
1331
1332 node = listEMail;
1333 while( node ) {
1334 ItemEMail *email = node->data;
1335 if( ADDRITEM_ID(email) == NULL ) {
1336 addrcache_id_email( book->addressCache, email );
1337 }
1338 addrcache_person_add_email( book->addressCache, person, email );
1339 node = g_list_next( node );
1340 }
1341 book->dirtyFlag = TRUE;
1342 return person;
1343}
1344
1345#if 0
1346/*
1347* Load hash table visitor function.
1348*/
1349static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1350 AddrItemObject *obj = ( AddrItemObject * ) value;
1351
1352 if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1353 GHashTable *table = ( GHashTable * ) data;
1354 gchar *newKey = g_strdup( key );
1355 ItemEMail *email = ( ItemEMail * ) obj;
1356 if( ! g_hash_table_lookup( table, newKey ) ) {
1357 g_hash_table_insert( table, newKey, email );
1358 }
1359 }
1360}
1361
1362/*
1363* Load hash table with links to email addresses.
1364*/
1365static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
1366 g_return_if_fail( book != NULL );
1367 g_return_if_fail( table != NULL );
1368 g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
1369}
1370#endif
1371
1372/*
1373* Build available email list visitor function.
1374*/
1375static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1376 AddrItemObject *obj = ( AddrItemObject * ) value;
1377
1378 if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1379 AddressBookFile *book = data;
1380 ItemPerson *person = ( ItemPerson * ) obj;
1381 GList *node = person->listEMail;
1382 while( node ) {
1383 ItemEMail *email = node->data;
1384 /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1385
1386 if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1387 book->tempList = g_list_append( book->tempList, email );
1388 }
1389 node = g_list_next( node );
1390 }
1391 }
1392}
1393
1394/*
1395* Return link list of available email items (which have not already been linked to
1396* groups). Note that the list contains references to items and should be g_free()
1397* when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1398* destroy the addressbook data!
1399* Return: List of items, or NULL if none.
1400*/
1401GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1402 GList *list = NULL;
1403 GHashTable *table;
1404
1405 g_return_val_if_fail( book != NULL, NULL );
1406
1407 /* Load hash table with group email entries */
1408 table = g_hash_table_new( g_str_hash, g_str_equal );
1409 if( group ) {
1410 list = group->listEMail;
1411 while( list ) {
1412 ItemEMail *email = list->data;
1413 g_hash_table_insert( table, ADDRITEM_ID(email), email );
1414 list = g_list_next( list );
1415 }
1416 }
1417
1418 /* Build list of available email addresses which exclude those already in groups */
1419 book->tempList = NULL;
1420 book->tempHash = table;
1421 g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1422 list = book->tempList;
1423 book->tempList = NULL;
1424 book->tempHash = NULL;
1425
1426 /* Clear hash table */
1427 g_hash_table_destroy( table );
1428 table = NULL;
1429
1430 return list;
1431}
1432
1433/*
1434* Update address book email list for specified group.
1435* Enter: book Address book.
1436* group group to update.
1437* listEMail New list of email addresses. This should *NOT* be g_free() when done.
1438* Note: The existing email addresses are replaced with the new addresses. Any references
1439* to old addresses in the groups are re-linked to the new addresses. All old addresses
1440* linked to the person are removed.
1441*/
1442void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1443 GList *oldData;
1444
1445 g_return_if_fail( book != NULL );
1446 g_return_if_fail( group != NULL );
1447
1448 /* Remember old list */
1449 oldData = group->listEMail;
1450 group->listEMail = listEMail;
1451 mgu_clear_list( oldData );
1452 g_list_free ( oldData );
1453 book->dirtyFlag = TRUE;
1454}
1455
1456/*
1457* Add group and email list to address book.
1458* Enter: book Address book.
1459* folder Parent folder, or NULL for root folder.
1460* listEMail New list of email addresses. This should *NOT* be g_free() when done.
1461* Return: Group object.
1462* Note: The existing email addresses are replaced with the new addresses. Any references
1463* to old addresses in the groups are re-linked to the new addresses. All old addresses
1464* linked to the person are removed.
1465*/
1466ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1467 ItemGroup *group = NULL;
1468 ItemFolder *f = folder;
1469
1470 g_return_val_if_fail( book != NULL, NULL );
1471
1472 if( ! f ) f = book->addressCache->rootFolder;
1473 group = addritem_create_item_group();
1474 addrcache_id_group( book->addressCache, group );
1475 addrcache_folder_add_group( book->addressCache, f, group );
1476 group->listEMail = listEMail;
1477 book->dirtyFlag = TRUE;
1478 return group;
1479}
1480
1481/*
1482* Add new folder to address book.
1483* Enter: book Address book.
1484* parent Parent folder.
1485* Return: Folder that was added. This should *NOT* be g_free() when done.
1486*/
1487ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1488 ItemFolder *folder = NULL;
1489 ItemFolder *p = parent;
1490
1491 g_return_val_if_fail( book != NULL, NULL );
1492
1493 if( ! p ) p = book->addressCache->rootFolder;
1494 folder = addritem_create_item_folder();
1495 addrcache_id_folder( book->addressCache, folder );
1496 if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1497 p->listFolder = g_list_append( p->listFolder, folder );
1498 ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1499 book->dirtyFlag = TRUE;
1500 }
1501 else {
1502 addritem_free_item_folder( folder );
1503 folder = NULL;
1504 }
1505 return folder;
1506}
1507
1508/*
1509* Update address book attribute list for specified person.
1510* Enter: book Address book.
1511* person Person to update.
1512* listAttrib New list of attributes.
1513* Note: The existing email addresses are replaced with the new addresses. All old attributes
1514* linked to the person are removed.
1515*/
1516void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1517 GList *node;
1518 GList *oldData;
1519
1520 g_return_if_fail( book != NULL );
1521 g_return_if_fail( person != NULL );
1522
1523 /* Remember old list */
1524 oldData = person->listAttrib;
1525
1526 /* Attach new address list to person. */
1527 node = listAttrib;
1528 while( node ) {
1529 UserAttribute *attrib = node->data;
1530 if( attrib->uid == NULL ) {
1531 /* Allocate an ID */
1532 addrcache_id_attribute( book->addressCache, attrib );
1533 }
1534 node = g_list_next( node );
1535 }
1536 person->listAttrib = listAttrib;
1537
1538 /* Free up old data */
1539 addritem_free_list_attribute( oldData );
1540 oldData = NULL;
1541 book->dirtyFlag = TRUE;
1542
1543}
1544
1545/*
1546* Add attribute data for person to address book.
1547* Enter: book Address book.
1548* person New person object.
1549* listAttrib New list of attributes.
1550* Note: Only attributes are inserted into address book.
1551*/
1552void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1553 GList *node;
1554
1555 g_return_if_fail( book != NULL );
1556 g_return_if_fail( person != NULL );
1557
1558 node = listAttrib;
1559 while( node ) {
1560 UserAttribute *attrib = node->data;
1561 if( attrib->uid == NULL ) {
1562 addrcache_id_attribute( book->addressCache, attrib );
1563 }
1564 addritem_person_add_attribute( person, attrib );
1565 node = g_list_next( node );
1566 }
1567 book->dirtyFlag = TRUE;
1568}
1569
1570/*
1571* Return address book file for specified object.
1572* Enter: aio Book item object.
1573* Return: Address book, or NULL if not found.
1574*/
1575AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1576 AddressBookFile *book = NULL;
1577
1578 if( aio ) {
1579 ItemFolder *parent = NULL;
1580 ItemFolder *root = NULL;
1581 if( aio->type == ITEMTYPE_EMAIL ) {
1582 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1583 if( person ) {
1584 parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1585 }
1586 }
1587 else {
1588 parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1589 }
1590 if( parent ) {
1591 root = addrcache_find_root_folder( parent );
1592 }
1593 if( root ) {
1594 book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1595 }
1596 }
1597 return book;
1598}
1599
1600/*
1601* Remove folder from address book. Children are re-parented to parent folder.
1602* param: folder Folder to remove.
1603* return: Folder, or NULL if not found. Note that object should still be freed.
1604*/
1605ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1606 ItemFolder *f;
1607
1608 g_return_val_if_fail( book != NULL, NULL );
1609
1610 f = addrcache_remove_folder( book->addressCache, folder );
1611 if( f ) book->dirtyFlag = TRUE;
1612 return f;
1613}
1614
1615/*
1616* Remove folder from address book. Children are deleted.
1617* param: folder Folder to remove.
1618* return: Folder, or NULL if not found. Note that object should still be freed.
1619*/
1620ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1621 ItemFolder *f;
1622
1623 g_return_val_if_fail( book != NULL, NULL );
1624
1625 f = addrcache_remove_folder_delete( book->addressCache, folder );
1626 if( f ) book->dirtyFlag = TRUE;
1627 return f;
1628}
1629
1630#define WORK_BUFLEN 1024
1631#define ADDRBOOK_DIGITS "0123456789"
1632
1633/*
1634* Return list of existing address book files.
1635* Enter: book Address book file.
1636* Return: File list.
1637*/
1638GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1639 gchar *adbookdir;
1640 GDir *dir;
1641 const gchar *dir_name;
1642 GStatBuf statbuf;
1643 gchar buf[ WORK_BUFLEN ];
1644 gchar numbuf[ WORK_BUFLEN ];
1645 gint len, lenpre, lensuf, lennum;
1646 long int val, maxval;
1647 GList *fileList = NULL;
1648
1649 g_return_val_if_fail( book != NULL, NULL );
1650
1651 if( book->path == NULL || *book->path == '\0' ) {
1652 book->retVal = MGU_NO_PATH;
1653 return NULL;
1654 }
1655
1656 strcpy( buf, book->path );
1657 len = strlen( buf );
1658 if( len > 0 ) {
1659 if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1660 buf[ len ] = G_DIR_SEPARATOR;
1661 buf[ ++len ] = '\0';
1662 }
1663 }
1664
1665 adbookdir = g_strdup( buf );
1666 strcat( buf, ADDRBOOK_PREFIX );
1667
1668 if( ( dir = g_dir_open( adbookdir, 0, NULL ) ) == NULL ) {
1669 book->retVal = MGU_OPEN_DIRECTORY;
1670 g_free( adbookdir );
1671 return NULL;
1672 }
1673
1674 lenpre = strlen( ADDRBOOK_PREFIX );
1675 lensuf = strlen( ADDRBOOK_SUFFIX );
1676 lennum = FILE_NUMDIGITS + lenpre;
1677 maxval = -1;
1678
1679 while( ( dir_name = g_dir_read_name( dir ) ) != NULL ) {
1680 gchar *endptr = NULL;
1681 gint i;
1682 gboolean flg;
1683
1684 strcpy( buf, adbookdir );
1685 strcat( buf, dir_name );
1686 g_stat( buf, &statbuf );
1687 if( S_IFREG & statbuf.st_mode ) {
1688 if( strncmp( dir_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1689 if( strncmp( (dir_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1690 strncpy( numbuf, (dir_name) + lenpre, FILE_NUMDIGITS );
1691 numbuf[ FILE_NUMDIGITS ] = '\0';
1692 flg = TRUE;
1693 for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1694 if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1695 flg = FALSE;
1696 break;
1697 }
1698 }
1699 if( flg ) {
1700 /* Get value */
1701 val = strtol( numbuf, &endptr, 10 );
1702 if( endptr && val > -1 ) {
1703 if( val > maxval ) maxval = val;
1704 fileList = g_list_append( fileList, g_strdup( dir_name ) );
1705 }
1706 }
1707 }
1708 }
1709 }
1710 }
1711 g_dir_close( dir );
1712 g_free( adbookdir );
1713
1714 book->maxValue = maxval;
1715 book->retVal = MGU_SUCCESS;
1716 return fileList;
1717}
1718
1719/*
1720* Return file name for specified file number.
1721* Enter: fileNum File number.
1722* Return: File name, or NULL if file number too large. Should be g_free() when done.
1723*/
1724gchar *addrbook_gen_new_file_name( gint fileNum ) {
1725 gchar fmt[ 30 ];
1726 gchar buf[ WORK_BUFLEN ];
1727 gint n = fileNum;
1728 long int nmax;
1729
1730 if( n < 1 ) n = 1;
1731 nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1732 if( fileNum > nmax ) return NULL;
1733 sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1734 sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1735 return g_strdup( buf );
1736}
1737
1738/* **********************************************************************
1739* Address book test functions...
1740* ***********************************************************************
1741*/
1742
1743#if 0
1744static void addrbook_show_attribs( GList *attr ) {
1745 while( attr ) {
1746 gchar *name = ((XMLAttr *)attr->data)->name;
1747 gchar *value = ((XMLAttr *)attr->data)->value;
1748 printf( "\tn/v = %s : %s\n", name, value );
1749 attr = g_list_next( attr );
1750 }
1751 printf( "\t---\n" );
1752}
1753#endif
1754
1755/*
1756* Test email address list.
1757*/
1758static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1759 guint prev_level;
1760 GList *attr;
1761
1762 for (;;) {
1763 prev_level = file->level;
1764 if( xml_parse_next_tag( file ) ) {
1765 longjmp( book->jumper, 1 );
1766 }
1767 if (file->level < prev_level) return;
1768 attr = xml_get_current_tag_attr(file);
1769 /* addrbook_show_attribs( attr ); */
1770 if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1771 addrbook_chkparse_addr_list( book, file );
1772 }
1773 }
1774}
1775
1776/*
1777* Test user attributes for person.
1778*/
1779static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1780 GList *attr;
1781 gchar *element;
1782
1783 attr = xml_get_current_tag_attr(file);
1784 /* addrbook_show_attribs( attr ); */
1785 element = xml_get_element( file );
1786 /* printf( "\t\tattrib value : %s\n", element ); */
1787}
1788
1789/*
1790* Test attribute list.
1791*/
1792static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1793 guint prev_level;
1794
1795 for (;;) {
1796 prev_level = file->level;
1797 if( xml_parse_next_tag( file ) ) {
1798 longjmp( book->jumper, 1 );
1799 }
1800 if (file->level < prev_level) return;
1801 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1802 addrbook_chkparse_attribute( book, file );
1803 addrbook_chkparse_attr_list( book, file );
1804 }
1805 }
1806}
1807
1808/*
1809* Test person.
1810*/
1811static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1812 GList *attr;
1813
1814 attr = xml_get_current_tag_attr(file);
1815 /* addrbook_show_attribs( attr ); */
1816 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1817 longjmp( book->jumper, 1 );
1818 }
1819 if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1820 addrbook_chkparse_addr_list( book, file );
1821 }
1822 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1823 longjmp( book->jumper, 1 );
1824 }
1825 if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1826 addrbook_chkparse_attr_list( book, file );
1827 }
1828}
1829
1830/*
1831* Test group member list.
1832*/
1833static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1834 GList *attr;
1835 guint prev_level;
1836
1837 for (;;) {
1838 prev_level = file->level;
1839 if( xml_parse_next_tag( file ) ) {
1840 longjmp( book->jumper, 1 );
1841 }
1842 if (file->level < prev_level) return;
1843 if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1844 attr = xml_get_current_tag_attr(file);
1845 /* addrbook_show_attribs( attr ); */
1846 addrbook_chkparse_member_list( book, file );
1847 }
1848 else {
1849 attr = xml_get_current_tag_attr( file );
1850 /* addrbook_show_attribs( attr ); */
1851 }
1852 }
1853}
1854
1855/*
1856* Test group.
1857*/
1858static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1859 GList *attr;
1860
1861 attr = xml_get_current_tag_attr(file);
1862 /* addrbook_show_attribs( attr ); */
1863 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1864 longjmp( book->jumper, 1 );
1865 }
1866 if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1867 addrbook_chkparse_member_list( book, file );
1868 }
1869}
1870
1871/*
1872* Test folder item list.
1873*/
1874static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1875 GList *attr;
1876 guint prev_level;
1877
1878 for (;;) {
1879 prev_level = file->level;
1880 if( xml_parse_next_tag( file ) ) {
1881 longjmp( book->jumper, 1 );
1882 }
1883 if (file->level < prev_level) return;
1884 if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1885 attr = xml_get_current_tag_attr(file);
1886 /* addrbook_show_attribs( attr ); */
1887 addrbook_chkparse_folder_list( book, file );
1888 }
1889 else {
1890 attr = xml_get_current_tag_attr( file );
1891 /* addrbook_show_attribs( attr ); */
1892 }
1893 }
1894}
1895
1896/*
1897* Test folder.
1898*/
1899static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1900 GList *attr;
1901
1902 attr = xml_get_current_tag_attr(file);
1903 /* addrbook_show_attribs( attr ); */
1904 if( xml_parse_next_tag( file ) ) { /* Consume closing tag */
1905 longjmp( book->jumper, 1 );
1906 }
1907 if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1908 addrbook_chkparse_folder_list( book, file );
1909 }
1910}
1911
1912/*
1913* Test address book.
1914*/
1915static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1916 GList *attr;
1917 gboolean retVal;
1918
1919 if( xml_get_dtd( file ) ) {
1920 return FALSE;
1921 }
1922 if( xml_parse_next_tag( file ) ) {
1923 return FALSE;
1924 }
1925
1926 if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1927 return FALSE;
1928 }
1929
1930 attr = xml_get_current_tag_attr(file);
1931 /* addrbook_show_attribs( attr ); */
1932
1933 retVal = TRUE;
1934 for (;;) {
1935 if (! file->level ) break;
1936 /* Get item tag */
1937 if( xml_parse_next_tag( file ) ) {
1938 longjmp( book->jumper, 1 );
1939 }
1940 /* Get next tag (person, group or folder) */
1941 if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1942 addrbook_chkparse_person( book, file );
1943 }
1944 else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1945 addrbook_chkparse_group( book, file );
1946 }
1947 else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1948 addrbook_chkparse_folder( book, file );
1949 }
1950 }
1951 return retVal;
1952}
1953
1954/*
1955* Test address book file by parsing contents.
1956* Enter: book Address book file to check.
1957* fileName File name to check.
1958* Return: MGU_SUCCESS if file appears to be valid format.
1959*/
1960gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1961 XMLFile *file = NULL;
1962 gchar *fileSpec = NULL;
1963
1964 g_return_val_if_fail( book != NULL, -1 );
1965
1966 fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1967 book->retVal = MGU_OPEN_FILE;
1968 file = xml_open_file( fileSpec );
1969 g_free( fileSpec );
1970 if( file ) {
1971 book->retVal = MGU_BAD_FORMAT;
1972 if( setjmp( book->jumper ) ) {
1973 /* printf( "Caught Ya!!!\n" ); */
1974 xml_close_file( file );
1975 return book->retVal;
1976 }
1977 if( addrbook_chkread_tree( book, file ) ) {
1978 book->retVal = MGU_SUCCESS;
1979 }
1980 xml_close_file( file );
1981 }
1982 return book->retVal;
1983}
1984
1985/*
1986* Return link list of all persons in address book. Note that the list contains
1987* references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1988* this will destroy the addressbook data!
1989* Return: List of items, or NULL if none.
1990*/
1991GList *addrbook_get_all_persons( AddressBookFile *book ) {
1992 g_return_val_if_fail( book != NULL, NULL );
1993 return addrcache_get_all_persons( book->addressCache );
1994}
1995
1996/*
1997* Add person and address data to address book.
1998* Enter: book Address book.
1999* folder Folder where to add person, or NULL for root folder.
2000* name Common name.
2001* address EMail address.
2002* remarks Remarks.
2003* Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
2004* this will destroy the address book data.
2005*/
2006ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
2007 const gchar *address, const gchar *remarks )
2008{
2009 ItemPerson *person = NULL;
2010
2011 g_return_val_if_fail( book != NULL, NULL );
2012
2013 person = addrcache_add_contact( book->addressCache, folder, name, address, remarks );
2014 if( person ) book->dirtyFlag = TRUE;
2015 return person;
2016}
2017
2018/*
2019* End of Source.
2020*/