# HG changeset patch # User Mark Doliner # Date 1076472376 0 # Node ID 9790cda80d52dc7080c97f83bd2a702448f94e34 # Parent ad524b8c9c7129d2bc13b916ca96761ac6204580 [gaim-migrate @ 8948] Various bits o' chat code cleanup for oscar. Mostly I just wanted to re-use some code for incoming i18n chat messages. committer: Tailor Script diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/aim.h --- a/src/protocols/oscar/aim.h Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/aim.h Wed Feb 11 04:06:16 2004 +0000 @@ -862,6 +862,7 @@ /* 0x0004 */ faim_export int aim_im_reqparams(aim_session_t *sess); /* 0x0006 */ faim_export int aim_im_sendch1_ext(aim_session_t *sess, struct aim_sendimext_args *args); /* 0x0006 */ faim_export int aim_im_sendch1(aim_session_t *, const char *destsn, fu16_t flags, const char *msg); +/* 0x0006 */ faim_export int aim_im_sendch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance); /* 0x0006 */ faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum); /* 0x0006 */ faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args); /* 0x0006 */ faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port); @@ -1127,8 +1128,6 @@ faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn); -faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance); - faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange); faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name); @@ -1400,6 +1399,7 @@ faim_internal int aim_tlvlist_add_32(aim_tlvlist_t **list, const fu16_t type, const fu32_t value); faim_internal int aim_tlvlist_add_caps(aim_tlvlist_t **list, const fu16_t type, const fu32_t caps); faim_internal int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *userinfo); +faim_internal int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance); faim_internal int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl); faim_internal int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const fu16_t type, const fu16_t lenth, const fu8_t *value); diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/chat.c --- a/src/protocols/oscar/chat.c Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/chat.c Wed Feb 11 04:06:16 2004 +0000 @@ -85,72 +85,6 @@ return 0; } -static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) -{ - fu8_t *buf; - int buflen; - aim_bstream_t bs; - - buflen = 2 + 1 + strlen(roomname) + 2; - - if (!(buf = malloc(buflen))) - return 0; - - aim_bstream_init(&bs, buf, buflen); - - aimbs_put16(&bs, exchange); - aimbs_put8(&bs, strlen(roomname)); - aimbs_putraw(&bs, roomname, strlen(roomname)); - aimbs_put16(&bs, instance); - - aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); - - 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 - * family 0x000e, with a little added on to specify the exchange and room - * name. - */ -faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) -{ - aim_frame_t *fr; - aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; - struct chatsnacinfo csi; - - if (!sess || !conn || !roomname || !strlen(roomname)) - return -EINVAL; - - if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) - return -ENOMEM; - - memset(&csi, 0, sizeof(csi)); - csi.exchange = exchange; - strncpy(csi.name, roomname, sizeof(csi.name)); - csi.instance = instance; - - snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); - aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); - - /* - * Requesting service chat (0x000e) - */ - aimbs_put16(&fr->data, 0x000e); - - aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance); - aim_tlvlist_write(&fr->data, &tl); - aim_tlvlist_free(&tl); - - aim_tx_enqueue(sess, fr); - - return 0; -} - faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) { int namelen; @@ -179,96 +113,6 @@ } /* - * conn must be a BOS connection! - */ -faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) -{ - int i; - aim_frame_t *fr; - aim_msgcookie_t *cookie; - struct aim_invite_priv *priv; - fu8_t ckstr[8]; - aim_snacid_t snacid; - aim_tlvlist_t *otl = NULL, *itl = NULL; - fu8_t *hdr; - int hdrlen; - aim_bstream_t hdrbs; - - if (!sess || !conn || !sn || !msg || !roomname) - return -EINVAL; - - if (conn->type != AIM_CONN_TYPE_BOS) - return -EINVAL; - - 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); - - /* - * Cookie - */ - for (i = 0; i < 8; i++) - ckstr[i] = (fu8_t)rand(); - - /* XXX should be uncached by an unwritten 'invite accept' handler */ - if ((priv = malloc(sizeof(struct aim_invite_priv)))) { - priv->sn = strdup(sn); - priv->roomname = strdup(roomname); - priv->exchange = exchange; - priv->instance = instance; - } - - if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) - aim_cachecookie(sess, cookie); - else - free(priv); - - /* ICBM Header */ - aimbs_putraw(&fr->data, ckstr, 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 = malloc(hdrlen); - aim_bstream_init(&hdrbs, hdr, hdrlen); - - aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ - aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ - aim_putcap(&hdrbs, AIM_CAPS_CHAT); - - aim_tlvlist_add_16(&itl, 0x000a, 0x0001); - aim_tlvlist_add_noval(&itl, 0x000f); - aim_tlvlist_add_raw(&itl, 0x000c, strlen(msg), msg); - aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); - - aim_tlvlist_write(&fr->data, &otl); - - free(hdr); - aim_tlvlist_free(&itl); - aim_tlvlist_free(&otl); - - aim_tx_enqueue(sess, fr); - - return 0; -} - -/* * Subtype 0x0002 - General room information. Lots of stuff. * * Values I know are in here but I havent attached @@ -583,12 +427,12 @@ * possibly others * */ -static int incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) +static int incomingim_ch3(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { + int ret = 0, i; + aim_rxcallback_t userfunc; aim_userinfo_t userinfo; - aim_rxcallback_t userfunc; - int ret = 0; - fu8_t *cookie; + fu8_t cookie[8]; fu16_t channel; aim_tlvlist_t *otl; char *msg = NULL; @@ -599,9 +443,10 @@ memset(&userinfo, 0, sizeof(aim_userinfo_t)); /* - * ICBM Cookie. Uncache it. + * Read ICBM Cookie. */ - cookie = aimbs_getraw(bs, 8); + for (i = 0; i < 8; i++) + cookie[i] = aimbs_get8(bs); if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { free(ck->data); @@ -611,10 +456,7 @@ /* * Channel ID * - * Channels 1 and 2 are implemented in the normal ICBM - * parser. - * - * We only do channel 3 here. + * Channel 0x0003 is used for chat messages. * */ channel = aimbs_get16(bs); @@ -682,7 +524,6 @@ ret = userfunc(sess, rx, &userinfo, len, msg, charset); aim_info_free(&userinfo); - free(cookie); free(msg); aim_tlvlist_free(&otl); @@ -697,7 +538,7 @@ else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) return userlistchange(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0006) - return incomingmsg(sess, mod, rx, snac, bs); + return incomingim_ch3(sess, mod, rx, snac, bs); return 0; } diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/im.c --- a/src/protocols/oscar/im.c Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/im.c Wed Feb 11 04:06:16 2004 +0000 @@ -422,6 +422,94 @@ return aim_im_sendch1_ext(sess, &args); } +/* + * Subtype 0x0006 - Send a chat invitation. + */ +faim_export int aim_im_sendch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) +{ + aim_conn_t *conn; + aim_frame_t *fr; + aim_snacid_t snacid; + int i; + aim_msgcookie_t *cookie; + struct aim_invite_priv *priv; + fu8_t ck[8]; + aim_tlvlist_t *otl = NULL, *itl = NULL; + fu8_t *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] = (fu8_t)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 = malloc(sizeof(struct aim_invite_priv)))) { + priv->sn = strdup(sn); + priv->roomname = strdup(roomname); + priv->exchange = exchange; + priv->instance = instance; + } + + if ((cookie = aim_mkcookie(ck, AIM_COOKIETYPE_INVITE, priv))) + aim_cachecookie(sess, cookie); + else + 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 = 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_tlvlist_add_16(&itl, 0x000a, 0x0001); + aim_tlvlist_add_noval(&itl, 0x000f); + aim_tlvlist_add_raw(&itl, 0x000c, strlen(msg), msg); + aim_tlvlist_add_chatroom(&itl, 0x2711, exchange, roomname, instance); + aim_tlvlist_write(&hdrbs, &itl); + + aim_tlvlist_add_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); + + aim_tlvlist_write(&fr->data, &otl); + + free(hdr); + aim_tlvlist_free(&itl); + aim_tlvlist_free(&otl); + + aim_tx_enqueue(sess, fr); + + return 0; +} + /** * Subtype 0x0006 - Send your icon to a given user. * @@ -1887,7 +1975,7 @@ memset(&userinfo, 0x00, sizeof(aim_userinfo_t)); /* - * Read ICBM Cookie. And throw away. + * Read ICBM Cookie. */ for (i = 0; i < 8; i++) cookie[i] = aimbs_get8(bs); diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/oscar.c Wed Feb 11 04:06:16 2004 +0000 @@ -329,33 +329,51 @@ return encodingflag; } -static fu32_t oscar_encoding_parse(const char *enc) +/* + * Take a string of the form charset="bleh" where bleh is + * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and + * return a newly allocated string containing bleh. + */ +static gchar *oscar_encoding_extract(const char *encoding) { - char *charset; - - /* If anything goes wrong, fall back on ASCII and print a message */ - if (enc == NULL) { - gaim_debug(GAIM_DEBUG_WARNING, "oscar", - "Encoding was null, that's odd\n"); + gchar *ret = NULL; + char *begin, *end; + + /* Make sure encoding begings with charset= */ + if (strncmp(encoding, "text/aolrtf; charset=", 21)) + 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; +} + +/* + * Return the flag specifying the given encoding. + */ +static fu32_t oscar_encoding_parse(const char *encoding) +{ + if ((encoding == NULL) || encoding[0] == '\0') { + gaim_debug(GAIM_DEBUG_WARNING, "oscar", "Empty encoding, assuming ASCII\n"); return 0; } - charset = strstr(enc, "charset="); - if (charset == NULL) { - gaim_debug(GAIM_DEBUG_WARNING, "oscar", - "No charset specified for info, assuming ASCII\n"); + + if (!strcmp(encoding, "us-ascii") || !strcmp(encoding, "utf-8")) { + /* UTF-8 is our native encoding, ASCII is a proper subset */ return 0; - } - charset += 8; - if (!strcmp(charset, "\"us-ascii\"") || !strcmp(charset, "\"utf-8\"")) { - /* UTF-8 is our native charset, ASCII is a proper subset */ - return 0; - } else if (!strcmp(charset, "\"iso-8859-1\"")) { + } else if (!strcmp(encoding, "iso-8859-1")) { return AIM_IMFLAGS_ISO_8859_1; - } else if (!strcmp(charset, "\"unicode-2-0\"")) { + } else if (!strcmp(encoding, "unicode-2-0")) { return AIM_IMFLAGS_UNICODE; } else { gaim_debug(GAIM_DEBUG_WARNING, "oscar", - "Unrecognized character set '%s', using ASCII\n", charset); + "Unrecognized character encoding '%s', falling back to ASCII\n", encoding); return 0; } } @@ -1825,14 +1843,7 @@ /* Available message stuff */ free(bi->availmsg); if (info->avail != NULL) - if (info->avail_encoding) { - gchar *enc = g_strdup_printf("charset=\"%s\"", info->avail_encoding); - bi->availmsg = oscar_encoding_to_utf8(enc, info->avail, info->avail_len); - g_free(enc); - } else { - /* No explicit encoding means utf8. Yay. */ - bi->availmsg = g_strdup(info->avail); - } + bi->availmsg = oscar_encoding_to_utf8(info->avail_encoding, info->avail, info->avail_len); else bi->availmsg = NULL; @@ -3208,7 +3219,9 @@ g_string_append_printf(text, _("Idle: Active")); if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { - away_utf8 = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len); + gchar *charset = oscar_encoding_extract(userinfo->away_encoding); + away_utf8 = oscar_encoding_to_utf8(charset, userinfo->away, userinfo->away_len); + g_free(charset); if (away_utf8 != NULL) { g_string_append_printf(text, "
%s", away_utf8); g_free(away_utf8); @@ -3216,7 +3229,9 @@ } if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { - info_utf8 = oscar_encoding_to_utf8(userinfo->info_encoding, userinfo->info, userinfo->info_len); + gchar *charset = oscar_encoding_extract(userinfo->info_encoding); + info_utf8 = oscar_encoding_to_utf8(charset, userinfo->info, userinfo->info_len); + g_free(charset); if (info_utf8 != NULL) { g_string_append_printf(text, "
%s", info_utf8); g_free(info_utf8); @@ -3412,15 +3427,13 @@ static int gaim_conv_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) { GaimConnection *gc = sess->aux_data; + struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); + gchar *utf8; va_list ap; aim_userinfo_t *info; - GError *err = NULL; + int len; char *msg; - char *tmp; - int len; char *charset; - int convlen; - struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); va_start(ap, fr); info = va_arg(ap, aim_userinfo_t *); @@ -3429,24 +3442,9 @@ charset = va_arg(ap, char *); va_end(ap); - if (charset) { - if (strcmp(charset, "unicode-2-0") == 0) - charset = "UCS-2BE"; - } else { - charset = "iso-8859-1"; - } - - tmp = g_convert(msg, len, "UTF-8", charset, NULL, &convlen, &err); - - if (err) { - gaim_debug(GAIM_DEBUG_INFO, "oscar", - "Unicode Chat conversion: %s\n", err->message); - tmp = g_strdup(_("(There was an error receiving this message)")); - g_error_free(err); - } - - serv_got_chat_in(gc, ccon->id, info->sn, 0, tmp, time((time_t)NULL)); - g_free(tmp); + utf8 = oscar_encoding_to_utf8(charset, msg, len); + serv_got_chat_in(gc, ccon->id, info->sn, 0, utf8, time((time_t)NULL)); + g_free(utf8); return 1; } @@ -5334,7 +5332,7 @@ if (!ccon) return; - aim_chat_invite(od->sess, od->conn, name, message ? message : "", + aim_im_sendch2_chatinvite(od->sess, name, message ? message : "", ccon->exchange, ccon->name, 0x0); } @@ -5590,7 +5588,9 @@ } if ((userinfo != NULL) && (userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { - gchar *away_utf8 = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len); + gchar *charset = oscar_encoding_extract(userinfo->away_encoding); + gchar *away_utf8 = away_utf8 = oscar_encoding_to_utf8(charset, userinfo->away, userinfo->away_len); + g_free(charset); if (away_utf8 != NULL) { gchar *tmp1, *tmp2; const char *tmp3; diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/service.c --- a/src/protocols/oscar/service.c Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/service.c Wed Feb 11 04:06:16 2004 +0000 @@ -97,6 +97,47 @@ return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); } +/* + * Join a room of name roomname. This is the first step to joining an + * already created room. It's basically a Service Request for + * family 0x000e, with a little added on to specify the exchange and room + * name. + */ +faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) +{ + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + struct chatsnacinfo csi; + + if (!sess || !conn || !roomname || !strlen(roomname)) + return -EINVAL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) + return -ENOMEM; + + memset(&csi, 0, sizeof(csi)); + csi.exchange = exchange; + strncpy(csi.name, roomname, sizeof(csi.name)); + csi.instance = instance; + + snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); + aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); + + /* + * Requesting service chat (0x000e) + */ + aimbs_put16(&fr->data, 0x000e); + + aim_tlvlist_add_chatroom(&tl, 0x0001, exchange, roomname, instance); + aim_tlvlist_write(&fr->data, &tl); + aim_tlvlist_free(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; +} + /* Subtype 0x0005 - Redirect */ static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { diff -r ad524b8c9c71 -r 9790cda80d52 src/protocols/oscar/tlv.c --- a/src/protocols/oscar/tlv.c Wed Feb 11 04:04:48 2004 +0000 +++ b/src/protocols/oscar/tlv.c Wed Feb 11 04:06:16 2004 +0000 @@ -510,6 +510,40 @@ } /** + * Adds the given chatroom info to a TLV chain. + * + * @param list Destination chain. + * @param type TLV type to add. + * @param roomname The name of the chat. + * @param instance The instance. + * @retun The size of the value added. + */ +faim_internal int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) +{ + fu8_t *buf; + int len; + aim_bstream_t bs; + + len = 2 + 1 + strlen(roomname) + 2; + + if (!(buf = malloc(len))) + return 0; + + aim_bstream_init(&bs, buf, len); + + aimbs_put16(&bs, exchange); + aimbs_put8(&bs, strlen(roomname)); + aimbs_putraw(&bs, roomname, strlen(roomname)); + aimbs_put16(&bs, instance); + + len = aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); + + free(buf); + + return len; +} + +/** * Adds a TLV with a zero length to a TLV chain. * * @param list Destination chain.