2007-05-03 [wwp] 2.9.1cvs41
[claws.git] / src / common / xmlprops.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2002-2007 Match Grun and the Claws Mail team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 /*
21  * General functions for saving properties to an XML file.
22  *
23  * The file is structured as follows:
24  *
25  *   <property-list>
26  *     <property name="first-name" value="Axle" >/
27  *     <property name="last-name"  value="Rose" >/
28  *   </property-list>
29  *              
30  * ***********************************************************************
31  */
32
33
34 #include <glib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38
39 #include "prefs.h"
40 #include "xml.h"
41 #include "mgutils.h"
42 #include "xmlprops.h"
43
44 /* Element tag names */
45 #define XMLS_ELTAG_PROP_LIST     "property-list"
46 #define XMLS_ELTAG_PROPERTY      "property"
47
48 /* Attribute tag names */
49 #define XMLS_ATTAG_NAME          "name"
50 #define XMLS_ATTAG_VALUE         "value"
51
52 /*
53  * Create new props.
54  */
55 XmlProperty *xmlprops_create( void ) {
56         XmlProperty *props;
57
58         props = g_new0( XmlProperty, 1 );
59         props->path = NULL;
60         props->encoding = NULL;
61         props->propertyTable = g_hash_table_new( g_str_hash, g_str_equal );
62         props->retVal = MGU_SUCCESS;
63         return props;
64 }
65
66 /*
67  * Properties - file path.
68  */
69 void xmlprops_set_path( XmlProperty *props, const gchar *value ) {
70         g_return_if_fail( props != NULL );
71         props->path = mgu_replace_string( props->path, value );
72 }
73 void xmlprops_set_encoding( XmlProperty *props, const gchar *value ) {
74         g_return_if_fail( props != NULL );
75         props->encoding = mgu_replace_string( props->encoding, value );
76 }
77
78 /*
79  * Free hash table visitor function.
80  */
81 static gint xmlprops_free_entry_vis( gpointer key, gpointer value, gpointer data ) {
82         g_free( key );
83         g_free( value );
84         key = NULL;
85         value = NULL;
86         return TRUE;
87 }
88
89 /*
90  * Clear all properties.
91  * Enter: props Property object.
92  */
93 void xmlprops_clear( XmlProperty *props ) {
94         g_return_if_fail( props != NULL );
95         g_hash_table_foreach_remove(
96                 props->propertyTable, xmlprops_free_entry_vis, NULL );
97 }
98
99 /*
100  * Free props.
101  * Enter: props Property object.
102  */
103 void xmlprops_free( XmlProperty *props ) {
104         g_return_if_fail( props != NULL );
105
106         /* Clear property table */
107         xmlprops_clear( props );
108         g_hash_table_destroy( props->propertyTable );
109
110         /* Free up internal objects */
111         g_free( props->path );
112         g_free( props->encoding );
113
114         props->path = NULL;
115         props->encoding = NULL;
116         props->propertyTable = NULL;
117         props->retVal = 0;
118
119         g_free( props );
120 }
121
122 static void xmlprops_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
123         gint i;
124         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
125         fputs( "<", fp );
126         fputs( name, fp );
127 }
128
129 static void xmlprops_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
130         gint i;
131         for( i = 0; i < lvl; i++ ) fputs( "  ", fp );
132         fputs( "</", fp );
133         fputs( name, fp );
134         fputs( ">\n", fp );
135 }
136
137 static void xmlprops_write_attr( FILE *fp, gchar *name, gchar *value ) {
138         fputs( " ", fp );
139         fputs( name, fp );
140         fputs( "=\"", fp );
141         xml_file_put_escape_str( fp, value );
142         fputs( "\"", fp );
143 }
144
145 static void xmlprops_write_vis( gpointer key, gpointer value, gpointer data ) {
146         FILE *fp = ( FILE * ) data;
147
148         xmlprops_write_elem_s( fp, 1, XMLS_ELTAG_PROPERTY );
149         xmlprops_write_attr( fp, XMLS_ATTAG_NAME, key );
150         xmlprops_write_attr( fp, XMLS_ATTAG_VALUE, value );
151         fputs( " />\n", fp );
152 }
153
154 static gint xmlprops_write_to( XmlProperty *props, const gchar *fileSpec ) {
155         PrefFile *pfile;
156         FILE *fp;
157
158         props->retVal = MGU_OPEN_FILE;
159         pfile = prefs_write_open( fileSpec );
160         if( pfile ) {
161                 fp = pfile->fp;
162                 fprintf( fp, "<?xml version=\"1.0\"" );
163                 if( props->encoding && *props->encoding ) {
164                         fprintf( fp, " encoding=\"%s\"", props->encoding );
165                 }
166                 fprintf( fp, " ?>\n" );
167                 xmlprops_write_elem_s( fp, 0, XMLS_ELTAG_PROP_LIST );
168                 fputs( ">\n", fp );
169
170                 /* Output all properties */
171                 g_hash_table_foreach( props->propertyTable, xmlprops_write_vis, fp );
172
173                 xmlprops_write_elem_e( fp, 0, XMLS_ELTAG_PROP_LIST );
174                 props->retVal = MGU_SUCCESS;
175                 if( prefs_file_close( pfile ) < 0 ) {
176                         props->retVal = MGU_ERROR_WRITE;
177                 }
178         }
179
180         return props->retVal;
181 }
182
183 /*
184  * Save properties to file.
185  * return: Status code.
186  */
187 gint xmlprops_save_file( XmlProperty *props ) {
188         g_return_val_if_fail( props != NULL, -1 );
189
190         props->retVal = MGU_NO_FILE;
191         if( props->path == NULL || *props->path == '\0' ) return props->retVal;
192         xmlprops_write_to( props, props->path );
193         /*
194         if( props->retVal == MGU_SUCCESS ) {
195         }
196         */
197         return props->retVal;
198 }
199
200 static void xmlprops_print_vis( gpointer key, gpointer value, gpointer data ) {
201         FILE *stream = ( FILE * ) data;
202
203         fprintf( stream, "-\tname/value:\t%s / %s\n", (char *)key, (char *)value );
204 }
205
206 void xmlprops_print( XmlProperty *props, FILE *stream ) {
207         fprintf( stream, "Property File: %s\n", props->path );
208         g_hash_table_foreach( props->propertyTable, xmlprops_print_vis, stream );
209         fprintf( stream, "---\n" );
210 }
211
212 static void xmlprops_save_property(
213                 XmlProperty *props, const gchar *name, const gchar *value )
214 {
215         gchar *key;
216         gchar *val;
217
218         if( strlen( name ) == 0 ) return;
219         if( strlen( value ) == 0 ) return;
220         if( g_hash_table_lookup( props->propertyTable, name ) ) return;
221         key = g_strdup( name );
222         val = g_strdup( value );
223         g_hash_table_insert( props->propertyTable, key, val );
224 }
225
226 #define ATTR_BUFSIZE 256
227
228 static void xmlprops_read_props( XmlProperty *props, XMLFile *file ) {
229         GList *attr;
230         gchar *name, *value;
231         gchar pName[ ATTR_BUFSIZE ];
232         gchar pValue[ ATTR_BUFSIZE ];
233
234         while( TRUE ) {
235                 *pName = '\0';
236                 *pValue = '\0';
237                 if (! file->level ) break;
238                 xml_parse_next_tag( file );
239                 xml_get_current_tag( file );
240                 if( xml_compare_tag( file, XMLS_ELTAG_PROPERTY ) ) {
241                         attr = xml_get_current_tag_attr( file );
242                         while( attr ) {
243                                 name = ( ( XMLAttr * ) attr->data )->name;
244                                 value = ( ( XMLAttr * ) attr->data )->value;
245                                 if( strcmp( name, XMLS_ATTAG_NAME ) == 0 ) {
246                                         strcpy( pName, value );
247                                 }
248                                 else if( strcmp( name, XMLS_ATTAG_VALUE ) == 0 ) {
249                                         strcpy( pValue, value );
250                                 }
251                                 attr = g_list_next( attr );
252                         }
253                         xmlprops_save_property( props, pName, pValue );
254                 }
255         }
256 }
257
258 #undef ATTR_BUFSIZE
259
260 /*
261  * Load properties from file.
262  * return: Status code.
263  */
264 gint xmlprops_load_file( XmlProperty *props ) {
265         XMLFile *file = NULL;
266
267         g_return_val_if_fail( props != NULL, -1 );
268         props->retVal = MGU_NO_FILE;
269         file = xml_open_file( props->path );
270         if( file == NULL ) {
271                 return props->retVal;
272         }
273
274         props->retVal = MGU_BAD_FORMAT;
275         if( xml_get_dtd( file ) == 0 ) {
276                 if( xml_parse_next_tag( file ) == 0 ) {
277                         if( xml_compare_tag( file, XMLS_ELTAG_PROP_LIST ) ) {
278                                 xmlprops_read_props( props, file );
279                                 props->retVal = MGU_SUCCESS;
280                         }
281                 }
282         }
283         xml_close_file( file );
284
285         return props->retVal;
286 }
287
288 /*
289  * Set property.
290  * Enter: props Property object.
291  *        name  Property name.
292  *        value New value to save.
293  */
294 void xmlprops_set_property(
295                 XmlProperty *props, const gchar *name, const gchar *value )
296 {
297         gchar *key = NULL;
298         gchar *val;
299
300         g_return_if_fail( props != NULL );
301         if( name == NULL || strlen( name ) == 0 ) return;
302         if( value == NULL || strlen( value ) == 0 ) return;
303         val = g_hash_table_lookup( props->propertyTable, name );
304         if( val == NULL ) {
305                 key = g_strdup( name );
306         }
307         else {
308                 g_free( val );
309         }
310         val = g_strdup( value );
311         g_hash_table_insert( props->propertyTable, key, val );
312 }
313
314 /*
315  * Set property to integer value.
316  * Enter: props Property object.
317  *        name  Property name.
318  *        value New value to save.
319  */
320 void xmlprops_set_property_i(
321                 XmlProperty *props, const gchar *name, const gint value )
322 {
323         gchar buf[32];
324
325         g_return_if_fail( props != NULL );
326         sprintf( buf, "%d", value );
327         xmlprops_set_property( props, name, buf );
328 }
329
330 /*
331  * Set property to boolean value.
332  * Enter: props Property object.
333  *        name  Property name.
334  *        value New value to save.
335  */
336 void xmlprops_set_property_b(
337                 XmlProperty *props, const gchar *name, const gboolean value )
338 {
339         g_return_if_fail( props != NULL );
340         if( value ) {
341                 xmlprops_set_property( props, name, "y" );
342         }
343         else {
344                 xmlprops_set_property( props, name, "n" );
345         }
346 }
347
348 /*
349  * Get property.
350  * Enter:  props Property object.
351  *         name  Property name.
352  * Return: value found, or NULL if none. Should be g_free() when done.
353  */
354 gchar *xmlprops_get_property( XmlProperty *props, const gchar *name ) {
355         gchar *val, *value;
356
357         value = NULL;
358         g_return_val_if_fail( props != NULL, value );
359         val = g_hash_table_lookup( props->propertyTable, name );
360         if( val ) {
361                 value = g_strdup( val );
362         }
363         return value;
364 }
365
366 /*
367  * Get property into a buffer.
368  * Enter:  props Property object.
369  *         name  Property name.
370  * Return: value found, or NULL if none. Should be g_free() when done.
371  */
372 void xmlprops_get_property_s(
373                 XmlProperty *props, const gchar *name, gchar *buffer ) {
374         gchar *val;
375
376         g_return_if_fail( props != NULL );
377         if( buffer == NULL ) return;
378         val = g_hash_table_lookup( props->propertyTable, name );
379         if( val ) {
380                 strcpy( buffer, val );
381         }
382 }
383
384 /*
385  * Get property as integer value.
386  * Enter:  props Property object.
387  *         name  Property name.
388  * Return: value found, or zero if not found.
389  */
390 gint xmlprops_get_property_i( XmlProperty *props, const gchar *name ) {
391         gchar *val;
392         gchar *endptr;
393         gint value;
394
395         value = 0;
396         g_return_val_if_fail( props != NULL, value );
397         val = g_hash_table_lookup( props->propertyTable, name );
398         if( val ) {
399                 endptr = NULL;
400                 value = strtol( val, &endptr, 10 );
401         }
402         return value;
403 }
404
405 /*
406  * Get property as boolean value.
407  * Enter:  props Property object.
408  *         name  Property name.
409  * Return: value found, or FALSE if not found.
410  */
411 gboolean xmlprops_get_property_b( XmlProperty *props, const gchar *name ) {
412         gchar *val;
413         gboolean value;
414
415         value = FALSE;
416         g_return_val_if_fail( props != NULL, value );
417         val = g_hash_table_lookup( props->propertyTable, name );
418         if( val ) {
419                 value = ( g_ascii_strcasecmp( val, "y" ) == 0 );
420         }
421         return value;
422 }
423
424 /*
425 * End of Source.
426 */
427
428