2 * Claws Mail -- 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 * ***********************************************************************
35 #include "claws-features.h"
48 #include "file-utils.h"
50 /* Element tag names */
51 #define XMLS_ELTAG_PROP_LIST "property-list"
52 #define XMLS_ELTAG_PROPERTY "property"
54 /* Attribute tag names */
55 #define XMLS_ATTAG_NAME "name"
56 #define XMLS_ATTAG_VALUE "value"
58 static void xmlprops_clear ( XmlProperty
*props
);
60 typedef struct _HashLoopData
{
68 XmlProperty
*xmlprops_create( void ) {
71 props
= g_new0( XmlProperty
, 1 );
73 props
->encoding
= NULL
;
74 props
->propertyTable
= g_hash_table_new( g_str_hash
, g_str_equal
);
75 props
->retVal
= MGU_SUCCESS
;
80 * Properties - file path.
82 void xmlprops_set_path( XmlProperty
*props
, const gchar
*value
) {
83 cm_return_if_fail( props
!= NULL
);
84 props
->path
= mgu_replace_string( props
->path
, value
);
88 * Free hash table visitor function.
90 static gint
xmlprops_free_entry_vis( gpointer key
, gpointer value
, gpointer data
) {
99 * Clear all properties.
100 * Enter: props Property object.
102 static void xmlprops_clear( XmlProperty
*props
) {
103 cm_return_if_fail( props
!= NULL
);
104 g_hash_table_foreach_remove(
105 props
->propertyTable
, xmlprops_free_entry_vis
, NULL
);
110 * Enter: props Property object.
112 void xmlprops_free( XmlProperty
*props
) {
113 cm_return_if_fail( props
!= NULL
);
115 /* Clear property table */
116 xmlprops_clear( props
);
117 g_hash_table_destroy( props
->propertyTable
);
119 /* Free up internal objects */
120 g_free( props
->path
);
121 g_free( props
->encoding
);
124 props
->encoding
= NULL
;
125 props
->propertyTable
= NULL
;
131 static int xmlprops_write_elem_s( FILE *fp
, gint lvl
, gchar
*name
) {
133 for( i
= 0; i
< lvl
; i
++ ) {
134 if(claws_fputs( " ", fp
) == EOF
)
137 if(claws_fputs( "<", fp
) == EOF
)
139 if(claws_fputs( name
, fp
) == EOF
)
145 static int xmlprops_write_elem_e( FILE *fp
, gint lvl
, gchar
*name
) {
147 for( i
= 0; i
< lvl
; i
++ ) {
148 if(claws_fputs( " ", fp
) == EOF
)
151 if(claws_fputs( "</", fp
) == EOF
)
153 if(claws_fputs( name
, fp
) == EOF
)
155 if(claws_fputs( ">\n", fp
) == EOF
)
161 static int xmlprops_write_attr( FILE *fp
, gchar
*name
, gchar
*value
) {
162 if(claws_fputs( " ", fp
) == EOF
)
164 if(claws_fputs( name
, fp
) == EOF
)
166 if(claws_fputs( "=\"", fp
) == EOF
)
168 if(xml_file_put_escape_str( fp
, value
) < 0)
170 if(claws_fputs( "\"", fp
) == EOF
)
176 static void xmlprops_write_vis( gpointer key
, gpointer value
, gpointer d
) {
177 HashLoopData
*data
= (HashLoopData
*)d
;
179 if(xmlprops_write_elem_s( data
->fp
, 1, XMLS_ELTAG_PROPERTY
) < 0)
181 if(xmlprops_write_attr( data
->fp
, XMLS_ATTAG_NAME
, key
) < 0)
183 if(xmlprops_write_attr( data
->fp
, XMLS_ATTAG_VALUE
, value
) < 0)
185 if(claws_fputs( " />\n", data
->fp
) == EOF
)
189 static gint
xmlprops_write_to( XmlProperty
*props
, const gchar
*fileSpec
) {
194 props
->retVal
= MGU_OPEN_FILE
;
195 pfile
= prefs_write_open( fileSpec
);
198 if(fprintf( fp
, "<?xml version=\"1.0\"" ) < 0)
200 if( props
->encoding
&& *props
->encoding
) {
201 if(fprintf( fp
, " encoding=\"%s\"", props
->encoding
) < 0)
204 if(fprintf( fp
, " ?>\n" ) < 0)
206 if(xmlprops_write_elem_s( fp
, 0, XMLS_ELTAG_PROP_LIST
) < 0)
208 if(claws_fputs( ">\n", fp
) == EOF
)
211 /* Output all properties */
214 g_hash_table_foreach( props
->propertyTable
, xmlprops_write_vis
, &data
);
219 if(xmlprops_write_elem_e( fp
, 0, XMLS_ELTAG_PROP_LIST
) < 0)
222 props
->retVal
= MGU_SUCCESS
;
223 if( prefs_file_close( pfile
) < 0 ) {
224 props
->retVal
= MGU_ERROR_WRITE
;
229 props
->retVal
= MGU_ERROR_WRITE
;
230 if( prefs_file_close_revert( pfile
) < 0 ) {
231 props
->retVal
= MGU_ERROR_WRITE
;
236 return props
->retVal
;
240 * Save properties to file.
241 * return: Status code.
243 gint
xmlprops_save_file( XmlProperty
*props
) {
244 cm_return_val_if_fail( props
!= NULL
, -1 );
246 props
->retVal
= MGU_NO_FILE
;
247 if( props
->path
== NULL
|| *props
->path
== '\0' ) return props
->retVal
;
248 xmlprops_write_to( props
, props
->path
);
250 return props
->retVal
;
253 static void xmlprops_save_property(
254 XmlProperty
*props
, const gchar
*name
, const gchar
*value
)
259 if( strlen( name
) == 0 ) return;
260 if( strlen( value
) == 0 ) return;
261 if( g_hash_table_lookup( props
->propertyTable
, name
) ) return;
262 key
= g_strdup( name
);
263 val
= g_strdup( value
);
264 g_hash_table_insert( props
->propertyTable
, key
, val
);
267 #define ATTR_BUFSIZE 256
269 static void xmlprops_read_props( XmlProperty
*props
, XMLFile
*file
) {
276 pName
= g_strdup("");
277 pValue
= g_strdup("");
278 if (! file
->level
) break;
279 xml_parse_next_tag( file
);
280 if( xml_compare_tag( file
, XMLS_ELTAG_PROPERTY
) ) {
281 attr
= xml_get_current_tag_attr( file
);
283 name
= ( ( XMLAttr
* ) attr
->data
)->name
;
284 value
= ( ( XMLAttr
* ) attr
->data
)->value
;
285 if( strcmp( name
, XMLS_ATTAG_NAME
) == 0 ) {
287 pName
= g_strdup( value
);
289 else if( strcmp( name
, XMLS_ATTAG_VALUE
) == 0 ) {
291 pValue
= g_strdup( value
);
293 attr
= g_list_next( attr
);
295 xmlprops_save_property( props
, pName
, pValue
);
305 * Load properties from file.
306 * return: Status code.
308 gint
xmlprops_load_file( XmlProperty
*props
) {
309 XMLFile
*file
= NULL
;
311 cm_return_val_if_fail( props
!= NULL
, -1 );
312 props
->retVal
= MGU_NO_FILE
;
313 file
= xml_open_file( props
->path
);
315 return props
->retVal
;
318 props
->retVal
= MGU_BAD_FORMAT
;
319 if( xml_get_dtd( file
) == 0 ) {
320 if( xml_parse_next_tag( file
) == 0 ) {
321 if( xml_compare_tag( file
, XMLS_ELTAG_PROP_LIST
) ) {
322 xmlprops_read_props( props
, file
);
323 props
->retVal
= MGU_SUCCESS
;
327 xml_close_file( file
);
329 return props
->retVal
;
334 * Enter: props Property object.
335 * name Property name.
336 * value New value to save.
338 void xmlprops_set_property(
339 XmlProperty
*props
, const gchar
*name
, const gchar
*value
)
344 cm_return_if_fail( props
!= NULL
);
345 if( name
== NULL
|| strlen( name
) == 0 ) return;
346 if( value
== NULL
|| strlen( value
) == 0 ) return;
347 val
= g_hash_table_lookup( props
->propertyTable
, name
);
349 key
= g_strdup( name
);
354 val
= g_strdup( value
);
355 g_hash_table_insert( props
->propertyTable
, key
, val
);
359 * Set property to integer value.
360 * Enter: props Property object.
361 * name Property name.
362 * value New value to save.
364 void xmlprops_set_property_i(
365 XmlProperty
*props
, const gchar
*name
, const gint value
)
369 cm_return_if_fail( props
!= NULL
);
370 sprintf( buf
, "%d", value
);
371 xmlprops_set_property( props
, name
, buf
);
375 * Set property to boolean value.
376 * Enter: props Property object.
377 * name Property name.
378 * value New value to save.
380 void xmlprops_set_property_b(
381 XmlProperty
*props
, const gchar
*name
, const gboolean value
)
383 cm_return_if_fail( props
!= NULL
);
385 xmlprops_set_property( props
, name
, "y" );
388 xmlprops_set_property( props
, name
, "n" );
393 * Get property into a buffer.
394 * Enter: props Property object.
395 * name Property name.
396 * Return: value found, or NULL if none. Should be g_free() when done.
398 void xmlprops_get_property_s(
399 XmlProperty
*props
, const gchar
*name
, gchar
*buffer
) {
402 cm_return_if_fail( props
!= NULL
);
403 if( buffer
== NULL
) return;
404 val
= g_hash_table_lookup( props
->propertyTable
, name
);
406 strcpy( buffer
, val
);
411 * Get property as integer value.
412 * Enter: props Property object.
413 * name Property name.
414 * Return: value found, or zero if not found.
416 gint
xmlprops_get_property_i( XmlProperty
*props
, const gchar
*name
) {
422 cm_return_val_if_fail( props
!= NULL
, value
);
423 val
= g_hash_table_lookup( props
->propertyTable
, name
);
426 value
= strtol( val
, &endptr
, 10 );
432 * Get property as boolean value.
433 * Enter: props Property object.
434 * name Property name.
435 * Return: value found, or FALSE if not found.
437 gboolean
xmlprops_get_property_b( XmlProperty
*props
, const gchar
*name
) {
442 cm_return_val_if_fail( props
!= NULL
, value
);
443 val
= g_hash_table_lookup( props
->propertyTable
, name
);
445 value
= ( g_ascii_strcasecmp( val
, "y" ) == 0 );