Index: Makefile
===================================================================
--- Makefile	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ Makefile	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -10,5 +10,6 @@
 
 # Program variables
-objects = account.o bitlbee.o chat.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
+#objects = bitlbee.o chat.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
+objects = bitlbee.o help.o ipc.o irc.o irc_commands.o irc_send.o irc_user.o nick.o set.o
 headers = account.h bitlbee.h commands.h conf.h config.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
 subdirs = lib protocols
Index: count.c
===================================================================
--- account.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,359 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2010 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Account management functions                                         */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#define BITLBEE_CORE
-#include "bitlbee.h"
-#include "account.h"
-#include "chat.h"
-
-account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
-{
-	account_t *a;
-	set_t *s;
-	
-	if( irc->accounts )
-	{
-		for( a = irc->accounts; a->next; a = a->next );
-		a = a->next = g_new0( account_t, 1 );
-	}
-	else
-	{
-		irc->accounts = a = g_new0 ( account_t, 1 );
-	}
-	
-	a->prpl = prpl;
-	a->user = g_strdup( user );
-	a->pass = g_strdup( pass );
-	a->auto_connect = 1;
-	a->irc = irc;
-	
-	s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
-	s->flags |= ACC_SET_NOSAVE;
-	
-	s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
-	
-	s = set_add( &a->set, "nick_source", "handle", NULL, a );
-	
-	s = set_add( &a->set, "password", NULL, set_eval_account, a );
-	s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
-	
-	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 );
-	
-	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
-	   things that have to be done now, although I can't think of anything. */
-	if( prpl->init )
-		prpl->init( a );
-	
-	s = set_add( &a->set, "away", NULL, set_eval_account, a );
-	s->flags |= SET_NULL_OK;
-	
-	if( a->flags & ACC_FLAG_STATUS_MESSAGE )
-	{
-		s = set_add( &a->set, "status", NULL, set_eval_account, a );
-		s->flags |= SET_NULL_OK;
-	}
-	
-	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( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
-		return SET_INVALID;
-	
-	if( strcmp( set->key, "server" ) == 0 )
-	{
-		g_free( acc->server );
-		if( value && *value )
-		{
-			acc->server = g_strdup( value );
-			return value;
-		}
-		else
-		{
-			acc->server = g_strdup( set->def );
-			return g_strdup( set->def );
-		}
-	}
-	else if( strcmp( set->key, "username" ) == 0 )
-	{
-		g_free( acc->user );
-		acc->user = g_strdup( value );
-		return value;
-	}
-	else if( strcmp( set->key, "password" ) == 0 )
-	{
-		if( value )
-		{
-			g_free( acc->pass );
-			acc->pass = g_strdup( value );
-			return NULL;	/* password shouldn't be visible in plaintext! */
-		}
-		else
-		{
-			/* NULL can (should) be stored in the set_t
-			   variable, but is otherwise not correct. */
-			return SET_INVALID;
-		}
-	}
-	else if( strcmp( set->key, "auto_connect" ) == 0 )
-	{
-		if( !is_bool( value ) )
-			return SET_INVALID;
-		
-		acc->auto_connect = bool2int( value );
-		return value;
-	}
-	else if( strcmp( set->key, "away" ) == 0 ||
-	         strcmp( set->key, "status" ) == 0 )
-	{
-		if( acc->ic && acc->ic->flags & OPT_LOGGED_IN )
-		{
-			/* If we're currently on-line, set the var now already
-			   (bit of a hack) and send an update. */
-			g_free( set->value );
-			set->value = g_strdup( value );
-			
-			imc_away_send_update( acc->ic );
-		}
-		
-		return value;
-	}
-	
-	return SET_INVALID;
-}
-
-account_t *account_get( irc_t *irc, char *id )
-{
-	account_t *a, *ret = NULL;
-	char *handle, *s;
-	int nr;
-	
-	/* This checks if the id string ends with (...) */
-	if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
-	{
-		struct prpl *proto;
-		
-		*s = *handle = 0;
-		handle ++;
-		
-		if( ( proto = find_protocol( id ) ) )
-		{
-			for( a = irc->accounts; a; a = a->next )
-				if( a->prpl == proto &&
-				    a->prpl->handle_cmp( handle, a->user ) == 0 )
-					ret = a;
-		}
-		
-		/* Restore the string. */
-		handle --;
-		*handle = '(';
-		*s = ')';
-		
-		if( ret )
-			return ret;
-	}
-	
-	if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
-	{
-		for( a = irc->accounts; a; a = a->next )
-			if( ( nr-- ) == 0 )
-				return( a );
-		
-		return( NULL );
-	}
-	
-	for( a = irc->accounts; a; a = a->next )
-	{
-		if( g_strcasecmp( id, a->prpl->name ) == 0 )
-		{
-			if( !ret )
-				ret = a;
-			else
-				return( NULL ); /* We don't want to match more than one... */
-		}
-		else if( strstr( a->user, id ) )
-		{
-			if( !ret )
-				ret = a;
-			else
-				return( NULL );
-		}
-	}
-	
-	return( ret );
-}
-
-void account_del( irc_t *irc, account_t *acc )
-{
-	account_t *a, *l = NULL;
-	struct chat *c, *nc;
-	
-	if( acc->ic )
-		/* Caller should have checked, accounts still in use can't be deleted. */
-		return;
-	
-	for( a = irc->accounts; a; a = (l=a)->next )
-		if( a == acc )
-		{
-			if( l )
-				l->next = a->next;
-			else
-				irc->accounts = a->next;
-			
-			for( c = irc->chatrooms; c; c = nc )
-			{
-				nc = c->next;
-				if( acc == c->acc )
-					chat_del( irc, c );
-			}
-			
-			while( a->set )
-				set_del( &a->set, a->set->key );
-			
-			g_hash_table_destroy( a->nicks );
-			
-			g_free( a->user );
-			g_free( a->pass );
-			g_free( a->server );
-			if( a->reconnect )	/* This prevents any reconnect still queued to happen */
-				cancel_auto_reconnect( a );
-			g_free( a );
-			
-			break;
-		}
-}
-
-void account_on( irc_t *irc, account_t *a )
-{
-	if( a->ic )
-	{
-		/* Trying to enable an already-enabled account */
-		return;
-	}
-	
-	cancel_auto_reconnect( a );
-	
-	a->reconnect = 0;
-	a->prpl->login( a );
-}
-
-void account_off( irc_t *irc, account_t *a )
-{
-	imc_logout( a->ic, FALSE );
-	a->ic = NULL;
-	if( a->reconnect )
-	{
-		/* Shouldn't happen */
-		cancel_auto_reconnect( a );
-	}
-}
-
-struct account_reconnect_delay
-{
-	int start;
-	char op;
-	int step;
-	int max;
-};
-
-int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
-{
-	memset( p, 0, sizeof( *p ) );
-	/* A whole day seems like a sane "maximum maximum". */
-	p->max = 86400;
-	
-	/* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */
-	while( *value && isdigit( *value ) )
-		p->start = p->start * 10 + *value++ - '0';
-	
-	/* Sure, call me evil for implementing my own fscanf here, but it's
-	   dead simple and I immediately know where to continue parsing. */
-	
-	if( *value == 0 )
-		/* If the string ends now, the delay is constant. */
-		return 1;
-	else if( *value != '+' && *value != '*' )
-		/* Otherwise allow either a + or a * */
-		return 0;
-	
-	p->op = *value++;
-	
-	/* + or * the delay by this number every time. */
-	while( *value && isdigit( *value ) )
-		p->step = p->step * 10 + *value++ - '0';
-	
-	if( *value == 0 )
-		/* Use the default maximum (one day). */
-		return 1;
-	else if( *value != '<' )
-		return 0;
-	
-	p->max = 0;
-	value ++;
-	while( *value && isdigit( *value ) )
-		p->max = p->max * 10 + *value++ - '0';
-	
-	return p->max > 0;
-}
-
-char *set_eval_account_reconnect_delay( set_t *set, char *value )
-{
-	struct account_reconnect_delay p;
-	
-	return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
-}
-
-int account_reconnect_delay( account_t *a )
-{
-	char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
-	struct account_reconnect_delay p;
-	
-	if( account_reconnect_delay_parse( setting, &p ) )
-	{
-		if( a->auto_reconnect_delay == 0 )
-			a->auto_reconnect_delay = p.start;
-		else if( p.op == '+' )
-			a->auto_reconnect_delay += p.step;
-		else if( p.op == '*' )
-			a->auto_reconnect_delay *= p.step;
-		
-		if( a->auto_reconnect_delay > p.max )
-			a->auto_reconnect_delay = p.max;
-	}
-	else
-	{
-		a->auto_reconnect_delay = 0;
-	}
-	
-	return a->auto_reconnect_delay;
-}
Index: count.h
===================================================================
--- account.h	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,72 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Account management functions                                         */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef _ACCOUNT_H
-#define _ACCOUNT_H
-
-typedef struct account
-{
-	struct prpl *prpl;
-	char *user;
-	char *pass;
-	char *server;
-	
-	int auto_connect;
-	int auto_reconnect_delay;
-	int reconnect;
-	int flags;
-	
-	set_t *set;
-	GHashTable *nicks;
-	
-	struct irc *irc;
-	struct im_connection *ic;
-	struct account *next;
-} account_t;
-
-account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass );
-account_t *account_get( irc_t *irc, char *id );
-void account_del( irc_t *irc, account_t *acc );
-void account_on( irc_t *irc, account_t *a );
-void account_off( irc_t *irc, account_t *a );
-
-char *set_eval_account( set_t *set, char *value );
-char *set_eval_account_reconnect_delay( set_t *set, char *value );
-int account_reconnect_delay( account_t *a );
-
-typedef enum
-{
-	ACC_SET_NOSAVE = 0x01,          /* Don't save this setting (i.e. stored elsewhere). */
-	ACC_SET_OFFLINE_ONLY = 0x02,    /* Allow changes only if the acct is offline. */
-	ACC_SET_ONLINE_ONLY = 0x04,     /* Allow changes only if the acct is online. */
-} account_set_flag_t;
-
-typedef enum
-{
-	ACC_FLAG_AWAY_MESSAGE = 0x01,   /* Supports away messages instead of just states. */
-	ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
-} account_flag_t;
-
-#endif
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ bitlbee.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -124,4 +124,5 @@
 #define CONF_FILE_DEF ETCDIR "bitlbee.conf"
 
+#include "bee.h"
 #include "irc.h"
 #include "storage.h"
@@ -158,5 +159,5 @@
 gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond );
 
-void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
+//void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
 void root_command( irc_t *irc, char *command[] );
 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
