changeset 2706:e841b14b5b89

[gaim-migrate @ 2719] oh committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sat, 10 Nov 2001 08:02:40 +0000
parents 5f431eefb0f2
children 7cdf02a9bc0e
files ChangeLog src/conversation.c src/gaim.h src/multi.h src/protocols/gg/gg.c src/protocols/icq/gaim_icq.c src/protocols/oscar/aim.h src/protocols/oscar/aim_cbtypes.h src/protocols/oscar/aim_internal.h src/protocols/oscar/icq.c src/protocols/oscar/oscar.c src/protocols/oscar/rxqueue.c src/protocols/toc/toc.c src/prpl.h src/server.c
diffstat 15 files changed, 336 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Nov 10 03:50:52 2001 +0000
+++ b/ChangeLog	Sat Nov 10 08:02:40 2001 +0000
@@ -3,6 +3,9 @@
 version 0.48:
 	* Right-click on links to open/copy URL
 	* Yahoo changes
+	* Oscar can send/receive offline messages in ICQ. Since the "real"
+	  ICQ protocol isn't working too well it's recommended that you
+	  use Oscar for ICQ.
 
 version 0.47 (11/01/2001):
 	* Better font loading (pays attention to charset now)
--- a/src/conversation.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/conversation.c	Sat Nov 10 08:02:40 2001 +0000
@@ -812,7 +812,7 @@
 
 	buf2 = g_malloc(limit);
 
-	if (c->gc->prpl->options & OPT_PROTO_HTML) {
+	if (c->gc->flags & OPT_CONN_HTML) {
 		if (convo_options & OPT_CONVO_SEND_LINKS)
 			linkify_text(buf);
 
@@ -2926,10 +2926,10 @@
 	if (!c->gc)
 		return;
 
-	if (!c->gc->prpl->checkbox)
+	if (!c->gc->checkbox)
 		return;
 
-	c->check = gtk_check_button_new_with_label(c->gc->prpl->checkbox);
+	c->check = gtk_check_button_new_with_label(c->gc->checkbox);
 	gtk_box_pack_start(GTK_BOX(c->lbox), c->check, FALSE, FALSE, 5);
 	gtk_widget_show(c->check);
 }
--- a/src/gaim.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/gaim.h	Sat Nov 10 08:02:40 2001 +0000
@@ -403,5 +403,6 @@
 extern char *str_to_utf8(unsigned char *);
 extern char *add_cr(char *);
 extern void strip_linefeed(char *);
+extern time_t get_time(int, int, int, int, int, int);
 
 #endif /* _GAIM_H_ */
--- a/src/multi.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/multi.h	Sat Nov 10 08:02:40 2001 +0000
@@ -32,6 +32,10 @@
 	/* we make this as an int in case if we want to add more protocols later */
 	int protocol;
 	struct prpl *prpl;
+	guint32 flags;
+
+	/* erg. */
+	char *checkbox;
 
 	/* all connections need an input watcher */
 	int inpa;
@@ -69,6 +73,8 @@
 	gboolean wants_to_die; /* defaults to FALSE */
 };
 
+#define OPT_CONN_HTML		0x00000001
+
 struct proto_user_opt {
 	char *label;
 	char *def;
--- a/src/protocols/gg/gg.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/gg/gg.c	Sat Nov 10 08:02:40 2001 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 2694 2001-11-06 23:58:24Z warmenhoven $
+ * $Id: gg.c 2719 2001-11-10 08:02:40Z warmenhoven $
  *
  * Copyright (C) 2001, Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  * 
@@ -534,6 +534,8 @@
 	struct agg_data *gd = gc->proto_data = g_new0(struct agg_data, 1);
 	char buf[80];
 
+	gc->checkbox = _("Send as message");
+
 	gd->sess = g_new0(struct gg_session, 1);
 
 	if (user->proto_opt[USEROPT_NICK][0])
@@ -957,7 +959,6 @@
 	ret->protocol = PROTO_GADUGADU;
 	ret->options = 0;
 	ret->name = agg_name;
-	ret->checkbox = _("Send as message");
 	ret->list_icon = agg_list_icon;
 	ret->away_states = agg_away_states;
 	ret->actions = agg_actions;
--- a/src/protocols/icq/gaim_icq.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/icq/gaim_icq.c	Sat Nov 10 08:02:40 2001 +0000
@@ -302,6 +302,8 @@
 	icq_Link *link;
 	char ps[9];
 
+	gc->checkbox = _("Send message through server");
+
 	icq_LogLevel = ICQ_LOG_MESSAGE;
 
 	g_snprintf(ps, sizeof(ps), "%s", user->password);
@@ -500,7 +502,6 @@
 
 void icq_init(struct prpl *ret) {
 	ret->protocol = PROTO_ICQ;
-	ret->checkbox = "Send message through server";
 	ret->name = icq_name;
 	ret->list_icon = icq_list_icon;
 	ret->away_states = icq_away_states;
--- a/src/protocols/oscar/aim.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/aim.h	Sat Nov 10 08:02:40 2001 +0000
@@ -966,6 +966,17 @@
 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn);
 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn);
 
