Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ irc_commands.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -263,5 +263,5 @@
 			irc->is_private = 1;
 		}
-		irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 );
+		irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
 	}
 }
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/jabber/iq.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -388,5 +388,5 @@
 				   just try to handle this as well as we can. */
 				jabber_buddy_remove_bare( ic, jid );
-				serv_got_update( ic, jid, 0, 0, 0, 0, 0, 0 );
+				imcb_buddy_status( ic, jid, 0, NULL, NULL );
 				/* FIXME! */
 			}
Index: protocols/jabber/presence.c
===================================================================
--- protocols/jabber/presence.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/jabber/presence.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -38,4 +38,6 @@
 	if( type == NULL )
 	{
+		int is_away = 0;
+		
 		if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
 		{
@@ -52,5 +54,9 @@
 		
 		if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 )
+		{
 			bud->away_state = (void*) jabber_away_state_by_code( c->text );
+			if( strcmp( c->text, "chat" ) != 0 )
+				is_away = OPT_AWAY;
+		}
 		else
 		{
@@ -66,6 +72,7 @@
 			bud->priority = 0;
 		
-		serv_got_update( ic, bud->bare_jid, 1, 0, 0, 0,
-		                 bud->away_state ? UC_UNAVAILABLE : 0, 0 );
+		/* FIXME: What to send if there are other resources??? */
+		imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away,
+		                   bud->away_state->full_name, bud->away_message );
 	}
 	else if( strcmp( type, "unavailable" ) == 0 )
@@ -87,5 +94,5 @@
 			   available anymore. */
 			if( jabber_buddy_by_jid( ic, from, 0 ) == NULL )
-				serv_got_update( ic, from, 0, 0, 0, 0, 0, 0 );
+				imcb_buddy_status( ic, from, 0, NULL, NULL );
 			
 			*s = '/';
@@ -93,5 +100,5 @@
 		else
 		{
-			serv_got_update( ic, from, 0, 0, 0, 0, 0, 0 );
+			imcb_buddy_status( ic, from, 0, NULL, NULL );
 		}
 	}
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/msn/msn.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -192,14 +192,4 @@
 }
 
-static char *msn_get_status_string( struct im_connection *ic, int number )
-{
-	const struct msn_away_state *st = msn_away_state_by_number( number );
-	
-	if( st )
-		return( (char*) st->name );
-	else
-		return( "" );
-}
-
 static void msn_set_away( struct im_connection *ic, char *state, char *message )
 {
@@ -399,5 +389,4 @@
 	ret->send_im = msn_send_im;
 	ret->away_states = msn_away_states;
-	ret->get_status_string = msn_get_status_string;
 	ret->set_away = msn_set_away;
 	ret->get_info = msn_get_info;
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/msn/ns.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -400,10 +400,11 @@
 		}
 		
-		serv_got_update( ic, cmd[3], 1, 0, 0, 0, st->number, 0 );
+		imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |
+		                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
 	}
 	else if( strcmp( cmd[0], "FLN" ) == 0 )
 	{
 		if( cmd[1] )
-			serv_got_update( ic, cmd[1], 0, 0, 0, 0, 0, 0 );
+			imcb_buddy_status( ic, cmd[1], 0, NULL, NULL );
 	}
 	else if( strcmp( cmd[0], "NLN" ) == 0 )
@@ -428,5 +429,6 @@
 		}
 		
-		serv_got_update( ic, cmd[2], 1, 0, 0, 0, st->number, 0 );
+		imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
+		                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
 	}
 	else if( strcmp( cmd[0], "RNG" ) == 0 )
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/nogaim.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -187,5 +187,5 @@
 
 	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_CONN_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
 		strip_html( text );
 	
@@ -494,10 +494,10 @@
 /* server.c */                    
 
-void serv_got_update( struct im_connection *ic, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps )
+void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
 {
 	user_t *u;
 	int oa, oo;
 	
-	u = user_findhandle( ic, handle );
+	u = user_findhandle( ic, (char*) handle );
 	
 	if( !u )
@@ -505,6 +505,6 @@
 		if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
 		{
-			add_buddy( ic, NULL, handle, NULL );
-			u = user_findhandle( ic, handle );
+			add_buddy( ic, NULL, (char*) handle, NULL );
+			u = user_findhandle( ic, (char*) handle );
 		}
 		else
@@ -512,12 +512,11 @@
 			if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
 			{
-				imcb_log( ic, "serv_got_update() for handle %s:", handle );
-				imcb_log( ic, "loggedin = %d, type = %d", loggedin, type );
+				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;
 		}
-		/* Why did we have this here....
-		return; */
 	}
 	