Index: at.c
===================================================================
--- chat.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,192 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2008 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Keep track of chatrooms the user is interested in                    */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include "bitlbee.h"
-#include "chat.h"
-
-struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel )
-{
-	struct chat *c, *l;
-	set_t *s;
-
-	if( acc->prpl->chat_join == NULL || !chat_chanok( channel ) ||
-	    chat_chancmp( channel, irc->channel ) == 0 )
-	{
-		return NULL;
-	}
-	
-	for( c = irc->chatrooms; c; c = c->next )
-	{
-		if( chat_chancmp( channel, c->channel ) == 0 )
-			return NULL;
-		
-		if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
-			return NULL;
-		
-		l = c;
-	}
-	
-	if( irc->chatrooms == NULL )
-		irc->chatrooms = c = g_new0( struct chat, 1 );
-	else
-		l->next = c = g_new0( struct chat, 1 );
-	
-	c->acc = acc;
-	c->handle = g_strdup( handle );
-	c->channel = g_strdup( channel );
-	
-	s = set_add( &c->set, "auto_join", "false", set_eval_bool, c );
-	/* s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); */
-	s = set_add( &c->set, "nick", NULL, NULL, c );
-	s->flags |= SET_NULL_OK;
-	
-	return c;
-}
-
-struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle )
-{
-	struct chat *c;
-	
-	for( c = irc->chatrooms; c; c = c->next )
-	{
-		if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
-			break;
-	}
-	
-	return c;
-}
-
-struct chat *chat_bychannel( irc_t *irc, char *channel )
-{
-	struct chat *c;
-	
-	for( c = irc->chatrooms; c; c = c->next )
-	{
-		if( chat_chancmp( channel, c->channel ) == 0 )
-			break;
-	}
-	
-	return c;
-}
-
-struct chat *chat_get( irc_t *irc, char *id )
-{
-	struct chat *c, *ret = NULL;
-	int nr;
-	
-	if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
-	{
-		for( c = irc->chatrooms; c; c = c->next )
-			if( ( nr-- ) == 0 )
-				return c;
-		
-		return NULL;
-	}
-	
-	for( c = irc->chatrooms; c; c = c->next )
-	{
-		if( strstr( c->handle, id ) )
-		{
-			if( !ret )
-				ret = c;
-			else
-				return NULL;
-		}
-		else if( strstr( c->channel, id ) )
-		{
-			if( !ret )
-				ret = c;
-			else
-				return NULL;
-		}
-	}
-	
-	return ret;
-}
-
-int chat_del( irc_t *irc, struct chat *chat )
-{
-	struct chat *c, *l = NULL;
-	
-	for( c = irc->chatrooms; c; c = (l=c)->next )
-		if( c == chat )
-			break;
-	
-	if( c == NULL )
-		return 0;
-	else if( l == NULL )
-		irc->chatrooms = c->next;
-	else
-		l->next = c->next;
-	
-	while( c->set )
-		set_del( &c->set, c->set->key );
-	
-	g_free( c->handle );
-	g_free( c->channel );
-	g_free( c );
-	
-	return 1;
-}
-
-int chat_chancmp( char *a, char *b )
-{
-	if( !chat_chanok( a ) || !chat_chanok( b ) )
-		return 0;
-	
-	if( a[0] == b[0] )
-		return nick_cmp( a + 1, b + 1 );
-	else
-		return -1;
-}
-
-int chat_chanok( char *a )
-{
-	if( strchr( CTYPES, a[0] ) != NULL )
-		return nick_ok( a + 1 );
-	else
-		return 0;
-}
-
-int chat_join( irc_t *irc, struct chat *c, const char *password )
-{
-	struct groupchat *gc;
-	char *nick = set_getstr( &c->set, "nick" );
-
-	if( c->acc->ic == NULL || c->acc->prpl->chat_join == NULL )
-		return 0;
-	
-	if( nick == NULL )
-		nick = irc->nick;
-	
-	if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) )
-	{
-		g_free( gc->channel );
-		gc->channel = g_strdup( c->channel );
-		return 1;
-	}
-	
-	return 0;
-}
Index: at.h
===================================================================
--- chat.h	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,51 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2008 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Keep track of chatrooms the user is interested in                    */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef _CHAT_H
-#define _CHAT_H
-
-struct chat
-{
-	account_t *acc;
-	
-	char *handle;
-	char *channel;
-	set_t *set;
-	
-	struct chat *next;
-};
-
-struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel );
-struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle );
-struct chat *chat_bychannel( irc_t *irc, char *channel );
-struct chat *chat_get( irc_t *irc, char *id );
-int chat_del( irc_t *irc, struct chat *chat );
-
-int chat_chancmp( char *a, char *b );
-int chat_chanok( char *a );
-
-int chat_join( irc_t *irc, struct chat *c, const char *password );
-
-#endif
Index: conf.c
===================================================================
--- conf.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ conf.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -369,5 +369,5 @@
 		if( g_strcasecmp( ini->section, "defaults" ) == 0 )
 		{
-			set_t *s = set_find( &irc->set, ini->key );
+			set_t *s = set_find( &irc->b->set, ini->key );
 			
 			if( s )
Index: ipc.c
===================================================================
--- ipc.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ ipc.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -138,5 +138,5 @@
 	
 	if( strchr( irc->umode, 'w' ) )
-		irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
+		irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
 }
 
@@ -147,5 +147,5 @@
 	
 	if( strchr( irc->umode, 's' ) )
-		irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
+		irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
 }
 
@@ -156,5 +156,5 @@
 	
 	if( strchr( irc->umode, 'o' ) )
-		irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
+		irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
 }
 
@@ -176,8 +176,8 @@
 		return;
 	
-	if( nick_cmp( cmd[1], irc->nick ) != 0 )
+	if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
 		return;		/* It's not for us. */
 	
-	irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
+	irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
 	irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
 }
@@ -188,5 +188,5 @@
 		ipc_to_master_str( "HELLO\r\n" );
 	else
-		ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
+		ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
 }
 
Index: irc.c
===================================================================
--- irc.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ irc.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -5,5 +5,5 @@
   \********************************************************************/
 
-/* The big hairy IRCd part of the project                               */
+/* The IRC-based UI (for now the only one)                              */
 
 /*
@@ -24,76 +24,9 @@
 */
 
-#define BITLBEE_CORE
 #include "bitlbee.h"
-#include "sock.h"
-#include "ipc.h"
-#include "dcc.h"
-
-static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
-
-GSList *irc_connection_list = NULL;
-
-static char *set_eval_password( set_t *set, char *value )
-{
-	irc_t *irc = set->data;
-	
-	if( irc->status & USTATUS_IDENTIFIED && value )
-	{
-		irc_setpass( irc, value );
-		return NULL;
-	}
-	else
-	{
-		return SET_INVALID;
-	}
-}
-
-static char *set_eval_charset( set_t *set, char *value )
-{
-	irc_t *irc = set->data;
-	GIConv ic, oc;
-
-	if( g_strcasecmp( value, "none" ) == 0 )
-		value = g_strdup( "utf-8" );
-
-	if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
-	{
-		return NULL;
-	}
-	if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
-	{
-		g_iconv_close( ic );
-		return NULL;
-	}
-	
-	if( irc->iconv != (GIConv) -1 )
-		g_iconv_close( irc->iconv );
-	if( irc->oconv != (GIConv) -1 )
-		g_iconv_close( irc->oconv );
-	
-	irc->iconv = ic;
-	irc->oconv = oc;
-
-	return value;
-}
-
-static char *set_eval_away_status( set_t *set, char *value )
-{
-	irc_t *irc = set->data;
-	account_t *a;
-	
-	g_free( set->value );
-	set->value = g_strdup( value );
-	
-	for( a = irc->accounts; a; a = a->next )
-	{
-		struct im_connection *ic = a->ic;
-		
-		if( ic && ic->flags & OPT_LOGGED_IN )
-			imc_away_send_update( ic );
-	}
-	
-	return value;
-}
+
+GSList *irc_connection_list;
+
+static char *set_eval_charset( set_t *set, char *value );
 
 irc_t *irc_new( int fd )
@@ -102,5 +35,8 @@
 	struct sockaddr_storage sock;
 	socklen_t socklen = sizeof( sock );
+	char *host = NULL, *myhost = NULL;
+	irc_user_t *iu;
 	set_t *s;
+	bee_t *b;
 	
 	irc = g_new0( irc_t, 1 );
@@ -114,10 +50,8 @@
 	irc->last_pong = gettime();
 	
-	irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
+	irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
 	irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
 	
 	strcpy( irc->umode, UMODE );
-	irc->mynick = g_strdup( ROOT_NICK );
-	irc->channel = g_strdup( ROOT_CHAN );
 	
 	irc->iconv = (GIConv) -1;
@@ -126,5 +60,5 @@
 	if( global.conf->hostname )
 	{
-		irc->myhost = g_strdup( global.conf->hostname );
+		myhost = g_strdup( global.conf->hostname );
 	}
 	else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) 
@@ -135,5 +69,5 @@
 		                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
 		{
-			irc->myhost = g_strdup( ipv6_unwrap( buf ) );
+			myhost = g_strdup( ipv6_unwrap( buf ) );
 		}
 	}
@@ -146,55 +80,56 @@
 		                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
 		{
-			irc->host = g_strdup( ipv6_unwrap( buf ) );
-		}
-	}
-	
-	if( irc->host == NULL )
-		irc->host = g_strdup( "localhost.localdomain" );
-	if( irc->myhost == NULL )
-		irc->myhost = g_strdup( "localhost.localdomain" );
-	
-	if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
-		irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
-	
-	irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
+			host = g_strdup( ipv6_unwrap( buf ) );
+		}
+	}
+	
+	if( host == NULL )
+		host = g_strdup( "localhost.localdomain" );
+	if( myhost == NULL )
+		myhost = g_strdup( "localhost.localdomain" );
+	
+	//if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
+	//	irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
 
 	irc_connection_list = g_slist_append( irc_connection_list, irc );
 	
