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