diff -Bur bitlbee-0.92/bitlbee.c bitlbee-all/bitlbee.c
--- bitlbee-0.92/bitlbee.c	2005-02-23 10:48:31.000000000 -0500
+++ bitlbee-all/bitlbee.c	2005-04-16 18:08:48.000000000 -0400
@@ -262,7 +262,7 @@
 	{
 		fgetc( fp );
 		line = deobfucrypt( irc, s );
-		root_command_string( irc, ru, line );
+		root_command_string( irc, ru, line, 0 );
 		g_free( line );
 	}
 	fclose( fp );
@@ -280,7 +280,7 @@
 	if( set_getint( irc, "auto_connect" ) )
 	{
 		strcpy( s, "account on" );	/* Can't do this directly because r_c_s alters the string */
-		root_command_string( irc, ru, s );
+		root_command_string( irc, ru, s, 0 );
 	}
 	
 	return( 1 );
@@ -451,7 +451,7 @@
 	g_main_quit( global.loop );
 }
 
-int root_command_string( irc_t *irc, user_t *u, char *command )
+int root_command_string( irc_t *irc, user_t *u, char *command, int flags )
 {
 	char *cmd[IRC_MAX_ARGS];
 	char *s;
diff -Bur bitlbee-0.92/bitlbee.h bitlbee-all/bitlbee.h
--- bitlbee-0.92/bitlbee.h	2005-02-23 17:26:59.000000000 -0500
+++ bitlbee-all/bitlbee.h	2005-04-16 18:00:20.000000000 -0400
@@ -119,7 +119,7 @@
 gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condition, gpointer data );
 gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condition, gpointer data );
 
-int root_command_string( irc_t *irc, user_t *u, char *command );
+int root_command_string( irc_t *irc, user_t *u, char *command, int flags );
 int root_command( irc_t *irc, char *command[] );
 int bitlbee_load( irc_t *irc, char *password );
 int bitlbee_save( irc_t *irc );
diff -Bur bitlbee-0.92/commands.c bitlbee-all/commands.c
--- bitlbee-0.92/commands.c	2005-02-08 16:48:35.000000000 -0500
+++ bitlbee-all/commands.c	2005-04-16 18:04:27.000000000 -0400
@@ -128,7 +128,7 @@
 	if( checkie == -2 )
 	{
 		setpassnc( irc, cmd[1] );
-		root_command_string( irc, user_find( irc, irc->mynick ), "save" );
+		root_command_string( irc, user_find( irc, irc->mynick ), "save", 0 );
 		irc->status = USTATUS_IDENTIFIED;
 	}
 	else
diff -Bur bitlbee-0.92/irc.c bitlbee-all/irc.c
--- bitlbee-0.92/irc.c	2005-02-23 18:32:02.000000000 -0500
+++ bitlbee-all/irc.c	2005-05-23 18:56:42.000000000 -0400
@@ -576,7 +576,7 @@
 		else
 			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
 	}
-	else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 )
+	else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 )
 	{
 		if( !( cmd[1] && cmd[2] ) )
 		{
@@ -620,7 +620,7 @@
 			{
 				irc->is_private = 1;
 			}
-			irc_send( irc, cmd[1], cmd[2] );
+			irc_send( irc, cmd[1], cmd[2], (g_strcasecmp( cmd[0], "NOTICE") == 0) ? IM_FLAG_AWAY : 0 );
 		}
 	}
 	else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 )
@@ -1289,7 +1289,7 @@
 	irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
 }
 
-int irc_send( irc_t *irc, char *nick, char *s )
+int irc_send( irc_t *irc, char *nick, char *s, int flags )
 {
 	struct conversation *c = NULL;
 	user_t *u = NULL;
@@ -1377,7 +1377,7 @@
 		}
 		
 		if( u->send_handler )
-			return( u->send_handler( irc, u, s ) );
+			return( u->send_handler( irc, u, s, flags ) );
 	}
 	else if( c && c->gc && c->gc->prpl )
 	{
@@ -1392,7 +1392,7 @@
 	user_t *u = data;
 	
 	u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
-	serv_send_im( u->gc->irc, u, u->sendbuf );
+	serv_send_im( u->gc->irc, u, u->sendbuf, 0 );
 	
 	g_free( u->sendbuf );
 	u->sendbuf = NULL;
@@ -1402,7 +1402,7 @@
 	return( FALSE );
 }
 
-int buddy_send_handler( irc_t *irc, user_t *u, char *msg )
+int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
 {
 	if( !u || !u->gc ) return( 0 );
 	
@@ -1432,7 +1432,7 @@
 	}
 	else
 	{
-		return( serv_send_im( irc, u, msg ) );
+		return( serv_send_im( irc, u, msg, flags ) );
 	}
 }
 
diff -Bur bitlbee-0.92/irc.h bitlbee-all/irc.h
--- bitlbee-0.92/irc.h	2005-02-08 15:58:30.000000000 -0500
+++ bitlbee-all/irc.h	2005-04-16 17:58:09.000000000 -0400
@@ -137,11 +137,11 @@
 void irc_whois( irc_t *irc, char *nick );
 int irc_away( irc_t *irc, char *away );
 
