diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2012-06-04 14:55:58 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2012-06-04 14:55:58 +0100 |
commit | a338faa2e8262c62b3c871c547e91654c5d206ef (patch) | |
tree | 54c47844cf33ca4b95bbca089ecf4924bb9cbc2b /storage_xml.c | |
parent | 0153ba9a0dbed83fa98281f4d1ad34ad08e379b5 (diff) |
Use xmltree to save user settings, in preparation for allowing other storage
media than local fs.
Diffstat (limited to 'storage_xml.c')
-rw-r--r-- | storage_xml.c | 148 |
1 files changed, 73 insertions, 75 deletions
diff --git a/storage_xml.c b/storage_xml.c index 566d0021..57bc464c 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2006 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* Storage backend that uses an XMLish format for all data. */ @@ -28,6 +28,7 @@ #include "base64.h" #include "arc.h" #include "md5.h" +#include "xmltree.h" #include <glib/gstdio.h> @@ -40,7 +41,7 @@ typedef enum } xml_pass_st; /* To make it easier later when extending the format: */ -#define XML_FORMAT_VERSION 1 +#define XML_FORMAT_VERSION "1" struct xml_parsedata { @@ -421,54 +422,17 @@ static storage_status_t xml_check_pass( const char *my_nick, const char *passwor return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY ); } -static int xml_printf( int fd, int indent, char *fmt, ... ) -{ - va_list params; - char *out; - char tabs[9] = "\t\t\t\t\t\t\t\t"; - int len; - - /* Maybe not very clean, but who needs more than 8 levels of indentation anyway? */ - if( write( fd, tabs, indent <= 8 ? indent : 8 ) != indent ) - return 0; - - va_start( params, fmt ); - out = g_markup_vprintf_escaped( fmt, params ); - va_end( params ); - - len = strlen( out ); - len -= write( fd, out, len ); - g_free( out ); - - return len == 0; -} - static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ); -static storage_status_t xml_save( irc_t *irc, int overwrite ) +struct xt_node *xml_generate( irc_t *irc ) { - char path[512], *path2, *pass_buf = NULL; + char *pass_buf = NULL; set_t *set; account_t *acc; - int fd; md5_byte_t pass_md5[21]; md5_state_t md5_state; GSList *l; - - path2 = g_strdup( irc->user->nick ); - nick_lc( path2 ); - g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" ); - g_free( path2 ); - - if( !overwrite && g_access( path, F_OK ) == 0 ) - return STORAGE_ALREADY_EXISTS; - - strcat( path, ".XXXXXX" ); - if( ( fd = mkstemp( path ) ) < 0 ) - { - irc_rootmsg( irc, "Error while opening configuration file." ); - return STORAGE_OTHER_ERROR; - } + struct xt_node *root, *cur; /* Generate a salted md5sum of the password. Use 5 bytes for the salt (to prevent dictionary lookups of passwords) to end up with a 21- @@ -481,15 +445,20 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Save the hash in base64-encoded form. */ pass_buf = base64_encode( pass_md5, 21 ); - if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) ) - goto write_error; + root = cur = xt_new_node( "user", NULL, NULL ); + xt_add_attr( cur, "nick", irc->user->nick ); + xt_add_attr( cur, "password", pass_buf ); + xt_add_attr( cur, "version", XML_FORMAT_VERSION ); g_free( pass_buf ); for( set = irc->b->set; set; set = set->next ) if( set->value && !( set->flags & SET_NOSAVE ) ) - if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) - goto write_error; + { + struct xt_node *xset; + xt_add_child( cur, xset = xt_new_node( "setting", set->value, NULL ) ); + xt_add_attr( xset, "name", set->key ); + } for( acc = irc->b->accounts; acc; acc = acc->next ) { @@ -501,24 +470,24 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) pass_b64 = base64_encode( pass_cr, pass_len ); g_free( pass_cr ); - if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" " - "autoconnect=\"%d\" tag=\"%s\"", acc->prpl->name, acc->user, - pass_b64, acc->auto_connect, acc->tag ) ) - { - g_free( pass_b64 ); - goto write_error; - } - g_free( pass_b64 ); + cur = xt_new_node( "account", NULL, NULL ); + xt_add_attr( cur, "protocol", acc->prpl->name ); + xt_add_attr( cur, "handle", acc->user ); + xt_add_attr( cur, "password", pass_b64 ); + xt_add_attr( cur, "autoconnect", acc->auto_connect ? "true" : "false" ); + xt_add_attr( cur, "tag", acc->tag ); + if( acc->server && acc->server[0] ) + xt_add_attr( cur, "server", acc->server ); - if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) ) - goto write_error; - if( !xml_printf( fd, 0, ">\n" ) ) - goto write_error; + g_free( pass_b64 ); for( set = acc->set; set; set = set->next ) if( set->value && !( set->flags & ACC_SET_NOSAVE ) ) - if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) - goto write_error; + { + struct xt_node *xset; + xt_add_child( cur, xset = xt_new_node( "setting", set->value, NULL ) ); + xt_add_attr( xset, "name", set->key ); + } /* This probably looks pretty strange. g_hash_table_foreach is quite a PITA already (but it can't get much better in @@ -527,11 +496,9 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) errors, so instead let's use the _find function and return TRUE on write errors. Which means, if we found something, there was an error. :-) */ - if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) ) - goto write_error; + g_hash_table_find( acc->nicks, xml_save_nick, cur ); - if( !xml_printf( fd, 1, "</account>\n" ) ) - goto write_error; + xt_add_child( root, cur ); } for( l = irc->channels; l; l = l->next ) @@ -541,21 +508,48 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) if( ic->flags & IRC_CHANNEL_TEMP ) continue; - if( !xml_printf( fd, 1, "<channel name=\"%s\" type=\"%s\">\n", - ic->name, set_getstr( &ic->set, "type" ) ) ) - goto write_error; + cur = xt_new_node( "channel", NULL, NULL ); + xt_add_attr( cur, "name", ic->name ); + xt_add_attr( cur, "type", set_getstr( &ic->set, "type" ) ); for( set = ic->set; set; set = set->next ) if( set->value && strcmp( set->key, "type" ) != 0 ) - if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) - goto write_error; + { + struct xt_node *xset; + xt_add_child( cur, xset = xt_new_node( "setting", set->value, NULL ) ); + xt_add_attr( xset, "name", set->key ); + } - if( !xml_printf( fd, 1, "</channel>\n" ) ) - goto write_error; + xt_add_child( root, cur ); + } + + return root; +} + +static storage_status_t xml_save( irc_t *irc, int overwrite ) +{ + char path[512], *path2, *xml; + struct xt_node *tree; + int fd; + + path2 = g_strdup( irc->user->nick ); + nick_lc( path2 ); + g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" ); + g_free( path2 ); + + if( !overwrite && g_access( path, F_OK ) == 0 ) + return STORAGE_ALREADY_EXISTS; + + strcat( path, ".XXXXXX" ); + if( ( fd = mkstemp( path ) ) < 0 ) + { + irc_rootmsg( irc, "Error while opening configuration file." ); + return STORAGE_OTHER_ERROR; } - if( !xml_printf( fd, 0, "</user>\n" ) ) - goto write_error; + tree = xml_generate( irc ); + xml = xt_to_string( tree ); + write( fd, xml, strlen( xml ) ); fsync( fd ); close( fd ); @@ -576,7 +570,6 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OK; write_error: - g_free( pass_buf ); irc_rootmsg( irc, "Write error. Disk full?" ); close( fd ); @@ -586,7 +579,12 @@ write_error: static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ) { - return !xml_printf( *( (int*) data ), 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", key, value ); + struct xt_node *node = xt_new_node( "buddy", NULL, NULL ); + xt_add_attr( node, "handle", key ); + xt_add_attr( node, "nick", value ); + xt_add_child( (struct xt_node *) data, node ); + + return FALSE; } static storage_status_t xml_remove( const char *nick, const char *password ) |