Statistics
| Revision:

root / src / addrbook.c @ 1

History | View | Annotate | Download (54.6 KB)

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 <dirent.h>
28
#include <sys/stat.h>
29
#include <math.h>
30
#include <setjmp.h>
31

    
32
#include "xml.h"
33
#include "mgutils.h"
34
#include "addritem.h"
35
#include "addrcache.h"
36
#include "addrbook.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
*/
52
AddressBookFile *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
*/
74
void 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
}
78
void 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
}
83
void 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
}
88
void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
89
        g_return_if_fail( book != NULL );
90
        book->accessFlag = value;
91
}
92
gboolean addrbook_get_modified( AddressBookFile *book ) {
93
        g_return_val_if_fail( book != NULL, FALSE );
94
        return book->modifyFlag;
95
}
96
gboolean addrbook_get_accessed( AddressBookFile *book ) {
97
        g_return_val_if_fail( book != NULL, FALSE );
98
        return book->accessFlag;
99
}
100
gboolean addrbook_get_read_flag( AddressBookFile *book ) {
101
        g_return_val_if_fail( book != NULL, FALSE );
102
        return book->readFlag;
103
}
104
gint addrbook_get_status( AddressBookFile *book ) {
105
        g_return_val_if_fail( book != NULL, -1 );
106
        return book->retVal;
107
}
108
ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
109
        g_return_val_if_fail( book != NULL, NULL );
110
        return addrcache_get_root_folder( book->addressCache );
111
}
112
GList *addrbook_get_list_folder( AddressBookFile *book ) {
113
        g_return_val_if_fail( book != NULL, NULL );
114
        return addrcache_get_list_folder( book->addressCache );
115
}
116
GList *addrbook_get_list_person( AddressBookFile *book ) {
117
        g_return_val_if_fail( book != NULL, NULL );
118
        return addrcache_get_list_person( book->addressCache );
119
}
120
gchar *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
*/
128
void 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
*/
149
void 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
*/
179
void 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
*/
201
void 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
*/
215
void 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
*/
230
ItemGroup *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
*/
245
ItemPerson *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
*/
261
ItemEMail *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

    
271
/* **********************************************************************
272
* Read/Write XML data file...
273
* ===========================
274
* Notes:
275
* 1)        The address book is structured as follows:
276
*
277
*                address-book
278
*                        person
279
*                                address-list
280
*                                        address
281
*                                attribute-list
282
*                                        attribute
283
*                        group
284
*                                member-list
285
*                                        member
286
*                        folder
287
*                                item-list
288
*                                        item
289
*
290
* 2)        This sequence of elements was chosen so that the most important
291
*         elements (person and their email addresses) appear first.
292
*
293
* 3)        Groups then appear. When groups are loaded, person's email
294
*        addresses have already been loaded and can be found.
295
*
296
* 4)        Finally folders are loaded. Any forward and backward references
297
*        to folders, groups and persons in the folders are resolved after
298
*        loading.
299
*
300
* ***********************************************************************
301
*/
302

    
303
/* Element tag names */
304
#define AB_ELTAG_ADDRESS         "address"
305
#define AB_ELTAG_ATTRIBUTE       "attribute"
306
#define AB_ELTAG_ATTRIBUTE_LIST  "attribute-list"
307
#define AB_ELTAG_ADDRESS_LIST    "address-list"
308
#define AB_ELTAG_MEMBER          "member"
309
#define AB_ELTAG_MEMBER_LIST     "member-list"
310
#define AB_ELTAG_ITEM            "item"
311
#define AB_ELTAG_ITEM_LIST       "item-list"
312
#define AB_ELTAG_ADDRESS_BOOK    "address-book"
313
#define AB_ELTAG_PERSON          "person"
314
#define AB_ELTAG_GROUP           "group"
315
#define AB_ELTAG_FOLDER          "folder"
316

    
317
/* Attribute tag names */
318
#define AB_ATTAG_TYPE            "type"
319
#define AB_ATTAG_UID             "uid"
320
#define AB_ATTAG_NAME            "name"
321
#define AB_ATTAG_REMARKS         "remarks"
322
#define AB_ATTAG_FIRST_NAME      "first-name"
323
#define AB_ATTAG_LAST_NAME       "last-name"
324
#define AB_ATTAG_NICK_NAME       "nick-name"
325
#define AB_ATTAG_COMMON_NAME     "cn"
326
#define AB_ATTAG_ALIAS           "alias"
327
#define AB_ATTAG_EMAIL           "email"
328
#define AB_ATTAG_EID             "eid"
329
#define AB_ATTAG_PID             "pid"
330

    
331
/* Attribute values */
332
#define AB_ATTAG_VAL_PERSON      "person"
333
#define AB_ATTAG_VAL_GROUP       "group"
334
#define AB_ATTAG_VAL_FOLDER      "folder"
335

    
336
/*
337
* Parse address item for person.
338
*/
339
static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) {
340
        GList *attr;
341
        gchar *name, *value;
342
        ItemEMail *email = NULL;
343

    
344
        attr = xml_get_current_tag_attr(file);
345
        while( attr ) {
346
                name = ((XMLAttr *)attr->data)->name;
347
                value = ((XMLAttr *)attr->data)->value;
348
                if( ! email ) email = addritem_create_item_email();
349
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
350
                        ADDRITEM_ID(email) = g_strdup( value );
351
                }
352
                else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) {
353
                        ADDRITEM_NAME(email) = g_strdup( value );
354
                }
355
                else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) {
356
                        email->address = g_strdup( value );
357
                }
358
                else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
359
                        email->remarks = g_strdup( value );
360
                }
361
                attr = g_list_next( attr );
362
        }
363
        if( email ) {
364
                if( person ) {
365
                        addrcache_person_add_email( book->addressCache, person, email );
366
                }
367
                else {
368
                        addritem_free_item_email( email );
369
                        email = NULL;
370
                }
371
        }
372
}
373

    
374
/*
375
* Parse email address list.
376
*/
377
static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
378
        GList *attr;
379
        guint prev_level;
380

    
381
        for (;;) {
382
                prev_level = file->level;
383
                if( xml_parse_next_tag( file ) ) {
384
                        longjmp( book->jumper, 1 );
385
                }
386
                if (file->level < prev_level) return;
387
                if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
388
                        attr = xml_get_current_tag_attr(file);
389
                        addrbook_parse_address( book, file, person );
390
                        addrbook_parse_addr_list( book, file, person );
391
                }
392
        }
393
}
394

    
395
/*
396
* Parse attibute for person.
397
*/
398
static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) {
399
        GList *attr;
400
        gchar *name, *value;
401
        gchar *element;
402
        UserAttribute *uAttr = NULL;
403

    
404
        attr = xml_get_current_tag_attr(file);
405
        while( attr ) {
406
                name = ((XMLAttr *)attr->data)->name;
407
                value = ((XMLAttr *)attr->data)->value;
408
                if( ! uAttr ) uAttr = addritem_create_attribute();
409
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
410
                        addritem_attrib_set_id( uAttr, value );
411
                }
412
                else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
413
                        addritem_attrib_set_name( uAttr, value );
414
                }
415
                attr = g_list_next( attr );
416
        }
417

    
418
        element = xml_get_element( file );
419
        addritem_attrib_set_value( uAttr, element );
