Index: protocols/oscar/aim.h
===================================================================
--- protocols/oscar/aim.h	(revision c3ffa45876c584d3e86c0796f2210538bcebc377)
+++ protocols/oscar/aim.h	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
@@ -466,4 +466,5 @@
 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);
@@ -572,4 +573,9 @@
 };
 
+struct aim_chat_invitation {
+	struct gaim_connection * gc;
+	char * name;
+	guint8 exchange;
+};
 
 #define AIM_VISIBILITYCHANGE_PERMITADD    0x05
Index: protocols/oscar/chat.c
===================================================================
--- protocols/oscar/chat.c	(revision c3ffa45876c584d3e86c0796f2210538bcebc377)
+++ protocols/oscar/chat.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
@@ -180,29 +180,4 @@
 	
 	aim_tx_enqueue(sess, fr);
-
-	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;
Index: protocols/oscar/im.c
===================================================================
--- protocols/oscar/im.c	(revision c3ffa45876c584d3e86c0796f2210538bcebc377)
+++ protocols/oscar/im.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
@@ -1369,4 +1369,28 @@
 }
 
+
+static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
+{
+
+	/* XXX aim_chat_roominfo_free() */
+	g_free(args->info.chat.roominfo.name);
+
+	return;
+}
+
+static void incomingim_ch2_chat(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata)
+{
+
+	/*
+	 * Chat room info.
+	 */
+	if (servdata)
+		aim_chat_readroominfo(servdata, &args->info.chat.roominfo);
+
+	args->destructor = (void *)incomingim_ch2_chat_free;
+
+	return;
+}
+
 static void incomingim_ch2_icqserverrelay_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
 {
@@ -1617,4 +1641,6 @@
 	if (args.reqclass & AIM_CAPS_ICQSERVERRELAY)
 		incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);
+	else if (args.reqclass & AIM_CAPS_CHAT)
+		incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr);
 
 
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision c3ffa45876c584d3e86c0796f2210538bcebc377)
+++ protocols/oscar/oscar.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
@@ -62,5 +62,5 @@
    static int gaim_caps = AIM_CAPS_UTF8; */
 
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY;
+static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_CHAT;
 static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02};
 
@@ -156,5 +156,4 @@
 }
 
-#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;
@@ -171,5 +170,5 @@
 	return c;
 }
-#endif
+
 
 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
@@ -1076,12 +1075,13 @@
 }
 
+void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv);
+void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv);
+	
 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);
@@ -1091,13 +1091,21 @@
 		*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);
+
+		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);
 	}
-#endif
+
 	return 1;
 }
@@ -2484,4 +2492,136 @@
 }
 
+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_chat_invite(od->sess, od->conn, 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_chat_invite(od->sess, od->conn, 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 struct prpl *my_protocol = NULL;
 
@@ -2497,4 +2637,8 @@
 	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;
Index: protocols/oscar/tlv.c
===================================================================
--- protocols/oscar/tlv.c	(revision c3ffa45876c584d3e86c0796f2210538bcebc377)
+++ protocols/oscar/tlv.c	(revision ab4afbab829a4a5bf520d4e1425a743cdb8c4865)
@@ -340,4 +340,29 @@
 }
 
+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.