-int irc_send( irc_t *irc, char *nick, char *s );
+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 );
 
-int buddy_send_handler( irc_t *irc, user_t *u, char *msg );
+int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
 
 #endif
diff -Bur bitlbee-0.92/protocols/nogaim.c bitlbee-all/protocols/nogaim.c
--- bitlbee-0.92/protocols/nogaim.c	2005-02-23 10:47:58.000000000 -0500
+++ bitlbee-all/protocols/nogaim.c	2005-05-15 22:51:55.000000000 -0400
@@ -167,7 +167,7 @@
    should be a compare function inside the PRPL module, but I do it this
    way for now because I don't want to touch the Gaim code too much since
    it's not going to be here for too long anymore. */
-int handle_cmp( char *a, char *b, int protocol )
+int handle_cmp( const char *a, const char *b, int protocol )
 {
 	if( protocol == PROTO_TOC || protocol == PROTO_ICQ )
 	{
@@ -283,6 +283,9 @@
 		msg = buf;
 	else
 		msg = text;
+
+	if( g_strcasecmp( set_getstr(gc->irc, "html" ), "strip" ) == 0 )
+		strip_html( msg );
 	
 	irc_usermsg( gc->irc, "%s - %s", proto_name[gc->protocol], msg );
 }
@@ -596,6 +599,11 @@
 		for( c = gc->conversations; c; c = c->next )
 			remove_chat_buddy_silent( c, handle );
 	}
+
+	if( ( type & UC_UNAVAILABLE ) && ( gc->prpl->get_away ) )
+	{
+		//		gc->prpl->get_away( gc, handle );
+	}
 	
 	if( ( type & UC_UNAVAILABLE ) && ( gc->protocol == PROTO_OSCAR || gc->protocol == PROTO_TOC ) )
 	{
@@ -628,6 +636,20 @@
 	}
 }
 
+void serv_got_away( struct gaim_connection *gc, char *handle, char *away)
+{
+	user_t *u;
+
+	u = user_findhandle( gc, handle );
+	if(!u || !away) return;
+	if(u->away)
+		g_free(u->away);
+
+	u->away = g_strdup(away);
+	if( g_strcasecmp( set_getstr( gc->irc, "html" ), "strip" ) == 0 )
+		strip_html(u->away);
+}
+
 void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len )
 {
 	irc_t *irc = gc->irc;
@@ -829,7 +851,7 @@
 		irc_usermsg( b->gc->irc, "User %s added to conversation %d", handle, b->id );
 	
 	/* It might be yourself! */
-	if( g_strcasecmp( handle, b->gc->user->username ) == 0 )
+	if( handle_cmp( handle, b->gc->user->username, b->gc->protocol ) == 0 )
 	{
 		u = user_find( b->gc->irc, b->gc->irc->nick );
 		if( !b->joined )
@@ -993,15 +1015,21 @@
 	return( set_eval_bool( irc, set, value ) );
 }
 
-int serv_send_im( irc_t *irc, user_t *u, char *msg )
+int serv_send_im( irc_t *irc, user_t *u, char *msg, int flags )
 {
 	char buf[8192];
 	
 	if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 &&
 	    do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 )
 		msg = buf;
+
+	if( u->gc->flags & OPT_CONN_HTML) {
+		char * html = escape_html(msg);
+		strncpy(buf, html, 8192);
+		g_free(html);
+	}
 	
-	return( ((struct gaim_connection *)u->gc)->prpl->send_im( u->gc, u->handle, msg, strlen( msg ), 0 ) );
+	return( ((struct gaim_connection *)u->gc)->prpl->send_im( u->gc, u->handle, msg, strlen( msg ), flags ) );
 }
 
 int serv_send_chat( irc_t *irc, struct gaim_connection *gc, int id, char *msg )
@@ -1011,6 +1039,12 @@
 	if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 &&
 	    do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 )
 		msg = buf;
+
+	if( gc->flags & OPT_CONN_HTML) {
+		char * html = escape_html(msg);
+		strncpy(buf, html, 8192);
+		g_free(html);
+	}
 	
 	return( gc->prpl->chat_send( gc, id, msg ) );
 }
diff -Bur bitlbee-0.92/protocols/nogaim.h bitlbee-all/protocols/nogaim.h
--- bitlbee-0.92/protocols/nogaim.h	2004-10-29 19:42:07.000000000 -0400
+++ bitlbee-all/protocols/nogaim.h	2005-05-15 20:19:20.000000000 -0400
@@ -249,7 +249,7 @@
 extern struct prpl *proto_prpl[16];
 
 /* nogaim.c */
-int serv_send_im(irc_t *irc, user_t *u, char *msg);
+int serv_send_im(irc_t *irc, user_t *u, char *msg, int flags);
 int serv_send_chat(irc_t *irc, struct gaim_connection *gc, int id, char *msg );
 
 G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf );
@@ -258,7 +258,7 @@
 void nogaim_init();
 int proto_away( struct gaim_connection *gc, char *away );
 char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value );