420

    
421
        if( uAttr ) {
422
                if( person ) {
423
                        addritem_person_add_attribute( person, uAttr );
424
                }
425
                else {
426
                        addritem_free_attribute( uAttr );
427
                        uAttr = NULL;
428
                }
429
        }
430
}
431

    
432
/*
433
* Parse attribute list.
434
*/
435
static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){
436
        GList *attr;
437
        guint prev_level;
438

    
439
        for (;;) {
440
                prev_level = file->level;
441
                if( xml_parse_next_tag( file ) ) {
442
                        longjmp( book->jumper, 1 );
443
                }
444
                if (file->level < prev_level) return;
445
                if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
446
                        attr = xml_get_current_tag_attr(file);
447
                        addrbook_parse_attribute( file, person );
448
                        addrbook_parse_attr_list( book, file, person );
449
                }
450
        }
451
}
452

    
453
/*
454
* Parse person.
455
*/
456
static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) {
457
        GList *attr;
458
        gchar *name, *value;
459
        ItemPerson *person = NULL;
460

    
461
        attr = xml_get_current_tag_attr(file);
462
        while( attr ) {
463
                name = ((XMLAttr *)attr->data)->name;
464
                value = ((XMLAttr *)attr->data)->value;
465
                if( ! person ) person = addritem_create_item_person();
466
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
467
                        ADDRITEM_ID(person) = g_strdup( value );
468
                }
469
                else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) {
470
                        person->firstName = g_strdup( value );
471
                }
472
                else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) {
473
                        person->lastName = g_strdup( value );
474
                }
475
                else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) {
476
                        person->nickName = g_strdup( value );
477
                }
478
                else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) {
479
                        ADDRITEM_NAME(person) = g_strdup( value );
480
                }
481
                attr = g_list_next( attr );
482
        }
483
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
484
                longjmp( book->jumper, 1 );
485
        }
486
        if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
487
                addrbook_parse_addr_list( book, file, person );
488
                if( person ) {
489
                        addrcache_hash_add_person( book->addressCache, person );
490
                }
491
        }
492
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
493
                longjmp( book->jumper, 1 );
494
        }
495
        if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
496
                addrbook_parse_attr_list( book, file, person );
497
        }
498
}
499

    
500
/*
501
* Parse group member.
502
*/
503
static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) {
504
        GList *attr;
505
        gchar *name, *value;
506
        gchar *pid = NULL, *eid = NULL;
507
        ItemEMail *email = NULL;
508

    
509
        attr = xml_get_current_tag_attr(file);
510
        while( attr ) {
511
                name = ((XMLAttr *)attr->data)->name;
512
                value = ((XMLAttr *)attr->data)->value;
513
                if( strcmp( name, AB_ATTAG_PID ) == 0 ) {
514
                        pid = g_strdup( value );
515
                }
516
                else if( strcmp( name, AB_ATTAG_EID ) == 0 ) {
517
                        eid = g_strdup( value );
518
                }
519
                attr = g_list_next( attr );
520
        }
521
        email = addrcache_get_email( book->addressCache, pid, eid );
522
        if( email ) {
523
                if( group ) {
524
                        addrcache_group_add_email( book->addressCache, group, email );
525
                }
526
                else {
527
                        addritem_free_item_email( email );
528
                        email = NULL;
529
                }
530
        }
531
}
532

    
533
/*
534
* Parse group member list.
535
*/
536
static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){
537
        GList *attr;
538
        guint prev_level;
539

    
540
        for (;;) {
541
                prev_level = file->level;
542
                if( xml_parse_next_tag( file ) ) {
543
                        longjmp( book->jumper, 1 );
544
                }
545
                if (file->level < prev_level) return;
546
                if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
547
                        attr = xml_get_current_tag_attr(file);
548
                        addrbook_parse_member( book, file, group );
549
                        addrbook_parse_member_list( book, file, group );
550
                }
551
                else {
552
                        attr = xml_get_current_tag_attr( file );
553
                }
554
        }
555
}
556

    
557
/*
558
* Parse group.
559
*/
560
static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) {
561
        GList *attr;
562
        gchar *name, *value;
563
        ItemGroup *group = NULL;
564

    
565
        attr = xml_get_current_tag_attr(file);
566
        while( attr ) {
567
                name = ((XMLAttr *)attr->data)->name;
568
                value = ((XMLAttr *)attr->data)->value;
569
                if( ! group ) group = addritem_create_item_group();
570
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
571
                        ADDRITEM_ID(group) = g_strdup( value );
572
                }
573
                else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
574
                        ADDRITEM_NAME(group) = g_strdup( value );
575
                }
576
                else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
577
                        group->remarks = g_strdup( value );
578
                }
579
                attr = g_list_next( attr );
580
        }
581
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
582
                longjmp( book->jumper, 1 );
583
        }
584
        if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
585
                if( group ) {
586
                        addrcache_hash_add_group( book->addressCache, group );
587
                }
588
                addrbook_parse_member_list( book, file, group );
589
        }
590
}
591

    
592
/*
593
* Parse folder item.
594
*/
595
static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) {
596
        GList *attr;
597
        gchar *name, *value;
598
        gchar *uid = NULL;
599

    
600
        attr = xml_get_current_tag_attr(file);
601
        while( attr ) {
602
                name = ((XMLAttr *)attr->data)->name;
603
                value = ((XMLAttr *)attr->data)->value;
604
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
605
                        uid = g_strdup( value );
606
                }
607
                attr = g_list_next( attr );
608
        }
609
        if( folder ) {
610
                if( uid ) {
611
                        folder->listItems = g_list_append( folder->listItems, uid );
612
                }
613
        }
614
}
615

    
616
/*
617
* Parse folder item list.
618
*/
619
static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){
620
        GList *attr;
621
        guint prev_level;
622

    
623
        for (;;) {
624
                prev_level = file->level;
625
                if( xml_parse_next_tag( file ) ) {
626
                        longjmp( book->jumper, 1 );
627
                }
628
                if (file->level < prev_level) return;
629
                if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
630
                        attr = xml_get_current_tag_attr(file);
631
                        addrbook_parse_folder_item( book, file, folder );
632
                        addrbook_parse_folder_list( book, file, folder );
633
                }
634
                else {
635
                        attr = xml_get_current_tag_attr( file );
636
                }
637
        }
638
}
639

    
640
/*
641
* Parse folder.
642
*/
643
static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) {
644
        GList *attr;
645
        gchar *name, *value;
646
        ItemFolder *folder = NULL;
647

    
648
        attr = xml_get_current_tag_attr(file);
649
        while( attr ) {
650
                name = ((XMLAttr *)attr->data)->name;
651
                value = ((XMLAttr *)attr->data)->value;
652
                if( ! folder ) {
653
                        folder = addritem_create_item_folder();
654
                }
655
                if( strcmp( name, AB_ATTAG_UID ) == 0 ) {
656
                        ADDRITEM_ID(folder) = g_strdup( value );
657
                }
658
                else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
659
                        ADDRITEM_NAME(folder) = g_strdup( value );
660
                }
661
                else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) {
662
                        folder->remarks = g_strdup( value );
663
                }
664
                attr = g_list_next( attr );
665
        }
666
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
667
                longjmp( book->jumper, 1 );
668
        }
669
        if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
670
                if( folder ) {
671
                        if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
672
                                book->tempList = g_list_append( book->tempList, folder );
673
                                ADDRITEM_PARENT(folder) = NULL;        /* We will resolve folder later */
674
                        }
