Index: protocols/Makefile
===================================================================
--- protocols/Makefile	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/Makefile	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -10,5 +10,6 @@
 
 # [SH] Program variables
-objects = nogaim.o
+objects = account.o bee.o bee_ft.o bee_user.o nogaim.o
+
 
 # [SH] The next two lines should contain the directory name (in $(subdirs))
Index: protocols/account.c
===================================================================
--- protocols/account.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/account.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -0,0 +1,360 @@
+  /********************************************************************\
+  * 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( bee_t *bee, struct prpl *prpl, char *user, char *pass )
+{
+	account_t *a;
+	set_t *s;
+	
+	if( bee->accounts )
+	{
+		for( a = bee->accounts; a->next; a = a->next );
+		a = a->next = g_new0( account_t, 1 );
+	}
+	else
+	{
+		bee->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->bee = bee;
+	
+	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( bee_t *bee, 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 = bee->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 = bee->accounts; a; a = a->next )
+			if( ( nr-- ) == 0 )
+				return( a );
+		
+		return( NULL );
+	}
+	
+	for( a = bee->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( bee_t *bee, account_t *acc )
+{
+	account_t *a, *l = NULL;
+	
+	if( acc->ic )
+		/* Caller should have checked, accounts still in use can't be deleted. */
+		return;
+	
+	for( a = bee->accounts; a; a = (l=a)->next )
+		if( a == acc )
+		{
+			if( l )
+				l->next = a->next;
+			else
+				bee->accounts = a->next;
+			
+			/** FIXME
+			for( c = bee->chatrooms; c; c = nc )
+			{
+				nc = c->next;
+				if( acc == c->acc )
+					chat_del( bee, 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( bee_t *bee, 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( bee_t *bee, 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->bee->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 a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/account.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -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 bee *bee;
+	struct im_connection *ic;
+	struct account *next;
+} account_t;
+
+account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass );
+account_t *account_get( bee_t *bee, char *id );
+void account_del( bee_t *bee, account_t *acc );
+void account_on( bee_t *bee, account_t *a );
+void account_off( bee_t *bee, 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/bee.c
===================================================================
--- protocols/bee.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/bee.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -0,0 +1,47 @@
+#include "bitlbee.h"
+
+bee_t *bee_new()
+{
+	bee_t *b = g_new0( bee_t, 1 );
+	set_t *s;
+	
+	s = set_add( &b->set, "away", NULL, NULL/*set_eval_away_status*/, b );
+	s->flags |= SET_NULL_OK;
+	s = set_add( &b->set, "auto_connect", "true", set_eval_bool, b );
+	s = set_add( &b->set, "auto_reconnect", "true", set_eval_bool, b );
+	s = set_add( &b->set, "auto_reconnect_delay", "5*3<900", NULL/*set_eval_account_reconnect_delay*/, b );
+	s = set_add( &b->set, "debug", "false", set_eval_bool, b );
+	s = set_add( &b->set, "password", NULL, NULL/*set_eval_password*/, b );
+	s->flags |= SET_NULL_OK;
+	s = set_add( &b->set, "save_on_quit", "true", set_eval_bool, b );
+	s = set_add( &b->set, "status", NULL, NULL/*set_eval_away_status*/, b );
+	s->flags |= SET_NULL_OK;
+	s = set_add( &b->set, "strip_html", "true", NULL, b );
+	
+	return b;
+}
+
+void bee_free( bee_t *b )
+{
+	account_t *acc = b->accounts;
+	
+	while( acc )
+	{
+		if( acc->ic )
+			imc_logout( acc->ic, FALSE );
+		else if( acc->reconnect )
+			cancel_auto_reconnect( acc );
+		
+		if( acc->ic == NULL )
+			account_del( b, acc );
+		else
+			/* Nasty hack, but account_del() doesn't work in this
+			   case and we don't want infinite loops, do we? ;-) */
+			acc = acc->next;
+	}
+	
+	while( b->set )
+		set_del( &b->set, b->set->key );
+	
+	g_free( b );
+}
Index: protocols/bee.h
===================================================================
--- protocols/bee.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/bee.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -0,0 +1,102 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2010 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 __BEE_H__
+#define __BEE_H__
+
+struct bee_ui_funcs;
+
+typedef struct bee
+{
+	struct set *set;
+	
+	GSList *users;
+	struct account *accounts; /* TODO(wilmer): Use GSList here too? */
+	
+	const struct bee_ui_funcs *ui;
+	void *ui_data;
+} bee_t;
+
+bee_t *bee_new();
+void bee_free( bee_t *b );
+
+typedef enum
+{
+	BEE_USER_ONLINE = 1,    /* Compatibility with old OPT_LOGGED_IN flag */
+	BEE_USER_AWAY = 4,      /* Compatibility with old OPT_AWAY flag */
+} bee_user_flags_t;
+
+typedef struct bee_user
+{
+	struct im_connection *ic;
+	char *handle;
+	char *fullname;
+	char *group;
+
+	bee_user_flags_t flags;
+	char *status;
+	char *status_msg;
+	
+	bee_t *bee;
+	void *ui_data;
+} bee_user_t;
+
+typedef struct bee_ui_funcs
+{
+	gboolean (*user_new)( bee_t *bee, struct bee_user *bu );
+	gboolean (*user_free)( bee_t *bee, struct bee_user *bu );
+	gboolean (*user_fullname)( bee_t *bee, bee_user_t *bu );
+	gboolean (*user_status)( bee_t *bee, struct bee_user *bu, struct bee_user *old );
+	gboolean (*user_msg)( bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at );
+	
+	struct file_transfer* (*ft_in_start)( bee_t *bee, bee_user_t *bu, const char *file_name, size_t file_size );
+	gboolean (*ft_out_start)( struct im_connection *ic, struct file_transfer *ft );
+	void (*ft_close)( struct im_connection *ic, struct file_transfer *ft );
+	void (*ft_finished)( struct im_connection *ic, struct file_transfer *ft );
+} bee_ui_funcs_t;
+
+
+/* bee.c */
+bee_t *bee_new();
+void bee_free( bee_t *b );
+
+/* bee_user.c */
+bee_user_t *bee_user_new( bee_t *bee, struct im_connection *ic, const char *handle );
+int bee_user_free( bee_t *bee, struct im_connection *ic, const char *handle );
+bee_user_t *bee_user_by_handle( bee_t *bee, struct im_connection *ic, const char *handle );
+int bee_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, int flags );
+
+/* Callbacks from IM modules to core: */
+/* Buddy activity */
+/* To manipulate the status of a handle.
+ * - flags can be |='d with OPT_* constants. You will need at least:
+ *   OPT_LOGGED_IN and OPT_AWAY.
+ * - 'state' and 'message' can be NULL */
+G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
+/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
+/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
+G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, guint32 flags, time_t sent_at );
+
+#endif /* __BEE_H__ */
Index: protocols/bee_ft.c
===================================================================
--- protocols/bee_ft.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/bee_ft.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -0,0 +1,66 @@
+/********************************************************************\
+* BitlBee -- An IRC to other IM-networks gateway                     *
+*                                                                    *
+* Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net>             *
+\********************************************************************/
+
+/*
+  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 "ft.h"
+
+file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
+{
+	bee_t *bee = ic->bee; 
+	bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
+	
+	if( bee->ui->ft_in_start )
+		return bee->ui->ft_in_start( bee, bu, file_name, file_size );
+	else
+		return NULL;
+}
+
+gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft )
+{
+	bee_t *bee = ic->bee;
+	
+	if( bee->ui->ft_out_start )
+		return bee->ui->ft_out_start( ic, ft );
+	else
+		return FALSE;
+}
+
+void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason )
+{
+	bee_t *bee = ic->bee;
+	
+	if( file->canceled )
+		file->canceled( file, reason );
+	
+	if( bee->ui->ft_close )
+		bee->ui->ft_close( ic, file );
+}
+
+void imcb_file_finished( struct im_connection *ic, file_transfer_t *file )
+{
+	bee_t *bee = ic->bee;
+	
+	if( bee->ui->ft_finished )
+		bee->ui->ft_finished( ic, file );
+}
Index: protocols/bee_user.c
===================================================================
--- protocols/bee_user.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/bee_user.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -0,0 +1,197 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2010 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"
+
+bee_user_t *bee_user_new( bee_t *bee, struct im_connection *ic, const char *handle )
+{
+	bee_user_t *bu;
+	
+	if( bee_user_by_handle( bee, ic, handle ) != NULL )
+		return NULL;
+	
+	bu = g_new0( bee_user_t, 1 );
+	bu->bee = bee;
+	bu->ic = ic;
+	bu->handle = g_strdup( handle );
+	bee->users = g_slist_prepend( bee->users, bu );
+	
+	if( bee->ui->user_new )
+		bee->ui->user_new( bee, bu );
+	
+	return bu;
+}
+
+int bee_user_free( bee_t *bee, struct im_connection *ic, const char *handle )
+{
+	bee_user_t *bu;
+	
+	if( ( bu = bee_user_by_handle( bee, ic, handle ) ) == NULL )
+		return 0;
+	
+	if( bee->ui->user_free )
+		bee->ui->user_free( bee, bu );
+	
+	g_free( bu->handle );
+	g_free( bu->fullname );
+	g_free( bu->group );
+	g_free( bu->status );
+	g_free( bu->status_msg );
+	
+	bee->users = g_slist_remove( bee->users, bu );
+	
+	return 1;
+}
+
+bee_user_t *bee_user_by_handle( bee_t *bee, struct im_connection *ic, const char *handle )
+{
+	GSList *l;
+	
+	for( l = bee->users; l; l = l->next )
+	{
+		bee_user_t *bu = l->data;
+		
+		if( bu->ic == ic && ic->acc->prpl->handle_cmp( bu->handle, handle ) == 0 )
+			return bu;
+	}
+	
+	return NULL;
+}
+
+int bee_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, int flags )
+{
+	char *buf = NULL;
+	int st;
+	
+	if( ( bu->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+	{
+		buf = escape_html( msg );
+		msg = buf;
+	}
+	else
+		buf = g_strdup( msg );
+	
+	st = bu->ic->acc->prpl->buddy_msg( bu->ic, bu->handle, buf, flags );
+	g_free( buf );
+	
+	return st;
+}
+
+
+/* IM->UI callbacks */
+void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
+{
+	bee_t *bee = ic->bee;
+	bee_user_t *bu, *old;
+	
+	if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
+	{
+		if( g_strcasecmp( set_getstr( &ic->bee->set, "handle_unknown" ), "add" ) == 0 )
+		{
+			bu = bee_user_new( bee, ic, handle );
+		}
+		else
+		{
+			if( g_strcasecmp( set_getstr( &ic->bee->set, "handle_unknown" ), "ignore" ) != 0 )
+			{
+				imcb_log( ic, "imcb_buddy_status() for unknown handle %s:\n"
+				              "flags = %d, state = %s, message = %s", handle, flags,
+				              state ? state : "NULL", message ? message : "NULL" );
+			}
+			
+			return;
+		}
+	}
+	
+	/* May be nice to give the UI something to compare against. */
+	old = g_memdup( bu, sizeof( bee_user_t ) );
+	
+	/* TODO(wilmer): OPT_AWAY, or just state == NULL ? */
+	bu->flags = flags;
+	bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state );
+	bu->status_msg = g_strdup( message );
+	
+	if( bee->ui->user_status )
+		bee->ui->user_status( bee, bu, old );
+	
+	g_free( old->status_msg );
+	g_free( old->status );
+	g_free( old );
+#if 0	
+	/* LISPy... */
+	if( ( set_getbool( &ic->bee->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */
+	    ( u->online ) &&						/* Don't touch offline people */
+	    ( ( ( u->online != oo ) && !u->away ) ||			/* Voice joining people */
+	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* (De)voice people changing state */
+	{
+		char *from;
+		
+		if( set_getbool( &ic->bee->set, "simulate_netsplit" ) )
+		{
+			from = g_strdup( ic->irc->myhost );
+		}
+		else
+		{
+			from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
+			                                    ic->irc->myhost );
+		}
+		irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
+		                                          u->away?'-':'+', u->nick );
+		g_free( from );
+	}
+#endif
+}
+
+void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
+{
+	bee_t *bee = ic->bee;
+	bee_user_t *bu;
+	
+	bu = bee_user_by_handle( bee, ic, handle );
+	
+	if( !bu )
+	{
+		char *h = set_getstr( &bee->set, "handle_unknown" );
+		
+		if( g_strcasecmp( h, "ignore" ) == 0 )
+		{
+			return;
+		}
+		else if( g_strncasecmp( h, "add", 3 ) == 0 )
+		{
+			bu = bee_user_new( bee, ic, handle );
+		}
+	}
+	
+	if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
+		strip_html( msg );
+	
+	if( bee->ui->user_msg && bu )
+		bee->ui->user_msg( bee, bu, msg, sent_at );
+	else
+		imcb_log( ic, "Message from unknown handle %s:\n%s", handle, msg );
+}
Index: protocols/chat.c
===================================================================
--- protocols/chat.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/chat.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -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 a87e6ba665985301eedbe981a81110846aad8a9d)
+++ protocols/chat.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -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/ft.h
===================================================================
--- protocols/ft.h	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/ft.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -168,8 +168,8 @@
  * the canceled() and free() callbacks given in file will be called by this function.
  */
