static void sendframe_flap(FlapConnection *conn, FlapFrame *frame) { ByteStream bs; int payloadlen, bslen; payloadlen = byte_stream_curpos(&frame->data); byte_stream_new(&bs, 6 + payloadlen); /* FLAP header */ byte_stream_put8(&bs, 0x2a); byte_stream_put8(&bs, frame->channel); byte_stream_put16(&bs, frame->seqnum); byte_stream_put16(&bs, payloadlen); /* Payload */ byte_stream_rewind(&frame->data); byte_stream_putbs(&bs, &frame->data, payloadlen); bslen = byte_stream_curpos(&bs); byte_stream_rewind(&bs); flap_connection_send_byte_stream(&bs, conn, bslen); byte_stream_destroy(&bs); }
/* * Subtype 0x0008 */ int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange) { static const char ck[] = {"create"}; static const char lang[] = {"en"}; static const char charset[] = {"us-ascii"}; ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; byte_stream_new(&bs, 1142); snacid = aim_cachesnac(od, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, NULL, 0); /* exchange */ byte_stream_put16(&bs, exchange); /* * This looks to be a big hack. You'll note that this entire * SNAC is just a room info structure, but the hard room name, * here, is set to "create". * * Either this goes on the "list of questions concerning * why-the-hell-did-you-do-that", or this value is completely * ignored. Without experimental evidence, but a good knowledge of * AOL style, I'm going to guess that it is the latter, and that * the value of the room name in create requests is ignored. */ byte_stream_put8(&bs, strlen(ck)); byte_stream_putstr(&bs, ck); /* * instance * * Setting this to 0xffff apparently assigns the last instance. * */ byte_stream_put16(&bs, 0xffff); /* detail level */ byte_stream_put8(&bs, 0x01); aim_tlvlist_add_str(&tlvlist, 0x00d3, name); aim_tlvlist_add_str(&tlvlist, 0x00d6, charset); aim_tlvlist_add_str(&tlvlist, 0x00d7, lang); /* tlvcount */ byte_stream_put16(&bs, aim_tlvlist_count(tlvlist)); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, snacid, &bs); byte_stream_destroy(&bs); return 0; }
/** * Create a rendezvous "init recv" packet and send it on its merry way. * This is the first packet sent to the proxy server by the second client * involved in this rendezvous proxy session. * * @param conn The peer connection. * @param pin The 2 byte PIN sent to us by the other user. This acts * as our passcode when establishing the proxy session. */ static void peer_proxy_send_join_existing_conn(PeerConnection *conn, guint16 pin) { ProxyFrame frame; PurpleAccount *account; const gchar *bn; guint8 bn_length; memset(&frame, 0, sizeof(ProxyFrame)); frame.type = PEER_PROXY_TYPE_JOIN; frame.flags = 0x0000; account = purple_connection_get_account(conn->od->gc); bn = purple_account_get_username(account); bn_length = strlen(bn); byte_stream_new(&frame.payload, 1 + bn_length + 2 + 8 + 20); byte_stream_put8(&frame.payload, bn_length); byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length); byte_stream_put16(&frame.payload, pin); byte_stream_putraw(&frame.payload, conn->cookie, 8); byte_stream_put16(&frame.payload, 0x0001); /* Type */ byte_stream_put16(&frame.payload, 16); /* Length */ byte_stream_putcaps(&frame.payload, conn->type); /* Value */ peer_proxy_send(conn, &frame); }
/* * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists. * * Changes your visibility depending on changetype: * * AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you * AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list * AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names * AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again * * list should be a list of * screen names in the form "Screen Name One&ScreenNameTwo&" etc. * * Equivelents to options in WinAIM: * - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD * with only your name on it. * - Allow only users on my Buddy List: Send an * AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your * buddy list * - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD * with everyone listed that you want to see you. * - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only * yourself in the list * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with * the list of users to be blocked * * XXX ye gods. */ int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist) { FlapFrame *frame; int packlen = 0; guint16 subtype; char *localcpy = NULL, *tmpptr = NULL; int i; int listcount; aim_snacid_t snacid; if (!denylist) return -EINVAL; if (changetype == AIM_VISIBILITYCHANGE_PERMITADD) subtype = 0x05; else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE) subtype = 0x06; else if (changetype == AIM_VISIBILITYCHANGE_DENYADD) subtype = 0x07; else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE) subtype = 0x08; else return -EINVAL; localcpy = g_strdup(denylist); listcount = aimutil_itemcnt(localcpy, '&'); packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; frame = flap_frame_new(od, 0x02, packlen); snacid = aim_cachesnac(od, 0x0009, subtype, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0009, subtype, 0x00, snacid); for (i = 0; (i < (listcount - 1)) && (i < 99); i++) { tmpptr = aimutil_itemindex(localcpy, i, '&'); byte_stream_put8(&frame->data, strlen(tmpptr)); byte_stream_putstr(&frame->data, tmpptr); g_free(tmpptr); } g_free(localcpy); flap_connection_send(conn, frame); return 0; }
/* * Inverse of aim_info_extract() */ int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info) { GSList *tlvlist = NULL; if (!bs || !info) return -EINVAL; byte_stream_put8(bs, strlen(info->bn)); byte_stream_putstr(bs, info->bn); byte_stream_put16(bs, info->warnlevel); if (info->present & AIM_USERINFO_PRESENT_FLAGS) aim_tlvlist_add_16(&tlvlist, 0x0001, info->flags); if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE) aim_tlvlist_add_32(&tlvlist, 0x0002, info->membersince); if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE) aim_tlvlist_add_32(&tlvlist, 0x0003, info->onlinesince); if (info->present & AIM_USERINFO_PRESENT_IDLE) aim_tlvlist_add_16(&tlvlist, 0x0004, info->idletime); /* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */ #ifdef ICQ_OSCAR_SUPPORT if (atoi(info->bn) != 0) { if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) aim_tlvlist_add_16(&tlvlist, 0x0006, info->icqinfo.status); if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR) aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr); } #endif if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities); if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); byte_stream_put16(bs, aim_tlvlist_count(tlvlist)); aim_tlvlist_write(bs, &tlvlist); aim_tlvlist_free(tlvlist); return 0; }
/* * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add multiple buddies to your buddy list. * * This just builds the "set buddy list" command then queues it. * * buddy_list = "Screen Name One&ScreenNameTwo&"; * * XXX Clean this up. * */ int aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list) { ByteStream bs; aim_snacid_t snacid; int len = 0; char *localcpy = NULL; char *tmpptr = NULL; if (!buddy_list || !(localcpy = g_strdup(buddy_list))) return -EINVAL; for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT ")\n", tmpptr, strlen(tmpptr)); len += 1 + strlen(tmpptr); tmpptr = strtok(NULL, "&"); } byte_stream_new(&bs, len); strncpy(localcpy, buddy_list, strlen(buddy_list) + 1); for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT ")\n", tmpptr, strlen(tmpptr)); byte_stream_put8(&bs, strlen(tmpptr)); byte_stream_putstr(&bs, tmpptr); tmpptr = strtok(NULL, "&"); } snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, NULL, 0); flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); g_free(localcpy); return 0; }
/* * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add buddy to list. * * Adds a single buddy to your buddy list after login. * XXX This should just be an extension of setbuddylist() * */ int aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn) { ByteStream bs; aim_snacid_t snacid; if (!sn || !strlen(sn)) return -EINVAL; byte_stream_new(&bs, 1+strlen(sn)); byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, sn, strlen(sn)+1); flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; }
/* * Subtype 0x0015 - Request the info of a user using the short method. This is * what iChat uses. It normally is VERY leniently rate limited. * * @param bn The buddy name whose info you wish to request. * @param flags The bitmask which specifies the type of info you wish to request. * 0x00000001 - Info/profile. * 0x00000002 - Away message. * 0x00000004 - Capabilities. * 0x00000008 - Certification. * @return Return 0 if no errors, otherwise return the error number. */ int aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn) return -EINVAL; byte_stream_new(&bs, 4 + 1 + strlen(bn)); byte_stream_put32(&bs, flags); byte_stream_put8(&bs, strlen(bn)); byte_stream_putstr(&bs, bn); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1); flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE); byte_stream_destroy(&bs); return 0; }
/* * Subtype 0x0015 - Request the info a user using the short method. This is * what iChat uses. It normally is VERY leniently rate limited. * * @param sn The screen name whose info you wish to request. * @param flags The bitmask which specifies the type of info you wish to request. * 0x00000001 - Info/profile. * 0x00000002 - Away message. * 0x00000004 - Capabilities. * 0x00000008 - Certification. * @return Return 0 if no errors, otherwise return the error number. */ int aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags) { FlapConnection *conn; ByteStream data; aim_snacid_t snacid; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn) return -EINVAL; byte_stream_new(&data, 4 + 1 + strlen(sn)); byte_stream_put32(&data, flags); byte_stream_put8(&data, strlen(sn)); byte_stream_putstr(&data, sn); snacid = aim_cachesnac(od, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1); flap_connection_send_snac(od, conn, 0x0002, 0x0015, 0x0000, snacid, &data); g_free(data.data); return 0; }
/* * Subtype 0x000b - Huh? What is this? */ int aim_locate_000b(OscarData *od, const char *sn) { FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; return -EINVAL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn) return -EINVAL; frame = flap_frame_new(od, 0x02, 10+1+strlen(sn)); snacid = aim_cachesnac(od, 0x0002, 0x000b, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x000b, 0x0000, snacid); byte_stream_put8(&frame->data, strlen(sn)); byte_stream_putstr(&frame->data, sn); flap_connection_send(conn, frame); return 0; }
/* * Subtype 0x000b - Huh? What is this? */ int aim_locate_000b(OscarData *od, const char *bn) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; return -EINVAL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn) return -EINVAL; byte_stream_new(&bs, 1+strlen(bn)); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0); byte_stream_put8(&bs, strlen(bn)); byte_stream_putstr(&bs, bn); flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; }