675
                }
676
                addrbook_parse_folder_list( book, file, folder );
677
        }
678
}
679

    
680
/*
681
* Parse address book.
682
* Return: TRUE if data read successfully, FALSE if error reading data.
683
*/
684
static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) {
685
        gboolean retVal;
686
        GList *attr;
687
        gchar *name, *value;
688

    
689
        book->retVal = MGU_BAD_FORMAT;
690
        if( xml_get_dtd( file ) ) {
691
                return FALSE;
692
        }
693
        if( xml_parse_next_tag( file ) ) {
694
                longjmp( book->jumper, 1 );
695
        }
696
        if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
697
                return FALSE;
698
        }
699

    
700
        attr = xml_get_current_tag_attr(file);
701
        while( attr ) {
702
                name = ((XMLAttr *)attr->data)->name;
703
                value = ((XMLAttr *)attr->data)->value;
704
                if( strcmp( name, AB_ATTAG_NAME ) == 0 ) {
705
                        addrbook_set_name( book, value );
706
                }
707
                attr = g_list_next( attr );
708
        }
709

    
710
        retVal = TRUE;
711
        for (;;) {
712
                if (! file->level ) break;
713
                /* Get next item tag (person, group or folder) */
714
                if( xml_parse_next_tag( file ) ) {
715
                        longjmp( book->jumper, 1 );
716
                }
717
                if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
718
                        addrbook_parse_person( book, file );
719
                }
720
                else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
721
                        addrbook_parse_group( book, file );
722
                }
723
                else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
724
                        addrbook_parse_folder( book, file );
725
                }
726
        }
727
        if( retVal ) book->retVal = MGU_SUCCESS;
728
        return retVal;
729
}
730

    
731
/*
732
* Resolve folder items visitor function.
733
*/
734
static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) {
735
        AddressBookFile *book = data;
736
        AddrItemObject *obj = ( AddrItemObject * ) value;
737
        ItemFolder *rootFolder = book->addressCache->rootFolder;
738
        if( obj->parent == NULL ) {
739
                if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
740
                        rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj );
741
                        ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
742
                }
743
                else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
744
                        rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj );
745
                        ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder);
746
                }
747
        }
748
}
749

    
750
/*
751
* Resolve folder items. Lists of UID's are replaced with pointers to data items.
752
*/
753
static void addrbook_resolve_folder_items( AddressBookFile *book ) {
754
        GList *nodeFolder = NULL;
755
        GList *listRemove = NULL;
756
        GList *node = NULL;
757
        ItemFolder *rootFolder = book->addressCache->rootFolder;
758
        nodeFolder = book->tempList;
759
        while( nodeFolder ) {
760
                ItemFolder *folder = nodeFolder->data;
761
                listRemove = NULL;
762
                node = folder->listItems;
763
                while( node ) {
764
                        gchar *uid = node->data;
765
                        AddrItemObject *aio = addrcache_get_object( book->addressCache, uid );
766
                        if( aio ) {
767
                                if( aio->type == ITEMTYPE_FOLDER ) {
768
                                        ItemFolder *item = ( ItemFolder * ) aio;
769
                                        folder->listFolder = g_list_append( folder->listFolder, item );
770
                                        ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
771
                                        addrcache_hash_add_folder( book->addressCache, folder );
772
                                }
773
                                else if( aio->type == ITEMTYPE_PERSON ) {
774
                                        ItemPerson *item = ( ItemPerson * ) aio;
775
                                        folder->listPerson = g_list_append( folder->listPerson, item );
776
                                        ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
777
                                }
778
                                else if( aio->type == ITEMTYPE_GROUP ) {
779
                                        ItemGroup *item = ( ItemGroup * ) aio;
780
                                        folder->listGroup = g_list_append( folder->listGroup, item );
781
                                        ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
782
                                }
783
                                /* Replace data with pointer to item */
784
                                g_free( uid );
785
                                node->data = aio;
786
                        }
787
                        else {
788
                                /* Not found, append to remove list. */
789
                                listRemove = g_list_append( listRemove, uid );
790
                        }
791
                        node = g_list_next( node );
792
                }
793
                rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder );
794

    
795
                /* Process remove list */
796
                node = listRemove;
797
                while( node ) {
798
                        gchar *uid = node->data;
799
                        folder->listItems = g_list_remove( folder->listItems, uid );
800
                        g_free( uid );
801
                        node = g_list_next( node );
802
                }
803
                g_list_free( listRemove );
804
                nodeFolder = g_list_next( nodeFolder );
805
        }
806

    
807
        /* Remove folders with parents. */
808
        listRemove = NULL;
809
        node = rootFolder->listFolder;
810
        while( node ) {
811
                ItemFolder *folder = ( ItemFolder * ) node->data;
812
                if( ADDRITEM_PARENT(folder) ) {
813
                        /* Remove folders with parents */
814
                        listRemove = g_list_append( listRemove, folder );
815
                }
816
                else {
817
                        /* Add to root folder */
818
                        ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder);
819
                }
820
                node = g_list_next( node );
821
        }
822

    
823
        /* Process remove list */
824
        node = listRemove;
825
        while( node ) {
826
                rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data );
827
                node = g_list_next( node );
828
        }
829
        g_list_free( listRemove );
830

    
831
        /* Move all unparented persons and groups into root folder */
832
        g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book );
833

    
834
        /* Free up some more */
835
        nodeFolder = book->tempList;
836
        while( nodeFolder ) {
837
                ItemFolder *folder = nodeFolder->data;
838
                g_list_free( folder->listItems );
839
                folder->listItems = NULL;
840
                nodeFolder = g_list_next( nodeFolder );
841
        }
842
        g_list_free( book->tempList );
843
        book->tempList = NULL;
844

    
845
}
846

    
847
/*
848
* Read address book file.
849
*/
850
gint addrbook_read_data( AddressBookFile *book ) {
851
        XMLFile *file = NULL;
852
        gchar *fileSpec = NULL;
853

    
854
        g_return_val_if_fail( book != NULL, -1 );
855

    
856
        fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
857
        book->retVal = MGU_OPEN_FILE;
858
        book->accessFlag = FALSE;
859
        book->modifyFlag = FALSE;
860
        file = xml_open_file( fileSpec );
861
        g_free( fileSpec );
862
        if( file ) {
863
                book->tempList = NULL;
864

    
865
                /* Trap for parsing errors. */
866
                if( setjmp( book->jumper ) ) {
867
                        xml_close_file( file );
868
                        return book->retVal;
869
                }
870
                addrbook_read_tree( book, file );
871
                xml_close_file( file );
872

    
873
                /* Resolve folder items */
874
                addrbook_resolve_folder_items( book );
875
                book->tempList = NULL;
876
                book->readFlag = TRUE;
877
                book->dirtyFlag = FALSE;
878
        }
879
        return book->retVal;
880
}
881

    
882
static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
883
        gint i;
884
        for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
885
        fputs( "<", fp );
886
        fputs( name, fp );
887
}
888

    
889
static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
890
        gint i;
891
        for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
892
        fputs( "</", fp );
893
        fputs( name, fp );
894
        fputs( ">\n", fp );