-void imcb_file_canceled( file_transfer_t *file, char *reason );
+void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason );
 
-gboolean imcb_file_recv_start( file_transfer_t *ft );
+gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft );
 
-void imcb_file_finished( file_transfer_t *file );
+void imcb_file_finished( struct im_connection *ic, file_transfer_t *file );
 #endif
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/jabber/iq.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -392,5 +392,5 @@
 			if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
 			{
-				if( initial || imcb_find_buddy( ic, jid ) == NULL )
+				if( initial || bee_user_by_handle( ic->bee, ic, jid ) == NULL )
 					imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
 					                           group->text : NULL );
@@ -590,5 +590,5 @@
 	    strcmp( s, "result" ) == 0 )
 	{
-		if( imcb_find_buddy( ic, jid ) == NULL )
+		if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
 			imcb_add_buddy( ic, jid, NULL );
 	}
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/jabber/jabber.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -267,5 +267,5 @@
 	
 	while( jd->filetransfers )
-		imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
+		imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
 
 	while( jd->streamhosts )
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/jabber/jabber_util.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -279,6 +279,5 @@
 	presence_send_request( bla->ic, bla->handle, "subscribed" );
 	
-	if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
-		imcb_ask_add( bla->ic, bla->handle, NULL );
+	imcb_ask_add( bla->ic, bla->handle, NULL );
 	
 	g_free( bla->handle );