-	s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
-	s->flags |= SET_NULL_OK;
-	s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
-	s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
-	s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
-	s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
-	s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
-	s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc );
-	s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
-	s = set_add( &irc->set, "default_target", "root", NULL, irc );
-	s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
-	s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
-	s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
-	s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
-	s->flags |= SET_NULL_OK;
-	s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
-	s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
-	s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
-	s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
-	s->flags |= SET_NULL_OK;
-	s = set_add( &irc->set, "strip_html", "true", NULL, irc );
-	s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
-	s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
-	
-	conf_loaddefaults( irc );
+	b = irc->b = bee_new();
+	
+	s = set_add( &b->set, "away_devoice", "true", NULL/*set_eval_away_devoice*/, irc );
+	s = set_add( &b->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
+	s = set_add( &b->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
+	s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
+	//s = set_add( &b->set, "control_channel", irc->channel, NULL/*set_eval_control_channel*/, irc );
+	s = set_add( &b->set, "default_target", "root", NULL, irc );
+	s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
+	s = set_add( &b->set, "handle_unknown", "root", NULL, irc );
+	s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
+	s = set_add( &b->set, "ops", "both", NULL/*set_eval_ops*/, irc );
+	s = set_add( &b->set, "private", "true", set_eval_bool, irc );
+	s = set_add( &b->set, "query_order", "lifo", NULL, irc );
+	s = set_add( &b->set, "root_nick", ROOT_NICK, NULL/*set_eval_root_nick*/, irc );
+	s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
+	s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
+	s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
+
+	irc->root = iu = irc_user_new( irc, ROOT_NICK );
+	iu->host = g_strdup( myhost );
+	iu->fullname = g_strdup( ROOT_FN );
+	
+	iu = irc_user_new( irc, NS_NICK );
+	iu->host = g_strdup( myhost );
+	iu->fullname = g_strdup( ROOT_FN );
+	
+	irc->user = g_new0( irc_user_t, 1 );
+	irc->user->host = g_strdup( host );
+	
+	conf_loaddefaults( b );
 	
 	/* Evaluator sets the iconv/oconv structures. */
-	set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
-	
-	return( irc );
+	set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
+	
+	irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
+	
+	return irc;
 }
 
@@ -217,5 +152,5 @@
 		
 		ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
-	                           irc->nick ? irc->nick : "(NONE)", irc->host, reason );
+	                           irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
 	     	
 		g_free( reason );
@@ -227,5 +162,5 @@
 		
 		ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
-	        	           irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
+	        	           irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
 	}
 	
@@ -248,63 +183,25 @@
 }
 
-static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
-{
-	g_free( key );
-	
-	return( TRUE );
-}
-
-/* Because we have no garbage collection, this is quite annoying */
+static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
+
 void irc_free( irc_t * irc )
 {
-	user_t *user, *usertmp;
-	
 	log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
 	
-	if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) ) 
+	/*
+	if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 
 		if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
 			irc_usermsg( irc, "Error while saving settings!" );
+	*/
 	
 	irc_connection_list = g_slist_remove( irc_connection_list, irc );
 	
-	while( irc->accounts )
-	{
-		if( irc->accounts->ic )
-			imc_logout( irc->accounts->ic, FALSE );
-		else if( irc->accounts->reconnect )
-			cancel_auto_reconnect( irc->accounts );
-		
-		if( irc->accounts->ic == NULL )
-			account_del( irc, irc->accounts );
-		else
-			/* Nasty hack, but account_del() doesn't work in this
-			   case and we don't want infinite loops, do we? ;-) */
-			irc->accounts = irc->accounts->next;
-	}
-	
+	/*
 	while( irc->queries != NULL )
 		query_del( irc, irc->queries );
-	
-	while( irc->set )
-		set_del( &irc->set, irc->set->key );
-	
-	if (irc->users != NULL)
-	{
-		user = irc->users;
-		while( user != NULL )
-		{
-			g_free( user->nick );
-			g_free( user->away );
-			g_free( user->handle );
-			if( user->user != user->nick ) g_free( user->user );
-			if( user->host != user->nick ) g_free( user->host );
-			if( user->realname != user->nick ) g_free( user->realname );
-			b_event_remove( user->sendbuf_timer );
-					
-			usertmp = user;
-			user = user->next;
-			g_free( usertmp );
-		}
-	}
+	*/
+	
+	while( irc->users )
+		irc_user_free( irc, irc->users->data );
 	
 	if( irc->ping_source_id > 0 )
@@ -318,6 +215,6 @@
 	irc->fd = -1;
 	
-	g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
-	g_hash_table_destroy( irc->userhash );
+	g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
+	g_hash_table_destroy( irc->nick_user_hash );
 	
 	g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
@@ -332,16 +229,5 @@
 	g_free( irc->readbuffer );
 	
-	g_free( irc->nick );
-	g_free( irc->user );
-	g_free( irc->host );
-	g_free( irc->realname );
 	g_free( irc->password );
-	
-	g_free( irc->myhost );
-	g_free( irc->mynick );
-	
-	g_free( irc->channel );
-	
-	g_free( irc->last_target );
 	
 	g_free( irc );
@@ -355,16 +241,12 @@
 }
 
-/* USE WITH CAUTION!
-   Sets pass without checking */
-void irc_setpass (irc_t *irc, const char *pass) 
-{
-	g_free (irc->password);
-	
-	if (pass) {
-		irc->password = g_strdup (pass);
-	} else {
-		irc->password = NULL;
-	}
-}
+static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
+{
+	g_free( key );
+	
+	return( TRUE );
+}
+
+static char **irc_splitlines( char *buffer );
 
 void irc_process( irc_t *irc )
@@ -375,5 +257,5 @@
 	if( irc->readbuffer != NULL )
 	{
-		lines = irc_tokenize( irc->readbuffer );
+		lines = irc_splitlines( irc->readbuffer );
 		
 		for( i = 0; *lines[i] != '\0'; i ++ )
@@ -412,5 +294,5 @@
 						                  "`help set charset' for more information. Your "
 						                  "message was ignored.",
-						                  set_getstr( &irc->set, "charset" ) );
+						                  set_getstr( &irc->b->set, "charset" ) );
 						
 						g_free( conv );
@@ -419,5 +301,5 @@
 					else
 					{
-						irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
+						irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
 						           "Warning: invalid characters received at login time." );
 						
@@ -457,7 +339,9 @@
 }
 
-/* Splits a long string into separate lines. The array is NULL-terminated and, unless the string
-   contains an incomplete line at the end, ends with an empty string. */
-char **irc_tokenize( char *buffer )
+/* Splits a long string into separate lines. The array is NULL-terminated
+   and, unless the string contains an incomplete line at the end, ends with
+   an empty string. Could use g_strsplit() but this one does it in-place.
+   (So yes, it's destructive.) */
+static char **irc_splitlines( char *buffer )
 {
 	int i, j, n = 3;
@@ -590,34 +474,4 @@
 }
 
-void irc_reply( irc_t *irc, int code, char *format, ... )
-{
-	char text[IRC_MAX_LINE];
-	va_list params;
-	
-	va_start( params, format );
-	g_vsnprintf( text, IRC_MAX_LINE, format, params );
-	va_end( params );
-	irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );
-	
-	return;
-}
-
-int irc_usermsg( irc_t *irc, char *format, ... )
-{
-	char text[1024];
-	va_list params;
-	char is_private = 0;
-	user_t *u;
-	
-	u = user_find( irc, irc->mynick );
-	is_private = u->is_private;
-	
-	va_start( params, format );
-	g_vsnprintf( text, sizeof( text ), format, params );
-	va_end( params );
-	
-	return( irc_msgfrom( irc, u->nick, text ) );
-}
-
 void irc_write( irc_t *irc, char *format, ... ) 
 {
@@ -630,4 +484,33 @@
 	return;
 }
+
+void irc_write_all( int now, char *format, ... )
+{
+	va_list params;
+	GSList *temp;	
+	
+	va_start( params, format );
+	
+	temp = irc_connection_list;
+	while( temp != NULL )
+	{
+		irc_t *irc = temp->data;
+		
+		if( now )
+		{
+			g_free( irc->sendbuffer );
+			irc->sendbuffer = g_strdup( "\r\n" );
+		}
+		irc_vawrite( temp->data, format, params );
+		if( now )
+		{
+			bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
+		}
+		temp = temp->next;
+	}
+	
+	va_end( params );
+	return;
+} 
 
 void irc_vawrite( irc_t *irc, char *format, va_list params )
@@ -686,103 +569,16 @@
 }
 
