Index: account.c
===================================================================
--- account.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ account.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -58,4 +58,6 @@
 	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
 	set_setstr( &a->set, "username", user );
+	
+	a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
 	
 	/* This function adds some more settings (and might want to do more
@@ -126,5 +128,5 @@
 			for( a = irc->accounts; a; a = a->next )
 				if( a->prpl == proto &&
-				    a->prpl->cmp_buddynames( handle, a->user ) == 0 )
+				    a->prpl->handle_cmp( handle, a->user ) == 0 )
 					ret = a;
 		}
@@ -190,4 +192,6 @@
 				set_del( &a->set, a->set->key );
 			
+			g_hash_table_destroy( a->nicks );
+			
 			g_free( a->user );
 			g_free( a->pass );
Index: account.h
===================================================================
--- account.h	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ account.h	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -38,4 +38,5 @@
 	
 	set_t *set;
+	GHashTable *nicks;
 	
 	struct irc *irc;
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ bitlbee.h	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -124,4 +124,5 @@
 #include "commands.h"
 #include "account.h"
+#include "nick.h"
 #include "conf.h"
 #include "log.h"
Index: irc.c
===================================================================
--- irc.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ irc.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -204,9 +204,7 @@
 void irc_free(irc_t * irc)
 {
-	account_t *account, *accounttmp;
+	account_t *account;
 	user_t *user, *usertmp;
-	nick_t *nick, *nicktmp;
 	help_t *helpnode, *helpnodetmp;
-	set_t *setnode, *setnodetmp;
 	
 	log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
@@ -252,15 +250,9 @@
 		query_del(irc, irc->queries);
 	
-	if (irc->accounts != NULL) {
-		account = irc->accounts;
-		while (account != NULL) {
-			g_free(account->user);
-			g_free(account->pass);
-			g_free(account->server);
-			accounttmp = account;
-			account = account->next;
-			g_free(accounttmp);
-		}
-	}
+	while (irc->accounts)
+		account_del(irc, irc->accounts);
+	
+	while (irc->set)
+		set_del(&irc->set, irc->set->key);
 	
 	if (irc->users != NULL) {
@@ -287,15 +279,4 @@
 	g_hash_table_destroy(irc->watches);
 	
-	if (irc->nicks != NULL) {
-		nick = irc->nicks;
-		while (nick != NULL) {
-			g_free(nick->nick);
-			g_free(nick->handle);
-					
-			nicktmp = nick;
-			nick = nick->next;
-			g_free(nicktmp);
-		}
-	}
 	if (irc->help != NULL) {
 		helpnode = irc->help;
@@ -306,16 +287,4 @@
 			helpnode = helpnode->next;
 			g_free(helpnodetmp);
-		}
-	}
-	if (irc->set != NULL) {
-		setnode = irc->set;
-		while (setnode != NULL) {
-			g_free(setnode->key);
-			g_free(setnode->def);
-			g_free(setnode->value);
-			
-			setnodetmp = setnode;
-			setnode = setnode->next;
-			g_free(setnodetmp);
 		}
 	}
Index: irc.h
===================================================================
--- irc.h	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ irc.h	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -98,5 +98,5 @@
 
 #include "user.h"
-#include "nick.h"
+// #include "nick.h"
 
 extern GSList *irc_connection_list;
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ irc_commands.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -478,5 +478,6 @@
 		if( u->gc )
 			irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->acc->user,
-			           *u->gc->acc->server ? u->gc->acc->server : "", u->gc->acc->prpl->name );
+			           u->gc->acc->server && *u->gc->acc->server ? u->gc->acc->server : "",
+			           u->gc->acc->prpl->name );
 		else
 			irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
Index: nick.c
===================================================================
--- nick.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ nick.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -2,5 +2,5 @@
   * BitlBee -- An IRC to other IM-networks gateway                     *
   *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  * Copyright 2002-2006 Wilmer van der Gaast and others                *
   \********************************************************************/
 
@@ -27,48 +27,46 @@
 #include "bitlbee.h"
 
