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