Index: storage_xml.c
===================================================================
--- storage_xml.c	(revision 0153ba9a0dbed83fa98281f4d1ad34ad08e379b5)
+++ storage_xml.c	(revision a338faa2e8262c62b3c871c547e91654c5d206ef)
@@ -2,5 +2,5 @@
   * 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                *
   \********************************************************************/
 
@@ -29,4 +29,5 @@
 #include "arc.h"
 #include "md5.h"
+#include "xmltree.h"
 
 #include <glib/gstdio.h>
@@ -41,5 +42,5 @@
 
 /* To make it easier later when extending the format: */
-#define XML_FORMAT_VERSION 1
+#define XML_FORMAT_VERSION "1"
 
 struct xml_parsedata
@@ -422,52 +423,15 @@
 }
 
-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 )
-{
-	char path[512], *path2, *pass_buf = NULL;
+struct xt_node *xml_generate( irc_t *irc )
+{
+	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
@@ -482,6 +446,8 @@
 	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 );
@@ -489,6 +455,9 @@
 	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 )
@@ -502,22 +471,22 @@
 		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;
-		}
+		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 );
+		
 		g_free( pass_b64 );
-		
-		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;
 		
 		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
@@ -528,9 +497,7 @@
 		   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;
-		
-		if( !xml_printf( fd, 1, "</account>\n" ) )
-			goto write_error;
+		g_hash_table_find( acc->nicks, xml_save_nick, cur );
+		
+		xt_add_child( root, cur );
 	}
 	
@@ -542,19 +509,46 @@
 			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;
-		
-		if( !xml_printf( fd, 1, "</channel>\n" ) )
-			goto write_error;
-	}
-	
-	if( !xml_printf( fd, 0, "</user>\n" ) )
-		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 );
+			}
+		
+		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;
+	}
+	
+	tree = xml_generate( irc );
+	xml = xt_to_string( tree );
+	write( fd, xml, strlen( xml ) );
 	
 	fsync( fd );
@@ -577,5 +571,4 @@
 
 write_error:
-	g_free( pass_buf );
 	
 	irc_rootmsg( irc, "Write error. Disk full?" );
@@ -587,5 +580,10 @@
 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;
 }
 
