Index: account.c
===================================================================
--- account.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ account.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -28,7 +28,10 @@
 #include "account.h"
 
+char *set_eval_account( set_t *set, char *value );
+
 account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
 {
 	account_t *a;
+	set_t *s;
 	
 	if( irc->accounts )
@@ -48,5 +51,59 @@
 	a->irc = irc;
 	
+	s = set_add( &a->set, "auto_connect", NULL, set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE;
+	
+	s = set_add( &a->set, "password", NULL, set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE;
+	
+	s = set_add( &a->set, "server", NULL, set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
+	
+	s = set_add( &a->set, "username", NULL, set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
+	set_setstr( &a->set, "username", user );
+	
 	return( a );
+}
+
+char *set_eval_account( set_t *set, char *value )
+{
+	account_t *acc = set->data;
+	
+	/* Double-check: We refuse to edit on-line accounts. */
+	if( acc->gc )
+		return NULL;
+	
+	if( strcmp( set->key, "username" ) == 0 )
+	{
+		g_free( acc->user );
+		acc->user = g_strdup( value );
+		return value;
+	}
+	else if( strcmp( set->key, "password" ) == 0 )
+	{
+		g_free( acc->pass );
+		acc->pass = g_strdup( value );
+		return NULL;	/* password shouldn't be visible in plaintext! */
+	}
+	else if( strcmp( set->key, "server" ) == 0 )
+	{
+		g_free( acc->server );
+		if( *value )
+			acc->server = g_strdup( value );
+		else
+			acc->server = NULL;
+		return value;
+	}
+	else if( strcmp( set->key, "auto_connect" ) == 0 )
+	{
+		if( !is_bool( value ) )
+			return NULL;
+		
+		acc->auto_connect = bool2int( value );
+		return value;
+	}
+	
+	return NULL;
 }
 
@@ -130,4 +187,7 @@
 			}
 			
+			while( a->set )
+				set_del( &a->set, a->set->key );
+			
 			g_free( a->user );
 			g_free( a->pass );
Index: account.h
===================================================================
--- account.h	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ account.h	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -37,4 +37,6 @@
 	int reconnect;
 	
+	set_t *set;
+	
 	struct irc *irc;
 	struct gaim_connection *gc;
@@ -48,3 +50,6 @@
 void account_off( irc_t *irc, account_t *a );
 
+#define ACC_SET_NOSAVE		1
+#define ACC_SET_OFFLINE_ONLY	2
+
 #endif
Index: lib/misc.c
===================================================================
--- lib/misc.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ lib/misc.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -486,2 +486,36 @@
 	}
 }
+
+int is_bool( char *value )
+{
+	if( *value == 0 )
+		return 0;
+	
+	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
+		return 1;
+	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
+		return 1;
+	
+	while( *value )
+		if( !isdigit( *value ) )
+			return 0;
+		else
+			value ++;
+	
+	return 1;
+}
+
+int bool2int( char *value )
+{
+	int i;
+	
+	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
+		return 1;
+	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
+		return 0;
+	
+	if( sscanf( value, "%d", &i ) == 1 )
+		return i;
+	
+	return 0;
+}
Index: lib/misc.h
===================================================================
--- lib/misc.h	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ lib/misc.h	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -51,3 +51,6 @@
 G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count );
 
+G_MODULE_EXPORT int is_bool( char *value );
+G_MODULE_EXPORT int bool2int( char *value );
+
 #endif
Index: lib/rc4.c
===================================================================
--- lib/rc4.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ lib/rc4.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -165,5 +165,5 @@
 	if( clear_len < 0 )
 	{
-		*clear = g_strdup( "" );
+		*clear = (unsigned char*) g_strdup( "" );
 		return 0;
 	}
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ root_commands.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -232,7 +232,6 @@
 
 		a = account_add( irc, prpl, cmd[3], cmd[4] );
-		
 		if( cmd[5] )
-			a->server = g_strdup( cmd[5] );
+			set_setstr( &a->set, "server", cmd[5] );
 		
 		irc_usermsg( irc, "Account successfully added" );
@@ -358,4 +357,66 @@
 		}
 	}
+	else if( g_strcasecmp( cmd[1], "set" ) == 0 )
+	{
+		char *acc_handle, *set_name = NULL, *tmp;
+		
+		if( !cmd[2] )
+		{
+			irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
+			return;
+		}
+		
+		acc_handle = g_strdup( cmd[2] );
+		if( ( tmp = strchr( acc_handle, '/' ) ) )
+		{
+			*tmp = 0;
+			set_name = tmp + 1;
+		}
+		a = account_get( irc, acc_handle );
+		
+		if( a == NULL )
+		{
+			irc_usermsg( irc, "Invalid account" );
+			return;
+		}
+		
+		if( cmd[3] )
+		{
+			set_t *s = set_find( &a->set, set_name );
+			
+			if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY )
+			{
+				irc_usermsg( irc, "This setting can only be changed when the account is off-line" );
+				return;
+			}
+			
+			set_setstr( &a->set, set_name, cmd[3] );
+			
+			if( ( strcmp( cmd[3], "=" ) ) == 0 && cmd[4] )
+				irc_usermsg( irc, "Warning: Correct syntax: \002account set <variable> <value>\002 (without =)" );
+		}
+		if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
+		{
+			char *s = set_getstr( &a->set, set_name );
+			if( s )
+				irc_usermsg( irc, "%s = `%s'", set_name, s );
+			else
+				irc_usermsg( irc, "%s is empty", set_name );
+		}
+		else
+		{
+			set_t *s = a->set;
+			while( s )
+			{
+				if( s->value || s->def )
+					irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def );
+				else
+					irc_usermsg( irc, "%s is empty", s->key );
+				s = s->next;
+			}
+		}
+		
+		g_free( acc_handle );
+	}
 	else
 	{
@@ -682,4 +743,6 @@
 		if( s )
 			irc_usermsg( irc, "%s = `%s'", cmd[1], s );
+		else
+			irc_usermsg( irc, "%s is empty", cmd[1] );
 	}
 	else