-void irc_write_all( int now, char *format, ... )
-{
-	va_list params;
-	GSList *temp;	
-	
-	va_start( params, format );
-	
-	temp = irc_connection_list;
-	while( temp != NULL )
-	{
-		irc_t *irc = temp->data;
-		
-		if( now )
-		{
-			g_free( irc->sendbuffer );
-			irc->sendbuffer = g_strdup( "\r\n" );
-		}
-		irc_vawrite( temp->data, format, params );
-		if( now )
-		{
-			bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
-		}
-		temp = temp->next;
-	}
-	
-	va_end( params );
-	return;
-} 
-
-void irc_names( irc_t *irc, char *channel )
-{
-	user_t *u;
-	char namelist[385] = "";
-	struct groupchat *c = NULL;
-	char *ops = set_getstr( &irc->set, "ops" );
-	
-	/* RFCs say there is no error reply allowed on NAMES, so when the
-	   channel is invalid, just give an empty reply. */
-	
-	if( g_strcasecmp( channel, irc->channel ) == 0 )
-	{
-		for( u = irc->users; u; u = u->next ) if( u->online )
-		{
-			if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
-			{
-				irc_reply( irc, 353, "= %s :%s", channel, namelist );
-				*namelist = 0;
-			}
-			
-			if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
-				strcat( namelist, "+" );
-			else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
-			         ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
-				strcat( namelist, "@" );
-			
-			strcat( namelist, u->nick );
-			strcat( namelist, " " );
-		}
-	}
-	else if( ( c = irc_chat_by_channel( irc, channel ) ) )
-	{
-		GList *l;
-		
-		/* root and the user aren't in the channel userlist but should
-		   show up in /NAMES, so list them first: */
-		sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
-		                                 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
-		
-		for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
-		{
-			if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
-			{
-				irc_reply( irc, 353, "= %s :%s", channel, namelist );
-				*namelist = 0;
-			}
-			
-			strcat( namelist, u->nick );
-			strcat( namelist, " " );
-		}
-	}
-	
-	if( *namelist )
-		irc_reply( irc, 353, "= %s :%s", channel, namelist );
-	
-	irc_reply( irc, 366, "%s :End of /NAMES list", channel );
-}
-
 int irc_check_login( irc_t *irc )
 {
-	if( irc->user && irc->nick )
+	if( irc->user->user && irc->user->nick )
 	{
 		if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
 		{
-			irc_reply( irc, 464, ":This server is password-protected." );
+			irc_send_num( irc, 464, ":This server is password-protected." );
 			return 0;
 		}
 		else
 		{
-			irc_login( irc );
+			irc_send_login( irc );
 			return 1;
 		}
@@ -795,555 +591,32 @@
 }
 
-void irc_login( irc_t *irc )
-{
-	user_t *u;
-	
-	irc_reply( irc,   1, ":Welcome to the BitlBee gateway, %s", irc->nick );
-	irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
-	irc_reply( irc,   3, ":%s", IRCD_INFO );
-	irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
-	irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
-	                     "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
-	                     CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
-	irc_motd( irc );
-	irc->umode[0] = '\0';
-	irc_umode_set( irc, "+" UMODE, 1 );
-
-	u = user_add( irc, irc->mynick );
-	u->host = g_strdup( irc->myhost );
-	u->realname = g_strdup( ROOT_FN );
-	u->online = 1;
-	u->send_handler = root_command_string;
-	u->is_private = 0; /* [SH] The channel is root's personal playground. */
-	irc_spawn( irc, u );
-	
-	u = user_add( irc, NS_NICK );
-	u->host = g_strdup( irc->myhost );
-	u->realname = g_strdup( ROOT_FN );
-	u->online = 0;
-	u->send_handler = root_command_string;
-	u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */
-	
-	u = user_add( irc, irc->nick );
-	u->user = g_strdup( irc->user );
-	u->host = g_strdup( irc->host );
-	u->realname = g_strdup( irc->realname );
-	u->online = 1;
-	irc_spawn( irc, u );
-	
-	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
-	                  "If you've never used BitlBee before, please do read the help "
-	                  "information using the \x02help\x02 command. Lots of FAQs are "
-	                  "answered there.\n"
-	                  "If you already have an account on this server, just use the "
-	                  "\x02identify\x02 command to identify yourself." );
-	
-	if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
-		ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
-	
-	irc->status |= USTATUS_LOGGED_IN;
-	
-	/* This is for bug #209 (use PASS to identify to NickServ). */
-	if( irc->password != NULL )
-	{
-		char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
-		
-		irc_setpass( irc, NULL );
-		root_command( irc, send_cmd );
-		g_free( send_cmd[1] );
-	}
-}
-
-void irc_motd( irc_t *irc )
-{
-	int fd;
-	
-	fd = open( global.conf->motdfile, O_RDONLY );
-	if( fd == -1 )
-	{
-		irc_reply( irc, 422, ":We don't need MOTDs." );
-	}
-	else
-	{
-		char linebuf[80];	/* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */
-		char *add, max;
-		int len;
-		
-		linebuf[79] = len = 0;
-		max = sizeof( linebuf ) - 1;
-		
-		irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost );
-		while( read( fd, linebuf + len, 1 ) == 1 )
-		{
-			if( linebuf[len] == '\n' || len == max )
-			{
-				linebuf[len] = 0;
-				irc_reply( irc, 372, ":- %s", linebuf );
-				len = 0;
-			}
-			else if( linebuf[len] == '%' )
-			{
-				read( fd, linebuf + len, 1 );
-				if( linebuf[len] == 'h' )
-					add = irc->myhost;
-				else if( linebuf[len] == 'v' )
-					add = BITLBEE_VERSION;
-				else if( linebuf[len] == 'n' )
-					add = irc->nick;
-				else
-					add = "%";
-				
-				strncpy( linebuf + len, add, max - len );
-				while( linebuf[++len] );
-			}
-			else if( len < max )
-			{
-				len ++;
-			}
-		}
-		irc_reply( irc, 376, ":End of MOTD" );
-		close( fd );
-	}
-}
-
-void irc_topic( irc_t *irc, char *channel )
-{
-	struct groupchat *c = irc_chat_by_channel( irc, channel );
-	
-	if( c && c->topic )
-		irc_reply( irc, 332, "%s :%s", channel, c->topic );
-	else if( g_strcasecmp( channel, irc->channel ) == 0 )
-		irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC );
-	else
-		irc_reply( irc, 331, "%s :No topic for this channel", channel );
-}
-
-void irc_umode_set( irc_t *irc, char *s, int allow_priv )
-{
-	/* allow_priv: Set to 0 if s contains user input, 1 if you want
-	   to set a "privileged" mode (+o, +R, etc). */
-	char m[256], st = 1, *t;
-	int i;
-	char changes[512], *p, st2 = 2;
-	char badflag = 0;
-	
-	memset( m, 0, sizeof( m ) );
-	
-	for( t = irc->umode; *t; t ++ )
-		m[(int)*t] = 1;
-
-	p = changes;
-	for( t = s; *t; t ++ )
-	{
-		if( *t == '+' || *t == '-' )
-			st = *t == '+';
-		else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
-		{
-			if( m[(int)*t] != st)
-			{
-				if( st != st2 )
-					st2 = st, *p++ = st ? '+' : '-';
-				*p++ = *t;
-			}
-			m[(int)*t] = st;
-		}
-		else
-			badflag = 1;
-	}
-	*p = '\0';
-	
-	memset( irc->umode, 0, sizeof( irc->umode ) );
-	
-	for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
-		if( m[i] )
-			irc->umode[strlen(irc->umode)] = i;
-	
-	if( badflag )
-		irc_reply( irc, 501, ":Unknown MODE flag" );
-	/* Deliberately no !user@host on the prefix here */
-	if( *changes )
-		irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
-}
-
-void irc_spawn( irc_t *irc, user_t *u )
-{
-	irc_join( irc, u, irc->channel );
-}
-
-void irc_join( irc_t *irc, user_t *u, char *channel )
-{
-	char *nick;
-	
-	if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) )
-		irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel );
-	
-	if( nick_cmp( u->nick, irc->nick ) == 0 )
-	{
-		irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE );
-		irc_names( irc, channel );
-		irc_topic( irc, channel );
-	}
-	
-	nick = g_strdup( u->nick );
-	nick_lc( nick );
-	if( g_hash_table_lookup( irc->watches, nick ) )
-	{
-		irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );
-	}
-	g_free( nick );
-}
-
-void irc_part( irc_t *irc, user_t *u, char *channel )
-{
-	irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" );
-}
-
-void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker )
-{
-	irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" );
-}
-
-void irc_kill( irc_t *irc, user_t *u )
-{
-	char *nick, *s;
-	char reason[128];
-	
-	if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
-	{
-		if( u->ic->acc->server )
-			g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
-			            u->ic->acc->server );
-		else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
-			g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
-			            s + 1 );
-		else
-			g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
-			            u->ic->acc->prpl->name, irc->myhost );
-		
-		/* proto_opt might contain garbage after the : */
-		if( ( s = strchr( reason, ':' ) ) )
-			*s = 0;
-	}
-	else
-	{
-		strcpy( reason, "Leaving..." );
-	}
-	
-	irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason );
-	
-	nick = g_strdup( u->nick );
-	nick_lc( nick );
-	if( g_hash_table_lookup( irc->watches, nick ) )
-	{
-		irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );
-	}
-	g_free( nick );
-}
-
-int irc_send( irc_t *irc, char *nick, char *s, int flags )
-{
-	struct groupchat *c = NULL;
-	user_t *u = NULL;
-	
-	if( strchr( CTYPES, *nick ) )
-	{
-		if( !( c = irc_chat_by_channel( irc, nick ) ) )
-		{
-			irc_reply( irc, 403, "%s :Channel does not exist", nick );
-			return( 0 );
-		}
-	}
-	else
-	{
-		u = user_find( irc, nick );
-		
-		if( !u )
-		{
-			if( irc->is_private )
-				irc_reply( irc, 401, "%s :Nick does not exist", nick );
-			else
-				irc_usermsg( irc, "Nick `%s' does not exist!", nick );
-			return( 0 );
-		}
-	}
-	
-	if( *s == 1 && s[strlen(s)-1] == 1 )
-	{
-		if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 )
-		{
-			if( s[7] == ' ' ) s ++;
-			s += 3;
-			*(s++) = '/';
-			*(s++) = 'm';
-			*(s++) = 'e';
-			*(s++) = ' ';
-			s -= 4;
-			s[strlen(s)-1] = 0;
-		}
-		else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 )
-		{
-			u = user_find( irc, irc->mynick );
-			irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" );
-			return( 1 );
-		}
-		else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 )
-		{
-			u = user_find( irc, irc->mynick );
-			irc_privmsg( irc, u, "NOTICE", irc->nick, "", s );
-			return( 1 );
-		}
-		else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
-		{
-			if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
-			{
-				time_t current_typing_notice = time( NULL );
-				
-				if( current_typing_notice - u->last_typing_notice >= 5 )
-				{
-					u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
-					u->last_typing_notice = current_typing_notice;
-				}
-			}
-			return( 1 );
-		}
-		else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
-		{
-			if( u && u->ic && u->ic->acc->prpl->transfer_request )
-			{
-				file_transfer_t *ft = dcc_request( u->ic, s + 5 );
-				if ( ft )
-					u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
-			}
-			return( 1 );
-		}		
-		else
-		{
-			irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
-			return( 0 );
-		}
-	}
-	
-	if( u )
-	{
-		/* For the next message, we probably do have to send new notices... */
-		u->last_typing_notice = 0;
-		u->is_private = irc->is_private;
-		
-		if( u->is_private )
-		{
-			if( !u->online )
-				irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
-			else if( u->away )
-				irc_reply( irc, 301, "%s :%s", u->nick, u->away );
-		}
-		
-		if( u->send_handler )
-		{
-			u->send_handler( irc, u, s, flags );
-			return 1;
-		}
-	}
-	else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
-	{
-		return( imc_chat_msg( c, s, 0 ) );
-	}
-	
-	return( 0 );
-}
-
-static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond )
-{
-	user_t *u = data;
-	
-	/* Shouldn't happen, but just to be sure. */
-	if( u->sendbuf_len < 2 )
-		return FALSE;
-	
-	u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
-	imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
-	
-	g_free( u->sendbuf );
-	u->sendbuf = NULL;
-	u->sendbuf_len = 0;
-	u->sendbuf_timer = 0;
-	u->sendbuf_flags = 0;
-	
-	return FALSE;
-}
-
-void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
-{
-	if( !u || !u->ic ) return;
-	
-	if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
-	{
-		int delay;
-		
-		if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)
-		{
-			/* Flush the buffer */
-			b_event_remove( u->sendbuf_timer );
-			buddy_send_handler_delayed( u, -1, 0 );
-		}
-
-		if( u->sendbuf_len == 0 )
-		{
-			u->sendbuf_len = strlen( msg ) + 2;
-			u->sendbuf = g_new( char, u->sendbuf_len );
-			u->sendbuf[0] = 0;
-			u->sendbuf_flags = flags;
-		}
-		else
-		{
-			u->sendbuf_len += strlen( msg ) + 1;
-			u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );
-		}
-		
-		strcat( u->sendbuf, msg );
-		strcat( u->sendbuf, "\n" );
-		
-		delay = set_getint( &irc->set, "buddy_sendbuffer_delay" );
-		if( delay <= 5 )
-			delay *= 1000;
-		
-		if( u->sendbuf_timer > 0 )
-			b_event_remove( u->sendbuf_timer );
-		u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u );
-	}
-	else
-	{
-		imc_buddy_msg( u->ic, u->handle, msg, flags );
-	}
-}
-
-int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg )
-{
-	char last = 0;
-	char *s = msg, *line = msg;
-	
-	/* The almighty linesplitter .. woohoo!! */
-	while( !last )
-	{
-		if( *s == '\r' && *(s+1) == '\n' )
-			*(s++) = 0;
-		if( *s == '\n' )
-		{
-			last = s[1] == 0;
-			*s = 0;
-		}
-		else
-		{
-			last = s[0] == 0;
-		}
-		if( *s == 0 )
-		{
-			if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 )
-			{
-				irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host,
-				           type, to, line + 4 );
-			}
-			else
-			{
-				irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
-				           type, to, prefix ? prefix : "", line );
-			}
-			line = s + 1;
-		}
-		s ++;
-	}
-	
-	return( 1 );
-}
-
-int irc_msgfrom( irc_t *irc, char *nick, char *msg )
-{
-	user_t *u = user_find( irc, nick );
-	static char *prefix = NULL;
-	
-	if( !u ) return( 0 );
-	if( prefix && *prefix ) g_free( prefix );
-	
-	if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 )
-	{
-		int len = strlen( irc->nick) + 3;
-		prefix = g_new (char, len );
-		g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) );
-		prefix[len-1] = 0;
-	}
-	else
-	{
-		prefix = "";
-	}
-	
-	return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) );
-}
-
-int irc_noticefrom( irc_t *irc, char *nick, char *msg )
-{
-	user_t *u = user_find( irc, nick );
-	
-	if( u )
-		return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) );
-	else
-		return( 0 );
-}
-
-/* Returns 0 if everything seems to be okay, a number >0 when there was a
-   timeout. The number returned is the number of seconds we received no
-   pongs from the user. When not connected yet, we don't ping but drop the
-   connection when the user fails to connect in IRC_LOGIN_TIMEOUT secs. */
-static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond )
-{
-	irc_t *irc = _irc;
-	int rv = 0;
-	
-	if( !( irc->status & USTATUS_LOGGED_IN ) )
-	{
-		if( gettime() > ( irc->last_pong + IRC_LOGIN_TIMEOUT ) )
-			rv = gettime() - irc->last_pong;
-	}
-	else
-	{
-		if( ( gettime() > ( irc->last_pong + global.conf->ping_interval ) ) && !irc->pinging )
-		{
-			irc_write( irc, "PING :%s", IRC_PING_STRING );
-			irc->pinging = 1;
-		}
-		else if( gettime() > ( irc->last_pong + global.conf->ping_timeout ) )
-		{
-			rv = gettime() - irc->last_pong;
-		}
-	}
-	
-	if( rv > 0 )
-	{
-		irc_abort( irc, 0, "Ping Timeout: %d seconds", rv );
-		return FALSE;
-	}
-	
-	return TRUE;
-}
-
-struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel )
-{
-	struct groupchat *c;
-	account_t *a;
-	
-	/* This finds the connection which has a conversation which belongs to this channel */
-	for( a = irc->accounts; a; a = a->next )
-	{
-		if( a->ic == NULL )
-			continue;
-		
-		c = a->ic->groupchats;
-		while( c )
-		{
-			if( c->channel && g_strcasecmp( c->channel, channel ) == 0 )
-				return c;
-			
-			c = c->next;
-		}
-	}
-	
-	return NULL;
-}
+
+
+static char *set_eval_charset( set_t *set, char *value )
+{
+	irc_t *irc = set->data;
+	GIConv ic, oc;
+
+	if( g_strcasecmp( value, "none" ) == 0 )
+		value = g_strdup( "utf-8" );
+
+	if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
+	{
+		return NULL;
+	}
+	if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
+	{
+		g_iconv_close( ic );
+		return NULL;
+	}
+	
+	if( irc->iconv != (GIConv) -1 )
+		g_iconv_close( irc->iconv );
+	if( irc->oconv != (GIConv) -1 )
+		g_iconv_close( irc->oconv );
+	
+	irc->iconv = ic;
+	irc->oconv = oc;
+
+	return value;
+}
Index: irc.h
===================================================================
--- irc.h	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ irc.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -5,5 +5,5 @@
   \********************************************************************/
 