@@ -462,5 +461,5 @@
 		
 		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
-		    ( bare_exists || imcb_find_buddy( ic, jid ) ) )
+		    ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
 		{
 			*s = '/';
@@ -483,5 +482,6 @@
 		if( bud == NULL )
 			/* No match. Create it now? */
-			return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
+			return ( ( flags & GET_BUDDY_CREAT ) &&
+			         bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
 			           jabber_buddy_add( ic, jid_ ) : NULL;
 		else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
Index: protocols/jabber/s5bytestream.c
===================================================================
--- protocols/jabber/s5bytestream.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/jabber/s5bytestream.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -567,5 +567,5 @@
 	xt_free_node( reply );
 
-	imcb_file_canceled( tf->ft, "couldn't connect to any streamhosts" );
+	imcb_file_canceled( tf->ic, tf->ft, "couldn't connect to any streamhosts" );
 
 	bt->tf->watch_in = 0;
@@ -604,5 +604,5 @@
 		
 	if( !jabber_write_packet( tf->ic, reply ) )
-		imcb_file_canceled( tf->ft, "Error transmitting bytestream response" );
+		imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream response" );
 	xt_free_node( reply );
 }
@@ -644,5 +644,5 @@
 
 	if( tf->bytesread >= tf->ft->file_size )
-		imcb_file_finished( tf->ft );
+		imcb_file_finished( tf->ic, tf->ft );
 
 	tf->ft->write( tf->ft, tf->ft->buffer, ret );	
@@ -660,5 +660,5 @@
 	if( tf->watch_in )
 	{
-		imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" );
+		imcb_file_canceled( tf->ic, ft, "BUG in jabber file transfer: write_request called when already watching for input" );
 		return FALSE;
 	}
@@ -706,5 +706,5 @@
 
 	if( tf->byteswritten >= ft->file_size )
-		imcb_file_finished( ft );
+		imcb_file_finished( tf->ic, ft );
 	else
 		bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_can_write, bt );