-int handle_cmp( char *a, char *b, int protocol );
+int handle_cmp(const char *a,const char *b, int protocol );
 
 gboolean auto_reconnect( gpointer data );
 void cancel_auto_reconnect( struct account *a );
@@ -297,6 +297,7 @@
 
 /* server.c */                    
 G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps );
+G_MODULE_EXPORT void serv_got_away( struct gaim_connection *gc, char *handle, char *away);
 G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len );
 G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout );
 G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data );
@@ -314,6 +315,7 @@
 G_MODULE_EXPORT char *normalize( const char *s );
 G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec );
 G_MODULE_EXPORT void strip_html( char *msg );
+G_MODULE_EXPORT char * escape_html(const char *html);
 G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value);
 
 #ifdef WITH_MSN
diff -Bur bitlbee-0.92/protocols/oscar/aim.h bitlbee-all/protocols/oscar/aim.h
--- bitlbee-0.92/protocols/oscar/aim.h	2004-10-10 07:24:06.000000000 -0400
+++ bitlbee-all/protocols/oscar/aim.h	2005-05-23 21:57:53.000000000 -0400
@@ -439,6 +439,7 @@
 int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v);
 int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps);
 int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 type);
+int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
 int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *ui);
 int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl);
 int aim_counttlvchain(aim_tlvlist_t **list);
@@ -633,6 +634,12 @@
 	unsigned short instance;
 };
 
+struct aim_chat_invitation {
+  struct gaim_connection * gc;
+  char * name;
+  guint8 exchange;
+};
+
 #define AIM_IMFLAGS_AWAY		0x0001 /* mark as an autoreply */
 #define AIM_IMFLAGS_ACK			0x0002 /* request a receipt notice */
 #define AIM_IMFLAGS_UNICODE		0x0004
@@ -811,6 +818,9 @@
 aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const guint8 *cookie);
 
 int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type);
+int aim_send_im_ch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, unsigned short exchange, const char *roomname, unsigned short instance);
+int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2);
+
 aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, guint16 numfiles, guint32 totsize);
 
 aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn);
diff -Bur bitlbee-0.92/protocols/oscar/aim_cbtypes.h bitlbee-all/protocols/oscar/aim_cbtypes.h
--- bitlbee-0.92/protocols/oscar/aim_cbtypes.h	2004-07-14 08:28:33.000000000 -0400
+++ bitlbee-all/protocols/oscar/aim_cbtypes.h	2005-04-05 21:35:58.000000000 -0400
@@ -99,6 +99,7 @@
 #define AIM_CB_MSG_MISSEDCALL 0x000a
 #define AIM_CB_MSG_CLIENTAUTORESP 0x000b
 #define AIM_CB_MSG_ACK 0x000c
+#define AIM_CB_MSG_MTN 0x0014
 #define AIM_CB_MSG_DEFAULT 0xffff
 
 /*
diff -Bur bitlbee-0.92/protocols/oscar/chat.c bitlbee-all/protocols/oscar/chat.c
--- bitlbee-0.92/protocols/oscar/chat.c	2004-10-10 07:24:06.000000000 -0400
+++ bitlbee-all/protocols/oscar/chat.c	2005-03-26 16:47:45.000000000 -0500
@@ -182,31 +182,6 @@
 	return 0;
 }
 
-static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
-{
-	guint8 *buf;
-	int buflen;
-	aim_bstream_t bs;
-
-	buflen = 2 + 1 + strlen(roomname) + 2;
-	
-	if (!(buf = g_malloc(buflen)))
-		return 0;
-
-	aim_bstream_init(&bs, buf, buflen);
-
-	aimbs_put16(&bs, exchange);
-	aimbs_put8(&bs, strlen(roomname));
-	aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname));
-	aimbs_put16(&bs, instance);
-
-	aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
-
-	g_free(buf);
-
-	return 0;
-}
-
 /*
  * Join a room of name roomname.  This is the first step to joining an 
  * already created room.  It's basically a Service Request for 
diff -Bur bitlbee-0.92/protocols/oscar/im.c bitlbee-all/protocols/oscar/im.c
--- bitlbee-0.92/protocols/oscar/im.c	2004-10-10 07:24:06.000000000 -0400
+++ bitlbee-all/protocols/oscar/im.c	2005-05-23 21:55:50.000000000 -0400
@@ -365,6 +365,94 @@
 }
 
 /*
+ * Subtype 0x0006 - Send a chat invitation.
+ */
+int aim_send_im_ch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+	int i;
+	aim_msgcookie_t *cookie;
+	struct aim_invite_priv *priv;
+	guint8 ck[8];
+	aim_tlvlist_t *otl = NULL, *itl = NULL;
+	guint8 *hdr;
+	int hdrlen;
+	aim_bstream_t hdrbs;
+	
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+		return -EINVAL;
+	
+	if (!sn || !msg || !roomname)
+		return -EINVAL;
+	
+	for (i = 0; i < 8; i++)
+		ck[i] = (guint8)rand();
+	
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
+		return -ENOMEM;
+	
+	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
+	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	
+	/* XXX should be uncached by an unwritten 'invite accept' handler */
+	if ((priv = g_malloc(sizeof(struct aim_invite_priv)))) {
+		priv->sn = g_strdup(sn);
+		priv->roomname = g_strdup(roomname);
+		priv->exchange = exchange;
+		priv->instance = instance;
+	}
+	
+	if ((cookie = aim_mkcookie(ck, AIM_COOKIETYPE_INVITE, priv)))
+		aim_cachecookie(sess, cookie);
+	else
+		g_free(priv);
+	
+	/* ICBM Header */
+	aimbs_putraw(&fr->data, ck, 8); /* Cookie */
+	aimbs_put16(&fr->data, 0x0002); /* Channel */
+	aimbs_put8(&fr->data, strlen(sn)); /* Screename length */
+	aimbs_putraw(&fr->data, sn, strlen(sn)); /* Screenname */
+	
+	/*
+	 * TLV t(0005)
+	 *
+	 * Everything else is inside this TLV.
+	 *
+	 * Sigh.  AOL was rather inconsistent right here.  So we have
+	 * to play some minor tricks.  Right inside the type 5 is some
+	 * raw data, followed by a series of TLVs.  
+	 *
+	 */
+	hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2;
+	hdr = g_malloc(hdrlen);
+	aim_bstream_init(&hdrbs, hdr, hdrlen);
+	
+	aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
+	aimbs_putraw(&hdrbs, ck, sizeof(ck)); /* I think... */
+	aim_putcap(&hdrbs, AIM_CAPS_CHAT);
+	
+	aim_addtlvtochain16(&itl, 0x000a, 0x0001);
+	aim_addtlvtochain_noval(&itl, 0x000f);
+	aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg);
+	aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
+	aim_writetlvchain(&hdrbs, &itl);
+	
+	aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
+	
+	aim_writetlvchain(&fr->data, &otl);
+	
+	g_free(hdr);
+	aim_freetlvchain(&itl);
+	aim_freetlvchain(&otl);
+	
+	aim_tx_enqueue(sess, fr);
+	
+	return 0;
+}
+
+/*
  * This is also performance sensitive. (If you can believe it...)
  *
  */