-void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick )
-{
-	nick_t *m = NULL, *n = irc->nicks;
-	
-	while( n )
-	{
-		if( ( g_strcasecmp( n->handle, handle ) == 0 ) && n->proto == proto )
-		{
-			g_free( n->nick );
-			n->nick = nick_dup( nick );
-			nick_strip( n->nick );
-			
-			return;
-		}
-		n = ( m = n )->next;	// :-P
-	}
-	
-	if( m )
-		n = m->next = g_new0( nick_t, 1 );
+/* Store handles in lower case and strip spaces, because AIM is braindead. */
+static char *clean_handle( const char *orig )
+{
+	char *new = g_malloc( strlen( orig ) + 1 );
+	int i = 0;
+	
+	do {
+		if (*orig != ' ')
+			new[i++] = tolower( *orig );
+	}
+	while (*(orig++));
+	
+	return new;
+}
+
+void nick_set( account_t *acc, const char *handle, const char *nick )
+{
+	char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 );
+	
+	store_handle = clean_handle( handle );
+	strncpy( store_nick, nick, MAX_NICK_LENGTH );
+	nick_strip( store_nick );
+	
+	g_hash_table_replace( acc->nicks, store_handle, store_nick );
+}
+
+char *nick_get( account_t *acc, const char *handle, const char *realname )
+{
+	static char nick[MAX_NICK_LENGTH+1];
+	char *store_handle, *found_nick;
+	int inf_protection = 256;
+	
+	memset( nick, 0, MAX_NICK_LENGTH + 1 );
+	
+	store_handle = clean_handle( handle );
+	/* Find out if we stored a nick for this person already. If not, try
+	   to generate a sane nick automatically. */
+	if( ( found_nick = g_hash_table_lookup( acc->nicks, store_handle ) ) )
+	{
+		strncpy( nick, found_nick, MAX_NICK_LENGTH );
+	}
 	else
-		n = irc->nicks = g_new0( nick_t, 1 );
-	
-	n->handle = g_strdup( handle );
-	n->proto = proto;
-	n->nick = nick_dup( nick );
-	
-	nick_strip( n->nick );
-}
-
-char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname )
-{
-	static char nick[MAX_NICK_LENGTH+1];
-	nick_t *n = irc->nicks;
-	int inf_protection = 256;
-	
-	memset( nick, 0, MAX_NICK_LENGTH + 1 );
-	
-	while( n && !*nick )
-		if( ( n->proto == proto ) && ( g_strcasecmp( n->handle, handle ) == 0 ) )
-			strcpy( nick, n->nick );
-		else
-			n = n->next;
-	
-	if( !n )
 	{
 		char *s;
@@ -86,9 +84,12 @@
 		
 		nick_strip( nick );
-		if( set_getint( &irc->set, "lcnicks" ) )
+		if( set_getbool( &acc->irc->set, "lcnicks" ) )
 			nick_lc( nick );
 	}
-	
-	while( !nick_ok( nick ) || user_find( irc, nick ) )
+	g_free( store_handle );
+	
+	/* Now, find out if the nick is already in use at the moment, and make
+	   subtle changes to make it unique. */
+	while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
 	{
 		if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
@@ -106,17 +107,17 @@
 			int i;
 			
-			irc_usermsg( irc, "WARNING: Almost had an infinite loop in nick_get()! "
-			                  "This used to be a fatal BitlBee bug, but we tried to fix it. "
-			                  "This message should *never* appear anymore. "
-			                  "If it does, please *do* send us a bug report! "
-			                  "Please send all the following lines in your report:" );
-			
-			irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
+			irc_usermsg( acc->irc, "WARNING: Almost had an infinite loop in nick_get()! "
+			                       "This used to be a fatal BitlBee bug, but we tried to fix it. "
+			                       "This message should *never* appear anymore. "
+			                       "If it does, please *do* send us a bug report! "
+			                       "Please send all the following lines in your report:" );
+			
+			irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
 			for( i = 0; i < MAX_NICK_LENGTH; i ++ )
-				irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
-			
-			irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
-			                  "Good luck, and please don't forget to paste the lines up here "
-			                  "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
+				irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
+			
+			irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
+			                       "Good luck, and please don't forget to paste the lines up here "
+			                       "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
 			
 			g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
@@ -126,28 +127,10 @@
 	}
 	
-	return( nick );
-}
-
-void nick_del( irc_t *irc, const char *nick )
-{
-	nick_t *l = NULL, *n = irc->nicks;
-	
-	while( n )
-	{
-		if( g_strcasecmp( n->nick, nick ) == 0 )
-		{
-			if( l )
-				l->next = n->next;
-			else
-				irc->nicks = n->next;
-			
-			g_free( n->handle );
-			g_free( n->nick );
-			g_free( n );
-			
-			break;
-		}
-		n = (l=n)->next;
-	}
+	return nick;
+}
+
+void nick_del( account_t *acc, const char *handle )
+{
+	g_hash_table_remove( acc->nicks, handle );
 }
 
Index: nick.h
===================================================================
--- nick.h	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ nick.h	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -24,15 +24,7 @@
 */
 