895
}
896

    
897
static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) {
898
        fputs( " ", fp );
899
        fputs( name, fp );
900
        fputs( "=\"", fp );
901
        xml_file_put_escape_str( fp, value );
902
        fputs( "\"", fp );
903
}
904

    
905
/*
906
* Write file hash table visitor function.
907
*/
908
static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) {
909
        AddrItemObject *obj = ( AddrItemObject * ) value;
910
        FILE *fp = ( FILE * ) data;
911
        GList *node;
912

    
913
        if( ! obj ) return;
914
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
915
                ItemPerson *person = ( ItemPerson * ) value;
916
                if( person ) {
917
                        addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON );
918
                        addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) );
919
                        addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName );
920
                        addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName );
921
                        addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName );
922
                        addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) );
923
                        fputs( " >\n", fp);
924

    
925
                        /* Output email addresses */
926
                        addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST );
927
                        fputs( ">\n", fp );
928
                        node = person->listEMail;
929
                        while ( node ) {
930
                                ItemEMail *email = node->data;
931
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS );
932
                                addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) );
933
                                addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) );
934
                                addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address );
935
                                addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks );
936
                                fputs( " />\n", fp);
937
                                node = g_list_next( node );
938
                        }
939
                        addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST );
940

    
941
                        /* Output user attributes */
942
                        addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
943
                        fputs( ">\n", fp );
944
                        node = person->listAttrib;
945
                        while ( node ) {
946
                                UserAttribute *attrib = node->data;
947
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE );
948
                                addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid );
949
                                addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name );
950
                                fputs( " >", fp);
951
                                xml_file_put_escape_str( fp, attrib->value );
952
                                addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE );
953
                                node = g_list_next( node );
954
                        }
955
                        addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST );
956
                        addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON );
957
                }
958
        }
959
}
960

    
961
/*
962
* Write file hash table visitor function.
963
*/
964
static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) {
965
        AddrItemObject *obj = ( AddrItemObject * ) value;
966
        FILE *fp = ( FILE * ) data;
967
        GList *node;
968

    
969
        if( ! obj ) return;
970
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
971
                ItemGroup *group = ( ItemGroup * ) value;
972
                if( group ) {
973
                        addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP );
974
                        addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) );
975
                        addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) );
976
                        addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks );
977
                        fputs( " >\n", fp );
978

    
979
                        /* Output email address links */
980
                        addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST );
981
                        fputs( ">\n", fp );
982
                        node = group->listEMail;
983
                        while ( node ) {
984
                                ItemEMail *email = node->data;
985
                                ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email);
986
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER );
987
                                addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) );
988
                                addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) );
989
                                fputs( " />\n", fp );
990
                                node = g_list_next( node );
991
                        }
992
                        addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST );
993
                        addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP );
994
                }
995
        }
996
}
997

    
998
/*
999
* Write file hash table visitor function.
1000
*/
1001
static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) {
1002
        AddrItemObject *obj = ( AddrItemObject * ) value;
1003
        FILE *fp = ( FILE * ) data;
1004
        GList *node;
1005

    
1006
        if( ! obj ) return;
1007
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
1008
                ItemFolder *folder = ( ItemFolder * ) value;
1009
                if( folder ) {
1010
                        addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER );
1011
                        addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) );
1012
                        addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) );
1013
                        addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks );
1014
                        fputs( " >\n", fp );
1015
                        addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST );
1016
                        fputs( ">\n", fp );
1017

    
1018
                        /* Output persons */
1019
                        node = folder->listPerson;
1020
                        while ( node ) {
1021
                                ItemPerson *item = node->data;
1022
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1023
                                addrbook_write_attr( fp, AB_ATTAG_TYPE,  AB_ATTAG_VAL_PERSON );
1024
                                addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1025
                                fputs( " />\n", fp );
1026
                                node = g_list_next( node );
1027
                        }
1028

    
1029
                        /* Output groups */
1030
                        node = folder->listGroup;
1031
                        while ( node ) {
1032
                                ItemGroup *item = node->data;
1033
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1034
                                addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP );
1035
                                addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1036
                                fputs( " />\n", fp );
1037
                                node = g_list_next( node );
1038
                        }
1039

    
1040
                        /* Output folders */
1041
                        node = folder->listFolder;
1042
                        while ( node ) {
1043
                                ItemFolder *item = node->data;
1044
                                addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM );
1045
                                addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER );
1046
                                addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) );
1047
                                fputs( " />\n", fp );
1048
                                node = g_list_next( node );
1049
                        }
1050
                        addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST );
1051
                        addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER );
1052
                }
1053
        }
1054
}
1055

    
1056
/*
1057
* Output address book data to specified file.
1058
* return: Status code.
1059
*/
1060
gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
1061
        FILE *fp;
1062
        gchar *fileSpec;
1063
#ifndef DEV_STANDALONE
1064
        PrefFile *pfile;
1065
#endif
1066

    
1067
        g_return_val_if_fail( book != NULL, -1 );
1068
        g_return_val_if_fail( newFile != NULL, -1 );
1069

    
1070
        fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
1071

    
1072
        book->retVal = MGU_OPEN_FILE;
1073
#ifdef DEV_STANDALONE
1074
        fp = fopen( fileSpec, "wb" );
1075
        g_free( fileSpec );
1076
        if( fp ) {
1077
                fputs( "<?xml version=\"1.0\" ?>\n", fp );
1078
#else
1079
        pfile = prefs_file_open( fileSpec );
1080
        g_free( fileSpec );
1081
        if( pfile ) {
1082
                fp = pfile->fp;
1083
                fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1084
                                conv_get_internal_charset_str() );
1085
#endif
1086
                addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1087
                addrbook_write_attr( fp, AB_ATTAG_NAME, book->name );
1088
                fputs( " >\n", fp );
1089

    
1090
                /* Output all persons */
1091
                g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp );
1092

    
1093
                /* Output all groups */
1094
                g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp );
1095

    
1096
                /* Output all folders */
1097
                g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp );
1098

    
1099
                addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK );
1100
                book->retVal = MGU_SUCCESS;
1101
#ifdef DEV_STANDALONE
1102
                fclose( fp );
1103
#else
1104
                if( prefs_file_close( pfile ) < 0 ) {
1105
                        book->retVal = MGU_ERROR_WRITE;
1106
                }
1107
#endif
1108
        }
1109

    
1110
        fileSpec = NULL;
1111
        return book->retVal;
1112
}
1113

    
1114
/*
1115
* Output address book data to original file.
1116
* return: Status code.
1117
*/
1118
gint addrbook_save_data( AddressBookFile *book ) {
1119
        g_return_val_if_fail( book != NULL, -1 );
1120

    
1121
        book->retVal = MGU_NO_FILE;
1122
        if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal;
1123
        if( book->path == NULL || *book->path == '\0' ) return book->retVal;
1124

    
1125
        addrbook_write_to( book, book->fileName );
1126
        if( book->retVal == MGU_SUCCESS ) {
1127
                book->dirtyFlag = FALSE;
1128
        }
1129
        return book->retVal;
1130
}
1131

    
1132
/* **********************************************************************
1133
* Address book edit interface functions...
1134
* ***********************************************************************
1135
*/
1136

    
1137
/*
1138
* Move person's email item.
1139
* param: book       Address book.
1140
*        person     Person.
1141
*        itemMove   Item to move.
1142
*        itemTarget Target item before which to move item.
1143
*/
1144
ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person,
1145
                        ItemEMail *itemMove, ItemEMail *itemTarget )