@@ -1006,5 +1006,5 @@
 
 	if( !jabber_write_packet( tf->ic, iq ) )
-		imcb_file_canceled( tf->ft, "Error transmitting bytestream request" );
+		imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream request" );
 	return TRUE;
 }
@@ -1021,5 +1021,5 @@
 
 	if( jd->streamhosts==NULL ) /* we're done here unless we have a proxy to try */
-		imcb_file_canceled( tf->ft, error );
+		imcb_file_canceled( tf->ic, tf->ft, error );
 
 	/* MUST always return FALSE! */
Index: protocols/jabber/si.c
===================================================================
--- protocols/jabber/si.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/jabber/si.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -91,9 +91,9 @@
 
 	if( !foundft )
-		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature file transfers" );
+		imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature file transfers" );
 	else if( !foundbt )
-		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature byte streams (required)" );
+		imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)" );
 	else if( !foundsi )
-		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
+		imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
 		
 	return foundft && foundbt && foundsi;
@@ -109,5 +109,5 @@
 
 	/* and start the receive logic */
-	imcb_file_recv_start( tf->ft );
+	imcb_file_recv_start( tf->ic, tf->ft );
 
 }
@@ -156,5 +156,5 @@
 	if( bud == NULL )
 	{
-		imcb_file_canceled( ft, "Couldn't find buddy (BUG?)" );
+		imcb_file_canceled( ic, ft, "Couldn't find buddy (BUG?)" );
 		return;
 	}
Index: protocols/msn/Makefile
===================================================================
--- protocols/msn/Makefile	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/msn/Makefile	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -10,5 +10,5 @@
 
 # [SH] Program variables
-objects = invitation.o msn.o msn_util.o ns.o passport.o sb.o tables.o
+objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
 
 CFLAGS += -Wall
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/msn/msn.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -81,7 +81,9 @@
 	if( md )
 	{
+		/** Disabling MSN ft support for now.
 		while( md->filetransfers ) {
 			imcb_file_canceled( md->filetransfers->data, "Closing connection" );
 		}
+		*/
 		
 		if( md->fd >= 0 )
@@ -344,5 +346,5 @@
 	ret->send_typing = msn_send_typing;
 	ret->handle_cmp = g_strcasecmp;
-	ret->transfer_request = msn_ftp_transfer_request;
+	//ret->transfer_request = msn_ftp_transfer_request;
 
 	register_protocol(ret);
Index: protocols/msn/msn_util.c
===================================================================
--- protocols/msn/msn_util.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/msn/msn_util.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -96,6 +96,5 @@
 	msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
 	
-	if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
-		imcb_ask_add( bla->ic, bla->handle, NULL );
+	imcb_ask_add( bla->ic, bla->handle, NULL );
 	
 	g_free( bla->handle );
Index: protocols/msn/sb.c
===================================================================
--- protocols/msn/sb.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/msn/sb.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -691,4 +691,6 @@
 			}
 		}
+#if 0
+		// Disable MSN ft support for now.
 		else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
 		{
@@ -723,4 +725,5 @@
 			g_free( command );
 		}
+#endif
 		else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
 		{
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/nogaim.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -38,6 +38,4 @@
 #include "chat.h"
 
-static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
-
 GSList *connections;
 
@@ -91,6 +89,4 @@
 }
 #endif
