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