1146
{
1147
        ItemEMail *email = NULL;
1148

    
1149
        g_return_val_if_fail( book != NULL, NULL );
1150

    
1151
        email = addritem_move_email_before( person, itemMove, itemTarget );
1152
        if( email ) {
1153
                book->dirtyFlag = TRUE;
1154
        }
1155
        return email;
1156
}
1157

    
1158
/*
1159
* Move person's email item.
1160
* param: book       Address book.
1161
*        person     Person.
1162
*        itemMove   Item to move.
1163
*        itemTarget Target item after which to move item.
1164
*/
1165
ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
1166
                        ItemEMail *itemMove, ItemEMail *itemTarget )
1167
{
1168
        ItemEMail *email = NULL;
1169

    
1170
        g_return_val_if_fail( book != NULL, NULL );
1171

    
1172
        email = addritem_move_email_after( person, itemMove, itemTarget );
1173
        if( email ) {
1174
                book->dirtyFlag = TRUE;
1175
        }
1176
        return email;
1177
}
1178

    
1179
/*
1180
* Hash table visitor function.
1181
*/
1182
static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
1183
        g_free( key );
1184
        key = NULL;
1185
        value = NULL;
1186
        return TRUE;
1187
}
1188

    
1189
/*
1190
* Update address book email list for specified person.
1191
* Enter: book      Address book.
1192
*        person    Person to update.
1193
*        listEMail New list of email addresses.
1194
* Note: The existing email addresses are replaced with the new addresses. Any references
1195
* to old addresses in the groups are re-linked to the new addresses. All old addresses
1196
* linked to the person are removed.
1197
*/
1198
void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
1199
        GList *node;
1200
        GList *oldData;
1201
        GList *listGroup;
1202

    
1203
        g_return_if_fail( book != NULL );
1204
        g_return_if_fail( person != NULL );
1205

    
1206
        /* Remember old list */
1207
        oldData = person->listEMail;
1208

    
1209
        /* Attach new address list to person. */
1210
           node = listEMail;
1211
        while( node ) {
1212
                ItemEMail *email = node->data;
1213
                if( ADDRITEM_ID(email) == NULL ) {
1214
                        /* Allocate an ID */
1215
                        addrcache_id_email( book->addressCache, email );
1216
                }
1217
                ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
1218
                node = g_list_next( node );
1219
        }
1220
        person->listEMail = listEMail;
1221

    
1222
        /* Get groups where person's email is listed */
1223
        listGroup = addrcache_get_group_for_person( book->addressCache, person );
1224
        if( listGroup ) {
1225
                GHashTable *hashEMail;
1226
                GList *nodeGrp;
1227

    
1228
                /* Load hash table with new address entries */
1229
                hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
1230
                   node = listEMail;
1231
                while( node ) {
1232
                        ItemEMail *email = node->data;
1233
                        gchar *addr = g_strdup( email->address );
1234
                        g_strdown( addr );
1235
                        if( ! g_hash_table_lookup( hashEMail, addr ) ) {
1236
                                g_hash_table_insert( hashEMail, addr, email );
1237
                        }
1238
                        node = g_list_next( node );
1239
                }
1240

    
1241
                /* Re-parent new addresses to existing groups, where email address match. */
1242
                nodeGrp = listGroup;
1243
                while( nodeGrp ) {
1244
                        ItemGroup *group = ( ItemGroup * ) nodeGrp->data;
1245
                        GList *groupEMail = group->listEMail;
1246
                        GList *nodeGrpEM;
1247
                        GList *listRemove = NULL;
1248

    
1249
                        /* Process each email item linked to group */
1250
                        nodeGrpEM = groupEMail;
1251
                        while( nodeGrpEM ) {
1252
                                ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
1253
                                if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
1254
                                        /* Found an email address for this person */
1255
                                        ItemEMail *emailNew = NULL;
1256
                                        gchar *addr = g_strdup( emailGrp->address );
1257
                                        g_strdown( addr );
1258
                                        emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
1259
                                        g_free( addr );
1260
                                        if( emailNew ) {
1261
                                                /* Point to this entry */
1262
                                                nodeGrpEM->data = emailNew;
1263
                                        }
1264
                                        else {
1265
                                                /* Mark for removal */
1266
                                                listRemove = g_list_append( listRemove, emailGrp );
1267
                                        }
1268
                                }
1269
                                /* Move on to next email link */
1270
                                nodeGrpEM = g_list_next( nodeGrpEM );
1271
                        }
1272

    
1273
                        /* Process all removed links in current group */
1274
                        nodeGrpEM = listRemove;
1275
                        while( nodeGrpEM ) {
1276
                                ItemEMail *emailGrp = nodeGrpEM->data;
1277
                                groupEMail = g_list_remove( groupEMail, emailGrp );
1278
                                nodeGrpEM = g_list_next( nodeGrpEM );
1279
                        }
1280

    
1281
                        /* Move on to next group */
1282
                        nodeGrp = g_list_next( nodeGrp );
1283

    
1284
                }
1285

    
1286
                /* Clear hash table */
1287
                g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
1288
                g_hash_table_destroy( hashEMail );
1289
                hashEMail = NULL;
1290
                g_list_free( listGroup );
1291
                listGroup = NULL;
1292
        }
1293

    
1294
        /* Free up old data */
1295
        addritem_free_list_email( oldData );
1296
        oldData = NULL;
1297
        book->dirtyFlag = TRUE;
1298

    
1299
}
1300

    
1301
/*
1302
* Add person and address data to address book.
1303
* Enter: book      Address book.
1304
*        folder    Folder where to add person, or NULL for root folder.
1305
*        listEMail New list of email addresses.
1306
* Return: Person added.
1307
* Note: A new person is created with specified list of email addresses. All objects inserted
1308
* into address book.
1309
*/
1310
ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1311
        ItemPerson *person;
1312
        ItemFolder *f = folder;
1313
        GList *node;
1314

    
1315
        g_return_val_if_fail( book != NULL, NULL );
1316

    
1317
        if( ! f ) f = book->addressCache->rootFolder;
1318
        person = addritem_create_item_person();
1319
        addrcache_id_person( book->addressCache, person );
1320
        addrcache_folder_add_person( book->addressCache, f, person );
1321

    
1322
           node = listEMail;
1323
        while( node ) {
1324
                ItemEMail *email = node->data;
1325
                if( ADDRITEM_ID(email) == NULL ) {
1326
                        addrcache_id_email( book->addressCache, email );
1327
                }
1328
                addrcache_person_add_email( book->addressCache, person, email );
1329
                node = g_list_next( node );
1330
        }
1331
        book->dirtyFlag = TRUE;
1332
        return person;
1333
}
1334

    
1335
#if 0
1336
/*
1337
* Load hash table visitor function.
1338
*/
1339
static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
1340
        AddrItemObject *obj = ( AddrItemObject * ) value;
1341

1342
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
1343
                GHashTable *table = ( GHashTable * ) data;
1344
                gchar *newKey = g_strdup( key );
1345
                ItemEMail *email = ( ItemEMail * ) obj;
1346
                if( ! g_hash_table_lookup( table, newKey ) ) {
1347
                        g_hash_table_insert( table, newKey, email );
1348
                }
1349
        }
1350
}
1351