-/* The big hairy IRCd part of the project                               */
+/* The IRC-based UI (for now the only one)                              */
 
 /*
@@ -49,4 +49,6 @@
 } irc_status_t;
 
+struct irc_user;
+
 typedef struct irc
 {
@@ -59,11 +61,7 @@
 	GIConv iconv, oconv;
 
-	int sentbytes;
-	time_t oldtime;
+	struct irc_user *root;
+	struct irc_user *user;
 
-	char *nick;
-	char *user;
-	char *host;
-	char *realname;
 	char *password; /* HACK: Used to save the user's password, but before
 	                   logging in, this may contain a password we should
@@ -72,13 +70,4 @@
 	char umode[8];
 	
-	char *myhost;
-	char *mynick;
-
-	char *channel;
-	int c_id;
-
-	char is_private;		/* Not too nice... */
-	char *last_target;
-	
 	struct query *queries;
 	struct account *accounts;
@@ -86,17 +75,38 @@
 	struct chat *chatrooms;
 	
-	struct __USER *users;
-	GHashTable *userhash;
+	GSList *users;
+	GHashTable *nick_user_hash;
 	GHashTable *watches;
-	struct __NICK *nicks;
-	struct set *set;
 
 	gint r_watch_source_id;
 	gint w_watch_source_id;
 	gint ping_source_id;
+	
+	struct bee *b;
 } irc_t;
+
+typedef struct irc_user
+{
+	char *nick;
+	char *user;
+	char *host;
+	char *fullname;
+	
+	/* Nickname in lowercase for case sensitive searches */
+	char *key;
+	
+	char is_private;
+	
+	char *sendbuf;
+	int sendbuf_len;
+	guint sendbuf_timer;
+	int sendbuf_flags;
+	
+	//struct user *b;
+} irc_user_t;
 
 #include "user.h"
 
+/* irc.c */
 extern GSList *irc_connection_list;
 
@@ -105,39 +115,28 @@
 void irc_free( irc_t *irc );
 
-void irc_exec( irc_t *irc, char **cmd );
 void irc_process( irc_t *irc );
 char **irc_parse_line( char *line );
 char *irc_build_line( char **cmd );
 
-void irc_vawrite( irc_t *irc, char *format, va_list params );
 void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
 void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
-void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
-G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
-char **irc_tokenize( char *buffer );
+void irc_vawrite( irc_t *irc, char *format, va_list params );
 
-void irc_login( irc_t *irc );
 int irc_check_login( irc_t *irc );
-void irc_motd( irc_t *irc );
-void irc_names( irc_t *irc, char *channel );
-void irc_topic( irc_t *irc, char *channel );
-void irc_umode_set( irc_t *irc, char *s, int allow_priv );
-void irc_who( irc_t *irc, char *channel );
-void irc_spawn( irc_t *irc, user_t *u );
-void irc_join( irc_t *irc, user_t *u, char *channel );
-void irc_part( irc_t *irc, user_t *u, char *channel );
-void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
-void irc_kill( irc_t *irc, user_t *u );
-void irc_invite( irc_t *irc, char *nick, char *channel );
-void irc_whois( irc_t *irc, char *nick );
-void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
 
-int irc_send( irc_t *irc, char *nick, char *s, int flags );
-int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
-int irc_msgfrom( irc_t *irc, char *nick, char *msg );
-int irc_noticefrom( irc_t *irc, char *nick, char *msg );
+/* irc_commands.c */
+void irc_exec( irc_t *irc, char **cmd );
 
-void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
-struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
+/* irc_send.c */
+void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
+void irc_send_login( irc_t *irc );
+void irc_send_motd( irc_t *irc );
+int irc_usermsg( irc_t *irc, char *format, ... );
+
+/* irc_user.c */
+irc_user_t *irc_user_new( irc_t *irc, const char *nick );
+int irc_user_free( irc_t *irc, const char *nick );
+irc_user_t *irc_user_find( irc_t *irc, const char *nick );
+int irc_user_rename( irc_t *irc, const char *old, const char *new );
 
 #endif
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ irc_commands.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -2,5 +2,5 @@
   * BitlBee -- An IRC to other IM-networks gateway                     *
   *                                                                    *
-  * Copyright 2002-2006 Wilmer van der Gaast and others                *
+  * Copyright 2002-2010 Wilmer van der Gaast and others                *
   \********************************************************************/
 
@@ -39,5 +39,5 @@
 		   out we don't require it, which will break this feature.)
 		   Try to identify using the given password. */
-		return root_command( irc, send_cmd );
+		/*return root_command( irc, send_cmd );*/
 	}
 	/* Handling in pre-logged-in state, first see if this server is
@@ -53,10 +53,10 @@
 	else if( global.conf->auth_pass )
 	{
-		irc_reply( irc, 464, ":Incorrect password" );
+		irc_send_num( irc, 464, ":Incorrect password" );
 	}
 	else
 	{
 		/* Remember the password and try to identify after USER/NICK. */
-		irc_setpass( irc, cmd[1] );
+		/*irc_setpass( irc, cmd[1] ); */
 		irc_check_login( irc );
 	}
@@ -65,6 +65,6 @@
 static void irc_cmd_user( irc_t *irc, char **cmd )
 {
-	irc->user = g_strdup( cmd[1] );
-	irc->realname = g_strdup( cmd[4] );
+	irc->user->user = g_strdup( cmd[1] );
+	irc->user->fullname = g_strdup( cmd[4] );
 	
 	irc_check_login( irc );
@@ -73,21 +73,20 @@
 static void irc_cmd_nick( irc_t *irc, char **cmd )
 {
-	if( irc->nick )
-	{
-		irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
-	}
-	/* This is not clean, but for now it'll have to be like this... */
-	else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
-	{
-		irc_reply( irc, 433, ":This nick is already in use" );
+	if( irc->user->nick )
+	{
+		irc_send_num( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
+	}
+	else if( irc_user_find( irc, cmd[1] ) )
+	{
+		irc_send_num( irc, 433, ":This nick is already in use" );
 	}
 	else if( !nick_ok( cmd[1] ) )
 	{
 		/* [SH] Invalid characters. */
-		irc_reply( irc, 432, ":This nick contains invalid characters" );
-	}
-	else
-	{
-		irc->nick = g_strdup( cmd[1] );
+		irc_send_num( irc, 432, ":This nick contains invalid characters" );
+	}
+	else
+	{
+		irc->user->nick = g_strdup( cmd[1] );
 		
 		irc_check_login( irc );
@@ -95,4 +94,5 @@
 }
 
+#if 0
 static void irc_cmd_quit( irc_t *irc, char **cmd )
 {
@@ -116,9 +116,9 @@
 	{
 		irc_umode_set( irc, "+o", 1 );
-		irc_reply( irc, 381, ":Password accepted" );
-	}
-	else
-	{
-		irc_reply( irc, 432, ":Incorrect password" );
+		irc_send_num( irc, 381, ":Password accepted" );
+	}
+	else
+	{
+		irc_send_num( irc, 432, ":Incorrect password" );
 	}
 }
@@ -131,10 +131,10 @@
 		{
 			if( *cmd[2] == '+' || *cmd[2] == '-' )
-				irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
+				irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
 			else if( *cmd[2] == 'b' )
-				irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
+				irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
 		}
 		else
-			irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
+			irc_send_num( irc, 324, "%s +%s", cmd[1], CMODE );
 	}
 	else
@@ -145,8 +145,8 @@
 				irc_umode_set( irc, cmd[2], 0 );
 			else
-				irc_reply( irc, 221, "+%s", irc->umode );
+				irc_send_num( irc, 221, "+%s", irc->umode );
 		}
 		else
-			irc_reply( irc, 502, ":Don't touch their modes" );
+			irc_send_num( irc, 502, ":Don't touch their modes" );
 	}
 }