-
-/* nogaim.c */
 
 GList *protocols = NULL;
@@ -125,5 +121,4 @@
 }
 
-/* nogaim.c */
 void nogaim_init()
 {
@@ -156,6 +151,4 @@
 GSList *get_connections() { return connections; }
 
-/* multi.c */
-
 struct im_connection *imcb_new( account_t *acc )
 {
@@ -164,5 +157,5 @@
 	ic = g_new0( struct im_connection, 1 );
 	
-	ic->irc = acc->irc;
+	ic->bee = acc->bee;
 	ic->acc = acc;
 	acc->ic = ic;
@@ -178,5 +171,5 @@
 	
 	/* Destroy the pointer to this connection from the account list */
-	for( a = ic->irc->accounts; a; a = a->next )
+	for( a = ic->bee->accounts; a; a = a->next )
 		if( a->ic == ic )
 		{
@@ -199,10 +192,10 @@
 	va_end( params );
 
-	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
 		strip_html( text );
 	
 	/* Try to find a different connection on the same protocol. */
-	for( a = ic->irc->accounts; a; a = a->next )
+	for( a = ic->bee->accounts; a; a = a->next )
 		if( a->prpl == ic->acc->prpl && a->ic != ic )
 			break;
@@ -210,7 +203,8 @@
 	/* If we found one, include the screenname in the message. */
 	if( a )
-		irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
+		/* FIXME(wilmer): ui_log callback or so */
+		irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
 	else
-		irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
+		irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
 	
 	g_free( text );
@@ -263,8 +257,4 @@
 void imcb_connected( struct im_connection *ic )
 {
-	irc_t *irc = ic->irc;
-	struct chat *c;
-	user_t *u;
-	
 	/* MSN servers sometimes redirect you to a different server and do
 	   the whole login sequence again, so these "late" calls to this
@@ -273,6 +263,4 @@
 		return;
 	
-	u = user_find( ic->irc, ic->irc->nick );
-	
 	imcb_log( ic, "Logged in" );
 	
@@ -287,4 +275,5 @@
 	ic->acc->auto_reconnect_delay = 0;
 	
+	/*
 	for( c = irc->chatrooms; c; c = c->next )
 	{
@@ -295,4 +284,5 @@
 			chat_join( irc, c, NULL );
 	}
+	*/
 }
 
@@ -302,5 +292,5 @@
 	
 	a->reconnect = 0;
-	account_on( a->irc, a );
+	account_on( a->bee, a );
 	
 	return( FALSE );	/* Only have to run the timeout once */
@@ -315,7 +305,7 @@
 void imc_logout( struct im_connection *ic, int allow_reconnect )
 {
-	irc_t *irc = ic->irc;
-	user_t *t, *u;
+	bee_t *bee = ic->bee;
 	account_t *a;
+	GSList *l;
 	int delay;
 	
@@ -337,20 +327,15 @@
 	ic->away = NULL;
 	
-	u = irc->users;
-	while( u )
-	{
-		if( u->ic == ic )
-		{
-			t = u->next;
-			user_del( irc, u->nick );
-			u = t;
-		}
-		else
-			u = u->next;
-	}
-	
-	query_del_by_conn( ic->irc, ic );
-	
-	for( a = irc->accounts; a; a = a->next )
+	for( l = bee->users; l; l = l->next )
+	{
+		bee_user_t *bu = l->data;
+		
+		if( bu->ic == ic )
+			bee_user_free( bee, ic, bu->handle );
+	}
+	
+	//query_del_by_conn( ic->irc, ic );
+	
+	for( a = bee->accounts; a; a = a->next )
 		if( a->ic == ic )
 			break;
@@ -360,5 +345,5 @@
 		/* Uhm... This is very sick. */
 	}
-	else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
+	else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
 	         set_getbool( &a->set, "auto_reconnect" ) &&
 	         ( delay = account_reconnect_delay( a ) ) > 0 )
@@ -371,25 +356,18 @@
 }
 
-
-/* dialogs.c */
-
 void imcb_ask( struct im_connection *ic, char *msg, void *data,
                query_callback doit, query_callback dont )
 {
-	query_add( ic->irc, ic, msg, doit, dont, data );
-}
-
-
-/* list.c */
+	//query_add( ic->irc, ic, msg, doit, dont, data );
+}
 
 void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
 {
-	user_t *u;
-	char nick[MAX_NICK_LENGTH+1], *s;
-	irc_t *irc = ic->irc;
-	
-	if( user_findhandle( ic, handle ) )
-	{
-		if( set_getbool( &irc->set, "debug" ) )
+	bee_user_t *bu;
+	bee_t *bee = ic->bee;
+	
+	if( bee_user_by_handle( bee, ic, handle ) )
+	{
+		if( set_getbool( &bee->set, "debug" ) )
 			imcb_log( ic, "User already exists, ignoring add request: %s", handle );
 		
@@ -402,91 +380,22 @@
 	}
 	
-	memset( nick, 0, MAX_NICK_LENGTH + 1 );
-	strcpy( nick, nick_get( ic->acc, handle ) );
-	
-	u = user_add( ic->irc, nick );
-	
-//	if( !realname || !*realname ) realname = nick;
-//	u->realname = g_strdup( realname );
-	
-	if( ( s = strchr( handle, '@' ) ) )
-	{
-		u->host = g_strdup( s + 1 );
-		u->user = g_strndup( handle, s - handle );
-	}
-	else if( ic->acc->server )
-	{
-		u->host = g_strdup( ic->acc->server );
-		u->user = g_strdup( handle );
-		
-		/* s/ /_/ ... important for AOL screennames */
-		for( s = u->user; *s; s ++ )
-			if( *s == ' ' )
-				*s = '_';
-	}
-	else
-	{
-		u->host = g_strdup( ic->acc->prpl->name );
-		u->user = g_strdup( handle );
-	}
-	
-	u->ic = ic;
-	u->handle = g_strdup( handle );
-	if( group ) u->group = g_strdup( group );
-	u->send_handler = buddy_send_handler;
-	u->last_typing_notice = 0;
-}
-
-struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
-{
-	static struct buddy b[1];
-	user_t *u;
-	
-	u = user_findhandle( ic, handle );
-	
-	if( !u )
-		return( NULL );
-	
-	memset( b, 0, sizeof( b ) );
-	strncpy( b->name, handle, 80 );
-	strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
-	b->present = u->online;
-	b->ic = u->ic;
-	
-	return( b );
-}
-
-void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )
-{
-	user_t *u = user_findhandle( ic, handle );
-	char *set;
-	
-	if( !u || !realname ) return;
-	
-	if( g_strcasecmp( u->realname, realname ) != 0 )
-	{
-		if( u->realname != u->nick ) g_free( u->realname );
-		
-		u->realname = g_strdup( realname );
-		
-		if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
-			imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
-	}
-	
-	set = set_getstr( &ic->acc->set, "nick_source" );
-	if( strcmp( set, "handle" ) != 0 )
-	{
-		char *name = g_strdup( realname );
-		
-		if( strcmp( set, "first_name" ) == 0 )
-		{
-			int i;
-			for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
-			name[i] = '\0';
-		}
-		
-		imcb_buddy_nick_hint( ic, handle, name );
-		
-		g_free( name );
+	bu = bee_user_new( bee, ic, handle );
+	bu->group = g_strdup( group );
+}
+
+void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
+{
+	bee_t *bee = ic->bee;
+	bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
+	
+	if( !bu || !fullname ) return;
+	
+	if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
+	{
+		g_free( bu->fullname );
+		bu->fullname = g_strdup( fullname );
+		
+		if( bee->ui->user_fullname )
+			bee->ui->user_fullname( bee, bu );
 	}
 }
@@ -494,8 +403,5 @@
 void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
 {
-	user_t *u;
-	
-	if( ( u = user_findhandle( ic, handle ) ) )
-		user_del( ic->irc, u->nick );
+	bee_user_free( ic->bee, ic, handle );
 }
 
@@ -504,4 +410,5 @@
 void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
 {
+#if 0
 	user_t *u = user_findhandle( ic, handle );
 	char newnick[MAX_NICK_LENGTH+1], *orig_nick;
@@ -518,5 +425,5 @@
 		/* Some processing to make sure this string is a valid IRC nickname. */
 		nick_strip( newnick );
-		if( set_getbool( &ic->irc->set, "lcnicks" ) )
+		if( set_getbool( &ic->bee->set, "lcnicks" ) )
 			nick_lc( newnick );
 		
@@ -535,4 +442,5 @@
 		}
 	}