+struct aim_icq_offlinemsg {
+	fu32_t sender;
+	fu16_t year;
+	fu8_t month, day, hour, minute;
+	fu16_t type;
+	char *msg;
+};
+
+faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess);
+faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess);
+
 /* aim_util.c */
 /*
  * These are really ugly.  You'd think this was LISP.  I wish it was.
@@ -992,6 +1003,34 @@
 		(((*((buf)+2))<< 8)&0x0000ff00) + \
 		(((*((buf)+3)    )&0x000000ff)))
 
+/* Little-endian versions (damn ICQ) */
+#define aimutil_putle8(buf, data) ( \
+		(*(buf) = (unsigned char)(data) & 0xff), \
+		1)
+#define aimutil_getle8(buf) ( \
+		(*(buf)) & 0xff \
+		)
+#define aimutil_putle16(buf, data) ( \
+		(*((buf)+0) = (unsigned char)((data) >> 0) & 0xff),  \
+		(*((buf)+1) = (unsigned char)((data) >> 8) & 0xff), \
+		2)
+#define aimutil_getle16(buf) ( \
+		(((*((buf)+0)) << 0) & 0x00ff) + \
+		(((*((buf)+1)) << 8) & 0xff00) \
+		)
+#define aimutil_putle32(buf, data) ( \
+		(*((buf)+0) = (unsigned char)((data) >>  0) & 0xff), \
+		(*((buf)+1) = (unsigned char)((data) >>  8) & 0xff), \
+		(*((buf)+2) = (unsigned char)((data) >> 16) & 0xff), \
+		(*((buf)+3) = (unsigned char)((data) >> 24) & 0xff), \
+		4)
+#define aimutil_getle32(buf) ( \
+		(((*((buf)+0)) <<  0) & 0x000000ff) + \
+		(((*((buf)+1)) <<  8) & 0x0000ff00) + \
+		(((*((buf)+2)) << 16) & 0x00ff0000) + \
+		(((*((buf)+3)) << 24) & 0xff000000))
+
+
 faim_export int aimutil_putstr(u_char *, const char *, int);
 faim_export int aimutil_tokslen(char *toSearch, int index, char dl);
 faim_export int aimutil_itemcnt(char *toSearch, char dl);
--- a/src/protocols/oscar/aim_cbtypes.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/aim_cbtypes.h	Sat Nov 10 08:02:40 2001 +0000
@@ -23,6 +23,7 @@
 #define AIM_CB_FAM_TRN 0x000c
 #define AIM_CB_FAM_CTN 0x000d /* ChatNav */
 #define AIM_CB_FAM_CHT 0x000e /* Chat */
+#define AIM_CB_FAM_ICQ 0x0015
 #define AIM_CB_FAM_ATH 0x0017
 #define AIM_CB_FAM_OFT 0xfffe /* OFT/Rvous */
 #define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */
@@ -172,6 +173,16 @@
 #define AIM_CB_CHT_DEFAULT 0xffff
 
 /*
+ * SNAC Family: ICQ
+ *
+ * Most of these are actually special.
+ */ 
+#define AIM_CB_ICQ_ERROR 0x0001
+#define AIM_CB_ICQ_OFFLINEMSG 0x00f0
+#define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1
+#define AIM_CB_ICQ_DEFAULT 0xffff
+
+/*
  * SNAC Family: Authorizer
  *
  * Used only in protocol versions three and above.
--- a/src/protocols/oscar/aim_internal.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/aim_internal.h	Sat Nov 10 08:02:40 2001 +0000
@@ -72,9 +72,15 @@
 faim_internal fu8_t aimbs_get8(aim_bstream_t *bs);
 faim_internal fu16_t aimbs_get16(aim_bstream_t *bs);
 faim_internal fu32_t aimbs_get32(aim_bstream_t *bs);
+faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs);
+faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs);
+faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs);
 faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v);
 faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v);
 faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v);
+faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v);
+faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v);
+faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v);
 faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len);
 faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len);
 faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len);
--- a/src/protocols/oscar/icq.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/icq.c	Sat Nov 10 08:02:40 2001 +0000
@@ -6,16 +6,162 @@
 #define FAIM_INTERNAL
 #include <aim.h>
 
+faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+	int bslen;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+		return -EINVAL;
+
+	bslen = 2 + 4 + 2 + 2;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+
+	/* For simplicity, don't bother using a tlvlist */
+	aimbs_put16(&fr->data, 0x0001);
+	aimbs_put16(&fr->data, bslen);
+
+	aimbs_putle16(&fr->data, bslen - 2);
+	aimbs_putle32(&fr->data, atoi(sess->sn));
+	aimbs_putle16(&fr->data, 0x003c); /* I command thee. */
+	aimbs_putle16(&fr->data, snacid); /* eh. */
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
+faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+	int bslen;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+		return -EINVAL;
+
+	bslen = 2 + 4 + 2 + 2;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+
+	/* For simplicity, don't bother using a tlvlist */
+	aimbs_put16(&fr->data, 0x0001);
+	aimbs_put16(&fr->data, bslen);
+
+	aimbs_putle16(&fr->data, bslen - 2);
+	aimbs_putle32(&fr->data, atoi(sess->sn));
+	aimbs_putle16(&fr->data, 0x003e); /* I command thee. */
+	aimbs_putle16(&fr->data, snacid); /* eh. */
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
+faim_export int aim_icq_sendxmlreq(aim_session_t *sess, const char *xml)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+	int bslen;
+
+	if (!xml || !strlen(xml))
+		return -EINVAL;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+		return -EINVAL;
+
+	bslen = 2 + 10 + 2 + strlen(xml) + 1;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+
+	/* For simplicity, don't bother using a tlvlist */
+	aimbs_put16(&fr->data, 0x0001);
+	aimbs_put16(&fr->data, bslen);
+
+	aimbs_putle16(&fr->data, bslen - 2);
+	aimbs_putle32(&fr->data, atoi(sess->sn));
+	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
+	aimbs_putle16(&fr->data, snacid); /* eh. */
+	aimbs_putle16(&fr->data, 0x0998); /* shrug. */
+	aimbs_putle16(&fr->data, strlen(xml) + 1);
+	aimbs_putraw(&fr->data, xml, strlen(xml) + 1);
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
 /*
  * Response to 15/2, contains an ICQ packet.
  */
 static int icqresponse(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;
+	aim_tlvlist_t *tl;
+	aim_tlv_t *datatlv;
+	aim_bstream_t qbs;
+	fu32_t ouruin;
+	fu16_t cmdlen, cmd, reqid;
+
+	if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) {
+		faimdprintf(sess, 0, "corrupt ICQ response\n");
+		return 0;
+	}
+
+	aim_bstream_init(&qbs, datatlv->value, datatlv->length);
+
+	cmdlen = aimbs_getle16(&qbs);
+	ouruin = aimbs_getle32(&qbs);
+	cmd = aimbs_getle16(&qbs);
+	reqid = aimbs_getle16(&qbs);
+
+	faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if (cmd == 0x0041) {
+		fu16_t msglen;
+		struct aim_icq_offlinemsg msg;
+		aim_rxcallback_t userfunc;
+
+		memset(&msg, 0, sizeof(msg));
+
+		msg.sender = aimbs_getle32(&qbs);
+		msg.year = aimbs_getle16(&qbs);
+		msg.month = aimbs_getle8(&qbs);
+		msg.day = aimbs_getle8(&qbs);
+		msg.hour = aimbs_getle8(&qbs);
+		msg.minute = aimbs_getle8(&qbs);
+		msg.type = aimbs_getle16(&qbs);
+		msglen = aimbs_getle16(&qbs);
+		msg.msg = aimbs_getstr(&qbs, msglen);
+
+		if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG)))
+			ret = userfunc(sess, rx, &msg);
+
+		free(msg.msg);
+
+	} else if (cmd == 0x0042) {
+		aim_rxcallback_t userfunc;
+
+		if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE)))
+			ret = userfunc(sess, rx);
+	}
 
 	return ret;
 }
