2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2002-2007 Match Grun and the Claws Mail team
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 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * General functions for saving properties to an XML file.
23 * The file is structured as follows:
26 * <property name="first-name" value="Axle" >/
27 * <property name="last-name" value="Rose" >/
30 * ***********************************************************************
44 /* Element tag names */
45 #define XMLS_ELTAG_PROP_LIST "property-list"
46 #define XMLS_ELTAG_PROPERTY "property"
48 /* Attribute tag names */
49 #define XMLS_ATTAG_NAME "name"
50 #define XMLS_ATTAG_VALUE "value"
52 static void xmlprops_clear ( XmlProperty *props );
54 typedef struct _HashLoopData {
62 XmlProperty *xmlprops_create( void ) {
65 props = g_new0( XmlProperty, 1 );
67 props->encoding = NULL;
68 props->propertyTable = g_hash_table_new( g_str_hash, g_str_equal );
69 props->retVal = MGU_SUCCESS;
74 * Properties - file path.
76 void xmlprops_set_path( XmlProperty *props, const gchar *value ) {
77 g_return_if_fail( props != NULL );
78 props->path = mgu_replace_string( props->path, value );
82 * Free hash table visitor function.
84 static gint xmlprops_free_entry_vis( gpointer key, gpointer value, gpointer data ) {
93 * Clear all properties.
94 * Enter: props Property object.
96 static void xmlprops_clear( XmlProperty *props ) {
97 g_return_if_fail( props != NULL );
98 g_hash_table_foreach_remove(
99 props->propertyTable, xmlprops_free_entry_vis, NULL );
104 * Enter: props Property object.
106 void xmlprops_free( XmlProperty *props ) {
107 g_return_if_fail( props != NULL );
109 /* Clear property table */
110 xmlprops_clear( props );
111 g_hash_table_destroy( props->propertyTable );
113 /* Free up internal objects */
114 g_free( props->path );
115 g_free( props->encoding );
118 props->encoding = NULL;
119 props->propertyTable = NULL;
125 static int xmlprops_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
127 for( i = 0; i < lvl; i++ ) {
128 if(fputs( " ", fp ) == EOF)
131 if(fputs( "<", fp ) == EOF)
133 if(fputs( name, fp ) == EOF)
139 static int xmlprops_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
141 for( i = 0; i < lvl; i++ ) {
142 if(fputs( " ", fp ) == EOF)
145 if(fputs( "</", fp ) == EOF)
147 if(fputs( name, fp ) == EOF)
149 if(fputs( ">\n", fp ) == EOF)
155 static int xmlprops_write_attr( FILE *fp, gchar *name, gchar *value ) {
156 if(fputs( " ", fp ) == EOF)
158 if(fputs( name, fp ) == EOF)
160 if(fputs( "=\"", fp ) == EOF)
162 if(xml_file_put_escape_str( fp, value ) < 0)
164 if(fputs( "\"", fp ) == EOF)
170 static void xmlprops_write_vis( gpointer key, gpointer value, gpointer d ) {
171 HashLoopData *data = (HashLoopData *)d;
173 if(xmlprops_write_elem_s( data->fp, 1, XMLS_ELTAG_PROPERTY ) < 0)
175 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_NAME, key ) < 0)
177 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_VALUE, value ) < 0)
179 if(fputs( " />\n", data->fp ) == EOF)
183 static gint xmlprops_write_to( XmlProperty *props, const gchar *fileSpec ) {
188 props->retVal = MGU_OPEN_FILE;
189 pfile = prefs_write_open( fileSpec );
192 if(fprintf( fp, "<?xml version=\"1.0\"" ) < 0)
194 if( props->encoding && *props->encoding ) {
195 if(fprintf( fp, " encoding=\"%s\"", props->encoding ) < 0)
198 if(fprintf( fp, " ?>\n" ) < 0)
200 if(xmlprops_write_elem_s( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
202 if(fputs( ">\n", fp ) == EOF)
205 /* Output all properties */
208 g_hash_table_foreach( props->propertyTable, xmlprops_write_vis, &data );
213 if(xmlprops_write_elem_e( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
216 props->retVal = MGU_SUCCESS;
217 if( prefs_file_close( pfile ) < 0 ) {
222 props->retVal = MGU_ERROR_WRITE;
223 if( prefs_file_close_revert( pfile ) < 0 ) {
224 props->retVal = MGU_ERROR_WRITE;
229 return props->retVal;
233 * Save properties to file.
234 * return: Status code.
236 gint xmlprops_save_file( XmlProperty *props ) {
237 g_return_val_if_fail( props != NULL, -1 );
239 props->retVal = MGU_NO_FILE;
240 if( props->path == NULL || *props->path == '\0' ) return props->retVal;
241 xmlprops_write_to( props, props->path );
243 return props->retVal;
246 static void xmlprops_save_property(
247 XmlProperty *props, const gchar *name, const gchar *value )
252 if( strlen( name ) == 0 ) return;
253 if( strlen( value ) == 0 ) return;
254 if( g_hash_table_lookup( props->propertyTable, name ) ) return;
255 key = g_strdup( name );
256 val = g_strdup( value );
257 g_hash_table_insert( props->propertyTable, key, val );
260 #define ATTR_BUFSIZE 256
262 static void xmlprops_read_props( XmlProperty *props, XMLFile *file ) {
265 gchar pName[ ATTR_BUFSIZE ];
266 gchar pValue[ ATTR_BUFSIZE ];
271 if (! file->level ) break;
272 xml_parse_next_tag( file );
273 xml_get_current_tag( file );
274 if( xml_compare_tag( file, XMLS_ELTAG_PROPERTY ) ) {
275 attr = xml_get_current_tag_attr( file );
277 name = ( ( XMLAttr * ) attr->data )->name;
278 value = ( ( XMLAttr * ) attr->data )->value;
279 if( strcmp( name, XMLS_ATTAG_NAME ) == 0 ) {
280 strcpy( pName, value );
282 else if( strcmp( name, XMLS_ATTAG_VALUE ) == 0 ) {
283 strcpy( pValue, value );
285 attr = g_list_next( attr );
287 xmlprops_save_property( props, pName, pValue );
295 * Load properties from file.
296 * return: Status code.
298 gint xmlprops_load_file( XmlProperty *props ) {
299 XMLFile *file = NULL;
301 g_return_val_if_fail( props != NULL, -1 );
302 props->retVal = MGU_NO_FILE;
303 file = xml_open_file( props->path );
305 return props->retVal;
308 props->retVal = MGU_BAD_FORMAT;
309 if( xml_get_dtd( file ) == 0 ) {
310 if( xml_parse_next_tag( file ) == 0 ) {
311 if( xml_compare_tag( file, XMLS_ELTAG_PROP_LIST ) ) {
312 xmlprops_read_props( props, file );
313 props->retVal = MGU_SUCCESS;
317 xml_close_file( file );
319 return props->retVal;
324 * Enter: props Property object.
325 * name Property name.
326 * value New value to save.
328 void xmlprops_set_property(
329 XmlProperty *props, const gchar *name, const gchar *value )
334 g_return_if_fail( props != NULL );
335 if( name == NULL || strlen( name ) == 0 ) return;
336 if( value == NULL || strlen( value ) == 0 ) return;
337 val = g_hash_table_lookup( props->propertyTable, name );
339 key = g_strdup( name );
344 val = g_strdup( value );
345 g_hash_table_insert( props->propertyTable, key, val );
349 * Set property to integer value.
350 * Enter: props Property object.
351 * name Property name.
352 * value New value to save.
354 void xmlprops_set_property_i(
355 XmlProperty *props, const gchar *name, const gint value )
359 g_return_if_fail( props != NULL );
360 sprintf( buf, "%d", value );
361 xmlprops_set_property( props, name, buf );
365 * Set property to boolean value.
366 * Enter: props Property object.
367 * name Property name.
368 * value New value to save.
370 void xmlprops_set_property_b(
371 XmlProperty *props, const gchar *name, const gboolean value )
373 g_return_if_fail( props != NULL );
375 xmlprops_set_property( props, name, "y" );
378 xmlprops_set_property( props, name, "n" );
383 * Get property into a buffer.
384 * Enter: props Property object.
385 * name Property name.
386 * Return: value found, or NULL if none. Should be g_free() when done.
388 void xmlprops_get_property_s(
389 XmlProperty *props, const gchar *name, gchar *buffer ) {
392 g_return_if_fail( props != NULL );
393 if( buffer == NULL ) return;
394 val = g_hash_table_lookup( props->propertyTable, name );
396 strcpy( buffer, val );
401 * Get property as integer value.
402 * Enter: props Property object.
403 * name Property name.
404 * Return: value found, or zero if not found.
406 gint xmlprops_get_property_i( XmlProperty *props, const gchar *name ) {
412 g_return_val_if_fail( props != NULL, value );
413 val = g_hash_table_lookup( props->propertyTable, name );
416 value = strtol( val, &endptr, 10 );
422 * Get property as boolean value.
423 * Enter: props Property object.
424 * name Property name.
425 * Return: value found, or FALSE if not found.
427 gboolean xmlprops_get_property_b( XmlProperty *props, const gchar *name ) {
432 g_return_val_if_fail( props != NULL, value );
433 val = g_hash_table_lookup( props->propertyTable, name );
435 value = ( g_ascii_strcasecmp( val, "y" ) == 0 );