/* * Subtype 0x0004 - Set your client's capabilities. */ int aim_locate_setcaps(OscarData *od, guint32 caps) { FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; aim_tlvlist_add_caps(&tlvlist, 0x0005, caps); frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
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); }
/* * Attempt to send the contents of a given queue * * @return TRUE if the queue was completely emptied or was initially * empty; FALSE if rate limiting prevented it from being * emptied. */ static gboolean flap_connection_send_snac_queue(FlapConnection *conn, struct timeval now, GQueue *queue) { while (!g_queue_is_empty(queue)) { QueuedSnac *queued_snac; struct rateclass *rateclass; queued_snac = g_queue_peek_head(queue); rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype); if (rateclass != NULL) { guint32 new_current; new_current = rateclass_get_new_current(conn, rateclass, &now); if (rateclass->dropping_snacs || new_current <= rateclass->alert) /* Not ready to send this SNAC yet--keep waiting. */ return FALSE; rateclass->current = new_current; rateclass->last.tv_sec = now.tv_sec; rateclass->last.tv_usec = now.tv_usec; } flap_connection_send(conn, queued_snac->frame); g_free(queued_snac); g_queue_pop_head(queue); } /* We emptied the queue */ return TRUE; }
/* * 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 0x000b * * Send SecurID response. */ int aim_auth_securid_send(OscarData *od, const char *securid) { FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; int len; if (!od || !(conn = flap_connection_getbytype_all(od, SNAC_FAMILY_AUTH)) || !securid) return -EINVAL; len = strlen(securid); frame = flap_frame_new(od, 0x02, 10+2+len); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0); aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0); byte_stream_put16(&frame->data, len); byte_stream_putstr(&frame->data, securid); flap_connection_send(conn, frame); return 0; }
/** * This sends an empty channel 4 FLAP. This is sent to signify * that we're logging off. This shouldn't really be necessary-- * usually the AIM server will detect that the TCP connection has * been destroyed--but it's good practice. */ static void flap_connection_send_close(OscarData *od, FlapConnection *conn) { FlapFrame *frame; frame = flap_frame_new(od, 0x04, 0); flap_connection_send(conn, frame); }
/** * This sends a channel 1 SNAC containing the FLAP version. * The FLAP version is sent by itself at the beginning of every * connection to a FLAP server. It is always the very first * packet sent by both the server and the client after the SYN, * SYN/ACK, ACK handshake. */ void flap_connection_send_version(OscarData *od, FlapConnection *conn) { FlapFrame *frame; frame = flap_frame_new(od, 0x01, 4); byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ 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"}; FlapFrame *frame; aim_snacid_t snacid; GSList *tlvlist = NULL; frame = flap_frame_new(od, 0x02, 1152); snacid = aim_cachesnac(od, 0x000d, 0x0008, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x000d, 0x0008, 0x0000, snacid); /* exchange */ byte_stream_put16(&frame->data, 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(&frame->data, strlen(ck)); byte_stream_putstr(&frame->data, ck); /* * instance * * Setting this to 0xffff apparently assigns the last instance. * */ byte_stream_put16(&frame->data, 0xffff); /* detail level */ byte_stream_put8(&frame->data, 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(&frame->data, aim_tlvlist_count(tlvlist)); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0; }
/** * This sends an empty channel 5 FLAP. This is used as a keepalive * packet in FLAP connections. WinAIM 4.x and higher send these * _every minute_ to keep the connection alive. */ void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn) { FlapFrame *frame; frame = flap_frame_new(od, 0x05, 0); flap_connection_send(conn, frame); /* clean out SNACs over 60sec old */ aim_cleansnacs(od, 60); }
/* * 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; }
/** * This sends a channel 1 FLAP containing the FLAP version and * the authentication cookie. This is sent when connecting to * any FLAP server after the initial connection to the auth * server. It is always the very first packet sent by both the * server and the client after the SYN, SYN/ACK, ACK handshake. */ void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy) { FlapFrame *frame; GSList *tlvlist = NULL; frame = flap_frame_new(od, 0x01, 4 + 2 + 2 + length); byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_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; }
/* * 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; FlapFrame *frame; 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); frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0009, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x0009, 0x0000, snacid); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); 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 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 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 UCS2-BE * * 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; FlapFrame *frame; 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); } frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid); 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; }
/** * This sends a channel 2 FLAP containing a SNAC. The SNAC family and * subtype are looked up in the rate info for this connection, and if * sending this SNAC will induce rate limiting then we delay sending * of the SNAC by putting it into an outgoing holding queue. * * @param data The optional bytestream that makes up the data portion * of this SNAC. For empty SNACs this should be NULL. * @param high_priority If TRUE, the SNAC will be queued normally if * needed. If FALSE, it will be queued separately, to be sent * only if all high priority SNACs have been sent. */ void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority) { FlapFrame *frame; guint32 length; gboolean enqueue = FALSE; struct rateclass *rateclass; length = data != NULL ? data->offset : 0; frame = flap_frame_new(od, 0x02, 10 + length); aim_putsnac(&frame->data, family, subtype, snacid); if (length > 0) { byte_stream_rewind(data); byte_stream_putbs(&frame->data, data, length); } if (conn->queued_timeout != 0) enqueue = TRUE; else if ((rateclass = flap_connection_get_rateclass(conn, family, subtype)) != NULL) { struct timeval now; guint32 new_current; gettimeofday(&now, NULL); new_current = rateclass_get_new_current(conn, rateclass, &now); if (rateclass->dropping_snacs || new_current <= rateclass->alert) { purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert); enqueue = TRUE; } else { rateclass->current = new_current; rateclass->last.tv_sec = now.tv_sec; rateclass->last.tv_usec = now.tv_usec; } } if (enqueue) { /* We've been sending too fast, so delay this message */ QueuedSnac *queued_snac; queued_snac = g_new(QueuedSnac, 1); queued_snac->family = family; queued_snac->subtype = subtype; queued_snac->frame = frame; if (high_priority) { if (!conn->queued_snacs) conn->queued_snacs = g_queue_new(); g_queue_push_tail(conn->queued_snacs, queued_snac); } else { if (!conn->queued_lowpriority_snacs) conn->queued_lowpriority_snacs = g_queue_new(); g_queue_push_tail(conn->queued_lowpriority_snacs, queued_snac); } if (conn->queued_timeout == 0) conn->queued_timeout = purple_timeout_add(500, flap_connection_send_queued, conn); return; } flap_connection_send(conn, frame); }