--- a/src/protocols/oscar/oscar.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/oscar.c	Sat Nov 10 08:02:40 2001 +0000
@@ -240,6 +240,8 @@
 static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...);
 static int gaim_memrequest       (aim_session_t *,  aim_frame_t*, ...);
 static int gaim_selfinfo         (aim_session_t *,  aim_frame_t*, ...);
+static int gaim_offlinemsg       (aim_session_t *,  aim_frame_t*, ...);
+static int gaim_offlinemsgdone   (aim_session_t *,  aim_frame_t*, ...);
 
 static int gaim_directim_initiate  (aim_session_t *, aim_frame_t *, ...);
 static int gaim_directim_incoming  (aim_session_t *, aim_frame_t *, ...);
@@ -445,8 +447,11 @@
 		odata->icq = TRUE;
 		/* this is odd but it's necessary for a proper do_import and do_export */
 		gc->protocol = PROTO_ICQ;
-	} else
+		gc->checkbox = _("Send offline message");
+	} else {
 		gc->protocol = PROTO_TOC;
+		gc->flags |= OPT_CONN_HTML;
+	}
 
 	sess = g_new0(aim_session_t, 1);
 
@@ -645,6 +650,8 @@
 	aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0);
 	aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0);
 	aim_conn_addhandler(sess, bosconn, 0x0001, 0x000f, gaim_selfinfo, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
 
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
 	for (i = 0; i < (int)strlen(info->bosip); i++) {
@@ -1979,11 +1986,40 @@
 
 	aim_clientready(sess, fr->conn);
 
+	aim_icq_reqofflinemsgs(sess);
+
 	aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV);
 
 	return 1;
 }
 
+static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) {
+	va_list ap;
+	struct aim_icq_offlinemsg *msg;
+	struct gaim_connection *gc = sess->aux_data;
+
+	va_start(ap, fr);
+	msg = va_arg(ap, struct aim_icq_offlinemsg *);
+	va_end(ap);
+
+	if (msg->type == 0x0001) {
+		char sender[32];
+		time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
+		g_snprintf(sender, sizeof(sender), "%lu", msg->sender);
+		serv_got_im(gc, sender, msg->msg, 0, t);
+	} else {
+		debug_printf("unknown offline message type 0x%04x\n", msg->type);
+	}
+
+	return 1;
+}
+
+static int gaim_offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+	aim_icq_ackofflinemsgs(sess);
+	return 1;
+}
+
 static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	char *address, *SNs;
@@ -2088,9 +2124,11 @@
 	if (dim) {
 		ret = aim_send_im_direct(odata->sess, dim->conn, message);
 	} else {
-		if (imflags & IM_FLAG_AWAY)
+		if (imflags & IM_FLAG_AWAY) {
 			ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message);
-		else {
+		} else if (imflags & IM_FLAG_CHECKBOX) {
+			ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_OFFLINE, message);
+		} else {
 			struct aim_sendimext_args args;
 			GSList *h = odata->hasicons;
 			struct icon_req *ir = NULL;
@@ -2771,7 +2809,7 @@
 
 void oscar_init(struct prpl *ret) {
 	ret->protocol = PROTO_OSCAR;
-	ret->options = OPT_PROTO_HTML | OPT_PROTO_BUDDY_ICON;
+	ret->options = OPT_PROTO_BUDDY_ICON;
 	ret->name = oscar_name;
 	ret->list_icon = oscar_list_icon;
 	ret->away_states = oscar_away_states;
--- a/src/protocols/oscar/rxqueue.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/oscar/rxqueue.c	Sat Nov 10 08:02:40 2001 +0000
@@ -149,6 +149,39 @@
 	return aimutil_get32(bs->data + bs->offset - 4);
 }
 
+faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs)
+{
+	
+	if (aim_bstream_empty(bs) < 1)
+		return 0; /* XXX throw an exception */
+	
+	bs->offset++;
+	
+	return aimutil_getle8(bs->data + bs->offset - 1);
+}
+
+faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs)
+{
+	
+	if (aim_bstream_empty(bs) < 2)
+		return 0; /* XXX throw an exception */
+	
+	bs->offset += 2;
+	
+	return aimutil_getle16(bs->data + bs->offset - 2);
+}
+
+faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs)
+{
+	
+	if (aim_bstream_empty(bs) < 4)
+		return 0; /* XXX throw an exception */
+	
+	bs->offset += 4;
+	
+	return aimutil_getle32(bs->data + bs->offset - 4);
+}
+
 faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v)
 {
 
@@ -182,6 +215,39 @@
 	return 1;
 }
 
+faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v)
+{
+
+	if (aim_bstream_empty(bs) < 1)
+		return 0; /* XXX throw an exception */
+
+	bs->offset += aimutil_putle8(bs->data + bs->offset, v);
+
+	return 1;
+}
+
+faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v)
+{
+
+	if (aim_bstream_empty(bs) < 2)
+		return 0; /* XXX throw an exception */
+
+	bs->offset += aimutil_putle16(bs->data + bs->offset, v);
+
+	return 2;
+}
+
+faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v)
+{
+
+	if (aim_bstream_empty(bs) < 4)
+		return 0; /* XXX throw an exception */
+
+	bs->offset += aimutil_putle32(bs->data + bs->offset, v);
+
+	return 1;
+}
+
 faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len)
 {
 
--- a/src/protocols/toc/toc.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/protocols/toc/toc.c	Sat Nov 10 08:02:40 2001 +0000
@@ -144,6 +144,7 @@
 
 	gc = new_gaim_conn(user);
 	gc->proto_data = tdt = g_new0(struct toc_data, 1);
+	gc->flags |= OPT_CONN_HTML;
 
 	g_snprintf(buf, sizeof buf, "Looking up %s",
 		   user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST);
@@ -1363,7 +1364,7 @@
 void toc_init(struct prpl *ret)
 {
 	ret->protocol = PROTO_TOC;
-	ret->options = OPT_PROTO_HTML | OPT_PROTO_CORRECT_TIME;
+	ret->options = OPT_PROTO_CORRECT_TIME;
 	ret->name = toc_name;
 	ret->list_icon = toc_list_icon;
 	ret->away_states = toc_away_states;
--- a/src/prpl.h	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/prpl.h	Sat Nov 10 08:02:40 2001 +0000
@@ -55,7 +55,7 @@
 
 /* These should all be stuff that some plugins can do and others can't */
 /* TOC/Oscar send HTML-encoded messages; most other protocols don't */
-#define OPT_PROTO_HTML            0x00000001
+/* #define OPT_PROTO_HTML            0x00000001 this should be per-connection */
 /* TOC/Oscar have signon time, and the server's time needs to be adjusted to match
  * your computer's time. We wouldn't need this if everyone used NTP. */
 #define OPT_PROTO_CORRECT_TIME    0x00000002
@@ -81,7 +81,7 @@
 	char *(* name)();
 
 	/* for ICQ and Yahoo, who have off/on per-conversation options */
-	char *checkbox;
+	/* char *checkbox; this should be per-connection */
 
 	/* returns the XPM associated with the given user class */
 	char **(* list_icon)(int);
--- a/src/server.c	Sat Nov 10 03:50:52 2001 +0000
+++ b/src/server.c	Sat Nov 10 08:02:40 2001 +0000
@@ -187,7 +187,7 @@
 		char *buf = NULL;
 		if (message) {
 			buf = g_malloc(strlen(message) + 1);
-			if (gc->prpl->options & OPT_PROTO_HTML)
+			if (gc->flags & OPT_CONN_HTML)
 				strncpy(buf, message, strlen(message) + 1);
 			else
 				strncpy_nohtml(buf, message, strlen(message) + 1);