1352
/*
1353
* Load hash table with links to email addresses.
1354
*/
1355
static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
1356
        g_return_if_fail( book != NULL );
1357
        g_return_if_fail( table != NULL );
1358
        g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
1359
}
1360
#endif
1361

    
1362
/*
1363
* Build available email list visitor function.
1364
*/
1365
static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) {
1366
        AddrItemObject *obj = ( AddrItemObject * ) value;
1367

    
1368
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
1369
                AddressBookFile *book = data;
1370
                ItemPerson *person = ( ItemPerson * ) obj;
1371
                GList *node = person->listEMail;
1372
                while( node ) {
1373
                        ItemEMail *email = node->data;
1374
                        /* gchar *newKey = g_strdup( ADDRITEM_ID(email) ); */
1375

    
1376
                        if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) {
1377
                                book->tempList = g_list_append( book->tempList, email );
1378
                        }
1379
                        node = g_list_next( node );
1380
                }
1381
        }
1382
}
1383

    
1384
/*
1385
* Return link list of available email items (which have not already been linked to
1386
* groups). Note that the list contains references to items and should be g_free()
1387
* when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will
1388
* destroy the addressbook data!
1389
* Return: List of items, or NULL if none.
1390
*/
1391
GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) {
1392
        GList *list = NULL;
1393
        GHashTable *table;
1394

    
1395
        g_return_val_if_fail( book != NULL, NULL );
1396

    
1397
        /* Load hash table with group email entries */
1398
        table = g_hash_table_new( g_str_hash, g_str_equal );
1399
        if( group ) {
1400
                list = group->listEMail;
1401
                while( list ) {
1402
                        ItemEMail *email = list->data;
1403
                        g_hash_table_insert( table, ADDRITEM_ID(email), email );
1404
                        list = g_list_next( list );
1405
                }
1406
        }
1407

    
1408
        /* Build list of available email addresses which exclude those already in groups */
1409
        book->tempList = NULL;
1410
        book->tempHash = table;
1411
        g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book );
1412
        list = book->tempList;
1413
        book->tempList = NULL;
1414
        book->tempHash = NULL;
1415

    
1416
        /* Clear hash table */
1417
        g_hash_table_destroy( table );
1418
        table = NULL;
1419

    
1420
        return list;
1421
}
1422

    
1423
/*
1424
* Update address book email list for specified group.
1425
* Enter: book      Address book.
1426
*        group     group to update.
1427
*        listEMail New list of email addresses. This should *NOT* be g_free() when done.
1428
* Note: The existing email addresses are replaced with the new addresses. Any references
1429
* to old addresses in the groups are re-linked to the new addresses. All old addresses
1430
* linked to the person are removed.
1431
*/
1432
void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) {
1433
        GList *oldData;
1434

    
1435
        g_return_if_fail( book != NULL );
1436
        g_return_if_fail( group != NULL );
1437

    
1438
        /* Remember old list */
1439
        oldData = group->listEMail;
1440
        group->listEMail = listEMail;
1441
        mgu_clear_list( oldData );
1442
        oldData = NULL;
1443
        book->dirtyFlag = TRUE;
1444
}
1445

    
1446
/*
1447
* Add group and email list to address book.
1448
* Enter: book      Address book.
1449
*        folder    Parent folder, or NULL for root folder.
1450
*        listEMail New list of email addresses. This should *NOT* be g_free() when done.
1451
* Return: Group object.
1452
* Note: The existing email addresses are replaced with the new addresses. Any references
1453
* to old addresses in the groups are re-linked to the new addresses. All old addresses
1454
* linked to the person are removed.
1455
*/
1456
ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) {
1457
        ItemGroup *group = NULL;
1458
        ItemFolder *f = folder;
1459

    
1460
        g_return_val_if_fail( book != NULL, NULL );
1461

    
1462
        if( ! f ) f = book->addressCache->rootFolder;
1463
        group = addritem_create_item_group();
1464
        addrcache_id_group( book->addressCache, group );
1465
        addrcache_folder_add_group( book->addressCache, f, group );
1466
        group->listEMail = listEMail;
1467
        book->dirtyFlag = TRUE;
1468
        return group;
1469
}
1470

    
1471
/*
1472
* Add new folder to address book.
1473
* Enter: book   Address book.
1474
*        parent        Parent folder.
1475
* Return: Folder that was added. This should *NOT* be g_free() when done.
1476
*/
1477
ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) {
1478
        ItemFolder *folder = NULL;
1479
        ItemFolder *p = parent;
1480

    
1481
        g_return_val_if_fail( book != NULL, NULL );
1482

    
1483
        if( ! p ) p = book->addressCache->rootFolder;
1484
        folder = addritem_create_item_folder();
1485
        addrcache_id_folder( book->addressCache, folder );
1486
        if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
1487
                p->listFolder = g_list_append( p->listFolder, folder );
1488
                ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
1489
                book->dirtyFlag = TRUE;
1490
        }
1491
        else {
1492
                addritem_free_item_folder( folder );
1493
                folder = NULL;
1494
        }
1495
        return folder;
1496
}
1497

    
1498
/*
1499
* Update address book attribute list for specified person.
1500
* Enter: book       Address book.
1501
*        person     Person to update.
1502
*        listAttrib New list of attributes.
1503
* Note: The existing email addresses are replaced with the new addresses. All old attributes
1504
* linked to the person are removed.
1505
*/
1506
void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1507
        GList *node;
1508
        GList *oldData;
1509

    
1510
        g_return_if_fail( book != NULL );
1511
        g_return_if_fail( person != NULL );
1512

    
1513
        /* Remember old list */
1514
        oldData = person->listAttrib;
1515

    
1516
        /* Attach new address list to person. */
1517
           node = listAttrib;
1518
        while( node ) {
1519
                UserAttribute *attrib = node->data;
1520
                if( attrib->uid == NULL ) {
1521
                        /* Allocate an ID */
1522
                        addrcache_id_attribute( book->addressCache, attrib );
1523
                }
1524
                node = g_list_next( node );
1525
        }
1526
        person->listAttrib = listAttrib;
1527

    
1528
        /* Free up old data */
1529
        addritem_free_list_attribute( oldData );
1530
        oldData = NULL;
1531
        book->dirtyFlag = TRUE;
1532

    
1533
}
1534

    
1535
/*
1536
* Add attribute data for person to address book.
1537
* Enter: book       Address book.
1538
*        person     New person object.
1539
*        listAttrib New list of attributes.
1540
* Note: Only attributes are inserted into address book.
1541
*/
1542
void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) {
1543
        GList *node;
1544

    
1545
        g_return_if_fail( book != NULL );
1546
        g_return_if_fail( person != NULL );
1547

    
1548
           node = listAttrib;
1549
        while( node ) {
1550
                UserAttribute *attrib = node->data;
1551
                if( attrib->uid == NULL ) {
1552
                        addrcache_id_attribute( book->addressCache, attrib );
1553
                }
1554
                addritem_person_add_attribute( person, attrib );
1555
                node = g_list_next( node );
1556
        }
1557
        book->dirtyFlag = TRUE;
1558
}
1559

    
1560
/*
1561
* Return address book file for specified object.
1562
* Enter: aio Book item object.
1563
* Return: Address book, or NULL if not found.
1564
*/
1565
AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) {
1566
        AddressBookFile *book = NULL;
1567

    
1568
        if( aio ) {
1569
                ItemFolder *parent = NULL;
1570
                ItemFolder *root = NULL;
1571
                if( aio->type == ITEMTYPE_EMAIL ) {
1572
                        ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio);
1573
                        if( person ) {
1574
                                parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
1575
                        }
1576
                }
1577
                else {
1578
                        parent = ( ItemFolder * ) ADDRITEM_PARENT(aio);
1579
                }
1580
                if( parent ) {
1581
                        root = addrcache_find_root_folder( parent );
1582
                }
1583
                if( root ) {
1584
                        book = ( AddressBookFile * ) ADDRITEM_PARENT(root);
1585
                }
1586
        }
