2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2002-2012 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 * ***********************************************************************
45 /* Element tag names */
46 #define XMLS_ELTAG_PROP_LIST "property-list"
47 #define XMLS_ELTAG_PROPERTY "property"
49 /* Attribute tag names */
50 #define XMLS_ATTAG_NAME "name"
51 #define XMLS_ATTAG_VALUE "value"
53 static void xmlprops_clear ( XmlProperty *props );
55 typedef struct _HashLoopData {
63 XmlProperty *xmlprops_create( void ) {
66 props = g_new0( XmlProperty, 1 );
68 props->encoding = NULL;
69 props->propertyTable = g_hash_table_new( g_str_hash, g_str_equal );
70 props->retVal = MGU_SUCCESS;
75 * Properties - file path.
77 void xmlprops_set_path( XmlProperty *props, const gchar *value ) {
78 cm_return_if_fail( props != NULL );
79 props->path = mgu_replace_string( props->path, value );
83 * Free hash table visitor function.
85 static gint xmlprops_free_entry_vis( gpointer key, gpointer value, gpointer data ) {
94 * Clear all properties.
95 * Enter: props Property object.
97 static void xmlprops_clear( XmlProperty *props ) {
98 cm_return_if_fail( props != NULL );
99 g_hash_table_foreach_remove(
100 props->propertyTable, xmlprops_free_entry_vis, NULL );
105 * Enter: props Property object.
107 void xmlprops_free( XmlProperty *props ) {
108 cm_return_if_fail( props != NULL );
110 /* Clear property table */
111 xmlprops_clear( props );
112 g_hash_table_destroy( props->propertyTable );
114 /* Free up internal objects */
115 g_free( props->path );
116 g_free( props->encoding );
119 props->encoding = NULL;
120 props->propertyTable = NULL;
126 static int xmlprops_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
128 for( i = 0; i < lvl; i++ ) {
129 if(fputs( " ", fp ) == EOF)
132 if(fputs( "<", fp ) == EOF)
134 if(fputs( name, fp ) == EOF)
140 static int xmlprops_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
142 for( i = 0; i < lvl; i++ ) {
143 if(fputs( " ", fp ) == EOF)
146 if(fputs( "</", fp ) == EOF)
148 if(fputs( name, fp ) == EOF)
150 if(fputs( ">\n", fp ) == EOF)
156 static int xmlprops_write_attr( FILE *fp, gchar *name, gchar *value ) {
157 if(fputs( " ", fp ) == EOF)
159 if(fputs( name, fp ) == EOF)
161 if(fputs( "=\"", fp ) == EOF)
163 if(xml_file_put_escape_str( fp, value ) < 0)
165 if(fputs( "\"", fp ) == EOF)
171 static void xmlprops_write_vis( gpointer key, gpointer value, gpointer d ) {
172 HashLoopData *data = (HashLoopData *)d;
174 if(xmlprops_write_elem_s( data->fp, 1, XMLS_ELTAG_PROPERTY ) < 0)
176 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_NAME, key ) < 0)
178 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_VALUE, value ) < 0)
180 if(fputs( " />\n", data->fp ) == EOF)
184 static gint xmlprops_write_to( XmlProperty *props, const gchar *fileSpec ) {
189 props->retVal = MGU_OPEN_FILE;
190 pfile = prefs_write_open( fileSpec );
193 if(fprintf( fp, "<?xml version=\"1.0\"" ) < 0)
195 if( props->encoding && *props->encoding ) {
196 if(fprintf( fp, " encoding=\"%s\"", props->encoding ) < 0)
199 if(fprintf( fp, " ?>\n" ) < 0)
201 if(xmlprops_write_elem_s( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
203 if(fputs( ">\n", fp ) == EOF)
206 /* Output all properties */
209 g_hash_table_foreach( props->propertyTable, xmlprops_write_vis, &data );
214 if(xmlprops_write_elem_e( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
217 props->retVal = MGU_SUCCESS;
218 if( prefs_file_close( pfile ) < 0 ) {
219 props->retVal = MGU_ERROR_WRITE;
224 props->retVal = MGU_ERROR_WRITE;
225 if( prefs_file_close_revert( pfile ) < 0 ) {
226 props->retVal = MGU_ERROR_WRITE;
231 return props->retVal;
235 * Save properties to file.
236 * return: Status code.
238 gint xmlprops_save_file( XmlProperty *props ) {
239 cm_return_val_if_fail( props != NULL, -1 );
241 props->retVal = MGU_NO_FILE;
242 if( props->path == NULL || *props->path == '\0' ) return props->retVal;
243 xmlprops_write_to( props, props->path );
245 return props->retVal;
248 static void xmlprops_save_property(
249 XmlProperty *props, const gchar *name, const gchar *value )
254 if( strlen( name ) == 0 ) return;
255 if( strlen( value ) == 0 ) return;
256 if( g_hash_table_lookup( props->propertyTable, name ) ) return;
257 key = g_strdup( name );
258 val = g_strdup( value );
259 g_hash_table_insert( props->propertyTable, key, val );
262 #define ATTR_BUFSIZE 256
264 static void xmlprops_read_props( XmlProperty *props, XMLFile *file ) {
267 gchar pName[ ATTR_BUFSIZE ];
268 gchar pValue[ ATTR_BUFSIZE ];
273 if (! file->level ) break;
274 xml_parse_next_tag( file );
275 xml_get_current_tag( file );
276 if( xml_compare_tag( file, XMLS_ELTAG_PROPERTY ) ) {
277 attr = xml_get_current_tag_attr( file );
279 name = ( ( XMLAttr * ) attr->data )->name;
280 value = ( ( XMLAttr * ) attr->data )->value;
281 if( strcmp( name, XMLS_ATTAG_NAME ) == 0 ) {
282 strcpy( pName, value );
284 else if( strcmp( name, XMLS_ATTAG_VALUE ) == 0 ) {
285 strcpy( pValue, value );
287 attr = g_list_next( attr );
289 xmlprops_save_property( props, pName, pValue );
297 * Load properties from file.
298 * return: Status code.
300 gint xmlprops_load_file( XmlProperty *props ) {
301 XMLFile *file = NULL;
303 cm_return_val_if_fail( props != NULL, -1 );
304 props->retVal = MGU_NO_FILE;
305 file = xml_open_file( props->path );
307 return props->retVal;
310 props->retVal = MGU_BAD_FORMAT;
311 if( xml_get_dtd( file ) == 0 ) {
312 if( xml_parse_next_tag( file ) == 0 ) {
313 if( xml_compare_tag( file, XMLS_ELTAG_PROP_LIST ) ) {
314 xmlprops_read_props( props, file );
315 props->retVal = MGU_SUCCESS;
319 xml_close_file( file );
321 return props->retVal;
326 * Enter: props Property object.
327 * name Property name.
328 * value New value to save.
330 void xmlprops_set_property(
331 XmlProperty *props, const gchar *name, const gchar *value )
336 cm_return_if_fail( props != NULL );
337 if( name == NULL || strlen( name ) == 0 ) return;
338 if( value == NULL || strlen( value ) == 0 ) return;
339 val = g_hash_table_lookup( props->propertyTable, name );
341 key = g_strdup( name );
346 val = g_strdup( value );
347 g_hash_table_insert( props->propertyTable, key, val );
351 * Set property to integer value.
352 * Enter: props Property object.
353 * name Property name.
354 * value New value to save.
356 void xmlprops_set_property_i(
357 XmlProperty *props, const gchar *name, const gint value )
361 cm_return_if_fail( props != NULL );
362 sprintf( buf, "%d", value );
363 xmlprops_set_property( props, name, buf );
367 * Set property to boolean value.
368 * Enter: props Property object.
369 * name Property name.
370 * value New value to save.
372 void xmlprops_set_property_b(
373 XmlProperty *props, const gchar *name, const gboolean value )
375 cm_return_if_fail( props != NULL );
377 xmlprops_set_property( props, name, "y" );
380 xmlprops_set_property( props, name, "n" );
385 * Get property into a buffer.
386 * Enter: props Property object.
387 * name Property name.
388 * Return: value found, or NULL if none. Should be g_free() when done.
390 void xmlprops_get_property_s(
391 XmlProperty *props, const gchar *name, gchar *buffer ) {
394 cm_return_if_fail( props != NULL );
395 if( buffer == NULL ) return;
396 val = g_hash_table_lookup( props->propertyTable, name );
398 strcpy( buffer, val );
403 * Get property as integer value.
404 * Enter: props Property object.
405 * name Property name.
406 * Return: value found, or zero if not found.
408 gint xmlprops_get_property_i( XmlProperty *props, const gchar *name ) {
414 cm_return_val_if_fail( props != NULL, value );
415 val = g_hash_table_lookup( props->propertyTable, name );
418 value = strtol( val, &endptr, 10 );
424 * Get property as boolean value.
425 * Enter: props Property object.
426 * name Property name.
427 * Return: value found, or FALSE if not found.
429 gboolean xmlprops_get_property_b( XmlProperty *props, const gchar *name ) {
434 cm_return_val_if_fail( props != NULL, value );
435 val = g_hash_table_lookup( props->propertyTable, name );
437 value = ( g_ascii_strcasecmp( val, "y" ) == 0 );