@@ -183,5 +183,5 @@
 	else
 	{
-		irc_reply( irc, 403, "%s :No such channel", cmd[1] );
+		irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
 	}
 }
@@ -197,9 +197,9 @@
 		
 		if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
-			irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
+			irc_send_num( irc, 479, "%s :Invalid channel name", cmd[1] );
 		else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
 			chat_join( irc, c, cmd[2] );
 		else
-			irc_reply( irc, 403, "%s :No such channel", cmd[1] );
+			irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
 	}
 }
@@ -215,9 +215,9 @@
 		{
 			c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
-			irc_reply( irc, 341, "%s %s", nick, channel );
+			irc_send_num( irc, 341, "%s %s", nick, channel );
 			return;
 		}
 	
-	irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
+	irc_send_num( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
 }
 
@@ -226,5 +226,5 @@
 	if ( !cmd[2] ) 
 	{
-		irc_reply( irc, 412, ":No text to send" );
+		irc_send_num( irc, 412, ":No text to send" );
 	}
 	else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 
@@ -283,5 +283,5 @@
 		while( u )
 		{
-			irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
+			irc_send_num( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
 			u = u->next;
 		}
@@ -290,5 +290,5 @@
 		{
 			if( u->online )
-				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
+				irc_send_num( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
 			u = u->next;
 		}
@@ -297,10 +297,10 @@
 		{
 			if( ( u = user_findhandle( c->ic, l->data ) ) )
-				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
+				irc_send_num( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
 		}
 	else if( ( u = user_find( irc, channel ) ) )
-		irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
-	
-	irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
+		irc_send_num( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
+	
+	irc_send_num( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
 }
 
@@ -320,7 +320,7 @@
 		{
 			if( u->online && u->away )
-				irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
+				irc_send_num( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
 			else
-				irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
+				irc_send_num( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
 		}
 }
@@ -377,5 +377,5 @@
 		buff[strlen(buff)-1] = '\0';
 	
-	irc_reply( irc, 303, ":%s", buff );
+	irc_send_num( irc, 303, ":%s", buff );
 }
 
@@ -406,7 +406,7 @@
 			
 			if( u && u->online )
-				irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
+				irc_send_num( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
 			else
-				irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
+				irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
 		}
 		else if( cmd[i][0] == '-' )
@@ -419,5 +419,5 @@
 				g_free( okey );
 				
-				irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
+				irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
 			}
 		}
@@ -463,5 +463,5 @@
 		u->away[j] = 0;
 		
-		irc_reply( irc, 306, ":You're now away: %s", u->away );
+		irc_send_num( irc, 306, ":You're now away: %s", u->away );
 		/* irc_umode_set( irc, irc->myhost, "+a" ); */
 	}
@@ -471,5 +471,5 @@
 		u->away = NULL;
 		/* irc_umode_set( irc, irc->myhost, "-a" ); */
-		irc_reply( irc, 305, ":Welcome back" );
+		irc_send_num( irc, 305, ":Welcome back" );
 	}
 	
@@ -484,25 +484,25 @@
 	if( u )
 	{
-		irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
+		irc_send_num( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
 		
 		if( u->ic )
-			irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
+			irc_send_num( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
 			           u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
 			           u->ic->acc->prpl->name );
 		else
-			irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
+			irc_send_num( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
 		
 		if( !u->online )
-			irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
+			irc_send_num( irc, 301, "%s :%s", u->nick, "User is offline" );
 		else if( u->away )
-			irc_reply( irc, 301, "%s :%s", u->nick, u->away );
+			irc_send_num( irc, 301, "%s :%s", u->nick, u->away );
 		if( u->status_msg )
-			irc_reply( irc, 333, "%s :Status: %s", u->nick, u->status_msg );
-		
-		irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
-	}
-	else
-	{
-		irc_reply( irc, 401, "%s :Nick does not exist", nick );
+			irc_send_num( irc, 333, "%s :Status: %s", u->nick, u->status_msg );
+		
+		irc_send_num( irc, 318, "%s :End of /WHOIS list", nick );
+	}
+	else
+	{
+		irc_send_num( irc, 401, "%s :Nick does not exist", nick );
 	}
 }
@@ -515,6 +515,6 @@
 	   with not-found and irssi users will get better error messages */
 	
-	irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
-	irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
+	irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
+	irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
 }
 
@@ -541,5 +541,5 @@
 static void irc_cmd_version( irc_t *irc, char **cmd )
 {
-	irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
+	irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
 }
 
@@ -572,6 +572,7 @@
 		ipc_to_master( cmd );
 	
-	irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
-}
+	irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
+}
+#endif
 
 static const command_t irc_commands[] = {
@@ -579,4 +580,5 @@
 	{ "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
 	{ "nick",        1, irc_cmd_nick,        0 },
+#if 0
 	{ "quit",        0, irc_cmd_quit,        0 },
 	{ "ping",        0, irc_cmd_ping,        0 },
@@ -610,4 +612,5 @@
 	{ "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+#endif
 	{ NULL }
 };
@@ -628,17 +631,17 @@
 			if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
 			{
-				irc_reply( irc, 462, ":Only allowed before logging in" );
+				irc_send_num( irc, 462, ":Only allowed before logging in" );
 			}
 			else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
 			{
-				irc_reply( irc, 451, ":Register first" );
+				irc_send_num( irc, 451, ":Register first" );
 			}
 			else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
 			{
-				irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
+				irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
 			}
 			else if( n_arg < irc_commands[i].required_parameters )
 			{
-				irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
+				irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
 			}
 			else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
@@ -657,4 +660,4 @@
 	
 	if( irc->status >= USTATUS_LOGGED_IN )
-		irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
-}
+		irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
+}
Index: nick.c
===================================================================
--- nick.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ nick.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -78,5 +78,5 @@
 		
 		nick_strip( nick );
-		if( set_getbool( &acc->irc->set, "lcnicks" ) )
+		if( set_getbool( &acc->irc->b->set, "lcnicks" ) )
 			nick_lc( nick );
 	}