-typedef struct __NICK
-{
-	char *handle;
-	struct prpl *proto;
-	char *nick;
-	struct __NICK *next;
-} nick_t;
-
-void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick );
-char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname );
-void nick_del( irc_t *irc, const char *nick );
+void nick_set( account_t *acc, const char *handle, const char *nick );
+char *nick_get( account_t *acc, const char *handle, const char *realname );
+void nick_del( account_t *acc, const char *handle );
 void nick_strip( char *nick );
 
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/jabber/jabber.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -2380,5 +2380,5 @@
 	ret->alias_buddy = jabber_roster_update;
 	ret->group_buddy = jabber_group_change;
-	ret->cmp_buddynames = g_strcasecmp;
+	ret->handle_cmp = g_strcasecmp;
 
 	register_protocol (ret);
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/msn/msn.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -432,5 +432,5 @@
 	ret->rem_deny = msn_rem_deny;
 	ret->send_typing = msn_send_typing;
-	ret->cmp_buddynames = g_strcasecmp;
+	ret->handle_cmp = g_strcasecmp;
 
 	register_protocol(ret);
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/nogaim.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -366,5 +366,5 @@
 	
 	memset( nick, 0, MAX_NICK_LENGTH + 1 );
-	strcpy( nick, nick_get( gc->irc, handle, gc->acc->prpl, realname ) );
+	strcpy( nick, nick_get( gc->acc, handle, realname ) );
 	
 	u = user_add( gc->irc, nick );
@@ -378,5 +378,5 @@
 		u->user = g_strndup( handle, s - handle );
 	}
-	else if( *gc->acc->server )
+	else if( gc->acc->server )
 	{
 		char *colon;
@@ -778,5 +778,5 @@
 	
 	/* It might be yourself! */
-	if( b->gc->acc->prpl->cmp_buddynames( handle, b->gc->username ) == 0 )
+	if( b->gc->acc->prpl->handle_cmp( handle, b->gc->username ) == 0 )
 	{
 		u = user_find( b->gc->irc, b->gc->irc->nick );
@@ -1062,5 +1062,5 @@
 void bim_add_allow( struct gaim_connection *gc, char *handle )
 {
-	if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL )
+	if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL )
 	{
 		gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) );
@@ -1074,5 +1074,5 @@
 	GSList *l;
 	
-	if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) )
+	if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) )
 	{
 		g_free( l->data );
@@ -1085,5 +1085,5 @@
 void bim_add_block( struct gaim_connection *gc, char *handle )
 {
-	if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL )
+	if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL )
 	{
 		gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) );
@@ -1097,5 +1097,5 @@
 	GSList *l;
 	
-	if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) )
+	if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) )
 	{
 		g_free( l->data );
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/nogaim.h	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -165,5 +165,5 @@
 	
 	/* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */
-	int (* cmp_buddynames) (const char *who1, const char *who2);
+	int (* handle_cmp) (const char *who1, const char *who2);
 };
 
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/oscar/oscar.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -2681,7 +2681,8 @@
 	ret->set_permit_deny = oscar_set_permit_deny;
 	ret->keepalive = oscar_keepalive;
-	ret->cmp_buddynames = aim_sncmp;
 	ret->get_status_string = oscar_get_status_string;
 	ret->send_typing = oscar_send_typing;
+	
+	ret->handle_cmp = aim_sncmp;
 
 	register_protocol(ret);
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ protocols/yahoo/yahoo.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -409,5 +409,6 @@
 	ret->chat_leave = byahoo_chat_leave;
 	ret->chat_open = byahoo_chat_open;
-	ret->cmp_buddynames = g_strcasecmp;
+
+	ret->handle_cmp = g_strcasecmp;
 	
 	register_protocol(ret);
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ root_commands.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -466,5 +466,5 @@
 		else
 		{
-			nick_set( irc, cmd[2], a->gc->acc->prpl, cmd[3] );
+			nick_set( a, cmd[2], cmd[3] );
 		}
 	}
@@ -548,5 +548,5 @@
 		else if( u->send_handler == buddy_send_handler )
 		{
-			nick_set( irc, u->handle, u->gc->acc->prpl, cmd[2] );
+			nick_set( u->gc->acc, u->handle, cmd[2] );
 		}
 		
@@ -569,5 +569,5 @@
 	u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL );
 	user_del( irc, cmd[1] );
-	nick_del( irc, cmd[1] );
+	nick_del( u->gc->acc, u->handle );
 	
 	irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
@@ -879,56 +879,4 @@
 		else
 			irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
