sync with sylpheed 0.6.2cvs1
[claws.git] / src / addrindex.c
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 address index file.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "defs.h"
29
30 #include <glib.h>
31
32 #include "intl.h"
33 #include "mgutils.h"
34 #include "addritem.h"
35 #include "addrcache.h"
36 #include "addrbook.h"
37 #include "addrindex.h"
38 #include "xml.h"
39
40 #ifndef DEV_STANDALONE
41 #include "prefs.h"
42 #include "codeconv.h"
43 #endif
44
45 #include "vcard.h"
46
47 #ifdef USE_JPILOT
48 #include "jpilot.h"
49 #endif
50
51 #ifdef USE_LDAP
52 #include "syldap.h"
53 #endif
54
55 #define TAG_ADDRESS_INDEX    "addressbook"
56
57 #define TAG_IF_ADDRESS_BOOK  "book_list"
58 #define TAG_IF_VCARD         "vcard_list"
59 #define TAG_IF_JPILOT        "jpilot_list"
60 #define TAG_IF_LDAP          "ldap_list"
61
62 #define TAG_DS_ADDRESS_BOOK  "book"
63 #define TAG_DS_VCARD         "vcard"
64 #define TAG_DS_JPILOT        "jpilot"
65 #define TAG_DS_LDAP          "server"
66
67 // XML Attribute names
68 #define ATTAG_BOOK_NAME       "name"
69 #define ATTAG_BOOK_FILE       "file"
70
71 #define ATTAG_VCARD_NAME      "name"
72 #define ATTAG_VCARD_FILE      "file"
73
74 #define ATTAG_JPILOT_NAME     "name"
75 #define ATTAG_JPILOT_FILE     "file"
76 #define ATTAG_JPILOT_CUSTOM_1 "custom-1"
77 #define ATTAG_JPILOT_CUSTOM_2 "custom-2"
78 #define ATTAG_JPILOT_CUSTOM_3 "custom-3"
79 #define ATTAG_JPILOT_CUSTOM_4 "custom-4"
80 #define ATTAG_JPILOT_CUSTOM   "custom-"
81
82 #define ATTAG_LDAP_NAME       "name"
83 #define ATTAG_LDAP_HOST       "host"
84 #define ATTAG_LDAP_PORT       "port"
85 #define ATTAG_LDAP_BASE_DN    "base-dn"
86 #define ATTAG_LDAP_BIND_DN    "bind-dn"
87 #define ATTAG_LDAP_BIND_PASS  "bind-pass"
88 #define ATTAG_LDAP_CRITERIA   "criteria"
89 #define ATTAG_LDAP_MAX_ENTRY  "max-entry"
90 #define ATTAG_LDAP_TIMEOUT    "timeout"
91
92 #define DISP_NEW_COMMON       "Common Address"
93 #define DISP_NEW_PERSONAL     "Personal Address"
94
95 // Old address book
96 #define TAG_IF_OLD_COMMON     "common_address"
97 #define TAG_IF_OLD_PERSONAL   "personal_address"
98
99 #define DISP_OLD_COMMON       "Common Address"
100 #define DISP_OLD_PERSONAL     "Personal Address"
101
102 typedef struct _AddressIfAttr AddressIfAttrib;
103 struct _AddressIfAttr {
104         gchar *name;
105         gchar *value;
106 };
107
108 /*
109 * Build interface with default values.
110 */
111 static AddressInterface *addrindex_create_interface( gint type, gchar *name, gchar *tagIf, gchar *tagDS ) {
112         AddressInterface *iface = g_new0( AddressInterface, 1 );
113         ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE;
114         ADDRITEM_ID(iface) = NULL;
115         ADDRITEM_NAME(iface) = g_strdup( name );
116         ADDRITEM_PARENT(iface) = NULL;
117         ADDRITEM_SUBTYPE(iface) = type;
118         iface->type = type;
119         iface->name = g_strdup( name );
120         iface->listTag = g_strdup( tagIf );
121         iface->itemTag = g_strdup( tagDS );
122         iface->legacyFlag = FALSE;
123         iface->haveLibrary = TRUE;
124         iface->useInterface = TRUE;
125         iface->readOnly      = TRUE;
126         iface->getAccessFlag = NULL;
127         iface->getModifyFlag = NULL;
128         iface->getReadFlag   = NULL;
129         iface->getStatusCode = NULL;
130         iface->getReadData   = NULL;
131         iface->getRootFolder = NULL;
132         iface->getListFolder = NULL;
133         iface->getListPerson = NULL;
134         iface->getAllPersons = NULL;
135         iface->getName       = NULL;
136         iface->listSource = NULL;
137         return iface;
138 }
139
140 /*
141 * Build table of interfaces.
142 */
143 static void addrindex_build_if_list( AddressIndex *addrIndex ) {
144         AddressInterface *iface;
145
146         iface = addrindex_create_interface( ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK, TAG_DS_ADDRESS_BOOK );
147         iface->readOnly      = FALSE;
148         iface->getModifyFlag = ( void * ) addrbook_get_modified;
149         iface->getAccessFlag = ( void * ) addrbook_get_accessed;
150         iface->getReadFlag   = ( void * ) addrbook_get_read_flag;
151         iface->getStatusCode = ( void * ) addrbook_get_status;
152         iface->getReadData   = ( void * ) addrbook_read_data;
153         iface->getRootFolder = ( void * ) addrbook_get_root_folder;
154         iface->getListFolder = ( void * ) addrbook_get_list_folder;
155         iface->getListPerson = ( void * ) addrbook_get_list_person;
156         iface->getAllPersons = ( void * ) addrbook_get_all_persons;
157         iface->getName       = ( void * ) addrbook_get_name;
158         iface->setAccessFlag = ( void * ) addrbook_set_accessed;
159         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
160         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
161
162         iface = addrindex_create_interface( ADDR_IF_VCARD, "V-Card", TAG_IF_VCARD, TAG_DS_VCARD );
163         iface->getModifyFlag = ( void * ) vcard_get_modified;
164         iface->getAccessFlag = ( void * ) vcard_get_accessed;
165         iface->getReadFlag   = ( void * ) vcard_get_read_flag;
166         iface->getStatusCode = ( void * ) vcard_get_status;
167         iface->getReadData   = ( void * ) vcard_read_data;
168         iface->getRootFolder = ( void * ) vcard_get_root_folder;
169         iface->getListFolder = ( void * ) vcard_get_list_folder;
170         iface->getListPerson = ( void * ) vcard_get_list_person;
171         iface->getAllPersons = ( void * ) vcard_get_all_persons;
172         iface->getName       = ( void * ) vcard_get_name;
173         iface->setAccessFlag = ( void * ) vcard_set_accessed;
174         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
175         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
176
177         iface = addrindex_create_interface( ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT, TAG_DS_JPILOT );
178 #ifdef USE_JPILOT
179         iface->haveLibrary = jpilot_test_pilot_lib();
180         iface->useInterface = iface->haveLibrary;
181         iface->getModifyFlag = ( void * ) jpilot_get_modified;
182         iface->getAccessFlag = ( void * ) jpilot_get_accessed;
183         iface->getReadFlag   = ( void * ) jpilot_get_read_flag;
184         iface->getStatusCode = ( void * ) jpilot_get_status;
185         iface->getReadData   = ( void * ) jpilot_read_data;
186         iface->getRootFolder = ( void * ) jpilot_get_root_folder;
187         iface->getListFolder = ( void * ) jpilot_get_list_folder;
188         iface->getListPerson = ( void * ) jpilot_get_list_person;
189         iface->getAllPersons = ( void * ) jpilot_get_all_persons;
190         iface->getName       = ( void * ) jpilot_get_name;
191         iface->setAccessFlag = ( void * ) jpilot_set_accessed;
192 #else
193         iface->useInterface = FALSE;
194         iface->haveLibrary = FALSE;
195 #endif
196         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
197         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
198
199         iface = addrindex_create_interface( ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
200 #ifdef USE_LDAP
201         iface->haveLibrary = syldap_test_ldap_lib();
202         iface->useInterface = iface->haveLibrary;
203         iface->getAccessFlag = ( void * ) syldap_get_accessed;
204         // iface->getModifyFlag = ( void * ) syldap_get_modified;
205         // iface->getReadFlag   = ( void * ) syldap_get_read_flag;
206         iface->getStatusCode = ( void * ) syldap_get_status;
207         iface->getReadData   = ( void * ) syldap_read_data;
208         iface->getRootFolder = ( void * ) syldap_get_root_folder;
209         iface->getListFolder = ( void * ) syldap_get_list_folder;
210         iface->getListPerson = ( void * ) syldap_get_list_person;
211         iface->getName       = ( void * ) syldap_get_name;
212         iface->setAccessFlag = ( void * ) syldap_set_accessed;
213 #else
214         iface->useInterface = FALSE;
215         iface->haveLibrary = FALSE;
216 #endif
217         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
218         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
219
220         // Two old legacy data sources
221         iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - common", TAG_IF_OLD_COMMON, NULL );
222         iface->legacyFlag = TRUE;
223         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
224         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
225
226         iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - personal", TAG_IF_OLD_PERSONAL, NULL );
227         iface->legacyFlag = TRUE;
228         addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
229         ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
230
231 }
232
233 /*
234 * Free name-value pairs.
235 */
236 static void addrindex_free_attributes( GList *list ) {
237         GList *node = list;
238         while( node ) {
239                 AddressIfAttrib *nv = node->data;
240                 g_free( nv->name ); nv->name = NULL;
241                 g_free( nv->value ); nv->value = NULL;
242                 g_free( nv );
243                 node->data = NULL;
244                 node = g_list_next( node );
245         }
246         g_list_free( list );
247 }
248
249 /*
250 * Free up data source.
251 */
252 void addrindex_free_datasource( AddressIndex *addrIndex, AddressDataSource *ds ) {
253         AddressInterface *iface = NULL;
254         g_return_if_fail( addrIndex != NULL );
255         g_return_if_fail( ds != NULL );
256
257         if( ds->interface == NULL ) {
258                 iface = addrindex_get_interface( addrIndex, ds->type );
259         }
260         if( iface == NULL ) return;
261
262         if( iface->useInterface ) {
263                 if( iface->type == ADDR_IF_BOOK ) {
264                         AddressBookFile *abf = ds->rawDataSource;
265                         if( abf ) {
266                                 addrbook_free_book( abf );
267                         }
268                 }
269                 else if( iface->type == ADDR_IF_VCARD ) {
270                         VCardFile *vcf = ds->rawDataSource;
271                         if( vcf ) {
272                                 vcard_free( vcf );
273                         }
274                 }
275 #ifdef USE_JPILOT
276                 else if( iface->type == ADDR_IF_JPILOT ) {
277                         JPilotFile *jpf = ds->rawDataSource;
278                         if( jpf ) {
279                                 jpilot_free( jpf );
280                         }
281                 }
282 #endif
283 #ifdef USE_LDAP
284                 else if( iface->type == ADDR_IF_LDAP ) {
285                         SyldapServer *server = ds->rawDataSource;
286                         if( server ) {
287                                 syldap_free( server );
288                         }
289                 }
290 #endif
291         }
292         else {
293                 GList *list = ds->rawDataSource;
294                 addrindex_free_attributes( list );
295         }
296
297         g_free( ADDRITEM_ID(addrIndex) );
298         g_free( ADDRITEM_NAME(addrIndex) );
299
300         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
301         ADDRITEM_ID(addrIndex) = NULL;
302         ADDRITEM_NAME(addrIndex) = NULL;
303         ADDRITEM_PARENT(addrIndex) = NULL;
304         ADDRITEM_SUBTYPE(addrIndex) = 0;
305         ds->type = ADDR_IF_NONE;
306         ds->rawDataSource = NULL;
307         ds->interface = NULL;
308
309         ds->type = ADDR_IF_NONE;
310         ds->rawDataSource = NULL;
311         ds->interface = NULL;
312         g_free( ds );
313 }
314
315 static void addrindex_free_all_datasources( AddressInterface *iface ) {
316         GList *node = iface->listSource;
317         while( node ) {
318                 AddressDataSource *ds = node->data;
319                 if( iface->useInterface ) {
320                         if( iface->type == ADDR_IF_BOOK ) {
321                                 AddressBookFile *abf = ds->rawDataSource;
322                                 if( abf ) {
323                                         addrbook_free_book( abf );
324                                 }
325                         }
326                         else if( iface->type == ADDR_IF_VCARD ) {
327                                 VCardFile *vcf = ds->rawDataSource;
328                                 if( vcf ) {
329                                         vcard_free( vcf );
330                                 }
331                         }
332 #ifdef USE_JPILOT
333                         else if( iface->type == ADDR_IF_JPILOT ) {
334                                 JPilotFile *jpf = ds->rawDataSource;
335                                 if( jpf ) {
336                                         jpilot_free( jpf );
337                                 }
338                         }
339 #endif
340 #ifdef USE_LDAP
341                         else if( iface->type == ADDR_IF_LDAP ) {
342                                 SyldapServer *server = ds->rawDataSource;
343                                 if( server ) {
344                                         syldap_free( server );
345                                 }
346                         }
347 #endif
348                 }
349                 else {
350                         GList *list = ds->rawDataSource;
351                         addrindex_free_attributes( list );
352                 }
353
354                 ds->type = ADDR_IF_NONE;
355                 ds->rawDataSource = NULL;
356                 ds->interface = NULL;
357                 g_free( ds );
358                 node->data = NULL;
359                 node = g_list_next( node );
360         }
361 }
362
363 static void addrindex_free_interface( AddressInterface *iface ) {
364         addrindex_free_all_datasources( iface );
365
366         g_free( ADDRITEM_ID(iface) );
367         g_free( ADDRITEM_NAME(iface) );
368         g_free( iface->name );
369         g_free( iface->listTag );
370         g_free( iface->itemTag );
371
372         ADDRITEM_TYPE(iface) = ITEMTYPE_NONE;
373         ADDRITEM_ID(iface) = NULL;
374         ADDRITEM_NAME(iface) = NULL;
375         ADDRITEM_PARENT(iface) = NULL;
376         ADDRITEM_SUBTYPE(iface) = 0;
377         iface->type = ADDR_IF_NONE;
378         iface->name = NULL;
379         iface->listTag = NULL;
380         iface->itemTag = NULL;
381         iface->legacyFlag = FALSE;
382         iface->useInterface = FALSE;
383         iface->haveLibrary = FALSE;
384
385         g_list_free( iface->listSource );
386         iface->listSource = NULL;
387 }
388
389 /*
390 * Create new object.
391 */
392 AddressIndex *addrindex_create_index() {
393         AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
394
395         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_INDEX;
396         ADDRITEM_ID(addrIndex) = NULL;
397         ADDRITEM_NAME(addrIndex) = g_strdup( "Address Index" );
398         ADDRITEM_PARENT(addrIndex) = NULL;
399         ADDRITEM_SUBTYPE(addrIndex) = 0;
400         addrIndex->filePath = NULL;
401         addrIndex->fileName = NULL;
402         addrIndex->retVal = MGU_SUCCESS;
403         addrIndex->needsConversion = FALSE;
404         addrIndex->wasConverted = FALSE;
405         addrIndex->conversionError = FALSE;
406         addrIndex->interfaceList = NULL;
407         addrIndex->lastType = ADDR_IF_NONE;
408         addrIndex->dirtyFlag = FALSE;
409         addrindex_build_if_list( addrIndex );
410         return addrIndex;
411 }
412
413 /*
414 * Specify file to be used.
415 */
416 void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) {
417         g_return_if_fail( addrIndex != NULL );
418         addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value );
419 }
420 void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) {
421         g_return_if_fail( addrIndex != NULL );
422         addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value );
423 }
424 void addrindex_set_dirty( AddressIndex *addrIndex, const gboolean value ) {
425         g_return_if_fail( addrIndex != NULL );
426         addrIndex->dirtyFlag = value;
427 }
428
429 /*
430 * Return list of interfaces.
431 */
432 GList *addrindex_get_interface_list( AddressIndex *addrIndex ) {
433         g_return_val_if_fail( addrIndex != NULL, NULL );
434         return addrIndex->interfaceList;
435 }
436
437 /*
438 * Free up object.
439 */
440 void addrindex_free_index( AddressIndex *addrIndex ) {
441         GList *node;
442
443         g_return_if_fail( addrIndex != NULL );
444
445         g_free( ADDRITEM_ID(addrIndex) );
446         g_free( ADDRITEM_NAME(addrIndex) );
447         g_free( addrIndex->filePath );
448         g_free( addrIndex->fileName );
449         ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
450         ADDRITEM_ID(addrIndex) = NULL;
451         ADDRITEM_NAME(addrIndex) = NULL;
452         ADDRITEM_PARENT(addrIndex) = NULL;
453         ADDRITEM_SUBTYPE(addrIndex) = 0;
454         addrIndex->filePath = NULL;
455         addrIndex->fileName = NULL;
456         addrIndex->retVal = MGU_SUCCESS;
457         addrIndex->needsConversion = FALSE;
458         addrIndex->wasConverted = FALSE;
459         addrIndex->conversionError = FALSE;
460         addrIndex->lastType = ADDR_IF_NONE;
461         addrIndex->dirtyFlag = FALSE;
462         node = addrIndex->interfaceList;
463         while( node ) {
464                 AddressInterface *iface = node->data;
465                 addrindex_free_interface( iface );
466                 node = g_list_next( node );
467         }
468         g_list_free( addrIndex->interfaceList );
469         addrIndex->interfaceList = NULL;
470         g_free( addrIndex );
471 }
472
473 /*
474 * Print address index.
475 */
476 void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
477         g_return_if_fail( addrIndex != NULL );
478         fprintf( stream, "AddressIndex:\n" );
479         fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath );
480         fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName );
481         fprintf( stream, "\t   status: %d : '%s'\n", addrIndex->retVal, mgu_error2string( addrIndex->retVal ) );
482         fprintf( stream, "\tconverted: '%s'\n", addrIndex->wasConverted ? "yes" : "no" );
483         fprintf( stream, "\tcvt error: '%s'\n", addrIndex->conversionError ? "yes" : "no" );
484         fprintf( stream, "\t---\n" );
485 }
486
487 /*
488 * Retrieve specified interface from index.
489 */
490 AddressInterface *addrindex_get_interface( AddressIndex *addrIndex, AddressIfType ifType ) {
491         AddressInterface *retVal = NULL;
492         GList *node;
493
494         g_return_val_if_fail( addrIndex != NULL, NULL );
495
496         node = addrIndex->interfaceList;
497         while( node ) {
498                 AddressInterface *iface = node->data;
499                 node = g_list_next( node );
500                 if( iface->type == ifType ) {
501                         retVal = iface;
502                         break;
503                 }
504         }
505         return retVal;
506 }
507
508 AddressDataSource *addrindex_create_datasource() {
509         AddressDataSource *ds = NULL;
510         ds = g_new0( AddressDataSource, 1 );
511         ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
512         ADDRITEM_ID(ds) = NULL;
513         ADDRITEM_NAME(ds) = NULL;
514         ADDRITEM_PARENT(ds) = NULL;
515         ADDRITEM_SUBTYPE(ds) = 0;
516         ds->type = ADDR_IF_NONE;
517         ds->rawDataSource = NULL;
518         ds->interface = NULL;
519         return ds;
520 }
521
522 /*
523 * Add data source to index.
524 * Enter: addrIndex  Address index object.
525 *        ifType     Interface type to add.
526 *        dataSource Actual data source to add.
527 * Return: TRUE if data source was added.
528 * Note: The raw data object (for example, AddressBookFile or VCardFile object) should be
529 * supplied as the dataSource argument.
530 */
531 AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource ) {
532         AddressInterface *iface;
533         AddressDataSource *ds = NULL;
534
535         g_return_val_if_fail( addrIndex != NULL, NULL );
536         g_return_val_if_fail( dataSource != NULL, NULL );
537
538         iface = addrindex_get_interface( addrIndex, ifType );
539         if( iface ) {
540                 ds = addrindex_create_datasource();
541                 ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
542                 ds->type = ifType;
543                 ds->rawDataSource = dataSource;
544                 ds->interface = iface;
545                 iface->listSource = g_list_append( iface->listSource, ds );
546                 addrIndex->dirtyFlag = TRUE;
547         }
548         return ds;
549 }
550
551 /*
552 * Remove data source from index.
553 * Enter: addrIndex  Address index object.
554 *        dataSource Data source to remove.
555 * Return: Data source if removed, or NULL if data source was not found in
556 * index. Note the this object must still be freed.
557 */
558 AddressDataSource *addrindex_index_remove_datasource( AddressIndex *addrIndex, AddressDataSource *dataSource ) {
559         AddressDataSource *retVal = FALSE;
560         AddressInterface *iface;
561
562         g_return_val_if_fail( addrIndex != NULL, NULL );
563         g_return_val_if_fail( dataSource != NULL, NULL );
564
565         iface = addrindex_get_interface( addrIndex, dataSource->type );
566         if( iface ) {
567                 iface->listSource = g_list_remove( iface->listSource, dataSource );
568                 addrIndex->dirtyFlag = TRUE;
569                 dataSource->interface = NULL;
570                 retVal = dataSource;
571         }
572         return retVal;
573 }
574
575 static AddressInterface *addrindex_tag_get_interface( AddressIndex *addrIndex, gchar *tag, AddressIfType ifType ) {
576         AddressInterface *retVal = NULL;
577         GList *node = addrIndex->interfaceList;
578
579         while( node ) {
580                 AddressInterface *iface = node->data;
581                 node = g_list_next( node );
582                 if( tag ) {
583                         if( strcmp( iface->listTag, tag ) == 0 ) {
584                                 retVal = iface;
585                                 break;
586                         }
587                 }
588                 else {
589                         if( iface->type == ifType ) {
590                                 retVal = iface;
591                                 break;
592                         }
593                 }
594         }
595         return retVal;
596 }
597
598 static AddressInterface *addrindex_tag_get_datasource( AddressIndex *addrIndex, AddressIfType ifType, gchar *tag ) {
599         AddressInterface *retVal = NULL;
600         GList *node = addrIndex->interfaceList;
601
602         while( node ) {
603                 AddressInterface *iface = node->data;
604                 node = g_list_next( node );
605                 if( iface->type == ifType && iface->itemTag ) {
606                         if( strcmp( iface->itemTag, tag ) == 0 ) {
607                                 retVal = iface;
608                                 break;
609                         }
610                 }
611         }
612         return retVal;
613 }
614
615 /* **********************************************************************
616 * Interface XML parsing functions.
617 * ***********************************************************************
618 */
619 static void show_attribs( GList *attr ) {
620         while( attr ) {
621                 gchar *name = ((XMLAttr *)attr->data)->name;
622                 gchar *value = ((XMLAttr *)attr->data)->value;
623                 printf( "\tattr value : %s :%s:\n", name, value );
624                 attr = g_list_next( attr );
625         }
626         printf( "\t---\n" );
627 }
628
629 static void addrindex_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
630         gint i;
631         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
632         fputs( "<", fp );
633         fputs( name, fp );
634 }
635
636 static void addrindex_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
637         gint i;
638         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
639         fputs( "</", fp );
640         fputs( name, fp );
641         fputs( ">\n", fp );
642 }
643
644 static void addrindex_write_attr( FILE *fp, gchar *name, gchar *value ) {
645         fputs( " ", fp );
646         fputs( name, fp );
647         fputs( "=\"", fp );
648         xml_file_put_escape_str( fp, value );
649         fputs( "\"", fp );
650 }
651
652 /*
653 * Return list of name-value pairs.
654 */
655 static GList *addrindex_read_attributes( XMLFile *file ) {
656         GList *list = NULL;
657         AddressIfAttrib *nv;
658         GList *attr;
659         gchar *name;
660         gchar *value;
661
662         attr = xml_get_current_tag_attr( file );
663         while( attr ) {
664                 name = ((XMLAttr *)attr->data)->name;
665                 value = ((XMLAttr *)attr->data)->value;
666                 nv = g_new0( AddressIfAttrib, 1 );
667                 nv->name = g_strdup( name );
668                 nv->value = g_strdup( value );
669                 list = g_list_append( list, nv );
670                 attr = g_list_next( attr );
671         }
672         return list;
673 }
674
675 /*
676 * Output name-value pairs.
677 */
678 static void addrindex_write_attributes( FILE *fp, gchar *tag, GList *list, gint lvl ) {
679         GList *node;
680         AddressIfAttrib *nv;
681         if( list ) {
682                 addrindex_write_elem_s( fp, lvl, tag );
683                 node = list;
684                 while( node ) {
685                         nv = node->data;
686                         addrindex_write_attr( fp, nv->name, nv->value );
687                         node = g_list_next( node );
688                 }
689                 fputs(" />\n", fp);
690         }
691 }
692
693 static void addrindex_print_attributes( GList *list, FILE *stream ) {
694         GList *node = list;
695         while( node ) {
696                 AddressIfAttrib *nv = node->data;
697                 fprintf( stream, "%s : %s\n", nv->name, nv->value );
698                 node = g_list_next( node );
699         }
700 }
701
702 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
703         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
704         AddressBookFile *abf;
705         GList *attr;
706
707         abf = addrbook_create_book();
708         attr = xml_get_current_tag_attr( file );
709         while( attr ) {
710                 gchar *name = ((XMLAttr *)attr->data)->name;
711                 gchar *value = ((XMLAttr *)attr->data)->value;
712                 if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) {
713                         addrbook_set_name( abf, value );
714                 }
715                 else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) {
716                         addrbook_set_file( abf, value );
717                 }
718                 attr = g_list_next( attr );
719         }
720         ds->rawDataSource = abf;
721         return ds;
722 }
723
724 static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
725         AddressBookFile *abf = ds->rawDataSource;
726         if( abf ) {
727                 addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK );
728                 addrindex_write_attr( fp, ATTAG_BOOK_NAME, abf->name );
729                 addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName );
730                 fputs( " />\n", fp );
731         }
732 }
733
734 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
735         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
736         VCardFile *vcf;
737         GList *attr;
738
739         vcf = vcard_create();
740         attr = xml_get_current_tag_attr( file );
741         while( attr ) {
742                 gchar *name = ((XMLAttr *)attr->data)->name;
743                 gchar *value = ((XMLAttr *)attr->data)->value;
744                 if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) {
745                         vcard_set_name( vcf, value );
746                 }
747                 else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) {
748                         vcard_set_file( vcf, value );
749                 }
750                 attr = g_list_next( attr );
751         }
752         ds->rawDataSource = vcf;
753         return ds;
754 }
755
756 static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
757         VCardFile *vcf = ds->rawDataSource;
758         if( vcf ) {
759                 addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD );
760                 addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcf->name );
761                 addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path );
762                 fputs( " />\n", fp );
763         }
764 }
765
766 #ifdef USE_JPILOT
767 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
768         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
769         JPilotFile *jpf;
770         GList *attr;
771
772         jpf = jpilot_create();
773         attr = xml_get_current_tag_attr( file );
774         while( attr ) {
775                 gchar *name = ((XMLAttr *)attr->data)->name;
776                 gchar *value = ((XMLAttr *)attr->data)->value;
777                 if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) {
778                         jpilot_set_name( jpf, value );
779                 }
780                 else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) {
781                         jpilot_set_file( jpf, value );
782                 }
783                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) {
784                         jpilot_add_custom_label( jpf, value );
785                 }
786                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) {
787                         jpilot_add_custom_label( jpf, value );
788                 }
789                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) {
790                         jpilot_add_custom_label( jpf, value );
791                 }
792                 else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) {
793                         jpilot_add_custom_label( jpf, value );
794                 }
795                 attr = g_list_next( attr );
796         }
797         ds->rawDataSource = jpf;
798         return ds;
799 }
800
801 static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
802         JPilotFile *jpf = ds->rawDataSource;
803         if( jpf ) {
804                 gint ind;
805                 GList *node;
806                 GList *customLbl = jpilot_get_custom_labels( jpf );
807                 addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT );
808                 addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpf->name );
809                 addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path );
810                 node = customLbl;
811                 ind = 1;
812                 while( node ) {
813                         gchar name[256];
814                         sprintf( name, "%s%d", ATTAG_JPILOT_CUSTOM, ind );
815                         addrindex_write_attr( fp, name, node->data );
816                         ind++;
817                         node = g_list_next( node );
818                 }
819                 fputs( " />\n", fp );
820         }
821 }
822 #else
823 // Just read/write name-value pairs
824 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
825         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
826         GList *list = addrindex_read_attributes( file );
827         ds->rawDataSource = list;
828         return ds;
829 }
830
831 static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) {
832         GList *list = ds->rawDataSource;
833         if( list ) {
834                 addrindex_write_attributes( fp, TAG_DS_JPILOT, list, lvl );
835         }
836 }
837 #endif
838
839 #ifdef USE_LDAP
840 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
841         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
842         SyldapServer *server;
843         GList *attr;
844
845         server = syldap_create();
846         attr = xml_get_current_tag_attr( file );
847         while( attr ) {
848                 gchar *name = ((XMLAttr *)attr->data)->name;
849                 gchar *value = ((XMLAttr *)attr->data)->value;
850                 gint ivalue = atoi( value );
851                 if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) {
852                         syldap_set_name( server, value );
853                 }
854                 else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) {
855                         syldap_set_host( server, value );
856                 }
857                 else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) {
858                         syldap_set_port( server, ivalue );
859                 }
860                 else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) {
861                         syldap_set_base_dn( server, value );
862                 }
863                 else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) {
864                         syldap_set_bind_dn( server, value );
865                 }
866                 else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) {
867                         syldap_set_bind_password( server, value );
868                 }
869                 else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) {
870                         syldap_set_search_criteria( server, value );
871                 }
872                 else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) {
873                         syldap_set_max_entries( server, ivalue );
874                 }
875                 else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) {
876                         syldap_set_timeout( server, ivalue );
877                 }
878                 attr = g_list_next( attr );
879         }
880
881         ds->rawDataSource = server;
882         return ds;
883 }
884
885 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
886         SyldapServer *server = ds->rawDataSource;
887         if( server ) {
888                 gchar value[256];
889
890                 addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
891                 addrindex_write_attr( fp, ATTAG_LDAP_NAME, server->name );
892                 addrindex_write_attr( fp, ATTAG_LDAP_HOST, server->hostName );
893
894                 sprintf( value, "%d", server->port );   
895                 addrindex_write_attr( fp, ATTAG_LDAP_PORT, value );
896
897                 addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, server->baseDN );
898                 addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, server->bindDN );
899                 addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, server->bindPass );
900                 addrindex_write_attr( fp, ATTAG_LDAP_CRITERIA, server->searchCriteria );
901
902                 sprintf( value, "%d", server->maxEntries );
903                 addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value );
904                 sprintf( value, "%d", server->timeOut );
905                 addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value );
906
907                 fputs(" />\n", fp);
908         }
909 }
910 #else
911 // Just read/write name-value pairs
912 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
913         AddressDataSource *ds = g_new0( AddressDataSource, 1 );
914         GList *list = addrindex_read_attributes( file );
915         ds->rawDataSource = list;
916         return ds;
917 }
918
919 static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
920         GList *list = ds->rawDataSource;
921         if( list ) {
922                 addrindex_write_attributes( fp, TAG_DS_LDAP, list, lvl );
923         }
924 }
925 #endif
926
927 /* **********************************************************************
928 * Address index I/O functions.
929 * ***********************************************************************
930 */
931 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
932         guint prev_level;
933         //gchar *element;
934         //GList *attr;
935         XMLTag *xtag;
936         AddressInterface *iface = NULL, *dsIFace = NULL;
937         AddressDataSource *ds;
938
939         for (;;) {
940                 prev_level = file->level;
941                 xml_parse_next_tag( file );
942                 if( file->level < prev_level ) return;
943
944                 xtag = xml_get_current_tag( file );
945                 // printf( "tag : %s\n", xtag->tag );
946
947                 iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
948                 if( iface ) {
949                         addrIndex->lastType = iface->type;
950                         if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
951                         // printf( "found : %s\n", iface->name );
952                 }
953                 else {
954                         dsIFace = addrindex_tag_get_datasource( addrIndex, addrIndex->lastType, xtag->tag );
955                         if( dsIFace ) {
956                                 // Add data source to list
957                                 // printf( "\tdata source: %s\n", dsIFace->name );
958                                 ds = NULL;
959                                 if( addrIndex->lastType == ADDR_IF_BOOK ) {
960                                         ds = addrindex_parse_book( file );
961                                         if( ds->rawDataSource ) {
962                                                 addrbook_set_path( ds->rawDataSource, addrIndex->filePath );
963                                                 // addrbook_print_book( ds->rawDataSource, stdout );
964                                         }
965                                 }
966                                 else if( addrIndex->lastType == ADDR_IF_VCARD ) {
967                                         ds = addrindex_parse_vcard( file );
968                                         // if( ds->rawDataSource ) {
969                                         //      vcard_print_file( ds->rawDataSource, stdout );
970                                         // }
971                                 }
972                                 else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
973                                         ds = addrindex_parse_jpilot( file );
974                                         /*
975                                         if( ds->rawDataSource ) {
976                                                 jpilot_print_file( ds->rawDataSource, stdout );
977                                                 // addrindex_print_attributes( ds->rawDataSource, stdout );
978                                         }
979                                         */
980                                 }
981                                 else if( addrIndex->lastType == ADDR_IF_LDAP ) {
982                                         ds = addrindex_parse_ldap( file );
983                                         /*
984                                         if( ds->rawDataSource ) {
985                                                 syldap_print_data( ds->rawDataSource, stdout );
986                                                 // addrindex_print_attributes( ds->rawDataSource, stdout );
987                                         }
988                                         */
989                                 }
990                                 if( ds ) {
991                                         ds->type = addrIndex->lastType;
992                                         ds->interface = dsIFace;
993                                         dsIFace->listSource = g_list_append( dsIFace->listSource, ds );
994                                 }
995                                 // printf( "=============================\n\n" );
996                         }
997                 }
998                 /*
999                 element = xml_get_element( file );
1000                 attr = xml_get_current_tag_attr( file );
1001                 if( _interfaceLast_ && ! _interfaceLast_->legacyFlag ) {
1002                         show_attribs( attr );
1003                         printf( "\ttag  value : %s :\n", element );
1004                 }
1005                 */
1006                 addrindex_read_index( addrIndex, file );
1007         }
1008 }
1009
1010 static gint addrindex_read_file( AddressIndex *addrIndex ) {
1011         XMLFile *file = NULL;
1012         gchar *fileSpec = NULL;
1013
1014         g_return_val_if_fail( addrIndex != NULL, -1 );
1015
1016         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1017         addrIndex->retVal = MGU_NO_FILE;
1018         file = xml_open_file( fileSpec );
1019         g_free( fileSpec );
1020
1021         if( file == NULL ) {
1022                 // fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
1023                 return addrIndex->retVal;
1024         }
1025
1026         addrIndex->retVal = MGU_BAD_FORMAT;
1027         if( xml_get_dtd( file ) == 0 ) {
1028                 if( xml_parse_next_tag( file ) == 0 ) {
1029                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1030                                 addrindex_read_index( addrIndex, file );
1031                                 addrIndex->retVal = MGU_SUCCESS;
1032                         }
1033                 }
1034         }
1035         xml_close_file( file );
1036
1037         return addrIndex->retVal;
1038 }
1039
1040 static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) {
1041         GList *nodeIF, *nodeDS;
1042         gint lvlList = 1;
1043         gint lvlItem = 1 + lvlList;
1044
1045         nodeIF = addrIndex->interfaceList;
1046         while( nodeIF ) {
1047                 AddressInterface *iface = nodeIF->data;
1048                 if( ! iface->legacyFlag ) {
1049                         nodeDS = iface->listSource;
1050                         addrindex_write_elem_s( fp, lvlList, iface->listTag );
1051                         fputs( ">\n", fp );
1052                         while( nodeDS ) {
1053                                 AddressDataSource *ds = nodeDS->data;
1054                                 if( ds ) {
1055                                         if( iface->type == ADDR_IF_BOOK ) {
1056                                                 addrindex_write_book( fp, ds, lvlItem );
1057                                         }
1058                                         if( iface->type == ADDR_IF_VCARD ) {
1059                                                 addrindex_write_vcard( fp, ds, lvlItem );
1060                                         }
1061                                         if( iface->type == ADDR_IF_JPILOT ) {
1062                                                 addrindex_write_jpilot( fp, ds, lvlItem );
1063                                         }
1064                                         if( iface->type == ADDR_IF_LDAP ) {
1065                                                 addrindex_write_ldap( fp, ds, lvlItem );
1066                                         }
1067                                 }
1068                                 nodeDS = g_list_next( nodeDS );
1069                         }
1070                         addrindex_write_elem_e( fp, lvlList, iface->listTag );
1071                 }
1072                 nodeIF = g_list_next( nodeIF );
1073         }
1074 }
1075
1076 /*
1077 * Write data to specified file.
1078 * Enter: addrIndex Address index object.
1079 *        newFile   New file name.
1080 * return: Status code, from addrIndex->retVal.
1081 * Note: File will be created in directory specified by addrIndex.
1082 */
1083 gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) {
1084         FILE *fp;
1085         gchar *fileSpec;
1086 #ifndef DEV_STANDALONE
1087         PrefFile *pfile;
1088 #endif
1089
1090         g_return_val_if_fail( addrIndex != NULL, -1 );
1091
1092         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL );
1093         addrIndex->retVal = MGU_OPEN_FILE;
1094 #ifdef DEV_STANDALONE
1095         fp = fopen( fileSpec, "w" );
1096         g_free( fileSpec );
1097         if( fp ) {
1098                 fputs( "<?xml version=\"1.0\" ?>\n", fp );
1099 #else
1100         pfile = prefs_write_open( fileSpec );
1101         g_free( fileSpec );
1102         if( pfile ) {
1103                 fp = pfile->fp;
1104                 fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
1105                                 conv_get_current_charset_str() );
1106 #endif
1107                 addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX );
1108                 fputs( ">\n", fp );
1109
1110                 addrindex_write_index( addrIndex, fp );
1111                 addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX );
1112
1113                 addrIndex->retVal = MGU_SUCCESS;
1114 #ifdef DEV_STANDALONE
1115                 fclose( fp );
1116 #else
1117                 if( prefs_write_close( pfile ) < 0 ) {
1118                         addrIndex->retVal = MGU_ERROR_WRITE;
1119                 }
1120 #endif
1121         }
1122
1123         fileSpec = NULL;
1124         return addrIndex->retVal;
1125 }
1126
1127 /*
1128 * Save address index data to original file.
1129 * return: Status code, from addrIndex->retVal.
1130 */
1131 gint addrindex_save_data( AddressIndex *addrIndex ) {
1132         g_return_val_if_fail( addrIndex != NULL, -1 );
1133
1134         addrIndex->retVal = MGU_NO_FILE;
1135         if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal;
1136         if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal;
1137
1138         addrindex_write_to( addrIndex, addrIndex->fileName );
1139         if( addrIndex->retVal == MGU_SUCCESS ) {
1140                 addrIndex->dirtyFlag = FALSE;
1141         }
1142         return addrIndex->retVal;
1143 }
1144
1145 /*
1146 * Save all address book files which may have changed.
1147 * Return: Status code, set if there was a problem saving data.
1148 */
1149 gint addrindex_save_all_books( AddressIndex *addrIndex ) {
1150         gint retVal = MGU_SUCCESS;
1151         GList *nodeIf, *nodeDS;
1152
1153         nodeIf = addrIndex->interfaceList;
1154         while( nodeIf ) {
1155                 AddressInterface *iface = nodeIf->data;
1156                 if( iface->type == ADDR_IF_BOOK ) {
1157                         nodeDS = iface->listSource;
1158                         while( nodeDS ) {
1159                                 AddressDataSource *ds = nodeDS->data;
1160                                 AddressBookFile *abf = ds->rawDataSource;
1161                                 if( abf->dirtyFlag ) {
1162                                         if( abf->readFlag ) {
1163                                                 addrbook_save_data( abf );
1164                                                 if( abf->retVal != MGU_SUCCESS ) {
1165                                                         retVal = abf->retVal;
1166                                                 }
1167                                         }
1168                                 }
1169                                 nodeDS = g_list_next( nodeDS );
1170                         }
1171                         break;
1172                 }
1173                 nodeIf = g_list_next( nodeIf );
1174         }
1175         return retVal;
1176 }
1177
1178
1179 /* **********************************************************************
1180 * Address book conversion to new format.
1181 * ***********************************************************************
1182 */
1183
1184 #define ELTAG_IF_OLD_FOLDER   "folder"
1185 #define ELTAG_IF_OLD_GROUP    "group"
1186 #define ELTAG_IF_OLD_ITEM     "item"
1187 #define ELTAG_IF_OLD_NAME     "name"
1188 #define ELTAG_IF_OLD_ADDRESS  "address"
1189 #define ELTAG_IF_OLD_REMARKS  "remarks"
1190 #define ATTAG_IF_OLD_NAME     "name"
1191
1192 #define TEMPNODE_ROOT         0
1193 #define TEMPNODE_FOLDER       1
1194 #define TEMPNODE_GROUP        2
1195 #define TEMPNODE_ADDRESS      3
1196
1197 typedef struct _AddressCvt_Node AddressCvtNode;
1198 struct _AddressCvt_Node {
1199         gint  type;
1200         gchar *name;
1201         gchar *address;
1202         gchar *remarks;
1203         GList *list;
1204 };
1205
1206 /*
1207 * Parse current address item.
1208 */
1209 static AddressCvtNode *addrindex_parse_item( XMLFile *file ) {
1210         gchar *element;
1211         guint level;
1212         AddressCvtNode *nn;
1213
1214         nn = g_new0( AddressCvtNode, 1 );
1215         nn->type = TEMPNODE_ADDRESS;
1216         nn->list = NULL;
1217
1218         level = file->level;
1219
1220         for (;;) {
1221                 xml_parse_next_tag(file);
1222                 if (file->level < level) return nn;
1223
1224                 element = xml_get_element( file );
1225                 if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) {
1226                         nn->name = g_strdup( element );
1227                 }
1228                 if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) {
1229                         nn->address = g_strdup( element );
1230                 }
1231                 if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) {
1232                         nn->remarks = g_strdup( element );
1233                 }
1234                 xml_parse_next_tag(file);
1235         }
1236 }
1237
1238 /*
1239 * Create a temporary node below specified node.
1240 */
1241 static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) {
1242         AddressCvtNode *nn;
1243         nn = g_new0( AddressCvtNode, 1 );
1244         nn->type = type;
1245         nn->name = g_strdup( name );
1246         nn->remarks = g_strdup( rem );
1247         node->list = g_list_append( node->list, nn );
1248         return nn;
1249 }
1250
1251 /*
1252 * Process current temporary node.
1253 */
1254 static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) {
1255         GList *attr;
1256         guint prev_level;
1257         AddressCvtNode *newNode = NULL;
1258         gchar *name;
1259         gchar *value;
1260
1261         for (;;) {
1262                 prev_level = file->level;
1263                 xml_parse_next_tag( file );
1264                 if (file->level < prev_level) return;
1265                 name = NULL;
1266                 value = NULL;
1267
1268                 if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) {
1269                         attr = xml_get_current_tag_attr(file);
1270                         if (attr) {
1271                                 name = ((XMLAttr *)attr->data)->name;
1272                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1273                                         value = ((XMLAttr *)attr->data)->value;
1274                                 }
1275                         }
1276                         newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" );
1277                         addrindex_add_obj( file, newNode );
1278
1279                 }
1280                 else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) {
1281                         attr = xml_get_current_tag_attr(file);
1282                         if (attr) {
1283                                 name = ((XMLAttr *)attr->data)->name;
1284                                 if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) {
1285                                         value = ((XMLAttr *)attr->data)->value;
1286                                 }
1287                         }
1288                         newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" );
1289                         addrindex_add_obj( file, newNode );
1290                 }
1291                 else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) {
1292                         newNode = addrindex_parse_item( file );
1293                         node->list = g_list_append( node->list, newNode );
1294                 }
1295                 else {
1296                         // printf( "invalid: !!! \n" );
1297                         attr = xml_get_current_tag_attr( file );
1298                 }
1299         }
1300 }
1301
1302 /*
1303 * Consume all nodes below current tag.
1304 */
1305 static void addrindex_consume_tree( XMLFile *file ) {
1306         guint prev_level;
1307         gchar *element;
1308         GList *attr;
1309         XMLTag *xtag;
1310
1311         for (;;) {
1312                 prev_level = file->level;
1313                 xml_parse_next_tag( file );
1314                 if (file->level < prev_level) return;
1315
1316                 xtag = xml_get_current_tag( file );
1317                 // printf( "tag : %s\n", xtag->tag );
1318                 element = xml_get_element( file );
1319                 attr = xml_get_current_tag_attr( file );
1320                 // show_attribs( attr );
1321                 // printf( "\ttag  value : %s :\n", element );
1322                 addrindex_consume_tree( file );
1323         }
1324 }
1325
1326 /*
1327 * Print temporary tree.
1328 */
1329 static void addrindex_print_node( AddressCvtNode *node, FILE *stream  ) {
1330         GList *list;
1331
1332         fprintf( stream, "Node:\ttype :%d:\n", node->type );
1333         fprintf( stream, "\tname :%s:\n", node->name );
1334         fprintf( stream, "\taddr :%s:\n", node->address );
1335         fprintf( stream, "\trems :%s:\n", node->remarks );
1336         if( node->list ) {
1337                 fprintf( stream, "\t--list----\n" );
1338         }
1339         list = node->list;
1340         while( list ) {
1341                 AddressCvtNode *lNode = list->data;
1342                 list = g_list_next( list );
1343                 addrindex_print_node( lNode, stream );
1344         }
1345         fprintf( stream, "\t==list-%d==\n", node->type );
1346 }
1347
1348 /*
1349 * Free up temporary tree.
1350 */
1351 static void addrindex_free_node( AddressCvtNode *node ) {
1352         GList *list = node->list;
1353
1354         while( list ) {
1355                 AddressCvtNode *lNode = list->data;
1356                 list = g_list_next( list );
1357                 addrindex_free_node( lNode );
1358         }
1359         node->type = TEMPNODE_ROOT;
1360         g_free( node->name );
1361         g_free( node->address );
1362         g_free( node->remarks );
1363         g_list_free( node->list );
1364         g_free( node );
1365 }
1366
1367 /*
1368 * Process address book for specified node.
1369 */
1370 static void addrindex_process_node(
1371                 AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent,
1372                 ItemGroup *parentGrp, ItemFolder *folderGrp )
1373 {
1374         GList *list;
1375         ItemFolder *itemFolder = NULL;
1376         ItemGroup *itemGParent = parentGrp;
1377         ItemFolder *itemGFolder = folderGrp;
1378         AddressCache *cache = abf->addressCache;
1379
1380         if( node->type == TEMPNODE_ROOT ) {
1381                 itemFolder = parent;
1382         }
1383         else if( node->type == TEMPNODE_FOLDER ) {
1384                 itemFolder = addritem_create_item_folder();
1385                 addritem_folder_set_name( itemFolder, node->name );
1386                 addrcache_id_folder( cache, itemFolder );
1387                 addrcache_folder_add_folder( cache, parent, itemFolder );
1388                 itemGFolder = NULL;
1389         }
1390         else if( node->type == TEMPNODE_GROUP ) {
1391                 ItemGroup *itemGroup;
1392                 gchar *fName;
1393
1394                 // Create a folder for group
1395                 fName = g_strdup_printf( "Cvt - %s", node->name );
1396                 itemGFolder = addritem_create_item_folder();
1397                 addritem_folder_set_name( itemGFolder, fName );
1398                 addrcache_id_folder( cache, itemGFolder );
1399                 addrcache_folder_add_folder( cache, parent, itemGFolder );
1400                 g_free( fName );
1401
1402                 // Add group into folder
1403                 itemGroup = addritem_create_item_group();
1404                 addritem_group_set_name( itemGroup, node->name );
1405                 addrcache_id_group( cache, itemGroup );
1406                 addrcache_folder_add_group( cache, itemGFolder, itemGroup );
1407                 itemGParent = itemGroup;
1408         }
1409         else if( node->type == TEMPNODE_ADDRESS ) {
1410                 ItemPerson *itemPerson;
1411                 ItemEMail *itemEMail;
1412
1413                 // Create person and email objects
1414                 itemPerson = addritem_create_item_person();
1415                 addritem_person_set_common_name( itemPerson, node->name );
1416                 addrcache_id_person( cache, itemPerson );
1417                 itemEMail = addritem_create_item_email();
1418                 addritem_email_set_address( itemEMail, node->address );
1419                 addritem_email_set_remarks( itemEMail, node->remarks );
1420                 addrcache_id_email( cache, itemEMail );
1421                 addrcache_person_add_email( cache, itemPerson, itemEMail );
1422
1423                 // Add person into appropriate folder
1424                 if( itemGFolder ) {
1425                         addrcache_folder_add_person( cache, itemGFolder, itemPerson );
1426                 }
1427                 else {
1428                         addrcache_folder_add_person( cache, parent, itemPerson );
1429                 }
1430
1431                 // Add email address only into group
1432                 if( parentGrp ) {
1433                         addrcache_group_add_email( cache, parentGrp, itemEMail );
1434                 }
1435         }
1436
1437         list = node->list;
1438         while( list ) {
1439                 AddressCvtNode *lNode = list->data;
1440                 list = g_list_next( list );
1441                 addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder );
1442         }
1443 }
1444
1445 /*
1446 * Process address book to specified file number.
1447 */
1448 static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) {
1449         gboolean retVal = FALSE;
1450         AddressBookFile *abf = NULL;
1451         AddressCvtNode *rootNode = NULL;
1452         gchar *newFile = NULL;
1453         GList *fileList = NULL;
1454         gint fileNum  = 0;
1455
1456         // Setup root node
1457         rootNode = g_new0( AddressCvtNode, 1 );
1458         rootNode->type = TEMPNODE_ROOT;
1459         rootNode->name = g_strdup( "root" );
1460         rootNode->list = NULL;
1461         addrindex_add_obj( file, rootNode );
1462         // addrindex_print_node( rootNode, stdout );
1463
1464         // Create new address book
1465         abf = addrbook_create_book();
1466         addrbook_set_name( abf, displayName );
1467         addrbook_set_path( abf, addrIndex->filePath );
1468
1469         // Determine next available file number
1470         fileList = addrbook_get_bookfile_list( abf );
1471         if( fileList ) {
1472                 fileNum = 1 + abf->maxValue;
1473         }
1474         g_list_free( fileList );
1475         fileList = NULL;
1476
1477         newFile = addrbook_gen_new_file_name( fileNum );
1478         if( newFile ) {
1479                 addrbook_set_file( abf, newFile );
1480         }
1481
1482         addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL );
1483
1484         // addrbook_dump_book( abf, stdout );
1485         addrbook_save_data( abf );
1486         addrIndex->retVal = abf->retVal;
1487         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
1488
1489         addrbook_free_book( abf );
1490         abf = NULL;
1491         addrindex_free_node( rootNode );
1492         rootNode = NULL;
1493
1494         // Create entries in address index
1495         if( retVal ) {
1496                 abf = addrbook_create_book();
1497                 addrbook_set_name( abf, displayName );
1498                 addrbook_set_path( abf, addrIndex->filePath );
1499                 addrbook_set_file( abf, newFile );
1500                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
1501         }
1502
1503         return retVal;
1504 }
1505
1506 /*
1507 * Process tree converting data.
1508 */
1509 static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) {
1510         guint prev_level;
1511         gchar *element;
1512         GList *attr;
1513         XMLTag *xtag;
1514
1515         // Process file
1516         for (;;) {
1517                 prev_level = file->level;
1518                 xml_parse_next_tag( file );
1519                 if (file->level < prev_level) return;
1520
1521                 xtag = xml_get_current_tag( file );
1522                 // printf( "tag : %d : %s\n", prev_level, xtag->tag );
1523                 if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) {
1524                         if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) {
1525                                 addrIndex->needsConversion = FALSE;
1526                                 addrIndex->wasConverted = TRUE;
1527                                 continue;
1528                         }
1529                         return;
1530                 }
1531                 if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) {
1532                         if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) {
1533                                 addrIndex->needsConversion = FALSE;
1534                                 addrIndex->wasConverted = TRUE;
1535                                 continue;
1536                         }
1537                         return;
1538                 }
1539                 element = xml_get_element( file );
1540                 attr = xml_get_current_tag_attr( file );
1541                 // show_attribs( attr );
1542                 // printf( "\ttag  value : %s :\n", element );
1543                 addrindex_consume_tree( file );
1544         }
1545 }
1546
1547 static gint addrindex_convert_data( AddressIndex *addrIndex ) {
1548         XMLFile *file = NULL;
1549         gchar *fileSpec;
1550
1551         fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL );
1552         addrIndex->retVal = MGU_NO_FILE;
1553         file = xml_open_file( fileSpec );
1554         g_free( fileSpec );
1555
1556         if( file == NULL ) {
1557                 // fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName );
1558                 return addrIndex->retVal;
1559         }
1560
1561         addrIndex->retVal = MGU_BAD_FORMAT;
1562         if( xml_get_dtd( file ) == 0 ) {
1563                 if( xml_parse_next_tag( file ) == 0 ) {
1564                         if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) {
1565                                 addrindex_convert_tree( addrIndex, file );
1566                         }
1567                 }
1568         }
1569         xml_close_file( file );
1570         return addrIndex->retVal;
1571 }
1572
1573 /*
1574 * Create a new address book file.
1575 */
1576 static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) {
1577         gboolean retVal = FALSE;
1578         AddressBookFile *abf = NULL;
1579         gchar *newFile = NULL;
1580         GList *fileList = NULL;
1581         gint fileNum = 0;
1582
1583         // Create new address book
1584         abf = addrbook_create_book();
1585         addrbook_set_name( abf, displayName );
1586         addrbook_set_path( abf, addrIndex->filePath );
1587
1588         // Determine next available file number
1589         fileList = addrbook_get_bookfile_list( abf );
1590         if( fileList ) {
1591                 fileNum = 1 + abf->maxValue;
1592         }
1593         g_list_free( fileList );
1594         fileList = NULL;
1595
1596         newFile = addrbook_gen_new_file_name( fileNum );
1597         if( newFile ) {
1598                 addrbook_set_file( abf, newFile );
1599         }
1600
1601         addrbook_save_data( abf );
1602         addrIndex->retVal = abf->retVal;
1603         if( abf->retVal == MGU_SUCCESS ) retVal = TRUE;
1604         addrbook_free_book( abf );
1605         abf = NULL;
1606
1607         // Create entries in address index
1608         if( retVal ) {
1609                 abf = addrbook_create_book();
1610                 addrbook_set_name( abf, displayName );
1611                 addrbook_set_path( abf, addrIndex->filePath );
1612                 addrbook_set_file( abf, newFile );
1613                 addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf );
1614         }
1615
1616         return retVal;
1617 }
1618
1619 /*
1620 * Read data for address index performing a conversion if necesary.
1621 * Enter: addrIndex Address index object.
1622 * return: Status code, from addrIndex->retVal.
1623 * Note: New address book files will be created in directory specified by
1624 * addrIndex. Three files will be created, for the following:
1625 *       "Common addresses"
1626 *       "Personal addresses"
1627 *       "Gathered addresses" - a new address book.
1628 */
1629 gint addrindex_read_data( AddressIndex *addrIndex ) {
1630         g_return_val_if_fail( addrIndex != NULL, -1 );
1631
1632         addrIndex->conversionError = FALSE;
1633         addrindex_read_file( addrIndex );
1634         if( addrIndex->retVal == MGU_SUCCESS ) {
1635                 if( addrIndex->needsConversion ) {
1636                         if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) {
1637                                 addrIndex->conversionError = TRUE;
1638                         }
1639                         else {
1640                                 addrIndex->conversionError = TRUE;
1641                         }
1642                 }
1643                 addrIndex->dirtyFlag = TRUE;
1644         }
1645         return addrIndex->retVal;
1646 }
1647
1648 /*
1649 * Create new address books for a new address index.
1650 * Enter: addrIndex Address index object.
1651 * return: Status code, from addrIndex->retVal.
1652 * Note: New address book files will be created in directory specified by
1653 * addrIndex. Three files will be created, for the following:
1654 *       "Common addresses"
1655 *       "Personal addresses"
1656 *       "Gathered addresses" - a new address book.
1657 */
1658 gint addrindex_create_new_books( AddressIndex *addrIndex ) {
1659         gboolean flg;
1660
1661         g_return_val_if_fail( addrIndex != NULL, -1 );
1662
1663         flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON );
1664         if( flg ) {
1665                 flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL );
1666                 addrIndex->dirtyFlag = TRUE;
1667         }
1668         return addrIndex->retVal;
1669 }
1670
1671 /* **********************************************************************
1672 * New interface stuff.
1673 * ***********************************************************************
1674 */
1675
1676 /*
1677  * Return modified flag for specified data source.
1678  */
1679 gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) {
1680         gboolean retVal = FALSE;
1681         AddressInterface *iface;
1682
1683         if( ds == NULL ) return retVal;
1684         iface = ds->interface;
1685         if( iface == NULL ) return retVal;
1686         if( iface->getModifyFlag ) {
1687                 retVal = ( iface->getModifyFlag ) ( ds->rawDataSource );
1688         }
1689         return retVal;
1690 }
1691
1692 /*
1693  * Return accessed flag for specified data source.
1694  */
1695 gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) {
1696         gboolean retVal = FALSE;
1697         AddressInterface *iface;
1698
1699         if( ds == NULL ) return retVal;
1700         iface = ds->interface;
1701         if( iface == NULL ) return retVal;
1702         if( iface->getAccessFlag ) {
1703                 retVal = ( iface->getAccessFlag ) ( ds->rawDataSource );
1704         }
1705         return retVal;
1706 }
1707
1708 /*
1709  * Return data read flag for specified data source.
1710  */
1711 gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) {
1712         gboolean retVal = TRUE;
1713         AddressInterface *iface;
1714
1715         if( ds == NULL ) return retVal;
1716         iface = ds->interface;
1717         if( iface == NULL ) return retVal;
1718         if( iface->getReadFlag ) {
1719                 retVal = ( iface->getReadFlag ) ( ds->rawDataSource );
1720         }
1721         return retVal;
1722 }
1723
1724 /*
1725  * Return status code for specified data source.
1726  */
1727 gint addrindex_ds_get_status_code( AddressDataSource *ds ) {
1728         gint retVal = MGU_SUCCESS;
1729         AddressInterface *iface;
1730
1731         if( ds == NULL ) return retVal;
1732         iface = ds->interface;
1733         if( iface == NULL ) return retVal;
1734         if( iface->getStatusCode ) {
1735                 retVal = ( iface->getStatusCode ) ( ds->rawDataSource );
1736         }
1737         return retVal;
1738 }
1739
1740 /*
1741  * Return data read flag for specified data source.
1742  */
1743 gint addrindex_ds_read_data( AddressDataSource *ds ) {
1744         gint retVal = MGU_SUCCESS;
1745         AddressInterface *iface;
1746
1747         if( ds == NULL ) return retVal;
1748         iface = ds->interface;
1749         if( iface == NULL ) return retVal;
1750         if( iface->getReadData ) {
1751                 retVal = ( iface->getReadData ) ( ds->rawDataSource );
1752         }
1753         return retVal;
1754 }
1755
1756 /*
1757  * Return data read flag for specified data source.
1758  */
1759 ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) {
1760         ItemFolder *retVal = NULL;
1761         AddressInterface *iface;
1762
1763         if( ds == NULL ) return retVal;
1764         iface = ds->interface;
1765         if( iface == NULL ) return retVal;
1766         if( iface->getRootFolder ) {
1767                 retVal = ( iface->getRootFolder ) ( ds->rawDataSource );
1768         }
1769         return retVal;
1770 }
1771
1772 /*
1773  * Return list of folders for specified data source.
1774  */
1775 GList *addrindex_ds_get_list_folder( AddressDataSource *ds ) {
1776         GList *retVal = FALSE;
1777         AddressInterface *iface;
1778
1779         if( ds == NULL ) return retVal;
1780         iface = ds->interface;
1781         if( iface == NULL ) return retVal;
1782         if( iface->getListFolder ) {
1783                 retVal = ( iface->getListFolder ) ( ds->rawDataSource );
1784         }
1785         return retVal;
1786 }
1787
1788 /*
1789  * Return list of persons in root folder for specified data source.
1790  */
1791 GList *addrindex_ds_get_list_person( AddressDataSource *ds ) {
1792         GList *retVal = FALSE;
1793         AddressInterface *iface;
1794
1795         if( ds == NULL ) return retVal;
1796         iface = ds->interface;
1797         if( iface == NULL ) return retVal;
1798         if( iface->getListPerson ) {
1799                 retVal = ( iface->getListPerson ) ( ds->rawDataSource );
1800         }
1801         return retVal;
1802 }
1803
1804 /*
1805  * Return name for specified data source.
1806  */
1807 gchar *addrindex_ds_get_name( AddressDataSource *ds ) {
1808         gchar *retVal = FALSE;
1809         AddressInterface *iface;
1810
1811         if( ds == NULL ) return retVal;
1812         iface = ds->interface;
1813         if( iface == NULL ) return retVal;
1814         if( iface->getName ) {
1815                 retVal = ( iface->getName ) ( ds->rawDataSource );
1816         }
1817         return retVal;
1818 }
1819
1820 /*
1821  * Set the access flag inside the data source.
1822  */
1823 void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) {
1824         AddressInterface *iface;
1825
1826         if( ds == NULL ) return;
1827         iface = ds->interface;
1828         if( iface == NULL ) return;
1829         if( iface->setAccessFlag ) {
1830                 ( iface->setAccessFlag ) ( ds->rawDataSource, value );
1831         }
1832 }
1833
1834 /*
1835  * Return read only flag for specified data source.
1836  */
1837 gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) {
1838         AddressInterface *iface;
1839         if( ds == NULL ) return TRUE;
1840         iface = ds->interface;
1841         if( iface == NULL ) return TRUE;
1842         return iface->readOnly;
1843 }
1844
1845 /*
1846  * Return list of all persons for specified data source.
1847  */
1848 GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) {
1849         GList *retVal = NULL;
1850         AddressInterface *iface;
1851
1852         if( ds == NULL ) return retVal;
1853         iface = ds->interface;
1854         if( iface == NULL ) return retVal;
1855         if( iface->getAllPersons ) {
1856                 retVal = ( iface->getAllPersons ) ( ds->rawDataSource );
1857         }
1858         return retVal;
1859 }
1860
1861 /*
1862 * End of Source.
1863 */