@@ -531,10 +530,10 @@
 	}
 	
-	if( loggedin && !u->online )
+	if( ( flags & OPT_LOGGED_IN ) && !u->online )
 	{
 		irc_spawn( ic->irc, u );
 		u->online = 1;
 	}
-	else if( !loggedin && u->online )
+	else if( !( flags & OPT_LOGGED_IN ) && u->online )
 	{
 		struct groupchat *c;
@@ -545,17 +544,27 @@
 		/* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */
 		for( c = ic->conversations; c; c = c->next )
-			remove_chat_buddy_silent( c, handle );
-	}
-	
-	if( ( type & UC_UNAVAILABLE ) && ( strcmp( ic->acc->prpl->name, "oscar" ) == 0 || strcmp( ic->acc->prpl->name, "icq" ) == 0 ) )
-	{
-		u->away = g_strdup( "Away" );
-	}
-	else if( ( type & UC_UNAVAILABLE ) && ic->acc->prpl->get_status_string )
-	{
-		u->away = g_strdup( ic->acc->prpl->get_status_string( ic, type ) );
-	}
-	else
-		u->away = NULL;
+			remove_chat_buddy_silent( c, (char*) 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 waste_any_state_information_for_now(); */
 	
 	/* LISPy... */
@@ -612,5 +621,5 @@
 	
 	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_CONN_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
 		strip_html( msg );
 
@@ -718,5 +727,5 @@
 	
 	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
-	    ( ( ic->flags & OPT_CONN_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
 		strip_html( msg );
 	
@@ -925,5 +934,5 @@
 	int st;
 	
-	if( ( ic->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+	if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
 	{
 		buf = escape_html( msg );
@@ -941,5 +950,5 @@
 	char *buf = NULL;
 	
-	if( ( c->ic->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+	if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
 	{
 		buf = escape_html( msg );
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/nogaim.h	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -6,5 +6,6 @@
 
 /*
- * nogaim
+ * nogaim, soon to be known as im_api. Not a separate product (unless
+ * someone would be interested in such a thing), just a new name.
  *
  * Gaim without gaim - for BitlBee
@@ -15,5 +16,5 @@
  * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
  *                          (and possibly other members of the Gaim team)
- * Copyright 2002-2004 Wilmer van der Gaast <wilmer@gaast.net>
+ * Copyright 2002-2007 Wilmer van der Gaast <wilmer@gaast.net>
  */
 
@@ -44,5 +45,4 @@
 #include "sha.h"
 
-
 #define BUF_LEN MSG_LEN
 #define BUF_LONG ( BUF_LEN * 2 )
@@ -54,10 +54,11 @@
 
 #define WEBSITE "http://www.bitlbee.org/"
-#define IM_FLAG_AWAY 0x0020
 #define GAIM_AWAY_CUSTOM "Custom"
 
-#define OPT_CONN_HTML   0x00000001
-#define OPT_LOGGED_IN   0x00010000
-#define OPT_LOGGING_OUT 0x00020000
+/* Sharing flags between buddies and connections. Or planning to, at least... */
+#define OPT_LOGGED_IN   0x00000001
+#define OPT_LOGGING_OUT 0x00000002
+#define OPT_AWAY        0x00000004
+#define OPT_DOES_HTML   0x00000010
 
 /* ok. now the fun begins. first we create a connection structure */
@@ -65,5 +66,5 @@
 {
 	account_t *acc;
-	guint32 flags;
+	u_int32_t flags;
 	
 	/* each connection then can have its own protocol-specific data */
@@ -164,7 +165,4 @@
 	     (* chat_join)	(struct im_connection *, char *chat, char *nick, char *password);
 	
-	/* DIE! */
-	char *(* get_status_string) (struct im_connection *ic, int stat);
-	
 	GList *(* away_states)(struct im_connection *ic);
 	
@@ -201,5 +199,4 @@
 G_MODULE_EXPORT void serv_got_chat_left( struct groupchat *c );
 struct groupchat *chat_by_channel( char *channel );
-struct groupchat *chat_by_id( int id );
 
 /* Buddy management */
@@ -209,5 +206,6 @@
 
 /* Buddy activity */
-G_MODULE_EXPORT void serv_got_update( struct im_connection *ic, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps );
+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 );
 G_MODULE_EXPORT void serv_got_im( struct im_connection *ic, char *handle, char *msg, guint32 flags, time_t mtime, gint len );
 G_MODULE_EXPORT void serv_got_typing( struct im_connection *ic, char *handle, int timeout, int type );
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/oscar/oscar.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -365,5 +365,5 @@
 		   Let's hope nothing will break. ;-) */
 	} else {
-		ic->flags |= OPT_CONN_HTML;
+		ic->flags |= OPT_DOES_HTML;
 	}
 
@@ -968,7 +968,6 @@
 	aim_userinfo_t *info;
 	time_t time_idle = 0, signon = 0;
-	int type = 0;
-	int caps = 0;
-	char *tmp;
+	int flags = OPT_LOGGED_IN;
+	char *tmp, *state_string = NULL;
 
 	va_list ap;
@@ -977,33 +976,24 @@
 	va_end(ap);
 
-	if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
-		caps = info->capabilities;
-	if (info->flags & AIM_FLAG_ACTIVEBUDDY)
-		type |= UC_AB;
-
 	if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
-		if (info->flags & AIM_FLAG_UNCONFIRMED)
-			type |= UC_UNCONFIRMED;
-		if (info->flags & AIM_FLAG_ADMINISTRATOR)
-			type |= UC_ADMIN;
-		if (info->flags & AIM_FLAG_AOL)
-			type |= UC_AOL;
-		if (info->flags & AIM_FLAG_FREE)
-			type |= UC_NORMAL;
 		if (info->flags & AIM_FLAG_AWAY)
-			type |= UC_UNAVAILABLE;
-		if (info->flags & AIM_FLAG_WIRELESS)
-			type |= UC_WIRELESS;
-	}
+			flags |= OPT_AWAY;
+	}
+	
 	if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
-		type = (info->icqinfo.status << 7);
 		if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
 		      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
-			type |= UC_UNAVAILABLE;
+			flags |= OPT_AWAY;
 		}
-	}
-
-	if (caps & AIM_CAPS_ICQ)
-		caps ^= AIM_CAPS_ICQ;
+		
+		if( info->icqinfo.status & AIM_ICQ_STATE_DND )
+			state_string = "Do Not Disturb";
+		else if( info->icqinfo.status & AIM_ICQ_STATE_OUT )
+			state_string = "Not Available";
+		else if( info->icqinfo.status & AIM_ICQ_STATE_BUSY )
+			state_string = "Occupied";
+		else if( info->icqinfo.status & AIM_ICQ_STATE_INVISIBLE )
+			state_string = "Invisible";
+	}
 
 	if (info->present & AIM_USERINFO_PRESENT_IDLE) {
@@ -1020,6 +1010,6 @@
 	g_free(tmp);
 
-	serv_got_update(ic, info->sn, 1, info->warnlevel/10, signon,
-			time_idle, type, caps);
+	imcb_buddy_status(ic, info->sn, flags, state_string, NULL);
+	/* imcb_buddy_times(ic, info->sn, signon, time_idle); */
 
 	return 1;
@@ -1035,5 +1025,5 @@
 	va_end(ap);
 
-	serv_got_update(ic, info->sn, 0, 0, 0, 0, 0, 0);
+	imcb_buddy_status(ic, info->sn, 0, NULL, NULL );
 
 	return 1;
@@ -1046,5 +1036,5 @@
 	
 	if (args->icbmflags & AIM_IMFLAGS_AWAY)
-		flags |= IM_FLAG_AWAY;
+		flags |= OPT_AWAY;
 	
 	if ((args->icbmflags & AIM_IMFLAGS_UNICODE) || (args->icbmflags & AIM_IMFLAGS_ISO_8859_1)) {
@@ -1821,5 +1811,5 @@
 	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;
 	int ret = 0, len = strlen(message);
-	if (imflags & IM_FLAG_AWAY) {
+	if (imflags & OPT_AWAY) {
 		ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message);
 	} else {
@@ -2445,32 +2435,4 @@
 }
 
-static char *oscar_get_status_string( struct im_connection *ic, int number )
-{
-	struct oscar_data *od = ic->proto_data;
-	
-	if( ! number & UC_UNAVAILABLE )
-	{
-		return( NULL );
-	}
-	else if( od->icq )
-	{
-		number >>= 7;
-		if( number & AIM_ICQ_STATE_DND )
-			return( "Do Not Disturb" );
-		else if( number & AIM_ICQ_STATE_OUT )
-			return( "Not Available" );
-		else if( number & AIM_ICQ_STATE_BUSY )
-			return( "Occupied" );
-		else if( number & AIM_ICQ_STATE_INVISIBLE )
-			return( "Invisible" );
-		else
-			return( "Away" );
-	}
-	else
-	{
-		return( "Away" );
-	}
-}
-
 int oscar_send_typing(struct im_connection *ic, char * who, int typing)
 {
@@ -2633,5 +2595,4 @@
 	ret->rem_deny = oscar_rem_deny;
 	ret->set_permit_deny = oscar_set_permit_deny;
-	ret->get_status_string = oscar_get_status_string;
 	ret->send_typing = oscar_send_typing;
 	
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision 84b045d409f1e8da6d8bf379c6fef7236dcd9bcd)
+++ protocols/yahoo/yahoo.c	(revision 6bbb939e953bbe1ca9ed3101a1569abe4521f543)
@@ -293,43 +293,4 @@
 }
 
-static char *byahoo_get_status_string( struct im_connection *ic, int stat )
-{
-	enum yahoo_status a = stat >> 1;
-	
-	switch (a)
-	{
-	case YAHOO_STATUS_BRB:
-		return "Be Right Back";
-	case YAHOO_STATUS_BUSY:
-		return "Busy";
-	case YAHOO_STATUS_NOTATHOME:
-		return "Not At Home";
-	case YAHOO_STATUS_NOTATDESK:
-		return "Not At Desk";
-	case YAHOO_STATUS_NOTINOFFICE:
-		return "Not In Office";
-	case YAHOO_STATUS_ONPHONE:
-		return "On Phone";
-	case YAHOO_STATUS_ONVACATION:
-		return "On Vacation";
-	case YAHOO_STATUS_OUTTOLUNCH:
-		return "Out To Lunch";
-	case YAHOO_STATUS_STEPPEDOUT:
-		return "Stepped Out";
-	case YAHOO_STATUS_INVISIBLE:
-		return "Invisible";
-	case YAHOO_STATUS_CUSTOM:
-		return "Away";
-	case YAHOO_STATUS_IDLE:
-		return "Idle";
-	case YAHOO_STATUS_OFFLINE:
-		return "Offline";
-	case YAHOO_STATUS_NOTIFY:
-		return "Notify";
-	default:
-		return "Away";
-	}
-}
-
 static void byahoo_chat_send( struct groupchat *c, char *message, int flags )
 {
@@ -393,5 +354,4 @@
 	ret->add_buddy = byahoo_add_buddy;
 	ret->remove_buddy = byahoo_remove_buddy;
-	ret->get_status_string = byahoo_get_status_string;
 	ret->send_typing = byahoo_send_typing;
 	
@@ -586,8 +546,63 @@
 {
 	struct im_connection *ic = byahoo_get_ic_by_id( id );
-	
-	serv_got_update( ic, who, stat != YAHOO_STATUS_OFFLINE, 0, 0,
-	                 ( stat == YAHOO_STATUS_IDLE ) ? away : 0,
-	                 ( stat != YAHOO_STATUS_AVAILABLE ) | ( stat << 1 ), 0 );
+	char *state_string = NULL;
+	int flags = OPT_LOGGED_IN;
+	
+	if( away )
+		flags |= OPT_AWAY;
+	
+	switch (stat)
+	{
+	case YAHOO_STATUS_BRB:
+		state_string = "Be Right Back";
+		break;
+	case YAHOO_STATUS_BUSY:
+		state_string = "Busy";
+		break;
+	case YAHOO_STATUS_NOTATHOME:
+		state_string = "Not At Home";
+		break;
+	case YAHOO_STATUS_NOTATDESK:
+		state_string = "Not At Desk";
+		break;
+	case YAHOO_STATUS_NOTINOFFICE:
+		state_string = "Not In Office";
+		break;
+	case YAHOO_STATUS_ONPHONE:
+		state_string = "On Phone";
+		break;
+	case YAHOO_STATUS_ONVACATION:
+		state_string = "On Vacation";
+		break;
+	case YAHOO_STATUS_OUTTOLUNCH:
+		state_string = "Out To Lunch";
+		break;
+	case YAHOO_STATUS_STEPPEDOUT:
+		state_string = "Stepped Out";
+		break;
+	case YAHOO_STATUS_INVISIBLE:
+		state_string = "Invisible";
+		break;
+	case YAHOO_STATUS_CUSTOM:
+		state_string = "Away";
+		break;
+	case YAHOO_STATUS_IDLE:
+		state_string = "Idle";
+		break;
+	case YAHOO_STATUS_OFFLINE:
+		state_string = "Offline";
+		flags = 0;
+		break;
+	case YAHOO_STATUS_NOTIFY:
+		state_string = "Notify";
+		break;
+	}
+	
+	imcb_buddy_status( ic, who, flags, state_string, msg );
+	
+	/* Not implemented yet...
+	if( stat == YAHOO_STATUS_IDLE )
+		imcb_buddy_times( ic, who, 0, away );
+	*/
 }
 