@@ -96,5 +96,5 @@
 	/* 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 ) )
+	while( !nick_ok( nick ) || irc_user_find( acc->irc, nick ) )
 	{
 		if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
Index: protocols/Makefile
===================================================================
--- protocols/Makefile	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ protocols/Makefile	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -10,5 +10,7 @@
 
 # [SH] Program variables
-objects = nogaim.o
+#objects = account.o nogaim.o user.o
+objects = bee.o
+
 
 # [SH] The next two lines should contain the directory name (in $(subdirs))
Index: protocols/account.c
===================================================================
--- protocols/account.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/account.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,359 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2010 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Account management functions                                         */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "account.h"
+#include "chat.h"
+
+account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
+{
+	account_t *a;
+	set_t *s;
+	
+	if( irc->accounts )
+	{
+		for( a = irc->accounts; a->next; a = a->next );
+		a = a->next = g_new0( account_t, 1 );
+	}
+	else
+	{
+		irc->accounts = a = g_new0 ( account_t, 1 );
+	}
+	
+	a->prpl = prpl;
+	a->user = g_strdup( user );
+	a->pass = g_strdup( pass );
+	a->auto_connect = 1;
+	a->irc = irc;
+	
+	s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE;
+	
+	s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
+	
+	s = set_add( &a->set, "nick_source", "handle", NULL, a );
+	
+	s = set_add( &a->set, "password", NULL, set_eval_account, a );
+	s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
+	
+	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 );
+	
+	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
+	   things that have to be done now, although I can't think of anything. */
+	if( prpl->init )
+		prpl->init( a );
+	
+	s = set_add( &a->set, "away", NULL, set_eval_account, a );
+	s->flags |= SET_NULL_OK;
+	
+	if( a->flags & ACC_FLAG_STATUS_MESSAGE )
+	{
+		s = set_add( &a->set, "status", NULL, set_eval_account, a );
+		s->flags |= SET_NULL_OK;
+	}
+	
+	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( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
+		return SET_INVALID;
+	
+	if( strcmp( set->key, "server" ) == 0 )
+	{
+		g_free( acc->server );
+		if( value && *value )
+		{
+			acc->server = g_strdup( value );
+			return value;
+		}
+		else
+		{
+			acc->server = g_strdup( set->def );
+			return g_strdup( set->def );
+		}
+	}
+	else if( strcmp( set->key, "username" ) == 0 )
+	{
+		g_free( acc->user );
+		acc->user = g_strdup( value );
+		return value;
+	}
+	else if( strcmp( set->key, "password" ) == 0 )
+	{
+		if( value )
+		{
+			g_free( acc->pass );
+			acc->pass = g_strdup( value );
+			return NULL;	/* password shouldn't be visible in plaintext! */
+		}
+		else
+		{
+			/* NULL can (should) be stored in the set_t
+			   variable, but is otherwise not correct. */
+			return SET_INVALID;
+		}
+	}
+	else if( strcmp( set->key, "auto_connect" ) == 0 )
+	{
+		if( !is_bool( value ) )
+			return SET_INVALID;
+		
+		acc->auto_connect = bool2int( value );
+		return value;
+	}
+	else if( strcmp( set->key, "away" ) == 0 ||
+	         strcmp( set->key, "status" ) == 0 )
+	{
+		if( acc->ic && acc->ic->flags & OPT_LOGGED_IN )
+		{
+			/* If we're currently on-line, set the var now already
+			   (bit of a hack) and send an update. */
+			g_free( set->value );
+			set->value = g_strdup( value );
+			
+			imc_away_send_update( acc->ic );
+		}
+		
+		return value;
+	}
+	
+	return SET_INVALID;
+}
+
+account_t *account_get( irc_t *irc, char *id )
+{
+	account_t *a, *ret = NULL;
+	char *handle, *s;
+	int nr;
+	
+	/* This checks if the id string ends with (...) */
+	if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
+	{
+		struct prpl *proto;
+		
+		*s = *handle = 0;
+		handle ++;
+		
+		if( ( proto = find_protocol( id ) ) )
+		{
+			for( a = irc->accounts; a; a = a->next )
+				if( a->prpl == proto &&
+				    a->prpl->handle_cmp( handle, a->user ) == 0 )
+					ret = a;
+		}
+		
+		/* Restore the string. */
+		handle --;
+		*handle = '(';
+		*s = ')';
+		
+		if( ret )
+			return ret;
+	}
+	
+	if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
+	{
+		for( a = irc->accounts; a; a = a->next )
+			if( ( nr-- ) == 0 )
+				return( a );
+		
+		return( NULL );
+	}
+	
+	for( a = irc->accounts; a; a = a->next )
+	{
+		if( g_strcasecmp( id, a->prpl->name ) == 0 )
+		{
+			if( !ret )
+				ret = a;
+			else
+				return( NULL ); /* We don't want to match more than one... */
+		}
+		else if( strstr( a->user, id ) )
+		{
+			if( !ret )
+				ret = a;
+			else
+				return( NULL );
+		}
+	}
+	
+	return( ret );
+}
+
+void account_del( irc_t *irc, account_t *acc )
+{
+	account_t *a, *l = NULL;
+	struct chat *c, *nc;
+	
+	if( acc->ic )
+		/* Caller should have checked, accounts still in use can't be deleted. */
+		return;
+	
+	for( a = irc->accounts; a; a = (l=a)->next )
+		if( a == acc )
+		{
+			if( l )
+				l->next = a->next;
+			else
+				irc->accounts = a->next;
+			
+			for( c = irc->chatrooms; c; c = nc )
+			{
+				nc = c->next;
+				if( acc == c->acc )
+					chat_del( irc, c );
+			}
+			
+			while( a->set )
+				set_del( &a->set, a->set->key );
+			
+			g_hash_table_destroy( a->nicks );
+			
+			g_free( a->user );
+			g_free( a->pass );
+			g_free( a->server );
+			if( a->reconnect )	/* This prevents any reconnect still queued to happen */
+				cancel_auto_reconnect( a );
+			g_free( a );
+			
+			break;
+		}
+}
+
+void account_on( irc_t *irc, account_t *a )
+{
+	if( a->ic )
+	{
+		/* Trying to enable an already-enabled account */
+		return;
+	}
+	
+	cancel_auto_reconnect( a );
+	
+	a->reconnect = 0;
+	a->prpl->login( a );
+}
+
+void account_off( irc_t *irc, account_t *a )
+{
+	imc_logout( a->ic, FALSE );
+	a->ic = NULL;
+	if( a->reconnect )
+	{
+		/* Shouldn't happen */
+		cancel_auto_reconnect( a );
+	}
+}
+
+struct account_reconnect_delay
+{
+	int start;
+	char op;
+	int step;
+	int max;
+};
+
+int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
+{
+	memset( p, 0, sizeof( *p ) );
+	/* A whole day seems like a sane "maximum maximum". */
+	p->max = 86400;
+	
+	/* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */
+	while( *value && isdigit( *value ) )
+		p->start = p->start * 10 + *value++ - '0';
+	
+	/* Sure, call me evil for implementing my own fscanf here, but it's
+	   dead simple and I immediately know where to continue parsing. */
+	
+	if( *value == 0 )
+		/* If the string ends now, the delay is constant. */
+		return 1;
+	else if( *value != '+' && *value != '*' )
+		/* Otherwise allow either a + or a * */
+		return 0;
+	
+	p->op = *value++;
+	
+	/* + or * the delay by this number every time. */
+	while( *value && isdigit( *value ) )
+		p->step = p->step * 10 + *value++ - '0';
+	
+	if( *value == 0 )
+		/* Use the default maximum (one day). */
+		return 1;
+	else if( *value != '<' )
+		return 0;
+	
+	p->max = 0;
+	value ++;
+	while( *value && isdigit( *value ) )
+		p->max = p->max * 10 + *value++ - '0';
+	
+	return p->max > 0;
+}
+
+char *set_eval_account_reconnect_delay( set_t *set, char *value )
+{
+	struct account_reconnect_delay p;
+	
+	return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
+}
+
+int account_reconnect_delay( account_t *a )
+{
+	char *setting = set_getstr( &a->irc->b->set, "auto_reconnect_delay" );
+	struct account_reconnect_delay p;
+	
+	if( account_reconnect_delay_parse( setting, &p ) )
+	{
+		if( a->auto_reconnect_delay == 0 )
+			a->auto_reconnect_delay = p.start;
+		else if( p.op == '+' )
+			a->auto_reconnect_delay += p.step;
+		else if( p.op == '*' )
+			a->auto_reconnect_delay *= p.step;
+		
+		if( a->auto_reconnect_delay > p.max )
+			a->auto_reconnect_delay = p.max;
+	}
+	else
+	{
+		a->auto_reconnect_delay = 0;
+	}
+	
+	return a->auto_reconnect_delay;
+}
Index: protocols/account.h
===================================================================
--- protocols/account.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/account.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,72 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Account management functions                                         */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _ACCOUNT_H
+#define _ACCOUNT_H
+
+typedef struct account
+{
+	struct prpl *prpl;
+	char *user;
+	char *pass;
+	char *server;
+	
+	int auto_connect;
+	int auto_reconnect_delay;
+	int reconnect;
+	int flags;
+	
+	set_t *set;
+	GHashTable *nicks;
+	
+	struct irc *irc;
+	struct im_connection *ic;
+	struct account *next;
+} account_t;
+
+account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass );
+account_t *account_get( irc_t *irc, char *id );
+void account_del( irc_t *irc, account_t *acc );
+void account_on( irc_t *irc, account_t *a );
+void account_off( irc_t *irc, account_t *a );
+
+char *set_eval_account( set_t *set, char *value );
+char *set_eval_account_reconnect_delay( set_t *set, char *value );
+int account_reconnect_delay( account_t *a );
+
+typedef enum
+{
+	ACC_SET_NOSAVE = 0x01,          /* Don't save this setting (i.e. stored elsewhere). */
+	ACC_SET_OFFLINE_ONLY = 0x02,    /* Allow changes only if the acct is offline. */
+	ACC_SET_ONLINE_ONLY = 0x04,     /* Allow changes only if the acct is online. */
+} account_set_flag_t;
+
+typedef enum
+{
+	ACC_FLAG_AWAY_MESSAGE = 0x01,   /* Supports away messages instead of just states. */
+	ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
+} account_flag_t;
+
+#endif
Index: protocols/chat.c
===================================================================
--- protocols/chat.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/chat.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,192 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2008 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in                    */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "bitlbee.h"
+#include "chat.h"
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel )
+{
+	struct chat *c, *l;
+	set_t *s;
+
+	if( acc->prpl->chat_join == NULL || !chat_chanok( channel ) ||
+	    chat_chancmp( channel, irc->channel ) == 0 )
+	{
+		return NULL;
+	}
+	
+	for( c = irc->chatrooms; c; c = c->next )
+	{
+		if( chat_chancmp( channel, c->channel ) == 0 )
+			return NULL;
+		
+		if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+			return NULL;
+		
+		l = c;
+	}
+	
+	if( irc->chatrooms == NULL )
+		irc->chatrooms = c = g_new0( struct chat, 1 );
+	else
+		l->next = c = g_new0( struct chat, 1 );
+	
+	c->acc = acc;
+	c->handle = g_strdup( handle );
+	c->channel = g_strdup( channel );
+	
+	s = set_add( &c->set, "auto_join", "false", set_eval_bool, c );
+	/* s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); */
+	s = set_add( &c->set, "nick", NULL, NULL, c );
+	s->flags |= SET_NULL_OK;
+	
+	return c;
+}
+
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle )
+{
+	struct chat *c;
+	
+	for( c = irc->chatrooms; c; c = c->next )
+	{
+		if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+			break;
+	}
+	
+	return c;
+}
+
+struct chat *chat_bychannel( irc_t *irc, char *channel )
+{
+	struct chat *c;
+	
+	for( c = irc->chatrooms; c; c = c->next )
+	{
+		if( chat_chancmp( channel, c->channel ) == 0 )
+			break;
+	}
+	
+	return c;
+}
+
+struct chat *chat_get( irc_t *irc, char *id )
+{
+	struct chat *c, *ret = NULL;
+	int nr;
+	
+	if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
+	{
+		for( c = irc->chatrooms; c; c = c->next )
+			if( ( nr-- ) == 0 )
+				return c;
+		
+		return NULL;
+	}
+	
+	for( c = irc->chatrooms; c; c = c->next )
+	{
+		if( strstr( c->handle, id ) )
+		{
+			if( !ret )
+				ret = c;
+			else
+				return NULL;
+		}
+		else if( strstr( c->channel, id ) )
+		{
+			if( !ret )
+				ret = c;
+			else
+				return NULL;
+		}
+	}
+	
+	return ret;
+}
+
+int chat_del( irc_t *irc, struct chat *chat )
+{
+	struct chat *c, *l = NULL;
+	
+	for( c = irc->chatrooms; c; c = (l=c)->next )
+		if( c == chat )
+			break;
+	
+	if( c == NULL )
+		return 0;
+	else if( l == NULL )
+		irc->chatrooms = c->next;
+	else
+		l->next = c->next;
+	
+	while( c->set )
+		set_del( &c->set, c->set->key );
+	
+	g_free( c->handle );
+	g_free( c->channel );
+	g_free( c );
+	
+	return 1;
+}
+
+int chat_chancmp( char *a, char *b )
+{
+	if( !chat_chanok( a ) || !chat_chanok( b ) )
+		return 0;
+	
+	if( a[0] == b[0] )
+		return nick_cmp( a + 1, b + 1 );
+	else
+		return -1;
+}
+
+int chat_chanok( char *a )
+{
+	if( strchr( CTYPES, a[0] ) != NULL )
+		return nick_ok( a + 1 );
+	else
+		return 0;
+}
+
+int chat_join( irc_t *irc, struct chat *c, const char *password )
+{
+	struct groupchat *gc;
+	char *nick = set_getstr( &c->set, "nick" );
+
+	if( c->acc->ic == NULL || c->acc->prpl->chat_join == NULL )
+		return 0;
+	
+	if( nick == NULL )
+		nick = irc->nick;
+	
+	if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) )
+	{
+		g_free( gc->channel );
+		gc->channel = g_strdup( c->channel );
+		return 1;
+	}
+	
+	return 0;
+}
Index: protocols/chat.h
===================================================================
--- protocols/chat.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/chat.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,51 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2008 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in                    */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _CHAT_H
+#define _CHAT_H
+
+struct chat
+{
+	account_t *acc;
+	
+	char *handle;
+	char *channel;
+	set_t *set;
+	
+	struct chat *next;
+};
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel );
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle );
+struct chat *chat_bychannel( irc_t *irc, char *channel );
+struct chat *chat_get( irc_t *irc, char *id );
+int chat_del( irc_t *irc, struct chat *chat );
+
+int chat_chancmp( char *a, char *b );
+int chat_chanok( char *a );
+
+int chat_join( irc_t *irc, struct chat *c, const char *password );
+
+#endif
Index: protocols/user.c
===================================================================
--- protocols/user.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/user.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,106 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Stuff to handle, save and search buddies                             */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+
+user_t *user_add( irc_t *irc, char *nick )
+{
+	user_t *u, *lu = NULL;
+	char *key;
+	
+	if( !nick_ok( nick ) )
+		return( NULL );
+	
+	if( user_find( irc, nick ) != NULL )
+		return( NULL );
+	
+	return( u );
+}
+
+int user_del( irc_t *irc, char *nick )
+{
+	user_t *u, *t;
+	char *key;
+	gpointer okey, ovalue;
+	
+	if( !nick_ok( nick ) )
+		return( 0 );
+	
+	u = irc->users;
+	t = NULL;
+	while( u )
+	{
+		if( nick_cmp( u->nick, nick ) == 0 )
+		{
+			/* Get this key now already, since "nick" might be free()d
+			   at the time we start playing with the hash... */
+			key = g_strdup( nick );
+			nick_lc( key );
+			
+			if( t )
+				t->next = u->next;
+			else
+				irc->users = u->next;
+			if( u->online )
+				irc_kill( irc, u );
+			g_free( u->nick );
+			if( u->nick != u->user ) g_free( u->user );
+			if( u->nick != u->host ) g_free( u->host );
+			if( u->nick != u->realname ) g_free( u->realname );
+			g_free( u->group );
+			g_free( u->away );
+			g_free( u->handle );
+			g_free( u->sendbuf );
+			if( u->sendbuf_timer ) b_event_remove( u->sendbuf_timer );
+			g_free( u );
+			
+			return( 1 );
+		}
+		u = (t=u)->next;
+	}
+	
+	return( 0 );
+}
+
+user_t *user_findhandle( struct im_connection *ic, const char *handle )
+{
+	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( ic->acc->nicks, handle ) ) &&
+	    ( u = user_find( ic->irc, nick ) ) &&
+	    ( ic->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 = ic->irc->users; u; u = u->next )
+		if( u->ic == ic && u->handle && ic->acc->prpl->handle_cmp( u->handle, handle ) == 0 )
+			return u;
+	
+	return NULL;
+}
Index: protocols/user.h
===================================================================
--- protocols/user.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
+++ protocols/user.h	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -0,0 +1,40 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* Stuff to handle, save and search buddies                             */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __USER_H__
+#define __USER_H__
+
+struct __USER
+{
+	struct im_connection *ic;
+	char *handle;
+	char *fullname;
+	char *group;
+
+	char *away;
+	char *status_msg;
+} user_t;
+
+#endif /* __USER_H__ */
Index: set.c
===================================================================
--- set.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ set.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -225,4 +225,5 @@
 }
 
