+ /*
+ * Channel ID
+ *
+ * Channels 1 and 2 are implemented in the normal ICBM
+ * parser.
+ *
+ * We only do channel 3 here.
+ *
+ */
+ channel = aimutil_get16(command->data+i);
+ i += 2;
+
+ if (channel != 0x0003) {
+ printf("faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
+ return 1;
+ }
+
+ /*
+ * Start parsing TLVs right away.
+ */
+ outerlist = aim_readtlvchain(command->data+i, command->commandlen-i);
+
+ /*
+ * Type 0x0003: Source User Information
+ */
+ if (aim_gettlv(outerlist, 0x0003, 1)) {
+ struct aim_tlv_t *userinfotlv;
+
+ userinfotlv = aim_gettlv(outerlist, 0x0003, 1);
+ aim_extractuserinfo(userinfotlv->value, &userinfo);
+ }
+
+ /*
+ * Type 0x0001: Unknown.
+ */
+ if (aim_gettlv(outerlist, 0x0001, 1))
+ ;
+
+ /*
+ * Type 0x0005: Message Block. Conains more TLVs.
+ */
+ if (aim_gettlv(outerlist, 0x0005, 1))
+ {
+ struct aim_tlvlist_t *innerlist;
+ struct aim_tlv_t *msgblock;
+
+ msgblock = aim_gettlv(outerlist, 0x0005, 1);
+ innerlist = aim_readtlvchain(msgblock->value, msgblock->length);
+
+ /*
+ * Type 0x0001: Message.
+ */
+ if (aim_gettlv(innerlist, 0x0001, 1))
+ msg = aim_gettlv_str(innerlist, 0x0001, 1);
+
+ aim_freetlvchain(&innerlist);
+ }
+
+ userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG);
+ if (userfunc)
+ {
+ ret = userfunc(sess,
+ command,
+ &userinfo,
+ msg);
+ }
+ free(msg);
+ aim_freetlvchain(&outerlist);
+
+ return ret;
+}
+
+faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess,
+ struct aim_conn_t *conn)
+{
+ struct command_tx_struct *newpacket;
+ int i;
+
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 0x20)))
+ return -1;
+
+ newpacket->lock = 1;
+
+ i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid);
+
+ i+= aimutil_put16(newpacket->data+i, 0x000e);
+ i+= aimutil_put16(newpacket->data+i, 0x0001);
+
+ i+= aimutil_put16(newpacket->data+i, 0x0004);
+ i+= aimutil_put16(newpacket->data+i, 0x0001);
+
+ i+= aimutil_put16(newpacket->data+i, 0x0001);
+ i+= aimutil_put16(newpacket->data+i, 0x0003);
+
+ i+= aimutil_put16(newpacket->data+i, 0x0004);
+ i+= aimutil_put16(newpacket->data+i, 0x0686);
+
+ newpacket->lock = 0;
+ aim_tx_enqueue(sess, newpacket);
+
+ return (sess->snac_nextid++);
+}
+
+faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name)
+{
+ struct aim_conn_t *conn;
+
+ if ((conn = aim_chat_getconn(sess, name)))
+ aim_conn_close(conn);
+
+ if (!conn)
+ return -1;
+ return 0;
+}
+
+/*
+ * conn must be a BOS connection!
+ */
+faim_export unsigned long aim_chat_invite(struct aim_session_t *sess,
+ struct aim_conn_t *conn,
+ char *sn,
+ char *msg,
+ u_short exchange,
+ char *roomname,
+ u_short instance)
+{
+ struct command_tx_struct *newpacket;
+ int i,curbyte=0;
+ struct aim_msgcookie_t *cookie;
+ struct aim_invite_priv *priv;
+
+ if (!sess || !conn || !sn || !msg || !roomname)
+ return -1;
+
+ if (conn->type != AIM_CONN_TYPE_BOS)
+ return -1;
+
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
+ return -1;
+
+ newpacket->lock = 1;
+
+ curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
+
+ /*
+ * Cookie
+ */
+ for (i=0;i<8;i++)
+ curbyte += aimutil_put8(newpacket->data+curbyte, (u_char)rand());
+
+ /* XXX this should get uncached by the unwritten 'invite accept' handler */
+ if(!(priv = calloc(sizeof(struct aim_invite_priv), 1)))
+ return -1;
+ priv->sn = strdup(sn);
+ priv->roomname = strdup(roomname);
+ priv->exchange = exchange;
+ priv->instance = instance;
+
+ if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv)))
+ return -1;
+ aim_cachecookie(sess, cookie);
+
+ /*
+ * Channel (2)
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+
+ /*
+ * Dest sn
+ */
+ curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn));
+ curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn));
+
+ /*
+ * TLV t(0005)
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02);
+
+ /*
+ * Unknown info
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x3131);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x3538);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x3446);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x4100);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x748f);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x2420);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x6287);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x11d1);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x8222);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x4445);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x5354);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+
+ /*
+ * TLV t(000a) -- Unknown
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
+
+ /*
+ * TLV t(000f) -- Unknown
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+
+ /*
+ * TLV t(000c) -- Invitation message
+ */
+ curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000c, strlen(msg), msg);
+
+ /*
+ * TLV t(2711) -- Container for room information
+ */
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 3+strlen(roomname)+2);
+ curbyte += aimutil_put16(newpacket->data+curbyte, exchange);
+ curbyte += aimutil_put8(newpacket->data+curbyte, strlen(roomname));
+ curbyte += aimutil_putstr(newpacket->data+curbyte, roomname, strlen(roomname));
+ curbyte += aimutil_put16(newpacket->data+curbyte, instance);
+
+ newpacket->commandlen = curbyte;
+ newpacket->lock = 0;
+ aim_tx_enqueue(sess, newpacket);
+
+ return (sess->snac_nextid++);