Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ bitlbee.h	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -116,5 +116,5 @@
 	help_t *help;
 	conf_t *conf;
-	storage_t *storage;
+	GList *storage; /* The first backend in the list will be used for saving */
 	char *helpfile;
 	GMainLoop *loop;
Index: commands.c
===================================================================
--- commands.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ commands.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -86,5 +86,5 @@
 int cmd_identify( irc_t *irc, char **cmd )
 {
-	storage_status_t status = global.storage->load( irc->nick, cmd[1], irc );
+	storage_status_t status = storage_load( irc->nick, cmd[1], irc );
 	
 	switch (status) {
@@ -102,5 +102,5 @@
 		break;
 	}
-	
+
 	return( 0 );
 }
@@ -115,5 +115,5 @@
 
 	irc_setpass( irc, cmd[1] );
-	switch( global.storage->save( irc, FALSE )) {
+	switch( storage_save( irc, FALSE )) {
 		case STORAGE_ALREADY_EXISTS:
 			irc_usermsg( irc, "Nick is already registered" );
@@ -136,5 +136,5 @@
 	storage_status_t status;
 	
-	status = global.storage->remove (irc->nick, cmd[1]);
+	status = storage_remove (irc->nick, cmd[1]);
 	switch (status) {
 	case STORAGE_NO_SUCH_USER:
@@ -616,5 +616,5 @@
 int cmd_save( irc_t *irc, char **cmd )
 {
-	if( global.storage->save( irc, TRUE ) == STORAGE_OK )
+	if( storage_save( irc, TRUE ) == STORAGE_OK )
 		irc_usermsg( irc, "Configuration saved" );
 	else
Index: conf.c
===================================================================
--- conf.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ conf.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -50,5 +50,5 @@
 	conf->nofork = 0;
 	conf->verbose = 0;
-	conf->storage = "text";
+	conf->primary_storage = "text";
 	conf->runmode = RUNMODE_INETD;
 	conf->authmode = AUTHMODE_OPEN;
@@ -199,8 +199,13 @@
 				conf->motdfile = g_strdup( ini->value );
 			}
-			else if( g_strcasecmp( ini->key, "storage" ) == 0 )
-			{
-				g_free( conf->storage );
-				conf->storage = g_strdup( ini->value );
+			else if( g_strcasecmp( ini->key, "account_storage" ) == 0 )
+			{
+				g_free( conf->primary_storage );
+				conf->primary_storage = g_strdup( ini->value );
+			}
+			else if( g_strcasecmp( ini->key, "account_storage_migrate" ) == 0 )
+			{
+				g_strfreev( conf->migrate_storage );
+				conf->migrate_storage = g_strsplit( ini->value, " \t,;", -1 );
 			}
 			else if( g_strcasecmp( ini->key, "pinginterval" ) == 0 )
Index: conf.h
===================================================================
--- conf.h	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ conf.h	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -42,5 +42,6 @@
 	char *configdir;
 	char *motdfile;
-	char *storage;
+	char *primary_storage;
+	char **migrate_storage;
 	int ping_interval;
 	int ping_timeout;
Index: crypting.c
===================================================================
--- crypting.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ crypting.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -29,8 +29,4 @@
    the programs will be built. */
 
-#ifndef CRYPTING_MAIN
-#define BITLBEE_CORE
-#include "bitlbee.h"
-#include "irc.h"
 #include "md5.h"
 #include "crypting.h"
@@ -38,19 +34,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-
-#else
-
-typedef struct irc
-{
-	char *password;
-} irc_t;
-
-#include "md5.h"
-#include "crypting.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#endif
 
 /*\
@@ -83,5 +64,6 @@
 
 
-char *hashpass (irc_t *irc) {
+char *hashpass (const char *password)
+{
 	md5_state_t md5state;
 	md5_byte_t digest[16];
@@ -90,11 +72,10 @@
 	char *rv;
 	
-	if (irc->password == NULL) return (NULL);
+	if (password == NULL) return (NULL);
 	
-	rv = (char *)g_malloc (33);
-	memset (rv, 0, 33);
+	rv = g_new0 (char, 33);
 	
 	md5_init (&md5state);
-	md5_append (&md5state, (unsigned char *)irc->password, strlen (irc->password));
+	md5_append (&md5state, (const unsigned char *)password, strlen (password));
 	md5_finish (&md5state, digest);
 	
@@ -108,12 +89,12 @@
 }
 
-char *obfucrypt (irc_t *irc, char *line) 
+char *obfucrypt (char *line, const char *password) 
 {
 	int i, j;
 	char *rv;
 	
-	if (irc->password == NULL) return (NULL);
+	if (password == NULL) return (NULL);
 	
-	rv = g_new0(char, strlen (line) + 1);
+	rv = g_new0 (char, strlen (line) + 1);
 	
 	i = j = 0;
@@ -121,10 +102,9 @@
 		/* Encrypt/obfuscate the line, using the password */
 		if (*(signed char*)line < 0) *line = - (*line);
-		if (((signed char*)irc->password)[i] < 0) irc->password[i] = - irc->password[i];
 		
-		rv[j] = *line + irc->password[i]; /* Overflow intended */
+		rv[j] = *line + password[i]; /* Overflow intended */
 		
 		line++;
-		if (!irc->password[++i]) i = 0;
+		if (!password[++i]) i = 0;
 		j++;
 	}
@@ -133,20 +113,20 @@
 }
 
-char *deobfucrypt (irc_t *irc, char *line) 
+char *deobfucrypt (char *line, const char *password) 
 {
 	int i, j;
 	char *rv;
 	
-	if (irc->password == NULL) return (NULL);
+	if (password == NULL) return (NULL);
 	
-	rv = g_new0(char, strlen (line) + 1);
+	rv = g_new0 (char, strlen (line) + 1);
 	
 	i = j = 0;
 	while (*line) {
 		/* Decrypt/deobfuscate the line, using the pass */
-		rv[j] = *line - irc->password[i]; /* Overflow intended */
+		rv[j] = *line - password[i]; /* Overflow intended */
 		
 		line++;
-		if (!irc->password[++i]) i = 0;
+		if (!password[++i]) i = 0;
 		j++;
 	}
@@ -162,7 +142,6 @@
 int main( int argc, char *argv[] )
 {
-	irc_t *irc = g_new0( irc_t, 1 );
 	char *hash, *action, line[256];
-	char* (*func)( irc_t *, char * );
+	char* (*func)( char *, const char * );
 	
 	if( argc < 2 )
@@ -174,7 +153,5 @@
 	}
 	
-	irc->password = g_strdup( argv[1] );
-	
-	hash = hashpass( irc );
+	hash = hashpass( argv[1] );
 	action = argv[0] + strlen( argv[0] ) - strlen( "encode" );
 	
@@ -208,5 +185,5 @@
 		fgetc( stdin );
 		
-		out = func( irc, line );
+		out = func( line, argv[1] );
 		printf( "%s\n", out );
 		g_free( out );
Index: crypting.h
===================================================================
--- crypting.h	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ crypting.h	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -25,5 +25,5 @@
 
 int checkpass (const char *password, const char *md5sum);
-char *hashpass (irc_t *irc);
-char *obfucrypt (irc_t *irc, char *line);
-char *deobfucrypt (irc_t *irc, char *line);
+char *hashpass (const char *password);
+char *obfucrypt (char *line, const char *password);
+char *deobfucrypt (char *line, const char *password);
Index: irc.c
===================================================================
--- irc.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ irc.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -161,5 +161,5 @@
 	
 	if( irc->status >= USTATUS_IDENTIFIED && set_getint( irc, "save_on_quit" ) ) 
-		if( !global.storage->save( irc, TRUE ) )
+		if( storage_save( irc, TRUE ) != STORAGE_OK )
 			irc_usermsg( irc, "Error while saving settings!" );
 	
Index: storage.c
===================================================================
--- storage.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ storage.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -38,5 +38,5 @@
 }
 
-storage_t *storage_init(const char *name)
+static storage_t *storage_init_single(const char *name)
 {
 	GList *gl;
@@ -57,2 +57,129 @@
 	return st;
 }
+
+GList *storage_init(const char *primary, char **migrate)
+{
+	GList *ret = NULL;
+	int i;
+	storage_t *storage;
+
+	storage = storage_init_single(primary);
+	if (storage == NULL)
+		return NULL;
+
+	ret = g_list_append(ret, storage);
+
+	for (i = 0; migrate && migrate[i]; i++) {
+		storage = storage_init_single(migrate[i]);
+	
+		if (storage)
+			ret = g_list_append(ret, storage);
+	}
+
+	return ret;
+}
+
+storage_status_t storage_check_pass (const char *nick, const char *password)
+{
+	GList *gl;
+	
+	/* Loop until we don't get NO_SUCH_USER */
+
+	for (gl = global.storage; gl; gl = gl->next) {
+		storage_t *st = gl->data;
+		storage_status_t status;
+
+		status = st->check_pass(nick, password);
+		if (status != STORAGE_NO_SUCH_USER)
+			return status;
+	}
+	
+	return STORAGE_NO_SUCH_USER;
+}
+
+storage_status_t storage_load (const char *nick, const char *password, irc_t * irc)
+{
+	GList *gl;
+	
+	/* Loop until we don't get NO_SUCH_USER */
+	for (gl = global.storage; gl; gl = gl->next) {
+		storage_t *st = gl->data;
+		storage_status_t status;
+
+		status = st->load(nick, password, irc);
+		if (status == STORAGE_OK) {
+			irc_setpass(irc, password);
+			return status;
+		}
+		
+		if (status != STORAGE_NO_SUCH_USER) 
+			return status;
+	}
+	
+	return STORAGE_NO_SUCH_USER;
+}
+
+storage_status_t storage_save (irc_t *irc, int overwrite)
+{
+	return ((storage_t *)global.storage->data)->save(irc, overwrite);
+}
+
+storage_status_t storage_remove (const char *nick, const char *password)
+{
+	GList *gl;
+	storage_status_t ret = STORAGE_OK;
+	
+	/* Remove this account from all storage backends. If this isn't 
+	 * done, the account will still be usable, it'd just be 
+	 * loaded from a different backend. */
+	for (gl = global.storage; gl; gl = gl->next) {
+		storage_t *st = gl->data;
+		storage_status_t status;
+
+		status = st->remove(nick, password);
+		if (status != STORAGE_NO_SUCH_USER && 
+			status != STORAGE_OK)
+			ret = status;
+	}
+	
+	return ret;
+}
+
+storage_status_t storage_rename (const char *onick, const char *nnick, const char *password)
+{
+	storage_status_t status;
+	GList *gl = global.storage;
+	storage_t *primary_storage = gl->data;
+	irc_t *irc;
+
+	/* First, try to rename in the current write backend, assuming onick 
+	 * is stored there */
+	status = primary_storage->rename(onick, nnick, password);
+	if (status != STORAGE_NO_SUCH_USER)
+		return status;
+
+	/* Try to load from a migration backend and save to the current backend. 
+	 * Explicitly remove the account from the migration backend as otherwise 
+	 * it'd still be usable under the old name */
+	
+	irc = g_new0(irc_t, 1);
+	status = storage_load(onick, password, irc);
+	if (status != STORAGE_OK) {
+		irc_free(irc);
+		return status;
+	}
+
+	g_free(irc->nick);
+	irc->nick = g_strdup(nnick);
+
+	status = storage_save(irc, FALSE);
+	if (status != STORAGE_OK) {
+		irc_free(irc);
+		return status;
+	}
+	irc_free(irc);
+
+	storage_remove(onick, password);
+
+	return STORAGE_OK;
+}
Index: storage.h
===================================================================
--- storage.h	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ storage.h	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -53,6 +53,14 @@
 } storage_t;
 
+storage_status_t storage_check_pass (const char *nick, const char *password);
+
+storage_status_t storage_load (const char *nick, const char *password, irc_t * irc);
+storage_status_t storage_save (irc_t *irc, int overwrite);
+storage_status_t storage_remove (const char *nick, const char *password);
+
+storage_status_t storage_rename (const char *onick, const char *nnick, const char *password);
+
 void register_storage_backend(storage_t *);
-storage_t *storage_init(const char *name);
+GList *storage_init(const char *primary, char **migrate);
 
 #endif /* __STORAGE_H__ */
Index: storage_text.c
===================================================================
--- storage_text.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ storage_text.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -67,5 +67,6 @@
 	{
 		fgetc( fp );
-		line = deobfucrypt( irc, s );
+		line = deobfucrypt( s, password );
+		if (line == NULL) return STORAGE_OTHER_ERROR;
 		root_command_string( irc, ru, line, 0 );
 		g_free( line );
@@ -129,9 +130,9 @@
 	\*/
 	
-	hash = hashpass( irc );
+	hash = hashpass( irc->password );
 	if( hash == NULL )
 	{
 		irc_usermsg( irc, "Please register yourself if you want to save your settings." );
-		return( 0 );
+		return STORAGE_OTHER_ERROR;
 	}
 	
@@ -192,5 +193,5 @@
 			            proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" );
 		
-		line = obfucrypt( irc, s );
+		line = obfucrypt( s, irc->password );
 		if( *line )
 		{
@@ -210,5 +211,5 @@
 		{
 			g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
-			line = obfucrypt( irc, s );
+			line = obfucrypt( s, irc->password );
 			if( *line )
 			{
@@ -227,5 +228,5 @@
 	{
 		g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
-		line = obfucrypt( irc, s );
+		line = obfucrypt( s, irc->password );
 		if( *line )
 		{
@@ -270,5 +271,5 @@
 	FILE *fp;
 	
-	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
+	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
 	fp = fopen( s, "r" );
 	if (!fp)
Index: unix.c
===================================================================
--- unix.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
+++ unix.c	(revision 6aaa2213588f7c4c00a68c5622f6974679eaf196)
@@ -72,7 +72,8 @@
 		return( i );
 
-	global.storage = storage_init( global.conf->storage );
+	global.storage = storage_init( global.conf->primary_storage, 
+								   global.conf->migrate_storage );
 	if ( global.storage == NULL) {
-		log_message( LOGLVL_ERROR, "No such storage backend '%s'", global.conf->storage );
+		log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
 		return( 1 );
 	}