@@ -1987,6 +2075,90 @@
 	return ret;
 }
 
+/*
+ * Subtype 0x0014 - Send a mini typing notification (mtn) packet.
+ *
+ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
+ * and Gaim 0.60 and newer.
+ *
+ */
+int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
+		return -EINVAL;
+
+	if (!sn)
+		return -EINVAL;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);
+
+	/*
+	 * 8 days of light
+	 * Er, that is to say, 8 bytes of 0's
+	 */
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+
+	/*
+	 * Type 1 (should be 0x0001 for mtn)
+	 */
+	aimbs_put16(&fr->data, type1);
+
+	/*
+	 * Dest sn
+	 */
+	aimbs_put8(&fr->data, strlen(sn));
+	aimbs_putraw(&fr->data, sn, strlen(sn));
+
+	/*
+	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
+	 */
+	aimbs_put16(&fr->data, type2);
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
+/*
+ * Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
+ *
+ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
+ * and Gaim 0.60 and newer.
+ *
+ */
+static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
+{
+	int ret = 0;
+	aim_rxcallback_t userfunc;
+	char *sn;
+	guint8 snlen;
+	guint16 type1, type2;
+
+	aim_bstream_advance(bs, 8); /* Unknown - All 0's */
+	type1 = aimbs_get16(bs);
+	snlen = aimbs_get8(bs);
+	sn = aimbs_getstr(bs, snlen);
+	type2 = aimbs_get16(bs);
+
+	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+		ret = userfunc(sess, rx, type1, sn, type2);
+
+	g_free(sn);
+
+	return ret;
+}
+
 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
 {
 
@@ -2002,6 +2174,8 @@
 		return clientautoresp(sess, mod, rx, snac, bs);
 	else if (snac->subtype == 0x000c)
 		return msgack(sess, mod, rx, snac, bs);
+	else if (snac->subtype == 0x0014)
+		return mtn_receive(sess, mod, rx, snac, bs);
 
 	return 0;
 }
diff -Bur bitlbee-0.92/protocols/oscar/info.c bitlbee-all/protocols/oscar/info.c
--- bitlbee-0.92/protocols/oscar/info.c	2004-10-10 07:24:06.000000000 -0400
+++ bitlbee-all/protocols/oscar/info.c	2005-03-29 19:19:41.000000000 -0500
@@ -614,8 +614,10 @@
 {
 	aim_userinfo_t userinfo;
 	char *text_encoding = NULL, *text = NULL;
+	guint16 text_length = 0;
 	aim_rxcallback_t userfunc;
 	aim_tlvlist_t *tlvlist;
+	aim_tlv_t *tlv;
 	aim_snac_t *origsnac = NULL;
 	struct aim_priv_inforeq *inforeq;
 	int ret = 0;
@@ -649,10 +651,18 @@
 	 */
 	if (inforeq->infotype == AIM_GETINFO_GENERALINFO) {
 		text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
-		text = aim_gettlv_str(tlvlist, 0x0002, 1);
+		if((tlv = aim_gettlv(tlvlist, 0x0002, 1))) {
+			text = g_new0(char, tlv->length);
+			memcpy(text, tlv->value, tlv->length);
+			text_length = tlv->length;
+		}
 	} else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) {
 		text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
-		text = aim_gettlv_str(tlvlist, 0x0004, 1);
+		if((tlv = aim_gettlv(tlvlist, 0x0004, 1))) {
+			text = g_new0(char, tlv->length);
+			memcpy(text, tlv->value, tlv->length);
+			text_length = tlv->length;
+		}
 	} else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) {
 		aim_tlv_t *ct;
 
@@ -667,7 +677,7 @@
 	}
 
 	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text);
