add support for Ayatana indicator to Notification plugin
[claws.git] / src / common / xmlprops.c
blob4a3e1668acb3c26ccf4c70f14f6b2a2ab9240946
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
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:
25 * <property-list>
26 * <property name="first-name" value="Axle" >/
27 * <property name="last-name" value="Rose" >/
28 * </property-list>
30 * ***********************************************************************
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #include "claws-features.h"
36 #endif
38 #include <glib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
43 #include "prefs.h"
44 #include "xml.h"
45 #include "mgutils.h"
46 #include "xmlprops.h"
47 #include "utils.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 {
61 FILE *fp;
62 int error;
63 } HashLoopData;
66 * Create new props.
68 XmlProperty *xmlprops_create( void ) {
69 XmlProperty *props;
71 props = g_new0( XmlProperty, 1 );
72 props->path = NULL;
73 props->encoding = NULL;
74 props->propertyTable = g_hash_table_new( g_str_hash, g_str_equal );
75 props->retVal = MGU_SUCCESS;
76 return props;
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 ) {
91 g_free( key );
92 g_free( value );
93 key = NULL;
94 value = NULL;
95 return TRUE;
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 );
109 * Free props.
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 );
123 props->path = NULL;
124 props->encoding = NULL;
125 props->propertyTable = NULL;
126 props->retVal = 0;
128 g_free( props );
131 static int xmlprops_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
132 gint i;
133 for( i = 0; i < lvl; i++ ) {
134 if(claws_fputs( " ", fp ) == EOF)
135 return -1;
137 if(claws_fputs( "<", fp ) == EOF)
138 return -1;
139 if(claws_fputs( name, fp ) == EOF)
140 return -1;
142 return 0;
145 static int xmlprops_write_elem_e( FILE *fp, gint lvl, gchar *name ) {
146 gint i;
147 for( i = 0; i < lvl; i++ ) {
148 if(claws_fputs( " ", fp ) == EOF)
149 return -1;
151 if(claws_fputs( "</", fp ) == EOF)
152 return -1;
153 if(claws_fputs( name, fp ) == EOF)
154 return -1;
155 if(claws_fputs( ">\n", fp ) == EOF)
156 return -1;
158 return 0;
161 static int xmlprops_write_attr( FILE *fp, gchar *name, gchar *value ) {
162 if(claws_fputs( " ", fp ) == EOF)
163 return -1;
164 if(claws_fputs( name, fp ) == EOF)
165 return -1;
166 if(claws_fputs( "=\"", fp ) == EOF)
167 return -1;
168 if(xml_file_put_escape_str( fp, value ) < 0)
169 return -1;
170 if(claws_fputs( "\"", fp ) == EOF)
171 return -1;
173 return 0;
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)
180 data->error = 1;
181 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_NAME, key ) < 0)
182 data->error = 1;
183 if(xmlprops_write_attr( data->fp, XMLS_ATTAG_VALUE, value ) < 0)
184 data->error = 1;
185 if(claws_fputs( " />\n", data->fp ) == EOF)
186 data->error = 1;
189 static gint xmlprops_write_to( XmlProperty *props, const gchar *fileSpec ) {
190 PrefFile *pfile;
191 FILE *fp;
192 HashLoopData data;
194 props->retVal = MGU_OPEN_FILE;
195 pfile = prefs_write_open( fileSpec );
196 if( pfile ) {
197 fp = pfile->fp;
198 if(fprintf( fp, "<?xml version=\"1.0\"" ) < 0)
199 goto revert;
200 if( props->encoding && *props->encoding ) {
201 if(fprintf( fp, " encoding=\"%s\"", props->encoding ) < 0)
202 goto revert;
204 if(fprintf( fp, " ?>\n" ) < 0)
205 goto revert;
206 if(xmlprops_write_elem_s( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
207 goto revert;
208 if(claws_fputs( ">\n", fp ) == EOF)
209 goto revert;
211 /* Output all properties */
212 data.fp = fp;
213 data.error = 0;
214 g_hash_table_foreach( props->propertyTable, xmlprops_write_vis, &data );
216 if (data.error)
217 goto revert;
219 if(xmlprops_write_elem_e( fp, 0, XMLS_ELTAG_PROP_LIST ) < 0)
220 goto revert;
222 props->retVal = MGU_SUCCESS;
223 if( prefs_file_close( pfile ) < 0 ) {
224 props->retVal = MGU_ERROR_WRITE;
225 goto out;
227 goto out;
228 revert:
229 props->retVal = MGU_ERROR_WRITE;
230 if( prefs_file_close_revert( pfile ) < 0 ) {
231 props->retVal = MGU_ERROR_WRITE;
235 out:
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 )
256 gchar *key;
257 gchar *val;
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 ) {
270 GList *attr;
271 gchar *name, *value;
272 gchar *pName;
273 gchar *pValue;
275 while( TRUE ) {
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 );
282 while( attr ) {
283 name = ( ( XMLAttr * ) attr->data )->name;
284 value = ( ( XMLAttr * ) attr->data )->value;
285 if( strcmp( name, XMLS_ATTAG_NAME ) == 0 ) {
286 g_free(pName);
287 pName = g_strdup( value );
289 else if( strcmp( name, XMLS_ATTAG_VALUE ) == 0 ) {
290 g_free(pValue);
291 pValue = g_strdup( value );
293 attr = g_list_next( attr );
295 xmlprops_save_property( props, pName, pValue );
297 g_free(pName);
298 g_free(pValue);
302 #undef ATTR_BUFSIZE
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 );
314 if( file == NULL ) {
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;
333 * Set property.
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 )
341 gchar *key = NULL;
342 gchar *val;
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 );
348 if( val == NULL ) {
349 key = g_strdup( name );
351 else {
352 g_free( val );
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 )
367 gchar buf[32];
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 );
384 if( value ) {
385 xmlprops_set_property( props, name, "y" );
387 else {
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 ) {
400 gchar *val;
402 cm_return_if_fail( props != NULL );
403 if( buffer == NULL ) return;
404 val = g_hash_table_lookup( props->propertyTable, name );
405 if( val ) {
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 ) {
417 gchar *val;
418 gchar *endptr;
419 gint value;
421 value = 0;
422 cm_return_val_if_fail( props != NULL, value );
423 val = g_hash_table_lookup( props->propertyTable, name );
424 if( val ) {
425 endptr = NULL;
426 value = strtol( val, &endptr, 10 );
428 return value;
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 ) {
438 gchar *val;
439 gboolean value;
441 value = FALSE;
442 cm_return_val_if_fail( props != NULL, value );
443 val = g_hash_table_lookup( props->propertyTable, name );
444 if( val ) {
445 value = ( g_ascii_strcasecmp( val, "y" ) == 0 );
447 return value;
451 * End of Source.