talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

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 }