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