+		ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, text_length);
 
 	g_free(text_encoding);
 	g_free(text);
diff -Bur bitlbee-0.92/protocols/oscar/oscar.c bitlbee-all/protocols/oscar/oscar.c
--- bitlbee-0.92/protocols/oscar/oscar.c	2005-02-23 17:26:59.000000000 -0500
+++ bitlbee-all/protocols/oscar/oscar.c	2005-05-24 22:33:02.000000000 -0400
@@ -54,7 +54,7 @@
 /* Don't know if support for UTF8 is really working. For now it's UTF16 here.
    static int gaim_caps = AIM_CAPS_UTF8; */
 
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT;
+static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_CHAT;
 static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02};
 
 struct oscar_data {
@@ -82,6 +82,8 @@
 	gboolean icq;
 	GSList *evilhack;
 
+	GSList *info_requests; /*Used to separate away message requests the user made from automatic ones*/
+
 	struct {
 		guint maxbuddies; /* max users you can watch */
 		guint maxwatchers; /* max users who can watch you */
@@ -148,7 +150,6 @@
 	return tmp;
 }
 
-#if 0
 static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) {
 	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
 	struct chat_connection *c = NULL;
@@ -163,7 +164,7 @@
 
 	return c;
 }
-#endif
+
 
 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
 							aim_conn_t *conn) {
@@ -215,6 +216,8 @@
 static int gaim_ssi_parseack     (aim_session_t *, aim_frame_t *, ...);
 
 static int gaim_icqinfo          (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parseaiminfo     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parsemtn         (aim_session_t *, aim_frame_t *, ...);
 
 static char *msgerrreason[] = {
 	"Invalid error",
@@ -422,6 +425,11 @@
 		odata->create_rooms = g_slist_remove(odata->create_rooms, cr);
 		g_free(cr);
 	}
+	while(odata->info_requests) {
+		char * data = odata->info_requests->data;
+		odata->info_requests = g_slist_remove(odata->info_requests, data);
+		g_free(data);
+	}
 	if (odata->email)
 		g_free(odata->email);
 	if (odata->newp)
@@ -548,6 +556,8 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0);
 
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
 	for (i = 0; i < (int)strlen(info->bosip); i++) {
@@ -1071,33 +1081,6 @@
 	return 1;
 }
 
-static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
-#if 0
-	struct gaim_connection *gc = sess->aux_data;
-#endif
-
-	if (args->status != AIM_RENDEZVOUS_PROPOSE)
-		return 1;
-#if 0
-	if (args->reqclass & AIM_CAPS_CHAT) {
-		char *name = extract_name(args->info.chat.roominfo.name);
-		int *exch = g_new0(int, 1);
-		GList *m = NULL;
-		m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
-		*exch = args->info.chat.roominfo.exchange;
-		m = g_list_append(m, exch);
-		serv_got_chat_invite(gc,
-				     name ? name : args->info.chat.roominfo.name,
-				     userinfo->sn,
-				     (char *)args->msg,
-				     m);
-		if (name)
-			g_free(name);
-	}
-#endif
-	return 1;
-}
-
 static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {
 	char *uin, message;
 	struct oscar_data *od = (struct oscar_data *)data->gc->proto_data;
@@ -1201,6 +1184,12 @@
 	return 1;
 }
 
+int handle_cmp_aim(const char * a, const char * b) {
+	return handle_cmp(a, b, PROTO_TOC);
+}
+
+static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
+
 static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) {
 	int channel, ret = 0;
 	aim_userinfo_t *userinfo;
@@ -1357,6 +1346,10 @@
 	char *destn;
 	guint16 reason;
 	char buf[1024];
+	GSList *l;
+	struct oscar_data *od;
+
+	od = ((struct gaim_connection*)sess->aux_data)->proto_data;
 
 	va_start(ap, fr);
 	reason = (guint16)va_arg(ap, unsigned int);
@@ -1367,6 +1360,11 @@
 			(reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
 	do_error_dialog(sess->aux_data, buf, _("Gaim - Error"));
 
+	if((l = g_slist_find_custom(od->info_requests, destn, (GCompareFunc)handle_cmp_aim))) {
+		g_free(l->data);
+		od->info_requests = g_slist_remove(od->info_requests, l);
+	}
+
 	return 1;
 }
 
@@ -1663,6 +1661,7 @@
 	va_end(ap);
 
 	/* Maybe senderwarn and recverwarn should be user preferences... */
+	params->flags = 0x0000000b;
 	params->maxmsglen = 8000;
 	params->minmsginterval = 0;
 
@@ -1869,11 +1868,12 @@
 	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	if (odata->icq)
 		aim_icq_getallinfo(odata->sess, name);
-	else
-		/* people want the away message on the top, so we get the away message
-		 * first and then get the regular info, since it's too difficult to
-		 * insert in the middle. i hate people. */
+	else {
 		aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE);
+		aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO);
+		if(!g_slist_find_custom(odata->info_requests, name, (GCompareFunc)handle_cmp_aim))
+			odata->info_requests = g_slist_append(odata->info_requests, g_strdup(name));
+	}
 }
 
 static void oscar_get_away(struct gaim_connection *g, char *who) {
@@ -1885,7 +1885,7 @@
 				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_GENERALINFO);