+#endif
 }
 
@@ -544,4 +452,5 @@
 };
 
+#if 0
 static void imcb_ask_auth_cb_no( void *data )
 {
@@ -563,7 +472,9 @@
 	g_free( cbd );
 }
+#endif
 
 void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
 {
+#if 0
 	struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
 	char *s, *realname_ = NULL;
@@ -580,7 +491,9 @@
 	data->handle = g_strdup( handle );
 	query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
-}
-
-
+#endif
+}
+
+
+#if 0
 static void imcb_ask_add_cb_no( void *data )
 {
@@ -597,7 +510,9 @@
 	return imcb_ask_add_cb_no( data );
 }
+#endif
 
 void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
 {
+#if 0
 	struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
 	char *s;
@@ -612,163 +527,13 @@
 	data->handle = g_strdup( handle );
 	query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
-}
-
-
-/* server.c */                    
-
-void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
-{
+#endif
+}
+
+void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
+{
+#if 0
 	user_t *u;
-	int oa, oo;
-	
-	u = user_findhandle( ic, (char*) handle );
-	
-	if( !u )
-	{
-		if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
-		{
-			imcb_add_buddy( ic, (char*) handle, NULL );
-			u = user_findhandle( ic, (char*) handle );
-		}
-		else
-		{
-			if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
-			{
-				imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
-				imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
-				          state ? state : "NULL", message ? message : "NULL" );
-			}
-			
-			return;
-		}
-	}
-	
-	oa = u->away != NULL;
-	oo = u->online;
-	
-	g_free( u->away );
-	g_free( u->status_msg );
-	u->away = u->status_msg = NULL;
-	
-	if( ( flags & OPT_LOGGED_IN ) && !u->online )
-	{
-		irc_spawn( ic->irc, u );
-		u->online = 1;
-	}
-	else if( !( flags & OPT_LOGGED_IN ) && u->online )
-	{
-		struct groupchat *c;
-		
-		irc_kill( ic->irc, u );
-		u->online = 0;
-		
-		/* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
-		for( c = ic->groupchats; c; c = c->next )
-			remove_chat_buddy_silent( c, handle );
-	}
-	
-	if( flags & OPT_AWAY )
-	{
-		if( state && message )
-		{
-			u->away = g_strdup_printf( "%s (%s)", state, message );
-		}
-		else if( state )
-		{
-			u->away = g_strdup( state );
-		}
-		else if( message )
-		{
-			u->away = g_strdup( message );
-		}
-		else
-		{
-			u->away = g_strdup( "Away" );
-		}
-	}
-	else
-	{
-		u->status_msg = g_strdup( message );
-	}
-	
-	/* LISPy... */
-	if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */
-	    ( u->online ) &&						/* Don't touch offline people */
-	    ( ( ( u->online != oo ) && !u->away ) ||			/* Voice joining people */
-	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* (De)voice people changing state */
-	{
-		char *from;
-		
-		if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
-		{
-			from = g_strdup( ic->irc->myhost );
-		}
-		else
-		{
-			from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
-			                                    ic->irc->myhost );
-		}
-		irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
-		                                          u->away?'-':'+', u->nick );
-		g_free( from );
-	}
-}
-
-void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
-{
-	irc_t *irc = ic->irc;
-	char *wrapped;
-	user_t *u;
-	
-	u = user_findhandle( ic, handle );
-	
-	if( !u )
-	{
-		char *h = set_getstr( &irc->set, "handle_unknown" );
-		
-		if( g_strcasecmp( h, "ignore" ) == 0 )
-		{
-			if( set_getbool( &irc->set, "debug" ) )
-				imcb_log( ic, "Ignoring message from unknown handle %s", handle );
-			
-			return;
-		}
-		else if( g_strncasecmp( h, "add", 3 ) == 0 )
-		{
-			int private = set_getbool( &irc->set, "private" );
-			
-			if( h[3] )
-			{
-				if( g_strcasecmp( h + 3, "_private" ) == 0 )
-					private = 1;
-				else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
-					private = 0;
-			}
-			
-			imcb_add_buddy( ic, handle, NULL );
-			u = user_findhandle( ic, handle );
-			u->is_private = private;
-		}
-		else
-		{
-			imcb_log( ic, "Message from unknown handle %s:", handle );
-			u = user_find( irc, irc->mynick );
-		}
-	}
-	
-	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
-		strip_html( msg );
-
-	wrapped = word_wrap( msg, 425 );
-	irc_msgfrom( irc, u->nick, wrapped );
-	g_free( wrapped );
-}
-
-void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
-{
-	user_t *u;
-	
-	if( !set_getbool( &ic->irc->set, "typing_notice" ) )
+	
+	if( !set_getbool( &ic->bee->set, "typing_notice" ) )
 		return;
 	
@@ -780,8 +545,15 @@
 		irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
 	}
