File:  [Coherent Logic Development] / ChivanetAimPidgin / oscarprpl / src / c / family_chat.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Mon Jan 27 19:48:25 2025 UTC (6 months ago) by snw
Branches: MAIN, CoherentLogicDevelopment
CVS tags: test-tag, start, HEAD
Pidgin AIM Plugin for ChivaNet

    1: /*
    2:  * Purple's oscar protocol plugin
    3:  * This file is the legal property of its developers.
    4:  * Please see the AUTHORS file distributed alongside this file.
    5:  *
    6:  * This library is free software; you can redistribute it and/or
    7:  * modify it under the terms of the GNU Lesser General Public
    8:  * License as published by the Free Software Foundation; either
    9:  * version 2 of the License, or (at your option) any later version.
   10:  *
   11:  * This library is distributed in the hope that it will be useful,
   12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:  * Lesser General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU Lesser General Public
   17:  * License along with this library; if not, write to the Free Software
   18:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
   19: */
   20: 
   21: /*
   22:  * Family 0x000e - Routines for the Chat service.
   23:  *
   24:  */
   25: 
   26: #include "oscar.h"
   27: 
   28: #include <string.h>
   29: 
   30: /* Stored in the ->internal of chat connections */
   31: struct chatconnpriv
   32: {
   33: 	guint16 exchange;
   34: 	char *name;
   35: 	guint16 instance;
   36: };
   37: 
   38: void
   39: flap_connection_destroy_chat(OscarData *od, FlapConnection *conn)
   40: {
   41: 	struct chatconnpriv *ccp = (struct chatconnpriv *)conn->internal;
   42: 
   43: 	if (ccp)
   44: 		g_free(ccp->name);
   45: 	g_free(ccp);
   46: 
   47: 	return;
   48: }
   49: 
   50: int
   51: aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
   52: {
   53: 	if (!bs || !outinfo)
   54: 		return 0;
   55: 
   56: 	outinfo->exchange = byte_stream_get16(bs);
   57: 	outinfo->namelen = byte_stream_get8(bs);
   58: 	outinfo->name = (char *)byte_stream_getraw(bs, outinfo->namelen);
   59: 	outinfo->instance = byte_stream_get16(bs);
   60: 
   61: 	return 0;
   62: }
   63: 
   64: /*
   65:  * Subtype 0x0002 - General room information.  Lots of stuff.
   66:  *
   67:  * Values I know are in here but I haven't attached
   68:  * them to any of the 'Unknown's:
   69:  *	- Language (English)
   70:  *
   71:  */
   72: static int
   73: infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
   74: {
   75: 	aim_rxcallback_t userfunc;
   76: 	int ret = 0;
   77: 	guint8 detaillevel = 0;
   78: 	struct aim_chat_roominfo roominfo;
   79: 	GSList *tlvlist;
   80: 	guint16 maxmsglen, maxvisiblemsglen;
   81: 
   82: 	aim_chat_readroominfo(bs, &roominfo);
   83: 
   84: 	detaillevel = byte_stream_get8(bs);
   85: 
   86: 	if (detaillevel != 0x02) {
   87: 		purple_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
   88: 		return 1;
   89: 	}
   90: 
   91: 	byte_stream_get16(bs); /* skip the TLV count */
   92: 
   93: 	/*
   94: 	 * Everything else are TLVs.
   95: 	 */
   96: 	tlvlist = aim_tlvlist_read(bs);
   97: 
   98: 	/*
   99: 	 * Type 0x00d1: Maximum Message Length
  100: 	 */
  101: 	maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1);
  102: 
  103: 	/*
  104: 	 * Type 0x00da: Maximum visible message length
  105: 	 */
  106: 	maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
  107: 
  108: 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
  109: 		ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen);
  110: 	}
  111: 
  112: 	g_free(roominfo.name);
  113: 
  114: 	aim_tlvlist_free(tlvlist);
  115: 
  116: 	return ret;
  117: }
  118: 
  119: /* Subtypes 0x0003 and 0x0004 */
  120: static int
  121: userlistchange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
  122: {
  123: 	aim_userinfo_t *userinfo = NULL;
  124: 	aim_rxcallback_t userfunc;
  125: 	int curcount = 0, ret = 0;
  126: 
  127: 	while (byte_stream_bytes_left(bs)) {
  128: 		curcount++;
  129: 		userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
  130: 		aim_info_extract(od, bs, &userinfo[curcount-1]);
  131: 	}
  132: 
  133: 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
  134: 		ret = userfunc(od, conn, frame, curcount, userinfo);
  135: 
  136: 	aim_info_free(userinfo);
  137: 	g_free(userinfo);
  138: 
  139: 	return ret;
  140: }
  141: 
  142: /*
  143:  * Subtype 0x0005 - Send a Chat Message.
  144:  *
  145:  * Possible flags:
  146:  *   AIM_CHATFLAGS_NOREFLECT   --  Unset the flag that requests messages
  147:  *                                 should be sent to their sender.
  148:  *   AIM_CHATFLAGS_AWAY        --  Mark the message as an autoresponse
  149:  *                                 (Note that WinAIM does not honor this,
  150:  *                                 and displays the message as normal.)
  151:  *
  152:  * XXX convert this to use tlvchains
  153:  */
  154: int
  155: aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
  156: {
  157: 	int i;
  158: 	ByteStream bs;
  159: 	IcbmCookie *cookie;
  160: 	aim_snacid_t snacid;
  161: 	guint8 ckstr[8];
  162: 	GSList *tlvlist = NULL, *inner_tlvlist = NULL;
  163: 
  164: 	if (!od || !conn || !msg || (msglen <= 0))
  165: 		return 0;
  166: 
  167: 	byte_stream_new(&bs, 1142);
  168: 
  169: 	snacid = aim_cachesnac(od, SNAC_FAMILY_CHAT, 0x0005, 0x0000, NULL, 0);
  170: 
  171: 	/*
  172: 	 * Cookie
  173: 	 *
  174: 	 * XXX mkcookie should generate the cookie and cache it in one
  175: 	 * operation to preserve uniqueness.
  176: 	 */
  177: 	for (i = 0; i < 8; i++)
  178: 		ckstr[i] = (guint8)rand();
  179: 
  180: 	cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
  181: 	cookie->data = NULL; /* XXX store something useful here */
  182: 
  183: 	aim_cachecookie(od, cookie);
  184: 
  185: 	/* ICBM Header */
  186: 	byte_stream_putraw(&bs, ckstr, 8); /* Cookie */
  187: 	byte_stream_put16(&bs, 0x0003); /* Channel */
  188: 
  189: 	/*
  190: 	 * Type 1: Flag meaning this message is destined to the room.
  191: 	 */
  192: 	aim_tlvlist_add_noval(&tlvlist, 0x0001);
  193: 
  194: 	/*
  195: 	 * Type 6: Reflect
  196: 	 */
  197: 	if (!(flags & AIM_CHATFLAGS_NOREFLECT))
  198: 		aim_tlvlist_add_noval(&tlvlist, 0x0006);
  199: 
  200: 	/*
  201: 	 * Type 7: Autoresponse
  202: 	 */
  203: 	if (flags & AIM_CHATFLAGS_AWAY)
  204: 		aim_tlvlist_add_noval(&tlvlist, 0x0007);
  205: 
  206: 	/*
  207: 	 * SubTLV: Type 1: Message
  208: 	 */
  209: 	aim_tlvlist_add_raw(&inner_tlvlist, 0x0001, msglen, (guchar *)msg);
  210: 
  211: 	/*
  212: 	 * SubTLV: Type 2: Encoding
  213: 	 */
  214: 	if (encoding != NULL)
  215: 		aim_tlvlist_add_str(&inner_tlvlist, 0x0002, encoding);
  216: 
  217: 	/*
  218: 	 * SubTLV: Type 3: Language
  219: 	 */
  220: 	if (language != NULL)
  221: 		aim_tlvlist_add_str(&inner_tlvlist, 0x0003, language);
  222: 
  223: 	/*
  224: 	 * Type 5: Message block.  Contains more TLVs.
  225: 	 *
  226: 	 * This could include other information... We just
  227: 	 * put in a message TLV however.
  228: 	 *
  229: 	 */
  230: 	aim_tlvlist_add_frozentlvlist(&tlvlist, 0x0005, &inner_tlvlist);
  231: 
  232: 	aim_tlvlist_write(&bs, &tlvlist);
  233: 
  234: 	aim_tlvlist_free(inner_tlvlist);
  235: 	aim_tlvlist_free(tlvlist);
  236: 
  237: 	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs);
  238: 
  239: 	byte_stream_destroy(&bs);
  240: 
  241: 	return 0;
  242: }
  243: 
  244: /*
  245:  * Subtype 0x0006
  246:  *
  247:  * We could probably include this in the normal ICBM parsing
  248:  * code as channel 0x0003, however, since only the start
  249:  * would be the same, we might as well do it here.
  250:  *
  251:  * General outline of this SNAC:
  252:  *   snac
  253:  *   cookie
  254:  *   channel id
  255:  *   tlvlist
  256:  *     unknown
  257:  *     source user info
  258:  *       name
  259:  *       evility
  260:  *       userinfo tlvs
  261:  *         online time
  262:  *         etc
  263:  *     message metatlv
  264:  *       message tlv
  265:  *         message string
  266:  *       possibly others
  267:  *
  268:  */
  269: static int
  270: incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
  271: {
  272: 	int ret = 0, i;
  273: 	aim_rxcallback_t userfunc;
  274: 	aim_userinfo_t userinfo;
  275: 	guint8 cookie[8];
  276: 	guint16 channel;
  277: 	GSList *tlvlist;
  278: 	char *msg = NULL;
  279: 	int len = 0;
  280: 	char *encoding = NULL, *language = NULL;
  281: 	IcbmCookie *ck;
  282: 	aim_tlv_t *tlv;
  283: 	ByteStream tbs;
  284: 
  285: 	memset(&userinfo, 0, sizeof(aim_userinfo_t));
  286: 
  287: 	/*
  288: 	 * Read ICBM Cookie.
  289: 	 */
  290: 	for (i = 0; i < 8; i++)
  291: 		cookie[i] = byte_stream_get8(bs);
  292: 
  293: 	if ((ck = aim_uncachecookie(od, cookie, AIM_COOKIETYPE_CHAT))) {
  294: 		g_free(ck->data);
  295: 		g_free(ck);
  296: 	}
  297: 
  298: 	/*
  299: 	 * Channel ID
  300: 	 *
  301: 	 * Channel 0x0003 is used for chat messages.
  302: 	 *
  303: 	 */
  304: 	channel = byte_stream_get16(bs);
  305: 
  306: 	if (channel != 0x0003) {
  307: 		purple_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
  308: 		return 0;
  309: 	}
  310: 
  311: 	/*
  312: 	 * Start parsing TLVs right away.
  313: 	 */
  314: 	tlvlist = aim_tlvlist_read(bs);
  315: 
  316: 	/*
  317: 	 * Type 0x0003: Source User Information
  318: 	 */
  319: 	tlv = aim_tlv_gettlv(tlvlist, 0x0003, 1);
  320: 	if (tlv != NULL)
  321: 	{
  322: 		byte_stream_init(&tbs, tlv->value, tlv->length);
  323: 		aim_info_extract(od, &tbs, &userinfo);
  324: 	}
  325: 
  326: 	/*
  327: 	 * Type 0x0005: Message Block.  Conains more TLVs.
  328: 	 */
  329: 	tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1);
  330: 	if (tlv != NULL)
  331: 	{
  332: 		GSList *inner_tlvlist;
  333: 		aim_tlv_t *inner_tlv;
  334: 
  335: 		byte_stream_init(&tbs, tlv->value, tlv->length);
  336: 		inner_tlvlist = aim_tlvlist_read(&tbs);
  337: 
  338: 		/*
  339: 		 * Type 0x0001: Message.
  340: 		 */
  341: 		inner_tlv = aim_tlv_gettlv(inner_tlvlist, 0x0001, 1);
  342: 		if (inner_tlv != NULL)
  343: 		{
  344: 			len = inner_tlv->length;
  345: 			msg = aim_tlv_getvalue_as_string(inner_tlv);
  346: 		}
  347: 
  348: 		/*
  349: 		 * Type 0x0002: Encoding.
  350: 		 */
  351: 		encoding = aim_tlv_getstr(inner_tlvlist, 0x0002, 1);
  352: 
  353: 		/*
  354: 		 * Type 0x0003: Language.
  355: 		 */
  356: 		language = aim_tlv_getstr(inner_tlvlist, 0x0003, 1);
  357: 
  358: 		aim_tlvlist_free(inner_tlvlist);
  359: 	}
  360: 
  361: 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
  362: 		ret = userfunc(od, conn, frame, &userinfo, len, msg, encoding, language);
  363: 
  364: 	aim_info_free(&userinfo);
  365: 	g_free(msg);
  366: 	g_free(encoding);
  367: 	g_free(language);
  368: 	aim_tlvlist_free(tlvlist);
  369: 
  370: 	return ret;
  371: }
  372: 
  373: static int
  374: snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
  375: {
  376: 	if (snac->subtype == 0x0002)
  377: 		return infoupdate(od, conn, mod, frame, snac, bs);
  378: 	else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004))
  379: 		return userlistchange(od, conn, mod, frame, snac, bs);
  380: 	else if (snac->subtype == 0x0006)
  381: 		return incomingim_ch3(od, conn, mod, frame, snac, bs);
  382: 
  383: 	return 0;
  384: }
  385: 
  386: int
  387: chat_modfirst(OscarData *od, aim_module_t *mod)
  388: {
  389: 	mod->family = SNAC_FAMILY_CHAT;
  390: 	mod->version = 0x0001;
  391: 	mod->toolid = 0x0010;
  392: 	mod->toolversion = 0x0629;
  393: 	mod->flags = 0;
  394: 	strncpy(mod->name, "chat", sizeof(mod->name));
  395: 	mod->snachandler = snachandler;
  396: 
  397: 	return 0;
  398: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>