comparison src/protocols/oscar/login.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents edf8c5a70e5b
children d82efea341ef
comparison
equal deleted inserted replaced
2245:31157c54fe6e 2246:933346315b9b
10 10
11 #include "md5.h" 11 #include "md5.h"
12 12
13 static int aim_encode_password(const char *password, unsigned char *encoded); 13 static int aim_encode_password(const char *password, unsigned char *encoded);
14 14
15 faim_export int aim_sendflapver(struct aim_session_t *sess, struct aim_conn_t *conn) 15 faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn)
16 { 16 {
17 int curbyte=0; 17 aim_frame_t *fr;
18 18
19 struct command_tx_struct *newpacket; 19 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4)))
20
21 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0001, 4)))
22 return -ENOMEM; 20 return -ENOMEM;
23 21
24 newpacket->lock = 1; 22 aimbs_put32(&fr->data, 0x00000001);
25 23
26 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 24 aim_tx_enqueue(sess, fr);
27 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); 25
28 26 return 0;
29 newpacket->lock = 0; 27 }
30 28
31 return aim_tx_enqueue(sess, newpacket); 29 /*
32 } 30 * This is a bit confusing.
33 31 *
34 /* 32 * Normal SNAC login goes like this:
35 * In AIM 3.5 protocol, the first stage of login is to request 33 * - connect
36 * login from the Authorizer, passing it the screen name 34 * - server sends flap version
37 * for verification. If the name is invalid, a 0017/0003 35 * - client sends flap version
38 * is spit back, with the standard error contents. If valid, 36 * - client sends screen name (17/6)
39 * a 0017/0007 comes back, which is the signal to send 37 * - server sends hash key (17/7)
40 * it the main login command (0017/0002). 38 * - client sends auth request (17/2 -- aim_send_login)
41 */ 39 * - server yells
42 faim_export int aim_request_login(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) 40 *
43 { 41 * XOR login (for ICQ) goes like this:
44 int curbyte; 42 * - connect
45 struct command_tx_struct *newpacket; 43 * - server sends flap version
46 44 * - client sends auth request which contains flap version (aim_send_login)
45 * - server yells
46 *
47 * For the client API, we make them implement the most complicated version,
48 * and for the simpler version, we fake it and make it look like the more
49 * complicated process.
50 *
51 * This is done by giving the client a faked key, just so we can convince
52 * them to call aim_send_login right away, which will detect the session
53 * flag that says this is XOR login and ignore the key, sending an ICQ
54 * login request instead of the normal SNAC one.
55 *
56 * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/.
57 *
58 * XXX This may cause problems if the client relies on callbacks only
59 * being called from the context of aim_rxdispatch()...
60 *
61 */
62 static int goddamnicq(aim_session_t *sess, aim_conn_t *conn, const char *sn)
63 {
64 aim_frame_t fr;
65 aim_rxcallback_t userfunc;
66
67 sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN;
68 sess->flags |= AIM_SESS_FLAGS_XORLOGIN;
69
70 fr.conn = conn;
71
72 if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007)))
73 userfunc(sess, &fr, "");
74
75 return 0;
76 }
77
78 /*
79 * In AIM 3.5 protocol, the first stage of login is to request login from the
80 * Authorizer, passing it the screen name for verification. If the name is
81 * invalid, a 0017/0003 is spit back, with the standard error contents. If
82 * valid, a 0017/0007 comes back, which is the signal to send it the main
83 * login command (0017/0002).
84 *
85 * XXX make ICQ logins work again.
86 */
87 faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn)
88 {
89 aim_frame_t *fr;
90 aim_snacid_t snacid;
91 aim_tlvlist_t *tl = NULL;
92
47 if (!sess || !conn || !sn) 93 if (!sess || !conn || !sn)
48 return -EINVAL; 94 return -EINVAL;
49 95
50 /* 96 if ((sn[0] >= '0') || (sn[0] <= '9'))
51 * For ICQ, we enable the ancient horrible login and stuff 97 return goddamnicq(sess, conn, sn);
52 * a key packet into the queue to make it look like we got
53 * a reply back. This is so the client doesn't know we're
54 * really not doing MD5 login.
55 *
56 * This may sound stupid, but I'm not in the best of moods and
57 * I don't plan to keep support for this crap around much longer.
58 * Its all AOL's fault anyway, really. I hate AOL. Really. They
59 * always seem to be able to piss me off by doing the dumbest little
60 * things. Like disabling MD5 logins for ICQ UINs, or adding
61 * purposefully wrong TLV lengths, or adding superfluous information
62 * to host strings, or... I'll stop.
63 *
64 */
65 if ((sn[0] >= '0') && (sn[0] <= '9')) {
66 struct command_rx_struct *newrx;
67 int i;
68
69 /* XXX Uhm why doesn't this use aim_tx_new? */
70 if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct))))
71 return -ENOMEM;
72
73 memset(newrx, 0x00, sizeof(struct command_rx_struct));
74 newrx->lock = 1;
75 newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
76 newrx->hdr.oscar.type = 0x02;
77 newrx->hdr.oscar.seqnum = 0;
78 newrx->commandlen = 10+2+1;
79 newrx->nofree = 0;
80
81 if (!(newrx->data = malloc(newrx->commandlen))) {
82 free(newrx);
83 return -ENOMEM;
84 }
85
86 i = aim_putsnac(newrx->data, 0x0017, 0x0007, 0x0000, 0x0000);
87 i += aimutil_put16(newrx->data+i, 0x01);
88 i += aimutil_putstr(newrx->data+i, "0", 1);
89
90 newrx->conn = conn;
91
92 newrx->next = sess->queue_incoming;
93 sess->queue_incoming = newrx;
94
95 newrx->lock = 0;
96
97 sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN;
98
99 return 0;
100 }
101 98
102 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; 99 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
103 100
104 aim_sendflapver(sess, conn); 101 aim_sendflapver(sess, conn);
105 102
106 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(sn)))) 103 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn))))
107 return -ENOMEM; 104 return -ENOMEM;
108 105
109 newpacket->lock = 1; 106 snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
110 107 aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
111 curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0006, 0x0000, 0x00010000); 108
112 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); 109 aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
113 110 aim_writetlvchain(&fr->data, &tl);
114 newpacket->commandlen = curbyte; 111 aim_freetlvchain(&tl);
115 newpacket->lock = 0; 112
116 113 aim_tx_enqueue(sess, fr);
117 return aim_tx_enqueue(sess, newpacket); 114
115 return 0;
116 }
117
118 /*
119 * Part two of the ICQ hack. Note the ignoring of the key and clientinfo.
120 */
121 static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password)
122 {
123 static const char clientstr[] = {"ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85"};
124 static const char lang[] = {"en"};
125 static const char country[] = {"us"};
126 aim_frame_t *fr;
127 aim_tlvlist_t *tl = NULL;
128 char *password_encoded;
129
130 if (!(password_encoded = (char *) malloc(strlen(password))))
131 return -ENOMEM;
132
133 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) {
134 free(password_encoded);
135 return -ENOMEM;
136 }
137
138 aim_encode_password(password, password_encoded);
139
140 aimbs_put32(&fr->data, 0x00000001);
141 aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
142 aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded);
143 aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientstr), clientstr);
144 aim_addtlvtochain16(&tl, 0x0016, 0x010a);
145 aim_addtlvtochain16(&tl, 0x0017, 0x0004);
146 aim_addtlvtochain16(&tl, 0x0018, 0x0041);
147 aim_addtlvtochain16(&tl, 0x0019, 0x0001);
148 aim_addtlvtochain16(&tl, 0x001a, 0x0cd1);
149 aim_addtlvtochain32(&tl, 0x0014, 0x00000055);
150 aim_addtlvtochain_raw(&tl, 0x000f, strlen(lang), lang);
151 aim_addtlvtochain_raw(&tl, 0x000e, strlen(country), country);
152
153 aim_writetlvchain(&fr->data, &tl);
154
155 free(password_encoded);
156 aim_freetlvchain(&tl);
157
158 aim_tx_enqueue(sess, fr);
159
160 return 0;
118 } 161 }
119 162
120 /* 163 /*
121 * send_login(int socket, char *sn, char *password) 164 * send_login(int socket, char *sn, char *password)
122 * 165 *
174 * build = 0x0070 217 * build = 0x0070
175 * unknown= 0x0000008b 218 * unknown= 0x0000008b
176 * serverstore = 0x01 219 * serverstore = 0x01
177 * 220 *
178 */ 221 */
179 faim_export int aim_send_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *password, struct client_info_s *clientinfo, char *key) 222 faim_export int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *clientinfo, const char *key)
180 { 223 {
181 int curbyte=0; 224 aim_frame_t *fr;
182 struct command_tx_struct *newpacket; 225 aim_tlvlist_t *tl = NULL;
226 fu8_t digest[16];
227 aim_snacid_t snacid;
183 228
184 if (!clientinfo || !sn || !password) 229 if (!clientinfo || !sn || !password)
185 return -EINVAL; 230 return -EINVAL;
186 231
187 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) 232 if (sess->flags & AIM_SESS_FLAGS_XORLOGIN)
233 return goddamnicq2(sess, conn, sn, password);
234
235 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
188 return -ENOMEM; 236 return -ENOMEM;
189 237
190 newpacket->lock = 1; 238 if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) {
191 239 fr->hdr.flap.type = 0x01;
192 newpacket->hdr.oscar.type = (sess->flags & AIM_SESS_FLAGS_SNACLOGIN)?0x02:0x01; 240
193 241 /* Use very specific version numbers to further indicate hack */
194 if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) 242 clientinfo->major2 = 0x010a;
195 curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0002, 0x0000, 0x00010000); 243 clientinfo->major = 0x0004;
196 else { 244 clientinfo->minor = 0x003c;
197 curbyte = aimutil_put16(newpacket->data, 0x0000); 245 clientinfo->minor2 = 0x0001;
198 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); 246 clientinfo->build = 0x0cce;
247 clientinfo->unknown = 0x00000055;
199 } 248 }
200 249
201 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); 250 snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0);
202 251 aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid);
203 if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { 252
204 unsigned char digest[16]; 253 aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
205 254
206 aim_encode_password_md5(password, key, digest); 255 aim_encode_password_md5(password, key, digest);
207 curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest); 256 aim_addtlvtochain_raw(&tl, 0x0025, 16, digest);
208 } else { 257
209 char *password_encoded; 258 aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring);
210 259 aim_addtlvtochain16(&tl, 0x0016, (fu16_t)clientinfo->major2);
211 password_encoded = (char *) malloc(strlen(password)); 260 aim_addtlvtochain16(&tl, 0x0017, (fu16_t)clientinfo->major);
212 aim_encode_password(password, password_encoded); 261 aim_addtlvtochain16(&tl, 0x0018, (fu16_t)clientinfo->minor);
213 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded); 262 aim_addtlvtochain16(&tl, 0x0019, (fu16_t)clientinfo->minor2);
214 free(password_encoded); 263 aim_addtlvtochain16(&tl, 0x001a, (fu16_t)clientinfo->build);
215 } 264 aim_addtlvtochain_raw(&tl, 0x000e, strlen(clientinfo->country), clientinfo->country);
216 265 aim_addtlvtochain_raw(&tl, 0x000f, strlen(clientinfo->lang), clientinfo->lang);
217 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); 266 aim_addtlvtochain16(&tl, 0x0009, 0x0015);
218 267
219 if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { 268 aim_writetlvchain(&fr->data, &tl);
220 269
221 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, (unsigned short)clientinfo->major2); 270 aim_freetlvchain(&tl);
222 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, (unsigned short)clientinfo->major); 271
223 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, (unsigned short)clientinfo->minor); 272 aim_tx_enqueue(sess, fr);
224 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, (unsigned short)clientinfo->minor2); 273
225 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, (unsigned short)clientinfo->build); 274 return 0;
226 275 }
227 } else { 276
228 /* Use very specific version numbers, to further indicate the hack. */ 277 faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest)
229 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a);
230 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0004);
231 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x003c);
232 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001);
233 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, 0x0cce);
234 curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x00000055);
235 }
236
237 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country);
238 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang);
239
240 if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) {
241 curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
242 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
243 }
244
245 newpacket->commandlen = curbyte;
246 newpacket->lock = 0;
247
248 return aim_tx_enqueue(sess, newpacket);
249 }
250
251 faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest)
252 { 278 {
253 md5_state_t state; 279 md5_state_t state;
254 280
255 md5_init(&state); 281 md5_init(&state);
256 md5_append(&state, (const md5_byte_t *)key, strlen(key)); 282 md5_append(&state, (const md5_byte_t *)key, strlen(key));
276 * hope it doesn't change over time! 302 * hope it doesn't change over time!
277 * 303 *
278 * This is only used for the XOR method, not the better MD5 method. 304 * This is only used for the XOR method, not the better MD5 method.
279 * 305 *
280 */ 306 */
281 static int aim_encode_password(const char *password, unsigned char *encoded) 307 static int aim_encode_password(const char *password, fu8_t *encoded)
282 { 308 {
283 unsigned char encoding_table[] = { 309 fu8_t encoding_table[] = {
284 #if 0 /* old v1 table */ 310 #if 0 /* old v1 table */
285 0xf3, 0xb3, 0x6c, 0x99, 311 0xf3, 0xb3, 0x6c, 0x99,
286 0x95, 0x3f, 0xac, 0xb6, 312 0x95, 0x3f, 0xac, 0xb6,
287 0xc5, 0xfa, 0x6b, 0x63, 313 0xc5, 0xfa, 0x6b, 0x63,
288 0x69, 0x6c, 0xc3, 0x9f 314 0x69, 0x6c, 0xc3, 0x9f
302 } 328 }
303 329
304 /* 330 /*
305 * Generate an authorization response. 331 * Generate an authorization response.
306 * 332 *
307 * You probably don't want this unless you're writing an AIM server. 333 * You probably don't want this unless you're writing an AIM server. Which
308 * 334 * I hope you're not doing. Because it's far more difficult than it looks.
309 */ 335 *
310 faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, 336 */
311 struct aim_conn_t *conn, 337 faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus)
312 char *sn, int errorcode,
313 char *errorurl, char *bosip,
314 char *cookie, char *email,
315 int regstatus)
316 { 338 {
317 struct command_tx_struct *tx; 339 aim_tlvlist_t *tlvlist = NULL;
318 struct aim_tlvlist_t *tlvlist = NULL; 340 aim_frame_t *fr;
319 341
320 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0004, 1152))) 342 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x04, 1152)))
321 return -ENOMEM; 343 return -ENOMEM;
322 344
323 tx->lock = 1;
324
325 if (sn) 345 if (sn)
326 aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn)); 346 aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sn), sn);
327 else 347 else
328 aim_addtlvtochain_str(&tlvlist, 0x0001, sess->sn, strlen(sess->sn)); 348 aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sess->sn), sess->sn);
329 349
330 if (errorcode) { 350 if (errorcode) {
331 aim_addtlvtochain16(&tlvlist, 0x0008, errorcode); 351 aim_addtlvtochain16(&tlvlist, 0x0008, errorcode);
332 aim_addtlvtochain_str(&tlvlist, 0x0004, errorurl, strlen(errorurl)); 352 aim_addtlvtochain_raw(&tlvlist, 0x0004, strlen(errorurl), errorurl);
333 } else { 353 } else {
334 aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip)); 354 aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(bosip), bosip);
335 aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); 355 aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie);
336 aim_addtlvtochain_str(&tlvlist, 0x0011, email, strlen(email)); 356 aim_addtlvtochain_raw(&tlvlist, 0x0011, strlen(email), email);
337 aim_addtlvtochain16(&tlvlist, 0x0013, (unsigned short)regstatus); 357 aim_addtlvtochain16(&tlvlist, 0x0013, (fu16_t)regstatus);
338 } 358 }
339 359
340 tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist); 360 aim_writetlvchain(&fr->data, &tlvlist);
341 tx->lock = 0; 361 aim_freetlvchain(&tlvlist);
342 362
343 return aim_tx_enqueue(sess, tx); 363 aim_tx_enqueue(sess, fr);
364
365 return 0;
344 } 366 }
345 367
346 /* 368 /*
347 * Generate a random cookie. (Non-client use only) 369 * Generate a random cookie. (Non-client use only)
348 */ 370 */
349 faim_export int aim_gencookie(unsigned char *buf) 371 faim_export int aim_gencookie(fu8_t *buf)
350 { 372 {
351 int i; 373 int i;
352 374
353 srand(time(NULL)); 375 srand(time(NULL));
354 376
355 for (i=0; i < AIM_COOKIELEN; i++) 377 for (i = 0; i < AIM_COOKIELEN; i++)
356 buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0)); 378 buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0));
357 379
358 return i; 380 return i;
359 } 381 }
360 382
361 /* 383 /*
362 * Send Server Ready. (Non-client) 384 * Send Server Ready. (Non-client)
363 */ 385 */
364 faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn) 386 faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn)
365 { 387 {
366 struct command_tx_struct *tx; 388 aim_frame_t *fr;
367 int i; 389 aim_snacid_t snacid;
368 390
369 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+0x22))) 391 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+0x22)))
370 return -ENOMEM; 392 return -ENOMEM;
371 393
372 tx->lock = 1; 394 snacid = aim_cachesnac(sess, 0x0001, 0x0003, 0x0000, NULL, 0);
373 395
374 i = aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++); 396 aim_putsnac(&fr->data, 0x0001, 0x0003, 0x0000, snacid);
375 397 aimbs_put16(&fr->data, 0x0001);
376 i += aimutil_put16(tx->data+i, 0x0001); 398 aimbs_put16(&fr->data, 0x0002);
377 i += aimutil_put16(tx->data+i, 0x0002); 399 aimbs_put16(&fr->data, 0x0003);
378 i += aimutil_put16(tx->data+i, 0x0003); 400 aimbs_put16(&fr->data, 0x0004);
379 i += aimutil_put16(tx->data+i, 0x0004); 401 aimbs_put16(&fr->data, 0x0006);
380 i += aimutil_put16(tx->data+i, 0x0006); 402 aimbs_put16(&fr->data, 0x0008);
381 i += aimutil_put16(tx->data+i, 0x0008); 403 aimbs_put16(&fr->data, 0x0009);
382 i += aimutil_put16(tx->data+i, 0x0009); 404 aimbs_put16(&fr->data, 0x000a);
383 i += aimutil_put16(tx->data+i, 0x000a); 405 aimbs_put16(&fr->data, 0x000b);
384 i += aimutil_put16(tx->data+i, 0x000b); 406 aimbs_put16(&fr->data, 0x000c);
385 i += aimutil_put16(tx->data+i, 0x000c); 407 aimbs_put16(&fr->data, 0x0013);
386 i += aimutil_put16(tx->data+i, 0x0013); 408 aimbs_put16(&fr->data, 0x0015);
387 i += aimutil_put16(tx->data+i, 0x0015); 409
388 410 aim_tx_enqueue(sess, fr);
389 tx->commandlen = i; 411
390 tx->lock = 0; 412 return 0;
391
392 return aim_tx_enqueue(sess, tx);
393 } 413 }
394 414
395 415
396 /* 416 /*
397 * Send service redirect. (Non-Client) 417 * Send service redirect. (Non-Client)
398 */ 418 */
399 faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short servid, char *ip, char *cookie) 419 faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie)
400 { 420 {
401 struct command_tx_struct *tx; 421 aim_tlvlist_t *tlvlist = NULL;
402 struct aim_tlvlist_t *tlvlist = NULL; 422 aim_frame_t *fr;
403 int i; 423 aim_snacid_t snacid;
404 424
405 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) 425 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
406 return -ENOMEM; 426 return -ENOMEM;
407 427
408 tx->lock = 1; 428 snacid = aim_cachesnac(sess, 0x0001, 0x0005, 0x0000, NULL, 0);
409 429 aim_putsnac(&fr->data, 0x0001, 0x0005, 0x0000, snacid);
410 i = aim_putsnac(tx->data, 0x0001, 0x0005, 0x0000, 0x00000000);
411 430
412 aim_addtlvtochain16(&tlvlist, 0x000d, servid); 431 aim_addtlvtochain16(&tlvlist, 0x000d, servid);
413 aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip)); 432 aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(ip), ip);
414 aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); 433 aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie);
415 434
416 tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i; 435 aim_writetlvchain(&fr->data, &tlvlist);
417 aim_freetlvchain(&tlvlist); 436 aim_freetlvchain(&tlvlist);
418 437
419 tx->lock = 0; 438 aim_tx_enqueue(sess, fr);
420 439
421 return aim_tx_enqueue(sess, tx); 440 return 0;
422 } 441 }
423 442
424 443
425 static int hostonline(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 444 static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
426 { 445 {
427 aim_rxcallback_t userfunc; 446 aim_rxcallback_t userfunc;
428 int ret = 0; 447 int ret = 0;
429 unsigned short *families; 448 fu16_t *families;
430 int famcount, i; 449 int famcount;
431 450
432 famcount = datalen/2; 451 if (!(families = malloc(aim_bstream_empty(bs))))
433
434 if (!(families = malloc(datalen)))
435 return 0; 452 return 0;
436 453
437 for (i = 0; i < famcount; i++) 454 for (famcount = 0; aim_bstream_empty(bs); famcount++)
438 families[i] = aimutil_get16(data+(i*2)); 455 families[famcount] = aimbs_get16(bs);
439 456
440 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 457 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
441 ret = userfunc(sess, rx, famcount, families); 458 ret = userfunc(sess, rx, famcount, families);
442 459
443 free(families); 460 free(families);
444 461
445 return ret; 462 return ret;
446 } 463 }
447 464
448 static int redirect(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 465 static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
449 { 466 {
450 int serviceid; 467 int serviceid;
451 unsigned char *cookie; 468 fu8_t *cookie;
452 char *ip; 469 char *ip;
453 aim_rxcallback_t userfunc; 470 aim_rxcallback_t userfunc;
454 struct aim_tlvlist_t *tlvlist; 471 aim_tlvlist_t *tlvlist;
455 char *chathack = NULL; 472 char *chathack = NULL;
456 int chathackex = 0; 473 int chathackex = 0;
457 int ret = 0; 474 int ret = 0;
458 475
459 tlvlist = aim_readtlvchain(data, datalen); 476 tlvlist = aim_readtlvchain(bs);
460 477
461 if (!aim_gettlv(tlvlist, 0x000d, 1) || 478 if (!aim_gettlv(tlvlist, 0x000d, 1) ||
462 !aim_gettlv(tlvlist, 0x0005, 1) || 479 !aim_gettlv(tlvlist, 0x0005, 1) ||
463 !aim_gettlv(tlvlist, 0x0006, 1)) { 480 !aim_gettlv(tlvlist, 0x0006, 1)) {
464 aim_freetlvchain(&tlvlist); 481 aim_freetlvchain(&tlvlist);
540 * seems to be a big mystery. 557 * seems to be a big mystery.
541 * 558 *
542 */ 559 */
543 560
544 /* XXX parse this */ 561 /* XXX parse this */
545 static int rateresp(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 562 static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
546 { 563 {
547 aim_rxcallback_t userfunc; 564 aim_rxcallback_t userfunc;
548 565
549 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 566 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
550 return userfunc(sess, rx); 567 return userfunc(sess, rx);
551 568
552 return 0; 569 return 0;
553 } 570 }
554 571
555 static int ratechange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 572 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
556 { 573 {
557 aim_rxcallback_t userfunc; 574 aim_rxcallback_t userfunc;
558 int i = 0, code; 575 fu16_t code, rateclass;
559 unsigned long currentavg, maxavg; 576 fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect;
560 unsigned long rateclass, windowsize, clear, alert, limit, disconnect; 577
561 578 code = aimbs_get16(bs);
562 code = aimutil_get16(data+i); 579 rateclass = aimbs_get16(bs);
563 i += 2; 580
564 581 windowsize = aimbs_get32(bs);
565 rateclass = aimutil_get16(data+i); 582 clear = aimbs_get32(bs);
566 i += 2; 583 alert = aimbs_get32(bs);
567 584 limit = aimbs_get32(bs);
568 windowsize = aimutil_get32(data+i); 585 disconnect = aimbs_get32(bs);
569 i += 4; 586 currentavg = aimbs_get32(bs);
570 clear = aimutil_get32(data+i); 587 maxavg = aimbs_get32(bs);
571 i += 4;
572 alert = aimutil_get32(data+i);
573 i += 4;
574 limit = aimutil_get32(data+i);
575 i += 4;
576 disconnect = aimutil_get32(data+i);
577 i += 4;
578 currentavg = aimutil_get32(data+i);
579 i += 4;
580 maxavg = aimutil_get32(data+i);
581 i += 4;
582 588
583 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 589 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
584 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); 590 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
585 591
586 return 0; 592 return 0;
587 } 593 }
588 594
589 /* XXX parse this */ 595 /* XXX parse this */
590 static int selfinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 596 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
591 { 597 {
592 aim_rxcallback_t userfunc; 598 aim_rxcallback_t userfunc;
593 599
594 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 600 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
595 return userfunc(sess, rx); 601 return userfunc(sess, rx);
596 602
597 return 0; 603 return 0;
598 } 604 }
599 605
600 static int evilnotify(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 606 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
601 { 607 {
602 aim_rxcallback_t userfunc = NULL; 608 aim_rxcallback_t userfunc;
603 int i = 0; 609 fu16_t newevil;
604 unsigned short newevil;
605 struct aim_userinfo_s userinfo; 610 struct aim_userinfo_s userinfo;
606 611
607 newevil = aimutil_get16(data);
608 i += 2;
609
610 memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); 612 memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
611 613
612 if (datalen-i) 614 newevil = aimbs_get16(bs);
613 i += aim_extractuserinfo(sess, data+i, &userinfo); 615
616 if (aim_bstream_empty(bs))
617 aim_extractuserinfo(sess, bs, &userinfo);
614 618
615 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 619 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
616 return userfunc(sess, rx, newevil, &userinfo); 620 return userfunc(sess, rx, newevil, &userinfo);
617 621
618 return 0; 622 return 0;
619 } 623 }
620 624
621 static int motd(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 625 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
622 { 626 {
623 aim_rxcallback_t userfunc; 627 aim_rxcallback_t userfunc;
624 char *msg = NULL; 628 char *msg = NULL;
625 int ret = 0; 629 int ret = 0;
626 struct aim_tlvlist_t *tlvlist; 630 aim_tlvlist_t *tlvlist;
627 unsigned short id; 631 fu16_t id;
628 632
629 /* 633 /*
630 * Code. 634 * Code.
631 * 635 *
632 * Valid values: 636 * Valid values:
634 * 2 Advisory upgrade 638 * 2 Advisory upgrade
635 * 3 System bulletin 639 * 3 System bulletin
636 * 4 Nothing's wrong ("top o the world" -- normal) 640 * 4 Nothing's wrong ("top o the world" -- normal)
637 * 641 *
638 */ 642 */
639 id = aimutil_get16(data); 643 id = aimbs_get16(bs);
640 644
641 /* 645 /*
642 * TLVs follow 646 * TLVs follow
643 */ 647 */
644 if ((tlvlist = aim_readtlvchain(data+2, datalen-2))) 648 tlvlist = aim_readtlvchain(bs);
645 msg = aim_gettlv_str(tlvlist, 0x000b, 1); 649
650 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
646 651
647 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 652 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
648 ret = userfunc(sess, rx, id, msg); 653 ret = userfunc(sess, rx, id, msg);
649 654
650 free(msg); 655 free(msg);
652 aim_freetlvchain(&tlvlist); 657 aim_freetlvchain(&tlvlist);
653 658
654 return ret; 659 return ret;
655 } 660 }
656 661
657 static int hostversions(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 662 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
658 { 663 {
659 aim_rxcallback_t userfunc; 664 aim_rxcallback_t userfunc;
660 int vercount; 665 int vercount;
661 666 fu8_t *versions;
662 vercount = datalen/4; 667
668 vercount = aim_bstream_empty(bs)/4;
669 versions = aimbs_getraw(bs, aim_bstream_empty(bs));
663 670
664 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 671 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
665 return userfunc(sess, rx, vercount, data); 672 return userfunc(sess, rx, vercount, versions);
673
674 free(versions);
666 675
667 return 0; 676 return 0;
668 } 677 }
669 678
670 /* 679 /*
702 * on numerous ocassions. 711 * on numerous ocassions.
703 * 712 *
704 * Anyway, neener. We win again. 713 * Anyway, neener. We win again.
705 * 714 *
706 */ 715 */
707 static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) 716 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
708 { 717 {
709 aim_rxcallback_t userfunc; 718 aim_rxcallback_t userfunc;
710 unsigned long offset, len; 719 fu32_t offset, len;
711 int i = 0; 720 aim_tlvlist_t *list;
712 struct aim_tlvlist_t *list; 721 char *modname;
713 char *modname = NULL; 722
714 723 offset = aimbs_get32(bs);
715 offset = aimutil_get32(data); 724 len = aimbs_get32(bs);
716 i += 4; 725 list = aim_readtlvchain(bs);
717 726
718 len = aimutil_get32(data+4); 727 modname = aim_gettlv_str(list, 0x0001, 1);
719 i += 4;
720
721 list = aim_readtlvchain(data+i, datalen-i);
722
723 if (aim_gettlv(list, 0x0001, 1))
724 modname = aim_gettlv_str(list, 0x0001, 1);
725 728
726 faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe"); 729 faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe");
727 730
728 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 731 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
729 return userfunc(sess, rx, offset, len, modname); 732 return userfunc(sess, rx, offset, len, modname);
732 aim_freetlvchain(&list); 735 aim_freetlvchain(&list);
733 736
734 return 0; 737 return 0;
735 } 738 }
736 739
737 static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len) 740 #if 0
741 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)
738 { 742 {
739 int i; 743 int i;
740 744
741 if (!sess || !buf || !len) 745 if (!sess || !buf || !len)
742 return; 746 return;
752 756
753 faimdprintf(sess, 1, "\n\n"); 757 faimdprintf(sess, 1, "\n\n");
754 758
755 return; 759 return;
756 } 760 }
757 761 #endif
758 faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag) 762
759 { 763 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag)
760 struct command_tx_struct *tx; 764 {
761 int i = 0; 765 aim_frame_t *fr;
766 aim_snacid_t snacid;
762 767
763 if (!sess || !conn) 768 if (!sess || !conn)
764 return -EINVAL; 769 return -EINVAL;
765 770
766 if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) 771 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16)))
767 return -ENOMEM; 772 return -ENOMEM;
768 773
769 tx->lock = 1; 774 snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0);
770 775
771 i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); 776 aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid);
772 i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */ 777 aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */
773 778
774 if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */ 779 if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */
775 780
776 memcpy(tx->data+i, buf, 0x10); 781 aimbs_putraw(&fr->data, buf, 0x10);
777 i += 0x10;
778 782
779 } else if (buf && (len > 0)) { /* use input buffer */ 783 } else if (buf && (len > 0)) { /* use input buffer */
780 md5_state_t state; 784 md5_state_t state;
785 md5_byte_t digest[0x10];
781 786
782 md5_init(&state); 787 md5_init(&state);
783 md5_append(&state, (const md5_byte_t *)buf, len); 788 md5_append(&state, (const md5_byte_t *)buf, len);
784 md5_finish(&state, (md5_byte_t *)(tx->data+i)); 789 md5_finish(&state, digest);
785 i += 0x10; 790
791 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
786 792
787 } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ 793 } else if (len == 0) { /* no length, just hash NULL (buf is optional) */
788 md5_state_t state; 794 md5_state_t state;
789 unsigned char nil = '\0'; 795 fu8_t nil = '\0';
796 md5_byte_t digest[0x10];
790 797
791 /* 798 /*
792 * These MD5 routines are stupid in that you have to have 799 * These MD5 routines are stupid in that you have to have
793 * at least one append. So thats why this doesn't look 800 * at least one append. So thats why this doesn't look
794 * real logical. 801 * real logical.
795 */ 802 */
796 md5_init(&state); 803 md5_init(&state);
797 md5_append(&state, (const md5_byte_t *)&nil, 0); 804 md5_append(&state, (const md5_byte_t *)&nil, 0);
798 md5_finish(&state, (md5_byte_t *)(tx->data+i)); 805 md5_finish(&state, digest);
799 i += 0x10; 806
807 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
800 808
801 } else { 809 } else {
802 810
803 /* 811 /*
804 * This data is correct for AIM 3.5.1670. 812 * This data is correct for AIM 3.5.1670.
808 * 816 *
809 */ 817 */
810 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) { 818 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) {
811 819
812 #if 1 /* with "AnrbnrAqhfzcd" */ 820 #if 1 /* with "AnrbnrAqhfzcd" */
813 i += aimutil_put32(tx->data+i, 0x44a95d26); 821 aimbs_put32(&fr->data, 0x44a95d26);
814 i += aimutil_put32(tx->data+i, 0xd2490423); 822 aimbs_put32(&fr->data, 0xd2490423);
815 i += aimutil_put32(tx->data+i, 0x93b8821f); 823 aimbs_put32(&fr->data, 0x93b8821f);
816 i += aimutil_put32(tx->data+i, 0x51c54b01); 824 aimbs_put32(&fr->data, 0x51c54b01);
817 #else /* no filename */ 825 #else /* no filename */
818 i += aimutil_put32(tx->data+i, 0x1df8cbae); 826 aimbs_put32(&fr->data, 0x1df8cbae);
819 i += aimutil_put32(tx->data+i, 0x5523b839); 827 aimbs_put32(&fr->data, 0x5523b839);
820 i += aimutil_put32(tx->data+i, 0xa0e10db3); 828 aimbs_put32(&fr->data, 0xa0e10db3);
821 i += aimutil_put32(tx->data+i, 0xa46d3b39); 829 aimbs_put32(&fr->data, 0xa46d3b39);
822 #endif 830 #endif
823 831
824 } else if ((offset == 0x00001000) && (len == 0x00000000)) { 832 } else if ((offset == 0x00001000) && (len == 0x00000000)) {
825 833
826 i += aimutil_put32(tx->data+i, 0xd41d8cd9); 834 aimbs_put32(&fr->data, 0xd41d8cd9);
827 i += aimutil_put32(tx->data+i, 0x8f00b204); 835 aimbs_put32(&fr->data, 0x8f00b204);
828 i += aimutil_put32(tx->data+i, 0xe9800998); 836 aimbs_put32(&fr->data, 0xe9800998);
829 i += aimutil_put32(tx->data+i, 0xecf8427e); 837 aimbs_put32(&fr->data, 0xecf8427e);
830 838
831 } else 839 } else
832 faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n"); 840 faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n");
833 841
834 } 842 }
835 843
836 tx->commandlen = i; 844 aim_tx_enqueue(sess, fr);
837 tx->lock = 0; 845
838 aim_tx_enqueue(sess, tx); 846 return 0;
839 847 }
840 return 0; 848
841 } 849 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
842
843 static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
844 { 850 {
845 851
846 if (snac->subtype == 0x0003) 852 if (snac->subtype == 0x0003)
847 return hostonline(sess, mod, rx, snac, data, datalen); 853 return hostonline(sess, mod, rx, snac, bs);
848 else if (snac->subtype == 0x0005) 854 else if (snac->subtype == 0x0005)
849 return redirect(sess, mod, rx, snac, data, datalen); 855 return redirect(sess, mod, rx, snac, bs);
850 else if (snac->subtype == 0x0007) 856 else if (snac->subtype == 0x0007)
851 return rateresp(sess, mod, rx, snac, data, datalen); 857 return rateresp(sess, mod, rx, snac, bs);
852 else if (snac->subtype == 0x000a) 858 else if (snac->subtype == 0x000a)
853 return ratechange(sess, mod, rx, snac, data, datalen); 859 return ratechange(sess, mod, rx, snac, bs);
854 else if (snac->subtype == 0x000f) 860 else if (snac->subtype == 0x000f)
855 return selfinfo(sess, mod, rx, snac, data, datalen); 861 return selfinfo(sess, mod, rx, snac, bs);
856 else if (snac->subtype == 0x0010) 862 else if (snac->subtype == 0x0010)
857 return evilnotify(sess, mod, rx, snac, data, datalen); 863 return evilnotify(sess, mod, rx, snac, bs);
858 else if (snac->subtype == 0x0013) 864 else if (snac->subtype == 0x0013)
859 return motd(sess, mod, rx, snac, data, datalen); 865 return motd(sess, mod, rx, snac, bs);
860 else if (snac->subtype == 0x0018) 866 else if (snac->subtype == 0x0018)
861 return hostversions(sess, mod, rx, snac, data, datalen); 867 return hostversions(sess, mod, rx, snac, bs);
862 else if (snac->subtype == 0x001f) 868 else if (snac->subtype == 0x001f)
863 return memrequest(sess, mod, rx, snac, data, datalen); 869 return memrequest(sess, mod, rx, snac, bs);
864 870
865 return 0; 871 return 0;
866 } 872 }
867 873
868 faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod) 874 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod)
869 { 875 {
870 876
871 mod->family = 0x0001; 877 mod->family = 0x0001;
872 mod->version = 0x0000; 878 mod->version = 0x0000;
873 mod->flags = 0; 879 mod->flags = 0;