+#endif
+}
+
+struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
+{
+	return bee_user_by_handle( ic->bee, ic, handle );
 }
 
 struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
 {
+#if 0
 	struct groupchat *c;
 	
@@ -801,17 +573,20 @@
 	c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
 	
-	if( set_getbool( &ic->irc->set, "debug" ) )
+	if( set_getbool( &ic->bee->set, "debug" ) )
 		imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
 	
 	return c;
+#endif
+	return NULL;
 }
 
 void imcb_chat_free( struct groupchat *c )
 {
+#if 0
 	struct im_connection *ic = c->ic;
 	struct groupchat *l;
 	GList *ir;
 	
-	if( set_getbool( &ic->irc->set, "debug" ) )
+	if( set_getbool( &ic->bee->set, "debug" ) )
 		imcb_log( ic, "You were removed from conversation %p", c );
 	
@@ -846,8 +621,10 @@
 		g_free( c );
 	}
+#endif
 }
 
 void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
 {
+#if 0
 	struct im_connection *ic = c->ic;
 	char *wrapped;
@@ -860,6 +637,6 @@
 	u = user_findhandle( ic, who );
 	
-	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
 		strip_html( msg );
 	
@@ -874,8 +651,10 @@
 	}
 	g_free( wrapped );
+#endif
 }
 
 void imcb_chat_log( struct groupchat *c, char *format, ... )
 {
+#if 0
 	irc_t *irc = c->ic->irc;
 	va_list params;
@@ -892,8 +671,10 @@
 	
 	g_free( text );
+#endif
 }
 
 void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
 {
+#if 0
 	struct im_connection *ic = c->ic;
 	user_t *u = NULL;
@@ -906,6 +687,6 @@
 		u = user_findhandle( ic, who );
 	
-	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
 		strip_html( topic );
 	
@@ -915,15 +696,14 @@
 	if( c->joined && u )
 		irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
-}
-
-
-/* buddy_chat.c */
+#endif
+}
 
 void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
 {
+#if 0
 	user_t *u = user_findhandle( b->ic, handle );
 	int me = 0;
 	
-	if( set_getbool( &b->ic->irc->set, "debug" ) )
+	if( set_getbool( &b->ic->bee->set, "debug" ) )
 		imcb_log( b->ic, "User %s added to conversation %p", handle, b );
 	
@@ -952,4 +732,5 @@
 		b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
 	}
