void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_logins) { FlapFrame *frame; GSList *tlvlist = NULL; frame = flap_frame_new(od, 0x01, 1152 + length); byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy); if (ci->clientstring != NULL) aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring); else { gchar *clientstring = oscar_get_clientstring(); aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring); g_free(clientstring); } aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major); aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03)); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); }
/* * 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; }
/* * Part two of the ICQ hack. Note the ignoring of the key. */ static int goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci) { FlapFrame *frame; GSList *tlvlist = NULL; int passwdlen; guint8 *password_encoded; guint32 distrib; passwdlen = strlen(password); password_encoded = (guint8 *)g_malloc(passwdlen+1); if (passwdlen > MAXICQPASSLEN) passwdlen = MAXICQPASSLEN; frame = flap_frame_new(od, 0x01, 1152); aim_encode_password(password, password_encoded); distrib = oscar_get_ui_info_int( od->icq ? "prpl-icq-distid" : "prpl-aim-distid", ci->distrib); byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ aim_tlvlist_add_str(&tlvlist, 0x0001, sn); aim_tlvlist_add_raw(&tlvlist, 0x0002, passwdlen, password_encoded); if (ci->clientstring != NULL) aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring); else { gchar *clientstring = oscar_get_clientstring(); aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring); g_free(clientstring); } aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid); aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major); aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); aim_tlvlist_add_32(&tlvlist, 0x0014, distrib); /* distribution chan */ aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang); aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country); aim_tlvlist_write(&frame->data, &tlvlist); g_free(password_encoded); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
/* * Subtype 0x0006 * * In AIM 3.5 protocol, the first stage of login is to request login from the * Authorizer, passing it the username for verification. If the name is * invalid, a 0017/0003 is spit back, with the standard error contents. If * valid, a 0017/0007 comes back, which is the signal to send it the main * login command (0017/0002). * */ int aim_request_login(OscarData *od, FlapConnection *conn, const char *sn) { FlapFrame *frame; aim_snacid_t snacid; GSList *tlvlist = NULL; if (!od || !conn || !sn) return -EINVAL; #ifdef USE_XOR_FOR_ICQ if (aim_snvalid_icq(sn)) return goddamnicq(od, conn, sn); #endif frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0); aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, 0x0000, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); /* Tell the server we support SecurID logins. */ aim_tlvlist_add_noval(&tlvlist, 0x004b); /* Unknown. Sent in recent WinAIM clients.*/ aim_tlvlist_add_noval(&tlvlist, 0x005a); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
/* * Subtype 0x0009 - Set directory profile data. * * This is not the same as aim_location_setprofile! * privacy: 1 to allow searching, 0 to disallow. * */ int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); if (first) aim_tlvlist_add_str(&tlvlist, 0x0001, first); if (last) aim_tlvlist_add_str(&tlvlist, 0x0002, last); if (middle) aim_tlvlist_add_str(&tlvlist, 0x0003, middle); if (maiden) aim_tlvlist_add_str(&tlvlist, 0x0004, maiden); if (state) aim_tlvlist_add_str(&tlvlist, 0x0007, state); if (city) aim_tlvlist_add_str(&tlvlist, 0x0008, city); if (nickname) aim_tlvlist_add_str(&tlvlist, 0x000c, nickname); if (zip) aim_tlvlist_add_str(&tlvlist, 0x000d, zip); if (street) aim_tlvlist_add_str(&tlvlist, 0x0021, street); byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; }
/* * Subtype 0x000f * * XXX pass these in better * */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; /* ?? privacy ?? */ aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); if (interest1) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1); if (interest2) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2); if (interest3) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3); if (interest4) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4); if (interest5) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5); byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; }
/* * Subtype 0x000f * * XXX pass these in better * */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy) { FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; /* ?? privacy ?? */ aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); if (interest1) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1); if (interest2) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2); if (interest3) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3); if (interest4) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4); if (interest5) aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5); frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x000f, 0x0000, 0); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
/* * Subtype 0x0002 * * This is the initial login request packet. * * NOTE!! If you want/need to make use of the aim_sendmemblock() function, * then the client information you send here must exactly match the * executable that you're pulling the data from. * * Java AIM 1.1.19: * clientstring = "AOL Instant Messenger (TM) version 1.1.19 for Java built 03/24/98, freeMem 215871 totalMem 1048567, i686, Linus, #2 SMP Sun Feb 11 03:41:17 UTC 2001 2.4.1-ac9, IBM Corporation, 1.1.8, 45.3, Tue Mar 27 12:09:17 PST 2001" * clientid = 0x0001 * major = 0x0001 * minor = 0x0001 * point = (not sent) * build = 0x0013 * unknown= (not sent) * * AIM for Linux 1.1.112: * clientstring = "AOL Instant Messenger (SM)" * clientid = 0x1d09 * major = 0x0001 * minor = 0x0001 * point = 0x0001 * build = 0x0070 * unknown= 0x0000008b * serverstore = 0x01 * * @param truncate_pass Truncate the password to 8 characters. This * usually happens for AOL accounts. We are told that we * should truncate it if the 0x0017/0x0007 SNAC contains * a TLV of type 0x0026 with data 0x0000. * @param allow_multiple_logins Allow multiple logins? If TRUE, the AIM * server will prompt the user when multiple logins occur. If * FALSE, existing connections (on other clients) will be * disconnected automatically as we connect. */ int aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins) { FlapFrame *frame; GSList *tlvlist = NULL; guint8 digest[16]; aim_snacid_t snacid; size_t password_len; guint32 distrib; if (!ci || !sn || !password) return -EINVAL; #ifdef USE_XOR_FOR_ICQ /* If we're signing on an ICQ account then use the older, XOR login method */ if (aim_snvalid_icq(sn)) return goddamnicq2(od, conn, sn, password, ci); #endif frame = flap_frame_new(od, 0x02, 1152); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, 0x0000, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); /* Truncate ICQ and AOL passwords, if necessary */ password_len = strlen(password); if (oscar_util_valid_name_icq(sn) && (password_len > MAXICQPASSLEN)) password_len = MAXICQPASSLEN; else if (truncate_pass && password_len > 8) password_len = 8; aim_encode_password_md5(password, password_len, key, digest); distrib = oscar_get_ui_info_int( od->icq ? "prpl-icq-distid" : "prpl-aim-distid", ci->distrib); aim_tlvlist_add_raw(&tlvlist, 0x0025, 16, digest); #ifndef USE_OLD_MD5 aim_tlvlist_add_noval(&tlvlist, 0x004c); #endif if (ci->clientstring != NULL) aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring); else { gchar *clientstring = oscar_get_clientstring(); aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring); g_free(clientstring); } aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid); aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major); aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); aim_tlvlist_add_32(&tlvlist, 0x0014, distrib); aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang); aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country); /* * If set, old-fashioned buddy lists will not work. You will need * to use SSI. */ aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03)); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
/* * Subtype 0x0004 * * Gives BOS your profile. * * profile_encoding and awaymsg_encoding MUST be set if profile or * away are set, respectively, and their value may or may not be * restricted to a few choices. I am currently aware of: * * us-ascii Just that * unicode-2-0 UTF-16BE * * profile_len and awaymsg_len MUST be set similarly, and they MUST * be the length of their respective strings in bytes. * * To get the previous behavior of awaymsg == "" un-setting the away * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the * obvious equivalent). * */ int aim_locate_setprofile(OscarData *od, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; char *encoding; static const char defencoding[] = {"text/aolrtf; charset=\"%s\""}; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; if (!profile && !awaymsg) return -EINVAL; if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) { return -EINVAL; } /* Build the packet first to get real length */ if (profile) { /* no + 1 here because of %s */ encoding = g_malloc(strlen(defencoding) + strlen(profile_encoding)); snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding); aim_tlvlist_add_str(&tlvlist, 0x0001, encoding); aim_tlvlist_add_raw(&tlvlist, 0x0002, profile_len, (const guchar *)profile); g_free(encoding); } /* * So here's how this works: * - You are away when you have a non-zero-length type 4 TLV stored. * - You become unaway when you clear the TLV with a zero-length * type 4 TLV. * - If you do not send the type 4 TLV, your status does not change * (that is, if you were away, you'll remain away). */ if (awaymsg) { if (awaymsg_len) { encoding = g_malloc(strlen(defencoding) + strlen(awaymsg_encoding)); snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding); aim_tlvlist_add_str(&tlvlist, 0x0003, encoding); aim_tlvlist_add_raw(&tlvlist, 0x0004, awaymsg_len, (const guchar *)awaymsg); g_free(encoding); } else aim_tlvlist_add_noval(&tlvlist, 0x0004); } byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; }
/* * Subtype 0x0005 - Send a Chat Message. * * Possible flags: * AIM_CHATFLAGS_NOREFLECT -- Unset the flag that requests messages * should be sent to their sender. * AIM_CHATFLAGS_AWAY -- Mark the message as an autoresponse * (Note that WinAIM does not honor this, * and displays the message as normal.) * * XXX convert this to use tlvchains */ int aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language) { int i; ByteStream bs; IcbmCookie *cookie; aim_snacid_t snacid; guint8 ckstr[8]; GSList *tlvlist = NULL, *inner_tlvlist = NULL; if (!od || !conn || !msg || (msglen <= 0)) return 0; byte_stream_new(&bs, 1142); snacid = aim_cachesnac(od, SNAC_FAMILY_CHAT, 0x0005, 0x0000, NULL, 0); /* * Cookie * * XXX mkcookie should generate the cookie and cache it in one * operation to preserve uniqueness. */ for (i = 0; i < 8; i++) ckstr[i] = (guint8)rand(); cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL); cookie->data = NULL; /* XXX store something useful here */ aim_cachecookie(od, cookie); /* ICBM Header */ byte_stream_putraw(&bs, ckstr, 8); /* Cookie */ byte_stream_put16(&bs, 0x0003); /* Channel */ /* * Type 1: Flag meaning this message is destined to the room. */ aim_tlvlist_add_noval(&tlvlist, 0x0001); /* * Type 6: Reflect */ if (!(flags & AIM_CHATFLAGS_NOREFLECT)) aim_tlvlist_add_noval(&tlvlist, 0x0006); /* * Type 7: Autoresponse */ if (flags & AIM_CHATFLAGS_AWAY) aim_tlvlist_add_noval(&tlvlist, 0x0007); /* * SubTLV: Type 1: Message */ aim_tlvlist_add_raw(&inner_tlvlist, 0x0001, msglen, (guchar *)msg); /* * SubTLV: Type 2: Encoding */ if (encoding != NULL) aim_tlvlist_add_str(&inner_tlvlist, 0x0002, encoding); /* * SubTLV: Type 3: Language */ if (language != NULL) aim_tlvlist_add_str(&inner_tlvlist, 0x0003, language); /* * Type 5: Message block. Contains more TLVs. * * This could include other information... We just * put in a message TLV however. * */ aim_tlvlist_add_frozentlvlist(&tlvlist, 0x0005, &inner_tlvlist); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs); byte_stream_destroy(&bs); return 0; }