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