-}
-
-static void cmd_import_buddies( irc_t *irc, char **cmd )
-{
-	struct gaim_connection *gc;
-	account_t *a;
-	nick_t *n;
-	
-	if( !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account" );
-		return;
-	}
-	else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return;
-	}
-	
-	if( cmd[2] )
-	{
-		if( g_strcasecmp( cmd[2], "clear" ) == 0 )
-		{
-			user_t *u;
-			
-			/* FIXME: Hmmm, this is actually pretty dangerous code... REMOVEME? :-) */
-			for( u = irc->users; u; u = u->next )
-				if( u->gc == gc )
-				{
-					u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL );
-					user_del( irc, u->nick );
-				}
-			
-			irc_usermsg( irc, "Old buddy list cleared." );
-		}
-		else
-		{
-			irc_usermsg( irc, "Invalid argument: %s", cmd[2] );
-			return;
-		}
-	}
-	
-	for( n = gc->irc->nicks; n; n = n->next )
-	{
-		if( n->proto == gc->acc->prpl && !user_findhandle( gc, n->handle ) )
-		{
-	                gc->acc->prpl->add_buddy( gc, n->handle );
-	                add_buddy( gc, NULL, n->handle, NULL );
-		}
-	}
-	
-	irc_usermsg( irc, "Sent all add requests. Please wait for a while, the server needs some time to handle all the adds." );
 }
 
@@ -951,5 +899,4 @@
 	{ "blist",          0, cmd_blist,          0 },
 	{ "nick",           1, cmd_nick,           0 },
-	{ "import_buddies", 1, cmd_import_buddies, 0 },
 	{ "qlist",          0, cmd_qlist,          0 },
 	{ NULL }
Index: storage_text.c
===================================================================
--- storage_text.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ storage_text.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -113,180 +113,7 @@
 
 		http_decode( s );
-		nick_set( irc, s, prpl, nick );
+		// FIXME!!!! nick_set( irc, s, prpl, nick );
 	}
 	fclose( fp );
-	
-	return STORAGE_OK;
-}
-
-static storage_status_t text_save( irc_t *irc, int overwrite )
-{
-	char s[512];
-	char path[512], new_path[512];
-	char *line;
-	nick_t *n;
-	set_t *set;
-	mode_t ou = umask( 0077 );
-	account_t *a;
-	FILE *fp;
-	char *hash;
-
-	if (!overwrite) {
-		g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
-		if (access( path, F_OK ) != -1)
-			return STORAGE_ALREADY_EXISTS;
-	
-		g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
-		if (access( path, F_OK ) != -1)
-			return STORAGE_ALREADY_EXISTS;
-	}
-	
-	/*\
-	 *  [SH] Nothing should be saved if no password is set, because the
-	 *  password is not set if it was wrong, or if one is not identified
-	 *  yet. This means that a malicious user could easily overwrite
-	 *  files owned by someone else:
-	 *  a Bad Thing, methinks
-	\*/
-
-	/* [WVG] No? Really? */
-
-	/*\
-	 *  [SH] Okay, okay, it wasn't really Wilmer who said that, it was
-	 *  me. I just thought it was funny.
-	\*/
-	
-	hash = hashpass( irc->password );
-	if( hash == NULL )
-	{
-		irc_usermsg( irc, "Please register yourself if you want to save your settings." );
-		return STORAGE_OTHER_ERROR;
-	}
-	
-	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
-	fp = fopen( path, "w" );
-	if( !fp ) return STORAGE_OTHER_ERROR;
-	for( n = irc->nicks; n; n = n->next )
-	{
-		strcpy( s, n->handle );
-		s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
-		http_encode( s );
-		g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick );
-		if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
-		{
-			irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
-			fclose( fp );
-			return STORAGE_OTHER_ERROR;
-		}
-	}
-	if( fclose( fp ) != 0 )
-	{
-		irc_usermsg( irc, "fclose() reported an error. Disk full?" );
-		return STORAGE_OTHER_ERROR;
-	}
-  
-	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
-	if( unlink( new_path ) != 0 )
-	{
-		if( errno != ENOENT )
-		{
-			irc_usermsg( irc, "Error while removing old .nicks file" );
-			return STORAGE_OTHER_ERROR;
-		}
-	}
-	if( rename( path, new_path ) != 0 )
-	{
-		irc_usermsg( irc, "Error while renaming new .nicks file" );
-		return STORAGE_OTHER_ERROR;
-	}
-	
-	g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
-	fp = fopen( path, "w" );
-	if( !fp ) return STORAGE_OTHER_ERROR;
-	if( fprintf( fp, "%s", hash ) != strlen( hash ) )
-	{
-		irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
-		fclose( fp );
-		return STORAGE_OTHER_ERROR;
-	}
-	g_free( hash );
-
-	for( a = irc->accounts; a; a = a->next )
-	{
-		if( !strcmp(a->prpl->name, "oscar") )
-			g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
-		else
-			g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
-			            a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
-		
-		line = obfucrypt( s, irc->password );
-		if( *line )
-		{
-			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
-			{
-				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
-				fclose( fp );
-				return STORAGE_OTHER_ERROR;
-			}
-		}
-		g_free( line );
-	}
-	
-	for( set = irc->set; set; set = set->next )
-	{
-		if( set->value && set->def )
-		{
-			g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
-			line = obfucrypt( s, irc->password );
-			if( *line )
-			{
-				if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
-				{
-					irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
-					fclose( fp );
-					return STORAGE_OTHER_ERROR;
-				}
-			}
-			g_free( line );
-		}
-	}
-	
-	if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
-	{
-		g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
-		line = obfucrypt( s, irc->password );
-		if( *line )
-		{
-			if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
-			{
-				irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
-				fclose( fp );
-				return STORAGE_OTHER_ERROR;
-			}
-		}
-		g_free( line );
-	}
-	if( fclose( fp ) != 0 )
-	{
-		irc_usermsg( irc, "fclose() reported an error. Disk full?" );
-		return STORAGE_OTHER_ERROR;
-	}
-	
- 	g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- 	if( unlink( new_path ) != 0 )
-	{
-		if( errno != ENOENT )
-		{
-			irc_usermsg( irc, "Error while removing old .accounts file" );
-			return STORAGE_OTHER_ERROR;
-		}
-	}
-	if( rename( path, new_path ) != 0 )
-	{
-		irc_usermsg( irc, "Error while renaming new .accounts file" );
-		return STORAGE_OTHER_ERROR;
-	}
-	
-	umask( ou );
 	
 	return STORAGE_OK;
