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