+/*
 char *set_eval_ops( set_t *set, char *value )
 {
@@ -246,2 +247,3 @@
 	return value;
 }
+*/
Index: unix.c
===================================================================
--- unix.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ unix.c	(revision 3ddb7477f51d3cf1632e2a8b6f7da4c0609a52cb)
@@ -62,5 +62,5 @@
 	
 	b_main_init();
-	nogaim_init();
+	//nogaim_init();
 	
 	srand( time( NULL ) ^ getpid() );
@@ -115,4 +115,5 @@
 	}
 
+	/*
 	global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
 	if( global.storage == NULL )
@@ -121,4 +122,5 @@
 		return( 1 );
 	}
+	*/
  	
 	/* Catch some signals to tell the user what's happening before quitting */
Index: er.c
===================================================================
--- user.c	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,231 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Stuff to handle, save and search buddies                             */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#define BITLBEE_CORE
-#include "bitlbee.h"
-
-user_t *user_add( irc_t *irc, char *nick )
-{
-	user_t *u, *lu = NULL;
-	char *key;
-	
-	if( !nick_ok( nick ) )
-		return( NULL );
-	
-	if( user_find( irc, nick ) != NULL )
-		return( NULL );
-	
-	if( ( u = irc->users ) )
-	{
-		while( u )
-		{
-			if( nick_cmp( nick, u->nick ) < 0 )
-				break;
-			
-			lu = u;
-			u = u->next;
-		}
-		
-		u = g_new0( user_t, 1 );
-		if( lu )
-		{
-			u->next = lu->next;
-			lu->next = u;
-		}
-		else
-		{
-			u->next = irc->users;
-			irc->users = u;
-		}
-	}
-	else
-	{
-		irc->users = u = g_new0( user_t, 1 );
-	}
-	
-	u->user = u->realname = u->host = u->nick = g_strdup( nick );
-	u->is_private = set_getbool( &irc->set, "private" );
-	
-	key = g_strdup( nick );
-	nick_lc( key );
-	g_hash_table_insert( irc->userhash, key, u );
-	
-	return( u );
-}
-
-int user_del( irc_t *irc, char *nick )
-{
-	user_t *u, *t;
-	char *key;
-	gpointer okey, ovalue;
-	
-	if( !nick_ok( nick ) )
-		return( 0 );
-	
-	u = irc->users;
-	t = NULL;
-	while( u )
-	{
-		if( nick_cmp( u->nick, nick ) == 0 )
-		{
-			/* Get this key now already, since "nick" might be free()d
-			   at the time we start playing with the hash... */
-			key = g_strdup( nick );
-			nick_lc( key );
-			
-			if( t )
-				t->next = u->next;
-			else
-				irc->users = u->next;
-			if( u->online )
-				irc_kill( irc, u );
-			g_free( u->nick );
-			if( u->nick != u->user ) g_free( u->user );
-			if( u->nick != u->host ) g_free( u->host );
-			if( u->nick != u->realname ) g_free( u->realname );
-			g_free( u->group );
-			g_free( u->away );
-			g_free( u->handle );
-			g_free( u->sendbuf );
-			if( u->sendbuf_timer ) b_event_remove( u->sendbuf_timer );
-			g_free( u );
-			
-			if( !g_hash_table_lookup_extended( irc->userhash, key, &okey, &ovalue ) || ovalue != u )
-			{
-				g_free( key );
-				return( 1 );	/* Although this is a severe error, the user is removed from the list... */
-			}
-			g_hash_table_remove( irc->userhash, key );
-			g_free( key );
-			g_free( okey );
-			
-			return( 1 );
-		}
-		u = (t=u)->next;
-	}
-	
-	return( 0 );
-}
-
-user_t *user_find( irc_t *irc, char *nick )
-{
-	char key[512] = "";
-	
-	strncpy( key, nick, sizeof( key ) - 1 );
-	if( nick_lc( key ) )
-		return( g_hash_table_lookup( irc->userhash, key ) );
-	else
-		return( NULL );
-}
-
-user_t *user_findhandle( struct im_connection *ic, const char *handle )
-{
-	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( ic->acc->nicks, handle ) ) &&
-	    ( u = user_find( ic->irc, nick ) ) &&
-	    ( ic->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 = ic->irc->users; u; u = u->next )
-		if( u->ic == ic && u->handle && ic->acc->prpl->handle_cmp( u->handle, handle ) == 0 )
-			return u;
-	
-	return NULL;
-}
-
-/* DO NOT PASS u->nick FOR oldnick !!! */
-void user_rename( irc_t *irc, char *oldnick, char *newnick )
-{
-	user_t *u = user_find( irc, oldnick );
-	gpointer okey, ovalue;
-	char *key;
-	
-	if( !u ) return;	/* Should've been checked by the caller... */
-	
-	g_free( u->nick );
-	if( u->nick == u->user ) u->user = NULL;
-	if( u->nick == u->host ) u->host = NULL;
-	if( u->nick == u->realname ) u->realname = NULL;
-	u->nick = g_strdup( newnick );
-	if( !u->user ) u->user = u->nick;
-	if( !u->host ) u->host = u->nick;
-	if( !u->realname ) u->realname = u->nick;
-	
-	/* Remove the old reference to this user from the hash and create a
-	   new one with the new nick. This is indeed a bit messy. */
-	key = g_strdup( oldnick );
-	nick_lc( key );
-	if( !g_hash_table_lookup_extended( irc->userhash, key, &okey, &ovalue ) || ovalue != u )
-	{
-		g_free( key );
-		return;		/* This really shouldn't happen! */	
-	}
-	g_hash_table_remove( irc->userhash, key );
-	g_free( key );
-	g_free( okey );
-	
-	key = g_strdup( newnick );
-	nick_lc( key );
-	g_hash_table_insert( irc->userhash, key, u );
-	
-	/* Also, let's try to keep the linked list nicely sorted. Fear this
-	   code. If my teacher would see this, she would cry. ;-) */
-	{
-		user_t *u1, *lu1;
-		
-		/* Remove the user from the old position in the chain. */
-		if( u == irc->users )
-		{
-			irc->users = u->next;
-		}
-		else
-		{
-			u1 = u;
-			for( lu1 = irc->users; lu1->next != u1; lu1 = lu1->next );
-			lu1->next = u1->next;
-		}
-		
-		/* Search for the new position. */
-		for( lu1 = NULL, u1 = irc->users; u1; u1 = u1->next )
-		{
-			if( nick_cmp( newnick, u1->nick ) < 0 )
-				break;
-			
-			lu1 = u1;
-		}
-		
-		/* Insert it at this new position. */
-		u->next = u1;
-		if( lu1 )
-			lu1->next = u;
-		else
-			irc->users = u;
-	}
-}
Index: er.h
===================================================================
--- user.h	(revision ba7d16f3c90de2744243efe6373ccebe51cfcb5a)
+++ 	(revision )
@@ -1,62 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* Stuff to handle, save and search buddies                             */
-
-/*
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License with
-  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
-*/
-#ifndef __USER_H__
-#define __USER_H__
-
-typedef struct __USER
-{
-	char *nick;
-	char *user;
-	char *host;
-	char *realname;
-	
-	char *away;
-	char *status_msg; /* Non-IRC extension, but nice on IM. */
-	
-	char is_private;
-	char online;
-	
-	char *handle;
-	char *group;
-	struct im_connection *ic;
-
- 	char *sendbuf;
- 	time_t last_typing_notice;
- 	int sendbuf_len;
- 	guint sendbuf_timer;
-    	int sendbuf_flags;
-	
-	void (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags );
-	
-	struct __USER *next;
-} user_t;
-
-user_t *user_add( struct irc *irc, char *nick );
-int user_del( irc_t *irc, char *nick );
-G_MODULE_EXPORT user_t *user_find( irc_t *irc, char *nick );
-G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, const char *handle );
-void user_rename( irc_t *irc, char *oldnick, char *newnick );
-
-#endif /* __USER_H__ */