@@ -690,4 +753,6 @@
 			if( s->value || s->def )
 				irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def );
+			else
+				irc_usermsg( irc, "%s is empty", s->key );
 			s = s->next;
 		}
Index: set.c
===================================================================
--- set.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ set.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -101,4 +101,14 @@
 }
 
+int set_getbool( set_t **head, char *key )
+{
+	char *s = set_getstr( head, key );
+	
+	if( !s )
+		return 0;
+	
+	return bool2int( s );
+}
+
 int set_setstr( set_t **head, char *key, char *value )
 {
@@ -166,5 +176,5 @@
 	
 	for( s = value; *s; s ++ )
-		if( *s < '0' || *s > '9' )
+		if( !isdigit( *s ) )
 			return NULL;
 	
@@ -174,9 +184,5 @@
 char *set_eval_bool( set_t *set, char *value )
 {
-	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
-		return( value );
-	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
-		return( value );
-	return( set_eval_int( set, value ) );
+	return is_bool( value ) ? value : NULL;
 }
 
Index: set.h
===================================================================
--- set.h	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ set.h	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -32,4 +32,6 @@
 	char *def;	/* Default */
 	
+	int flags;
+	
 	/* Eval: Returns NULL if the value is incorrect or exactly the
 	   passed value variable. When returning a corrected value,
@@ -40,5 +42,5 @@
 
 set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data );
-G_MODULE_EXPORT set_t *set_find( set_t **head, char *key );
+set_t *set_find( set_t **head, char *key );
 G_MODULE_EXPORT char *set_getstr( set_t **head, char *key );
 G_MODULE_EXPORT int set_getint( set_t **head, char *key );
Index: storage_xml.c
===================================================================
--- storage_xml.c	(revision 0a3c243b6659dc10efb227e507f324c2711d6dcd)
+++ storage_xml.c	(revision 5100caa16bb707d89f1873aca99b5f87abc1dd56)
@@ -157,9 +157,7 @@
 			xd->current_account = account_add( irc, prpl, handle, password );
 			if( server )
-				xd->current_account->server = g_strdup( server );
+				set_setstr( &xd->current_account->set, "server", server );
 			if( autoconnect )
-				/* Return value doesn't matter, since account_add() already sets
-				   a default! */
-				sscanf( autoconnect, "%d", &xd->current_account->auto_connect );
+				set_setstr( &xd->current_account->set, "auto_connect", autoconnect );
 		}
 		else
@@ -176,20 +174,17 @@
 	else if( g_strcasecmp( element_name, "setting" ) == 0 )
 	{
-		if( xd->current_account == NULL )
-		{
-			char *setting;
-			
-			if( xd->current_setting )
-			{
-				g_free( xd->current_setting );
-				xd->current_setting = NULL;
-			}
-			
-			if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
-				xd->current_setting = g_strdup( setting );
-			else
-				g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
-				             "Missing attributes for %s element", element_name );
-		}
+		char *setting;
+		
+		if( xd->current_setting )
+		{
+			g_free( xd->current_setting );
+			xd->current_setting = NULL;
+		}
+		
+		if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
+			xd->current_setting = g_strdup( setting );
+		else
+			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+			             "Missing attributes for %s element", element_name );
 	}
 	else if( g_strcasecmp( element_name, "buddy" ) == 0 )
@@ -243,8 +238,8 @@
 		   yet. */
 	}
-	else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 &&
-	         xd->current_setting && xd->current_account == NULL )
-	{
-		set_setstr( &irc->set, xd->current_setting, (char*) text );
+	else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )
+	{
+		set_setstr( xd->current_account ? &xd->current_account->set : &irc->set,
+		            xd->current_setting, (char*) text );
 		g_free( xd->current_setting );
 		xd->current_setting = NULL;
@@ -348,9 +343,14 @@
 }
 
-static int xml_printf( int fd, char *fmt, ... )
+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 );
@@ -404,5 +404,5 @@
 	pass_buf = base64_encode( (char*) pass_md5, 21 );
 	
-	if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
+	if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
 		goto write_error;
 	
@@ -411,5 +411,5 @@
 	for( set = irc->set; set; set = set->next )
 		if( set->value && set->def )
-			if( !xml_printf( fd, "\t<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
+			if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
 				goto write_error;
 	
@@ -423,5 +423,5 @@
 		g_free( pass_rc4 );
 		
-		if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) )
+		if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) )
 		{
 			g_free( pass_b64 );
@@ -430,19 +430,24 @@
 		g_free( pass_b64 );
 		
-		if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) )
+		if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) )
 			goto write_error;
-		if( !xml_printf( fd, ">\n" ) )
+		if( !xml_printf( fd, 0, ">\n" ) )
 			goto write_error;
+		
+		for( set = acc->set; set; set = set->next )
+			if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) )
+				if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
+					goto write_error;
 		
 		for( nick = irc->nicks; nick; nick = nick->next )
 			if( nick->proto == acc->prpl )
-				if( !xml_printf( fd, "\t\t<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )
+				if( !xml_printf( fd, 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )
 					goto write_error;
 		
-		if( !xml_printf( fd, "\t</account>\n" ) )
+		if( !xml_printf( fd, 1, "</account>\n" ) )
 			goto write_error;
 	}
 	
-	if( !xml_printf( fd, "</user>\n" ) )
+	if( !xml_printf( fd, 0, "</user>\n" ) )
 		goto write_error;
 	