+#endif
 }
 
@@ -957,8 +738,9 @@
 void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
 {
+#if 0
 	user_t *u;
 	int me = 0;
 	
-	if( set_getbool( &b->ic->irc->set, "debug" ) )
+	if( set_getbool( &b->ic->bee->set, "debug" ) )
 		imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
 	
@@ -980,6 +762,8 @@
 	if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
 		irc_part( b->ic->irc, u, b->channel );
-}
-
+#endif
+}
+
+#if 0
 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
 {
@@ -1000,10 +784,11 @@
 	}
 	
-	return( 0 );
-}
+	return 0;
+}
+#endif
 
 
 /* Misc. BitlBee stuff which shouldn't really be here */
-
+#if 0
 char *set_eval_away_devoice( set_t *set, char *value )
 {
@@ -1018,5 +803,5 @@
 	/* Horror.... */
 	
-	if( st != set_getbool( &irc->set, "away_devoice" ) )
+	if( st != set_getbool( &irc->b->set, "away_devoice" ) )
 	{
 		char list[80] = "";
@@ -1060,5 +845,5 @@
 	return value;
 }
-
+#endif
 
 
@@ -1067,10 +852,9 @@
    them all from some wrappers. We'll start to define some down here: */
 
-int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
+int imc_chat_msg( struct groupchat *c, char *msg, int flags )
 {
 	char *buf = NULL;
-	int st;
-	
-	if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+	
+	if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
 	{
 		buf = escape_html( msg );
@@ -1078,20 +862,4 @@
 	}
 	
-	st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
-	g_free( buf );
-	
-	return st;
-}
-
-int imc_chat_msg( struct groupchat *c, char *msg, int flags )
-{
-	char *buf = NULL;
-	
-	if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
-	{
-		buf = escape_html( msg );
-		msg = buf;
-	}
-	
 	c->ic->acc->prpl->chat_msg( c, msg, flags );
 	g_free( buf );
@@ -1107,5 +875,5 @@
 	
 	away = set_getstr( &ic->acc->set, "away" ) ?
-	     : set_getstr( &ic->irc->set, "away" );
+	     : set_getstr( &ic->bee->set, "away" );
 	if( away && *away )
 	{
@@ -1118,5 +886,5 @@
 		away = NULL;
 		msg = set_getstr( &ic->acc->set, "status" ) ?
-		    : set_getstr( &ic->irc->set, "status" );
+		    : set_getstr( &ic->bee->set, "status" );
 	}
 	
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/nogaim.h	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -2,5 +2,5 @@
   * BitlBee -- An IRC to other IM-networks gateway                     *
   *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  * Copyright 2002-2010 Wilmer van der Gaast and others                *
   \********************************************************************/
 
@@ -87,5 +87,5 @@
 	
 	/* BitlBee */
-	irc_t *irc;
+	bee_t *bee;
 	
 	struct groupchat *groupchats;
@@ -286,14 +286,6 @@
 G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
 
-/* Buddy activity */
-/* To manipulate the status of a handle.
- * - flags can be |='d with OPT_* constants. You will need at least:
- *   OPT_LOGGED_IN and OPT_AWAY.
- * - 'state' and 'message' can be NULL */
-G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
-/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
-/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
-G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
 G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
+G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
 G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
 
@@ -320,5 +312,4 @@
 /* Actions, or whatever. */
 int imc_away_send_update( struct im_connection *ic );
-int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
 int imc_chat_msg( struct groupchat *c, char *msg, int flags );
 
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision 3ab1d317831a6c1830bb648a1a8d63a41c92f651)
+++ protocols/oscar/oscar.c	(revision a87e6ba665985301eedbe981a81110846aad8a9d)
@@ -1190,6 +1190,5 @@
 	aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
 	// aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
-	if(imcb_find_buddy(data->ic, uin) == NULL)
-		imcb_ask_add(data->ic, uin, NULL);
+	imcb_ask_add(data->ic, uin, NULL);
 	
 	g_free(uin);
@@ -1952,4 +1951,5 @@
 	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	if (odata->icq) {
+		/** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
 		struct buddy *budlight = imcb_find_buddy(g, who);
 		if (budlight)
@@ -1957,4 +1957,5 @@
 				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
 					aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
+		*/
 	} else
 		aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
@@ -2094,5 +2095,5 @@
 		switch (curitem->type) {
 			case 0x0000: /* Buddy */
-				if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
+				if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
 					char *realname = NULL;
 