1587
        return book;
1588
}
1589

    
1590
/*
1591
* Remove folder from address book. Children are re-parented to parent folder.
1592
* param: folder Folder to remove.
1593
* return: Folder, or NULL if not found. Note that object should still be freed.
1594
*/
1595
ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) {
1596
        ItemFolder *f;
1597

    
1598
        g_return_val_if_fail( book != NULL, NULL );
1599

    
1600
        f = addrcache_remove_folder( book->addressCache, folder );
1601
        if( f ) book->dirtyFlag = TRUE;
1602
        return f;
1603
}
1604

    
1605
/*
1606
* Remove folder from address book. Children are deleted.
1607
* param: folder Folder to remove.
1608
* return: Folder, or NULL if not found. Note that object should still be freed.
1609
*/
1610
ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) {
1611
        ItemFolder *f;
1612

    
1613
        g_return_val_if_fail( book != NULL, NULL );
1614

    
1615
        f = addrcache_remove_folder_delete( book->addressCache, folder );
1616
        if( f ) book->dirtyFlag = TRUE;
1617
        return f;
1618
}
1619

    
1620
#define WORK_BUFLEN     1024
1621
#define ADDRBOOK_DIGITS "0123456789"
1622

    
1623
/*
1624
* Return list of existing address book files.
1625
* Enter: book Address book file.
1626
* Return: File list.
1627
*/
1628
GList *addrbook_get_bookfile_list( AddressBookFile *book ) {
1629
        gchar *adbookdir;
1630
        DIR *dp;
1631
        struct dirent *entry;
1632
        struct stat statbuf;
1633
        gchar buf[ WORK_BUFLEN ];
1634
        gchar numbuf[ WORK_BUFLEN ];
1635
        gint len, lenpre, lensuf, lennum;
1636
        long int val, maxval;
1637
        GList *fileList = NULL;
1638

    
1639
        g_return_val_if_fail( book != NULL, NULL );
1640

    
1641
        if( book->path == NULL || *book->path == '\0' ) {
1642
                book->retVal = MGU_NO_PATH;
1643
                return NULL;
1644
        }
1645

    
1646
        strcpy( buf, book->path );
1647
        len = strlen( buf );
1648
        if( len > 0 ) {
1649
                if( buf[ len-1 ] != G_DIR_SEPARATOR ) {
1650
                        buf[ len ] = G_DIR_SEPARATOR;
1651
                        buf[ ++len ] = '\0';
1652
                }
1653
        }
1654

    
1655
        adbookdir = g_strdup( buf );
1656
        strcat( buf, ADDRBOOK_PREFIX );
1657

    
1658
        if( ( dp = opendir( adbookdir ) ) == NULL ) {
1659
                book->retVal = MGU_OPEN_DIRECTORY;
1660
                g_free( adbookdir );
1661
                return NULL;
1662
        }
1663

    
1664
        lenpre = strlen( ADDRBOOK_PREFIX );
1665
        lensuf = strlen( ADDRBOOK_SUFFIX );
1666
        lennum = FILE_NUMDIGITS + lenpre;
1667
        maxval = -1;
1668

    
1669
        while( ( entry = readdir( dp ) ) != NULL ) {
1670
                gchar *endptr = NULL;
1671
                gint i;
1672
                gboolean flg;
1673

    
1674
                strcpy( buf, adbookdir );
1675
                strcat( buf, entry->d_name );
1676
                stat( buf, &statbuf );
1677
                if( S_IFREG & statbuf.st_mode ) {
1678
                        if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) {
1679
                                if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) {
1680
                                        strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS );
1681
                                        numbuf[ FILE_NUMDIGITS ] = '\0';
1682
                                        flg = TRUE;
1683
                                        for( i = 0; i < FILE_NUMDIGITS; i++ ) {
1684
                                                if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) {
1685
                                                        flg = FALSE;
1686
                                                        break;
1687
                                                }
1688
                                        }
1689
                                        if( flg ) {
1690
                                                /* Get value */
1691
                                                val = strtol( numbuf, &endptr, 10 );
1692
                                                if( endptr  && val > -1 ) {
1693
                                                        if( val > maxval ) maxval = val;
1694
                                                        fileList = g_list_append( fileList, g_strdup( entry->d_name ) );
1695
                                                }
1696
                                        }
1697
                                }
1698
                        }
1699
                }
1700
        }
1701
        closedir( dp );
1702
        g_free( adbookdir );
1703

    
1704
        book->maxValue = maxval; 
1705
        book->retVal = MGU_SUCCESS;
1706
        return fileList;
1707
}
1708

    
1709
/*
1710
* Return file name for specified file number.
1711
* Enter:  fileNum File number.
1712
* Return: File name, or NULL if file number too large. Should be g_free() when done.
1713
*/
1714
gchar *addrbook_gen_new_file_name( gint fileNum ) {
1715
        gchar fmt[ 30 ];
1716
        gchar buf[ WORK_BUFLEN ];
1717
        gint n = fileNum;
1718
        long int nmax;
1719

    
1720
        if( n < 1 ) n = 1;
1721
        nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
1722
        if( fileNum > nmax ) return NULL;
1723
        sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
1724
        sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
1725
        return g_strdup( buf );
1726
}
1727

    
1728
/* **********************************************************************
1729
* Address book test functions...
1730
* ***********************************************************************
1731
*/
1732

    
1733
#if 0
1734
static void addrbook_show_attribs( GList *attr ) {
1735
        while( attr ) {
1736
                gchar *name = ((XMLAttr *)attr->data)->name;
1737
                gchar *value = ((XMLAttr *)attr->data)->value;
1738
                printf( "\tn/v = %s : %s\n", name, value );
1739
                attr = g_list_next( attr );
1740
        }
1741
        printf( "\t---\n" );
1742
}
1743
#endif
1744

    
1745
/*
1746
* Test email address list.
1747
*/
1748
static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){
1749
        guint prev_level;
1750
        GList *attr;
1751

    
1752
        for (;;) {
1753
                prev_level = file->level;
1754
                if( xml_parse_next_tag( file ) ) {
1755
                        longjmp( book->jumper, 1 );
1756
                }
1757
                if (file->level < prev_level) return;
1758
                attr = xml_get_current_tag_attr(file);
1759
                /* addrbook_show_attribs( attr ); */
1760
                if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) {
1761
                        addrbook_chkparse_addr_list( book, file );
1762
                }
1763
        }
