- 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(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 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++);
+ 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 < sizeof(ckstr); i++)
+ aimutil_put8(ckstr, (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);
+
+ for (i = 0; i < sizeof(ckstr); i++)
+ aimbs_put8(&fr->data, ckstr[i]);
+
+
+ /*
+ * Channel (2)
+ */
+ aimbs_put16(&fr->data, 0x0002);
+
+ /*
+ * Dest sn
+ */
+ aimbs_put8(&fr->data, strlen(sn));
+ aimbs_putraw(&fr->data, sn, strlen(sn));
+
+ /*
+ * 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_addtlvtochain16(&itl, 0x000a, 0x0001);
+ aim_addtlvtochain_noval(&itl, 0x000f);
+ aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg);
+ aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
+ aim_writetlvchain(&hdrbs, &itl);
+
+ aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
+
+ aim_writetlvchain(&fr->data, &otl);
+
+ free(hdr);
+ aim_freetlvchain(&itl);
+ aim_freetlvchain(&otl);
+
+ aim_tx_enqueue(sess, fr);
+
+ return 0;