@@ -337,5 +164,4 @@
 	.check_pass = text_check_pass,
 	.remove = text_remove,
-	.load = text_load,
-	.save = text_save
+	.load = text_load
 };
Index: storage_xml.c
===================================================================
--- storage_xml.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ storage_xml.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -197,5 +197,5 @@
 		if( xd->current_account && handle && nick )
 		{
-			nick_set( irc, handle, xd->current_account->prpl, nick );
+			nick_set( xd->current_account, handle, nick );
 		}
 		else
@@ -365,9 +365,10 @@
 }
 
+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;
 	set_t *set;
-	nick_t *nick;
 	account_t *acc;
 	int fd;
@@ -440,8 +441,13 @@
 					goto write_error;
 		
-		for( nick = irc->nicks; nick; nick = nick->next )
-			if( nick->proto == acc->prpl )
-				if( !xml_printf( fd, 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )
-					goto write_error;
+		/* This probably looks pretty strange. g_hash_table_foreach
+		   is quite a PITA already (but it can't get much better in
+		   C without using #define, I'm afraid), and since it
+		   doesn't seem to be possible to abort the foreach on write
+		   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, (gpointer) fd ) )
+			goto write_error;
 		
 		if( !xml_printf( fd, 1, "</account>\n" ) )
@@ -476,4 +482,9 @@
 	
 	return STORAGE_OTHER_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 );
 }
 
Index: user.c
===================================================================
--- user.c	(revision 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b)
+++ user.c	(revision 5b52a4895e5a59ff6509f7771f4d8665737688c3)
@@ -143,14 +143,20 @@
 user_t *user_findhandle( struct gaim_connection *gc, char *handle )
 {
-	user_t *u = gc->irc->users;
-	
-	while( u )
-	{
-		if( u->gc == gc && u->handle && gc->acc->prpl->cmp_buddynames ( u->handle, handle ) == 0 )
-			break;
-		u = u->next;
-	}
-	
-	return( u );
+	user_t *u;
+	char *nick;
+	
+	/* First, let's try a hash lookup. If it works, it's probably faster. */
+	if( ( nick = g_hash_table_lookup( gc->acc->nicks, handle ) ) &&
+	    ( u = user_find( gc->irc, nick ) ) &&
+	    ( gc->acc->prpl->handle_cmp( handle, u->handle ) == 0 ) )
+		return u;
+	
+	/* However, it doesn't always work, so in that case we'll have to dig
+	   through the whole userlist. :-( */
+	for( u = gc->irc->users; u; u = u->next )
+		if( u->gc == gc && u->handle && gc->acc->prpl->handle_cmp( u->handle, handle ) == 0 )
+			return u;
+	
+	return NULL;
 }
 