1764
}
1765

    
1766
/*
1767
* Test user attributes for person.
1768
*/
1769
static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) {
1770
        GList *attr;
1771
        gchar *element;
1772

    
1773
        attr = xml_get_current_tag_attr(file);
1774
        /* addrbook_show_attribs( attr ); */
1775
        element = xml_get_element( file );
1776
        /* printf( "\t\tattrib value : %s\n", element ); */
1777
}
1778

    
1779
/*
1780
* Test attribute list.
1781
*/
1782
static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){
1783
        guint prev_level;
1784

    
1785
        for (;;) {
1786
                prev_level = file->level;
1787
                if( xml_parse_next_tag( file ) ) {
1788
                        longjmp( book->jumper, 1 );
1789
                }
1790
                if (file->level < prev_level) return;
1791
                if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) {
1792
                        addrbook_chkparse_attribute( book, file );
1793
                        addrbook_chkparse_attr_list( book, file );
1794
                }
1795
        }
1796
}
1797

    
1798
/*
1799
* Test person.
1800
*/
1801
static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) {
1802
        GList *attr;
1803

    
1804
        attr = xml_get_current_tag_attr(file);
1805
        /* addrbook_show_attribs( attr ); */
1806
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
1807
                longjmp( book->jumper, 1 );
1808
        }
1809
        if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) {
1810
                addrbook_chkparse_addr_list( book, file );
1811
        }
1812
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
1813
                longjmp( book->jumper, 1 );
1814
        }
1815
        if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) {
1816
                addrbook_chkparse_attr_list( book, file );
1817
        }
1818
}
1819

    
1820
/*
1821
* Test group member list.
1822
*/
1823
static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){
1824
        GList *attr;
1825
        guint prev_level;
1826

    
1827
        for (;;) {
1828
                prev_level = file->level;
1829
                if( xml_parse_next_tag( file ) ) {
1830
                        longjmp( book->jumper, 1 );
1831
                }
1832
                if (file->level < prev_level) return;
1833
                if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) {
1834
                        attr = xml_get_current_tag_attr(file);
1835
                        /* addrbook_show_attribs( attr ); */
1836
                        addrbook_chkparse_member_list( book, file );
1837
                }
1838
                else {
1839
                        attr = xml_get_current_tag_attr( file );
1840
                        /* addrbook_show_attribs( attr ); */
1841
                }
1842
        }
1843
}
1844

    
1845
/*
1846
* Test group.
1847
*/
1848
static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) {
1849
        GList *attr;
1850

    
1851
        attr = xml_get_current_tag_attr(file);
1852
        /* addrbook_show_attribs( attr ); */
1853
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
1854
                longjmp( book->jumper, 1 );
1855
        }
1856
        if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) {
1857
                addrbook_chkparse_member_list( book, file );
1858
        }
1859
}
1860

    
1861
/*
1862
* Test folder item list.
1863
*/
1864
static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){
1865
        GList *attr;
1866
        guint prev_level;
1867

    
1868
        for (;;) {
1869
                prev_level = file->level;
1870
                if( xml_parse_next_tag( file ) ) {
1871
                        longjmp( book->jumper, 1 );
1872
                }
1873
                if (file->level < prev_level) return;
1874
                if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) {
1875
                        attr = xml_get_current_tag_attr(file);
1876
                        /* addrbook_show_attribs( attr ); */
1877
                        addrbook_chkparse_folder_list( book, file );
1878
                }
1879
                else {
1880
                        attr = xml_get_current_tag_attr( file );
1881
                        /* addrbook_show_attribs( attr ); */
1882
                }
1883
        }
1884
}
1885

    
1886
/*
1887
* Test folder.
1888
*/
1889
static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) {
1890
        GList *attr;
1891

    
1892
        attr = xml_get_current_tag_attr(file);
1893
        /* addrbook_show_attribs( attr ); */
1894
        if( xml_parse_next_tag( file ) ) {        /* Consume closing tag */
1895
                longjmp( book->jumper, 1 );
1896
        }
1897
        if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) {
1898
                addrbook_chkparse_folder_list( book, file );
1899
        }
1900
}
1901

    
1902
/*
1903
* Test address book.
1904
*/
1905
static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) {
1906
        GList *attr;
1907
        gboolean retVal;
1908

    
1909
        if( xml_get_dtd( file ) ) {
1910
                return FALSE;
1911
        }
1912
        if( xml_parse_next_tag( file ) ) {
1913
                return FALSE;
1914
        }
1915

    
1916
        if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) {
1917
                return FALSE;
1918
        }
1919

    
1920
        attr = xml_get_current_tag_attr(file);
1921
        /* addrbook_show_attribs( attr ); */
1922

    
1923
        retVal = TRUE;
1924
        for (;;) {
1925
                if (! file->level ) break;
1926
                /* Get item tag */
1927
                if( xml_parse_next_tag( file ) ) {
1928
                        longjmp( book->jumper, 1 );
1929
                }
1930
                /* Get next tag (person, group or folder) */
1931
                if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) {
1932
                        addrbook_chkparse_person( book, file );
1933
                }
1934
                else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) {
1935
                        addrbook_chkparse_group( book, file );
1936
                }
1937
                else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) {
1938
                        addrbook_chkparse_folder( book, file );
1939
                }
1940
        }
1941
        return retVal;
1942
}
1943

    
1944
/*
1945
* Test address book file by parsing contents.
1946
* Enter: book     Address book file to check.
1947
*        fileName File name to check.
1948
* Return: MGU_SUCCESS if file appears to be valid format.
1949
*/
1950
gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) {
1951
        XMLFile *file = NULL;
1952
        gchar *fileSpec = NULL;
1953

    
1954
        g_return_val_if_fail( book != NULL, -1 );
1955

    
1956
        fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL );
1957
        book->retVal = MGU_OPEN_FILE;
1958
        file = xml_open_file( fileSpec );
1959
        g_free( fileSpec );
1960
        if( file ) {
1961
                book->retVal = MGU_BAD_FORMAT;
1962
                if( setjmp( book->jumper ) ) {
1963
                        /* printf( "Caught Ya!!!\n" ); */
1964
                        xml_close_file( file );
1965
                        return book->retVal;
1966
                }
1967
                if( addrbook_chkread_tree( book, file ) ) {
1968
                        book->retVal = MGU_SUCCESS;
1969
                }
1970
                xml_close_file( file );
1971
        }
1972
        return book->retVal;
1973
}
1974

    
1975
/*
1976
* Return link list of all persons in address book.  Note that the list contains
1977
* references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1978
* this will destroy the addressbook data!
1979
* Return: List of items, or NULL if none.
1980
*/
1981
GList *addrbook_get_all_persons( AddressBookFile *book ) {
1982
        g_return_val_if_fail( book != NULL, NULL );
1983
        return addrcache_get_all_persons( book->addressCache );
1984
}
1985

    
1986
/*
1987
* Add person and address data to address book.
1988
* Enter: book      Address book.
1989
*        folder    Folder where to add person, or NULL for root folder.
1990
*        name      Common name.
1991
*        address   EMail address.
1992
*        remarks   Remarks.
1993
* Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions...
1994
* this will destroy the address book data.
1995
*/
1996
ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
1997
                const gchar *address, const gchar *remarks )
1998
{
1999
        ItemPerson *person = NULL;
2000

    
2001
        g_return_val_if_fail( book != NULL, NULL );
2002

    
2003
        person = addrcache_add_contact( book->addressCache, folder, name, address, remarks );
2004
        if( person ) book->dirtyFlag = TRUE;
2005
        return person;
2006
}
2007

    
2008
/*
2009
* End of Source.
2010
*/