+		aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
 }
 
 static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *message)
@@ -1977,7 +1977,8 @@
 static void oscar_remove_buddy(struct gaim_connection *g, char *name, char *group) {
 	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	struct aim_ssi_item *ssigroup;
-	while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1));
+	while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) &&
+		   !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1));
 }
 
 static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) {
@@ -2286,6 +2287,144 @@
 
 }
 
+static char *oscar_encoding_extract(const char *encoding)
+{
+	char *ret = NULL;
+	char *begin, *end;
+
+	g_return_val_if_fail(encoding != NULL, NULL);
+
+	/* Make sure encoding begins with charset= */
+	if (strncmp(encoding, "text/plain; charset=", 20) &&
+		strncmp(encoding, "text/aolrtf; charset=", 21) &&
+		strncmp(encoding, "text/x-aolrtf; charset=", 23))
+	{
+		return NULL;
+	}
+
+	begin = strchr(encoding, '"');
+	end = strrchr(encoding, '"');
+
+	if ((begin == NULL) || (end == NULL) || (begin >= end))
+		return NULL;
+
+	ret = g_strndup(begin+1, (end-1) - begin);
+
+	return ret;
+}
+
+static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen)
+{
+	char *utf8 = g_new0(char, 8192);
+
+	if ((encoding == NULL) || encoding[0] == '\0') {
+		/*		gaim_debug_info("oscar", "Empty encoding, assuming UTF-8\n");*/
+	} else if (!g_strcasecmp(encoding, "iso-8859-1")) {
+		do_iconv("iso-8859-1", "UTF-8", text, utf8, textlen, 8192);
+	} else if (!g_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1")) {
+		do_iconv("Windows-1252", "UTF-8", text, utf8, textlen, 8192);
+	} else if (!g_strcasecmp(encoding, "unicode-2-0")) {
+		do_iconv("UCS-2BE", "UTF-8", text, utf8, textlen, 8192);
+	} else if (g_strcasecmp(encoding, "us-ascii") && strcmp(encoding, "utf-8")) {
+		/*		gaim_debug_warning("oscar", "Unrecognized character encoding \"%s\", "
+		  "attempting to convert to UTF-8 anyway\n", encoding);*/
+		do_iconv(encoding, "UTF-8", text, utf8, textlen, 8192);
+	}
+
+	/*
+	 * If utf8 is still NULL then either the encoding is us-ascii/utf-8 or
+	 * we have been unable to convert the text to utf-8 from the encoding
+	 * that was specified.  So we check if the text is valid utf-8 then
+	 * just copy it.
+	 */
+	if (*utf8 == 0) {
+		if (textlen != 0 && *text != '\0'
+                    && !g_utf8_validate(text, textlen, NULL))
+			strcpy(utf8, _("(There was an error receiving this message.  The buddy you are speaking to most likely has a buggy client.)"));
+		else
+			strncpy(utf8, text, textlen);
+	}
+
+	return utf8;
+}
+
+static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
+	va_list ap;
+	aim_userinfo_t *userinfo;
+	guint16 infotype;
+	char *text_encoding = NULL, *text = NULL, *extracted_encoding = NULL;
+	guint16 text_length;
+	char *utf8 = NULL;
+	GSList *l;
+
+	va_start(ap, fr);
+	userinfo = va_arg(ap, aim_userinfo_t *);
+	infotype = va_arg(ap, int);
+	text_encoding = va_arg(ap, char*);
+	text = va_arg(ap, char*);
+	text_length = va_arg(ap, int);
+	va_end(ap);
+
+	if(text_encoding)
+		extracted_encoding = oscar_encoding_extract(text_encoding);
+	if(infotype == AIM_GETINFO_GENERALINFO) {
+		/*Display idle time*/
+		char buff[256];
+		struct tm idletime;
+		if(userinfo->idletime) {
+			memset(&idletime, 0, sizeof(struct tm));
+			idletime.tm_mday = (userinfo->idletime / 60) / 24;
+			idletime.tm_hour = (userinfo->idletime / 60) % 24;
+			idletime.tm_min = userinfo->idletime % 60;
+			idletime.tm_sec = 0;
+			strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime);
+			serv_got_crap(gc, "%s: %s", _("Idle Time"), buff);
+		}
+		
+		if(text) {
+			utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length);
+			serv_got_crap(gc, "%s\n%s", _("User Info"), utf8);
+		} else {
+			serv_got_crap(gc, _("No user info available."));
+		}
+	} else if(infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) {
+		utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length);
+		if((l = g_slist_find_custom(od->info_requests, userinfo->sn, (GCompareFunc)handle_cmp_aim))) {
+			/*If the user requested info, display it, otherwise just pass it on*/
+			g_free(l->data);
+			od->info_requests = g_slist_remove(od->info_requests, l);
+			serv_got_crap(gc, "%s\n%s", _("Away Message"), utf8);
+		}
+		serv_got_away(gc, userinfo->sn, utf8);
+	}
+
+	g_free(utf8);
+   
+	return 1;
+}
+
+int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+	struct gaim_connection * gc = sess->aux_data;
+	va_list ap;
+	guint16 type1, type2;
+	char * sn;
+
+	va_start(ap, fr);
+	type1 = va_arg(ap, int);
+	sn = va_arg(ap, char*);
+	type2 = va_arg(ap, int);
+	va_end(ap);
+
+	if(type2 == 0x0001 || type2 == 0x0002)
+		serv_got_typing(gc, sn, 0);
+
+	return 1;
+}
+
 static char *oscar_get_status_string( struct gaim_connection *gc, int number )
 {
 	struct oscar_data *od = gc->proto_data;
@@ -2314,6 +2453,177 @@
 	}
 }
 
+int oscar_chat_send(struct gaim_connection * gc, int id, char *message)
+{
+	struct oscar_data * od = (struct oscar_data*)gc->proto_data;
+	struct chat_connection * ccon;
+	
+	if(!(ccon = find_oscar_chat(gc, id)))
+		return -1;
+	
+	int ret;
+	guint8 len = strlen(message);
+	char *s;
+	  	
+	for (s = message; *s; s++)
+		if (*s & 128)
+			break;
+	  	
+	/* Message contains high ASCII chars, time for some translation! */
+	if (*s) {
+		s = g_malloc(BUF_LONG);
+		/* Try if we can put it in an ISO8859-1 string first.
+		   If we can't, fall back to UTF16. */
+		if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
+			len = ret;
+		} else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) {
+			len = ret;
+		} else {
+			/* OOF, translation failed... Oh well.. */
+			g_free( s );
+			s = message;
+		}
+	} else {
+		s = message;
+	}
+	  	
+	ret = aim_chat_send_im(od->sess, ccon->conn, AIM_CHATFLAGS_NOREFLECT, s, len);
+	  	
+	if (s != message) {	
+		g_free(s);
+  }
+  
+  return (ret >= 0);
+}
+
+void oscar_chat_invite(struct gaim_connection * gc, int id, char *message, char *who)
+{
+	struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+	struct chat_connection *ccon = find_oscar_chat(gc, id);
+	
+	if (ccon == NULL)
+		return;
+	
+	aim_send_im_ch2_chatinvite(od->sess, who, message ? message : "",
+							  ccon->exchange, ccon->name, 0x0);
+}
+
+void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc)
+{
+	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
+
+	/* Notify the conversation window that we've left the chat */
+	serv_got_chat_left(gc, cc->id);
+
+	/* Destroy the chat_connection */
+	od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
+	if (cc->inpa > 0)
+		gaim_input_remove(cc->inpa);
+	aim_conn_kill(od->sess, &cc->conn);
+	g_free(cc->name);
+	g_free(cc->show);
+	g_free(cc);
+}
+
+void oscar_chat_leave(struct gaim_connection * gc, int id)
+{
+	struct chat_connection * ccon = find_oscar_chat(gc, id);
+
+	if(ccon == NULL)
+		return;
+
+	oscar_chat_kill(gc, ccon);
+}
+
+int oscar_chat_join(struct gaim_connection * gc, char * name)
+{
+    struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+	
+	aim_conn_t * cur;
+
+	if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) {
+	
+		return (aim_chatnav_createroom(od->sess, cur, name, 4) == 0);
+	
+	} else {
+		struct create_room * cr = g_new0(struct create_room, 1);
+		cr->exchange = 4;
+		cr->name = g_strdup(name);
+		od->create_rooms = g_slist_append(od->create_rooms, cr);
+		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV);
+		return 1;
+	}
+}
+
+int oscar_chat_open(struct gaim_connection * gc, char *who)
+{
+	struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+
+	static int chat_id = 0;
+	char * chatname = g_new0(char, strlen(gc->username)+4);
+	g_snprintf(chatname, strlen(gc->username) + 4, "%s%d", gc->username, chat_id++);
+  
+	int ret = oscar_chat_join(gc, chatname);
+
+	aim_send_im_ch2_chatinvite(od->sess, who, "",
+							   4, chatname, 0x0);
+	g_free(chatname);
+	
+	return ret;
+}
+
+void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv)
+{
+	oscar_chat_join(inv->gc, inv->name);
+	g_free(inv->name);
+	g_free(inv);
+}
+
+void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv)
+{
+	g_free(inv->name);
+	g_free(inv);
+}
+
+static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
+	struct gaim_connection *gc = sess->aux_data;
+
+	if (args->status != AIM_RENDEZVOUS_PROPOSE)
+		return 1;
+
+	if (args->reqclass & AIM_CAPS_CHAT) {
+		char *name = extract_name(args->info.chat.roominfo.name);
+		int *exch = g_new0(int, 1);
+		GList *m = NULL;
+		m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
+		*exch = args->info.chat.roominfo.exchange;
+		m = g_list_append(m, exch);
+
+		char txt[1024];
+
+		g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg );
+
+		struct aim_chat_invitation * inv = g_new0(struct aim_chat_invitation, 1);
+
+		inv->gc = gc;
+		inv->exchange = *exch;
+		inv->name = g_strdup(name);
+		
+		do_ask_dialog( gc, txt, inv, oscar_accept_chat, oscar_reject_chat);
+	
+		if (name)
+			g_free(name);
+	}
+
+	return 1;
+}
+
+int oscar_send_typing(struct gaim_connection *gc, char * who, int typing)
+{
+	struct oscar_data *od = gc->proto_data;
+	return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) );
+}
+
 static struct prpl *my_protocol = NULL;
 
 void oscar_init(struct prpl *ret) {
@@ -2327,6 +2637,10 @@
 	ret->get_away = oscar_get_away;
 	ret->add_buddy = oscar_add_buddy;
 	ret->remove_buddy = oscar_remove_buddy;
+	ret->chat_send = oscar_chat_send;
+	ret->chat_invite = oscar_chat_invite;
+	ret->chat_leave = oscar_chat_leave;
+	ret->chat_open = oscar_chat_open;
 	ret->add_permit = oscar_add_permit;
 	ret->add_deny = oscar_add_deny;
 	ret->rem_permit = oscar_rem_permit;
@@ -2335,5 +2649,7 @@
 	ret->keepalive = oscar_keepalive;
 	ret->get_status_string = oscar_get_status_string;
 
+	ret->send_typing = oscar_send_typing;
+
 	my_protocol = ret;
 }
diff -Bur bitlbee-0.92/protocols/oscar/tlv.c bitlbee-all/protocols/oscar/tlv.c
--- bitlbee-0.92/protocols/oscar/tlv.c	2004-09-21 16:34:44.000000000 -0400
+++ bitlbee-all/protocols/oscar/tlv.c	2005-03-26 16:48:17.000000000 -0500
@@ -373,6 +373,31 @@
 	return buflen;
 }
 
+int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
+{
+	guint8 *buf;
+	int buflen;
+	aim_bstream_t bs;
+
+	buflen = 2 + 1 + strlen(roomname) + 2;
+	
+	if (!(buf = g_malloc(buflen)))
+		return 0;
+
+	aim_bstream_init(&bs, buf, buflen);
+
+	aimbs_put16(&bs, exchange);
+	aimbs_put8(&bs, strlen(roomname));
+	aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname));
+	aimbs_put16(&bs, instance);
+
+	aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
+
+	g_free(buf);
+
+	return 0;
+}
+
 /**
  * aim_writetlvchain - Write a TLV chain into a data buffer.
  * @buf: Destination buffer
diff -Bur bitlbee-0.92/protocols/util.c bitlbee-all/protocols/util.c
--- bitlbee-0.92/protocols/util.c	2004-10-10 07:24:06.000000000 -0400
+++ bitlbee-all/protocols/util.c	2005-04-23 15:47:58.000000000 -0400
@@ -280,7 +280,7 @@
 	{ "lt",     '<' },
 	{ "gt",     '>' },
 	{ "amp",    '&' },
-	{ "quot",  '\'' },
+	{ "quot",   '"' },
 	{ "dquot",  '"' },
 	{ "aacute", 'á' },
 	{ "eacute", 'é' },
@@ -325,6 +325,8 @@
 			
 			if( *in )
 			{
+				if( g_strncasecmp( cs+1, "br", 2) == 0 )
+					*(s++) = '\n';
 				in ++;
 			}
 			else
@@ -365,7 +367,40 @@
 	
 	strcpy( start, out );
 	g_free( out );
-} 
+}
+
+char * escape_html(const char *html)
+{
+	const char *c = html;
+	GString *ret;
+
+	if (html == NULL)
+		return NULL;
+
+	ret = g_string_new("");
+
+	while (*c) {
+		switch (*c) {
+			case '&':
+				ret = g_string_append(ret, "&amp;");
+				break;
+			case '<':
+				ret = g_string_append(ret, "&lt;");
+				break;
+			case '>':
+				ret = g_string_append(ret, "&gt;");
+				break;
+			case '"':
+				ret = g_string_append(ret, "&quot;");
+				break;
+			default:
+				ret = g_string_append_c(ret, *c);
+		}
+		c++;
+	}
+
+	return g_string_free(ret, FALSE);
+}
 
 void info_string_append(GString *str, char *newline, char *name, char *value)
 {
diff -Bur bitlbee-0.92/user.h bitlbee-all/user.h
--- bitlbee-0.92/user.h	2004-10-29 19:58:00.000000000 -0400
+++ bitlbee-all/user.h	2005-04-16 18:08:07.000000000 -0400
@@ -43,7 +43,7 @@
  	int sendbuf_len;
  	guint sendbuf_timer;
 	
-	int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg );
+	int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags );
 	
 	struct __USER *next;
 } user_t;
