2703
|
1 /*
|
|
2 * Group 1. This is a very special group. All connections support
|
|
3 * this group, as it does some particularly good things (like rate limiting).
|
|
4 */
|
|
5
|
|
6 #define FAIM_INTERNAL
|
|
7 #include <aim.h>
|
|
8
|
|
9 #include "md5.h"
|
|
10
|
|
11 /* Client Online (group 1, subtype 2) */
|
|
12 faim_export int aim_clientready(aim_session_t *sess, aim_conn_t *conn)
|
|
13 {
|
|
14 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
|
|
15 struct snacgroup *sg;
|
|
16 aim_frame_t *fr;
|
|
17 aim_snacid_t snacid;
|
|
18
|
|
19 if (!ins)
|
|
20 return -EINVAL;
|
|
21
|
|
22 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
|
|
23 return -ENOMEM;
|
|
24
|
|
25 snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0);
|
|
26 aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid);
|
|
27
|
|
28 /*
|
|
29 * Send only the tool versions that the server cares about (that it
|
|
30 * marked as supporting in the server ready SNAC).
|
|
31 */
|
|
32 for (sg = ins->groups; sg; sg = sg->next) {
|
|
33 aim_module_t *mod;
|
|
34
|
|
35 if ((mod = aim__findmodulebygroup(sess, sg->group))) {
|
|
36 aimbs_put16(&fr->data, mod->family);
|
|
37 aimbs_put16(&fr->data, mod->version);
|
|
38 aimbs_put16(&fr->data, mod->toolid);
|
|
39 aimbs_put16(&fr->data, mod->toolversion);
|
|
40 } else
|
|
41 faimdprintf(sess, 1, "aim_clientready: server supports group 0x%04x but we don't!\n", sg->group);
|
|
42 }
|
|
43
|
|
44 aim_tx_enqueue(sess, fr);
|
|
45
|
|
46 return 0;
|
|
47 }
|
|
48
|
|
49 /*
|
|
50 * Host Online (group 1, type 3)
|
|
51 *
|
|
52 * See comments in conn.c about how the group associations are supposed
|
|
53 * to work, and how they really work.
|
|
54 *
|
|
55 * This info probably doesn't even need to make it to the client.
|
|
56 *
|
|
57 * We don't actually call the client here. This starts off the connection
|
|
58 * initialization routine required by all AIM connections. The next time
|
|
59 * the client is called is the CONNINITDONE callback, which should be
|
|
60 * shortly after the rate information is acknowledged.
|
|
61 *
|
|
62 */
|
|
63 static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
64 {
|
|
65 fu16_t *families;
|
|
66 int famcount;
|
|
67
|
|
68
|
|
69 if (!(families = malloc(aim_bstream_empty(bs))))
|
|
70 return 0;
|
|
71
|
|
72 for (famcount = 0; aim_bstream_empty(bs); famcount++) {
|
|
73 families[famcount] = aimbs_get16(bs);
|
|
74 aim_conn_addgroup(rx->conn, families[famcount]);
|
|
75 }
|
|
76
|
|
77 free(families);
|
|
78
|
|
79
|
|
80 /*
|
|
81 * Next step is in the Host Versions handler.
|
|
82 *
|
|
83 * Note that we must send this before we request rates, since
|
|
84 * the format of the rate information depends on the versions we
|
|
85 * give it.
|
|
86 *
|
|
87 */
|
|
88 aim_setversions(sess, rx->conn);
|
|
89
|
|
90 return 1;
|
|
91 }
|
|
92
|
|
93 /* Service request (group 1, type 4) */
|
|
94 faim_export int aim_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid)
|
|
95 {
|
|
96 return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid);
|
|
97 }
|
|
98
|
|
99 /* Redirect (group 1, type 5) */
|
|
100 static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
101 {
|
|
102 int serviceid;
|
|
103 fu8_t *cookie;
|
|
104 char *ip;
|
|
105 aim_rxcallback_t userfunc;
|
|
106 aim_tlvlist_t *tlvlist;
|
|
107 char *chathack = NULL;
|
|
108 int chathackex = 0;
|
|
109 int ret = 0;
|
|
110
|
|
111 tlvlist = aim_readtlvchain(bs);
|
|
112
|
|
113 if (!aim_gettlv(tlvlist, 0x000d, 1) ||
|
|
114 !aim_gettlv(tlvlist, 0x0005, 1) ||
|
|
115 !aim_gettlv(tlvlist, 0x0006, 1)) {
|
|
116 aim_freetlvchain(&tlvlist);
|
|
117 return 0;
|
|
118 }
|
|
119
|
|
120 serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
|
|
121 ip = aim_gettlv_str(tlvlist, 0x0005, 1);
|
|
122 cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
|
|
123
|
|
124 /*
|
|
125 * Chat hack.
|
|
126 */
|
|
127 if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
|
|
128 chathack = sess->pendingjoin;
|
|
129 chathackex = sess->pendingjoinexchange;
|
|
130 sess->pendingjoin = NULL;
|
|
131 sess->pendingjoinexchange = 0;
|
|
132 }
|
|
133
|
|
134 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
135 ret = userfunc(sess, rx, serviceid, ip, cookie, chathack, chathackex);
|
|
136
|
|
137 free(ip);
|
|
138 free(cookie);
|
|
139 free(chathack);
|
|
140
|
|
141 aim_freetlvchain(&tlvlist);
|
|
142
|
|
143 return ret;
|
|
144 }
|
|
145
|
|
146 /* Request Rate Information. (group 1, type 6) */
|
|
147 faim_internal int aim_reqrates(aim_session_t *sess, aim_conn_t *conn)
|
|
148 {
|
|
149 return aim_genericreq_n(sess, conn, 0x0001, 0x0006);
|
|
150 }
|
|
151
|
|
152 /*
|
|
153 * OSCAR defines several 'rate classes'. Each class has seperate
|
|
154 * rate limiting properties (limit level, alert level, disconnect
|
|
155 * level, etc), and a set of SNAC family/type pairs associated with
|
|
156 * it. The rate classes, their limiting properties, and the definitions
|
|
157 * of which SNACs are belong to which class, are defined in the
|
|
158 * Rate Response packet at login to each host.
|
|
159 *
|
|
160 * Logically, all rate offenses within one class count against further
|
|
161 * offenses for other SNACs in the same class (ie, sending messages
|
|
162 * too fast will limit the number of user info requests you can send,
|
|
163 * since those two SNACs are in the same rate class).
|
|
164 *
|
|
165 * Since the rate classes are defined dynamically at login, the values
|
|
166 * below may change. But they seem to be fairly constant.
|
|
167 *
|
|
168 * Currently, BOS defines five rate classes, with the commonly used
|
|
169 * members as follows...
|
|
170 *
|
|
171 * Rate class 0x0001:
|
|
172 * - Everything thats not in any of the other classes
|
|
173 *
|
|
174 * Rate class 0x0002:
|
|
175 * - Buddy list add/remove
|
|
176 * - Permit list add/remove
|
|
177 * - Deny list add/remove
|
|
178 *
|
|
179 * Rate class 0x0003:
|
|
180 * - User information requests
|
|
181 * - Outgoing ICBMs
|
|
182 *
|
|
183 * Rate class 0x0004:
|
|
184 * - A few unknowns: 2/9, 2/b, and f/2
|
|
185 *
|
|
186 * Rate class 0x0005:
|
|
187 * - Chat room create
|
|
188 * - Outgoing chat ICBMs
|
|
189 *
|
|
190 * The only other thing of note is that class 5 (chat) has slightly looser
|
|
191 * limiting properties than class 3 (normal messages). But thats just a
|
|
192 * small bit of trivia for you.
|
|
193 *
|
|
194 * The last thing that needs to be learned about the rate limiting
|
|
195 * system is how the actual numbers relate to the passing of time. This
|
|
196 * seems to be a big mystery.
|
|
197 *
|
|
198 */
|
|
199
|
|
200 static void rc_addclass(struct rateclass **head, struct rateclass *inrc)
|
|
201 {
|
|
202 struct rateclass *rc, *rc2;
|
|
203
|
|
204 if (!(rc = malloc(sizeof(struct rateclass))))
|
|
205 return;
|
|
206
|
|
207 memcpy(rc, inrc, sizeof(struct rateclass));
|
|
208 rc->next = NULL;
|
|
209
|
|
210 for (rc2 = *head; rc2 && rc2->next; rc2 = rc2->next)
|
|
211 ;
|
|
212
|
|
213 if (!rc2)
|
|
214 *head = rc;
|
|
215 else
|
|
216 rc2->next = rc;
|
|
217
|
|
218 return;
|
|
219 }
|
|
220
|
|
221 static struct rateclass *rc_findclass(struct rateclass **head, fu16_t id)
|
|
222 {
|
|
223 struct rateclass *rc;
|
|
224
|
|
225 for (rc = *head; rc; rc = rc->next) {
|
|
226 if (rc->classid == id)
|
|
227 return rc;
|
|
228 }
|
|
229
|
|
230 return NULL;
|
|
231 }
|
|
232
|
|
233 static void rc_addpair(struct rateclass *rc, fu16_t group, fu16_t type)
|
|
234 {
|
|
235 struct snacpair *sp, *sp2;
|
|
236
|
|
237 if (!(sp = malloc(sizeof(struct snacpair))))
|
|
238 return;
|
|
239 memset(sp, 0, sizeof(struct snacpair));
|
|
240
|
|
241 sp->group = group;
|
|
242 sp->subtype = type;
|
|
243 sp->next = NULL;
|
|
244
|
|
245 for (sp2 = rc->members; sp2 && sp2->next; sp2 = sp2->next)
|
|
246 ;
|
|
247
|
|
248 if (!sp2)
|
|
249 rc->members = sp;
|
|
250 else
|
|
251 sp2->next = sp;
|
|
252
|
|
253 return;
|
|
254 }
|
|
255
|
|
256 /* Rate Parameters (group 1, type 7) */
|
|
257 static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
258 {
|
|
259 aim_conn_inside_t *ins = (aim_conn_inside_t *)rx->conn->inside;
|
|
260 fu16_t numclasses, i;
|
|
261 aim_rxcallback_t userfunc;
|
|
262
|
|
263
|
|
264 /*
|
|
265 * First are the parameters for each rate class.
|
|
266 */
|
|
267 numclasses = aimbs_get16(bs);
|
|
268 for (i = 0; i < numclasses; i++) {
|
|
269 struct rateclass rc;
|
|
270
|
|
271 memset(&rc, 0, sizeof(struct rateclass));
|
|
272
|
|
273 rc.classid = aimbs_get16(bs);
|
|
274 rc.windowsize = aimbs_get32(bs);
|
|
275 rc.clear = aimbs_get32(bs);
|
|
276 rc.alert = aimbs_get32(bs);
|
|
277 rc.limit = aimbs_get32(bs);
|
|
278 rc.disconnect = aimbs_get32(bs);
|
|
279 rc.current = aimbs_get32(bs);
|
|
280 rc.max = aimbs_get32(bs);
|
|
281
|
|
282 /*
|
|
283 * The server will send an extra five bytes of parameters
|
|
284 * depending on the version we advertised in 1/17. If we
|
|
285 * didn't send 1/17 (evil!), then this will crash and you
|
|
286 * die, as it will default to the old version but we have
|
|
287 * the new version hardcoded here.
|
|
288 */
|
|
289 if (mod->version >= 3)
|
|
290 aimbs_getrawbuf(bs, rc.unknown, sizeof(rc.unknown));
|
|
291
|
|
292 rc_addclass(&ins->rates, &rc);
|
|
293 }
|
|
294
|
|
295 /*
|
|
296 * Then the members of each class.
|
|
297 */
|
|
298 for (i = 0; i < numclasses; i++) {
|
|
299 fu16_t classid, count;
|
|
300 struct rateclass *rc;
|
|
301 int j;
|
|
302
|
|
303 classid = aimbs_get16(bs);
|
|
304 count = aimbs_get16(bs);
|
|
305
|
|
306 rc = rc_findclass(&ins->rates, classid);
|
|
307
|
|
308 for (j = 0; j < count; j++) {
|
|
309 fu16_t group, subtype;
|
|
310
|
|
311 group = aimbs_get16(bs);
|
|
312 subtype = aimbs_get16(bs);
|
|
313
|
|
314 if (rc)
|
|
315 rc_addpair(rc, group, subtype);
|
|
316 }
|
|
317 }
|
|
318
|
|
319 /*
|
|
320 * We don't pass the rate information up to the client, as it really
|
|
321 * doesn't care. The information is stored in the connection, however
|
|
322 * so that we can do more fun stuff later (not really).
|
|
323 */
|
|
324
|
|
325 /*
|
|
326 * Last step in the conn init procedure is to acknowledge that we
|
|
327 * agree to these draconian limitations.
|
|
328 */
|
|
329 aim_rates_addparam(sess, rx->conn);
|
|
330
|
|
331 /*
|
|
332 * Finally, tell the client it's ready to go...
|
|
333 */
|
|
334 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE)))
|
|
335 userfunc(sess, rx);
|
|
336
|
|
337
|
|
338 return 1;
|
|
339 }
|
|
340
|
|
341 /* Add Rate Parameter (group 1, type 8) */
|
|
342 faim_internal int aim_rates_addparam(aim_session_t *sess, aim_conn_t *conn)
|
|
343 {
|
|
344 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
|
|
345 aim_frame_t *fr;
|
|
346 aim_snacid_t snacid;
|
|
347 struct rateclass *rc;
|
|
348
|
|
349 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
|
|
350 return -ENOMEM;
|
|
351
|
|
352 snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0);
|
|
353 aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid);
|
|
354
|
|
355 for (rc = ins->rates; rc; rc = rc->next)
|
|
356 aimbs_put16(&fr->data, rc->classid);
|
|
357
|
|
358 aim_tx_enqueue(sess, fr);
|
|
359
|
|
360 return 0;
|
|
361 }
|
|
362
|
|
363 /* Delete Rate Parameter (group 1, type 9) */
|
|
364 faim_internal int aim_rates_delparam(aim_session_t *sess, aim_conn_t *conn)
|
|
365 {
|
|
366 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
|
|
367 aim_frame_t *fr;
|
|
368 aim_snacid_t snacid;
|
|
369 struct rateclass *rc;
|
|
370
|
|
371 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
|
|
372 return -ENOMEM;
|
|
373
|
|
374 snacid = aim_cachesnac(sess, 0x0001, 0x0009, 0x0000, NULL, 0);
|
|
375 aim_putsnac(&fr->data, 0x0001, 0x0009, 0x0000, snacid);
|
|
376
|
|
377 for (rc = ins->rates; rc; rc = rc->next)
|
|
378 aimbs_put16(&fr->data, rc->classid);
|
|
379
|
|
380 aim_tx_enqueue(sess, fr);
|
|
381
|
|
382 return 0;
|
|
383 }
|
|
384
|
|
385 /* Rate Change (group 1, type 0x0a) */
|
|
386 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
387 {
|
|
388 aim_rxcallback_t userfunc;
|
|
389 fu16_t code, rateclass;
|
|
390 fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect;
|
|
391
|
|
392 code = aimbs_get16(bs);
|
|
393 rateclass = aimbs_get16(bs);
|
|
394
|
|
395 windowsize = aimbs_get32(bs);
|
|
396 clear = aimbs_get32(bs);
|
|
397 alert = aimbs_get32(bs);
|
|
398 limit = aimbs_get32(bs);
|
|
399 disconnect = aimbs_get32(bs);
|
|
400 currentavg = aimbs_get32(bs);
|
|
401 maxavg = aimbs_get32(bs);
|
|
402
|
|
403 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
404 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
|
|
405
|
|
406 return 0;
|
|
407 }
|
|
408
|
|
409 /*
|
|
410 * How Migrations work.
|
|
411 *
|
|
412 * The server sends a Server Pause message, which the client should respond to
|
|
413 * with a Server Pause Ack, which contains the families it needs on this
|
|
414 * connection. The server will send a Migration Notice with an IP address, and
|
|
415 * then disconnect. Next the client should open the connection and send the
|
|
416 * cookie. Repeat the normal login process and pretend this never happened.
|
|
417 *
|
|
418 * The Server Pause contains no data.
|
|
419 *
|
|
420 */
|
|
421
|
|
422 /* Service Pause (group 1, type 0x0b) */
|
|
423 static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
424 {
|
|
425 aim_rxcallback_t userfunc;
|
|
426
|
|
427 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
428 return userfunc(sess, rx);
|
|
429
|
|
430 return 0;
|
|
431 }
|
|
432
|
|
433 /*
|
|
434 * Service Pause Acknowledgement (group 1, type 0x0c)
|
|
435 *
|
|
436 * It is rather important that aim_sendpauseack() gets called for the exact
|
|
437 * same connection that the Server Pause callback was called for, since
|
|
438 * libfaim extracts the data for the SNAC from the connection structure.
|
|
439 *
|
|
440 * Of course, if you don't do that, more bad things happen than just what
|
|
441 * libfaim can cause.
|
|
442 *
|
|
443 */
|
|
444 faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn)
|
|
445 {
|
|
446 aim_frame_t *fr;
|
|
447 aim_snacid_t snacid;
|
|
448 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
|
|
449 struct snacgroup *sg;
|
|
450
|
|
451 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1024)))
|
|
452 return -ENOMEM;
|
|
453
|
|
454 snacid = aim_cachesnac(sess, 0x0001, 0x000c, 0x0000, NULL, 0);
|
|
455 aim_putsnac(&fr->data, 0x0001, 0x000c, 0x0000, snacid);
|
|
456
|
|
457 /*
|
|
458 * This list should have all the groups that the original
|
|
459 * Host Online / Server Ready said this host supports. And
|
|
460 * we want them all back after the migration.
|
|
461 */
|
|
462 for (sg = ins->groups; sg; sg = sg->next)
|
|
463 aimbs_put16(&fr->data, sg->group);
|
|
464
|
|
465 aim_tx_enqueue(sess, fr);
|
|
466
|
|
467 return 0;
|
|
468 }
|
|
469
|
|
470 /* Service Resume (group 1, type 0x0d) */
|
|
471 static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
472 {
|
|
473 aim_rxcallback_t userfunc;
|
|
474
|
|
475 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
476 return userfunc(sess, rx);
|
|
477
|
|
478 return 0;
|
|
479 }
|
|
480
|
|
481 /* Request self-info (group 1, type 0x0e) */
|
|
482 faim_export int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn)
|
|
483 {
|
|
484 return aim_genericreq_n(sess, conn, 0x0001, 0x000e);
|
|
485 }
|
|
486
|
|
487 /* Self User Info (group 1, type 0x0f) */
|
|
488 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
489 {
|
|
490 aim_rxcallback_t userfunc;
|
|
491 aim_userinfo_t userinfo;
|
|
492
|
|
493 aim_extractuserinfo(sess, bs, &userinfo);
|
|
494
|
|
495 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
496 return userfunc(sess, rx, &userinfo);
|
|
497
|
|
498 return 0;
|
|
499 }
|
|
500
|
|
501 /* Evil Notification (group 1, type 0x10) */
|
|
502 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
503 {
|
|
504 aim_rxcallback_t userfunc;
|
|
505 fu16_t newevil;
|
|
506 aim_userinfo_t userinfo;
|
|
507
|
|
508 memset(&userinfo, 0, sizeof(aim_userinfo_t));
|
|
509
|
|
510 newevil = aimbs_get16(bs);
|
|
511
|
|
512 if (aim_bstream_empty(bs))
|
|
513 aim_extractuserinfo(sess, bs, &userinfo);
|
|
514
|
|
515 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
516 return userfunc(sess, rx, newevil, &userinfo);
|
|
517
|
|
518 return 0;
|
|
519 }
|
|
520
|
|
521 /*
|
|
522 * Idle Notification (group 1, type 0x11)
|
|
523 *
|
|
524 * Should set your current idle time in seconds. Note that this should
|
|
525 * never be called consecutively with a non-zero idle time. That makes
|
|
526 * OSCAR do funny things. Instead, just set it once you go idle, and then
|
|
527 * call it again with zero when you're back.
|
|
528 *
|
|
529 */
|
|
530 faim_export int aim_bos_setidle(aim_session_t *sess, aim_conn_t *conn, fu32_t idletime)
|
|
531 {
|
|
532 return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime);
|
|
533 }
|
|
534
|
|
535 /*
|
|
536 * Service Migrate (group 1, type 0x12)
|
|
537 *
|
|
538 * This is the final SNAC sent on the original connection during a migration.
|
|
539 * It contains the IP and cookie used to connect to the new server, and
|
|
540 * optionally a list of the SNAC groups being migrated.
|
|
541 *
|
|
542 */
|
|
543 static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
544 {
|
|
545 aim_rxcallback_t userfunc;
|
|
546 int ret = 0;
|
|
547 fu16_t groupcount, i;
|
|
548 aim_tlvlist_t *tl;
|
|
549 char *ip = NULL;
|
|
550 aim_tlv_t *cktlv;
|
|
551
|
|
552 /*
|
|
553 * Apparently there's some fun stuff that can happen right here. The
|
|
554 * migration can actually be quite selective about what groups it
|
|
555 * moves to the new server. When not all the groups for a connection
|
|
556 * are migrated, or they are all migrated but some groups are moved
|
|
557 * to a different server than others, it is called a bifurcated
|
|
558 * migration.
|
|
559 *
|
|
560 * Let's play dumb and not support that.
|
|
561 *
|
|
562 */
|
|
563 groupcount = aimbs_get16(bs);
|
|
564 for (i = 0; i < groupcount; i++) {
|
|
565 fu16_t group;
|
|
566
|
|
567 group = aimbs_get16(bs);
|
|
568
|
|
569 faimdprintf(sess, 0, "bifurcated migration unsupported -- group 0x%04x\n", group);
|
|
570 }
|
|
571
|
|
572 tl = aim_readtlvchain(bs);
|
|
573
|
|
574 if (aim_gettlv(tl, 0x0005, 1))
|
|
575 ip = aim_gettlv_str(tl, 0x0005, 1);
|
|
576
|
|
577 cktlv = aim_gettlv(tl, 0x0006, 1);
|
|
578
|
|
579 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
580 ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL);
|
|
581
|
|
582 aim_freetlvchain(&tl);
|
|
583 free(ip);
|
|
584
|
|
585 return ret;
|
|
586 }
|
|
587
|
|
588 /* Message of the Day (group 1, type 0x13) */
|
|
589 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
590 {
|
|
591 aim_rxcallback_t userfunc;
|
|
592 char *msg = NULL;
|
|
593 int ret = 0;
|
|
594 aim_tlvlist_t *tlvlist;
|
|
595 fu16_t id;
|
|
596
|
|
597 /*
|
|
598 * Code.
|
|
599 *
|
|
600 * Valid values:
|
|
601 * 1 Mandatory upgrade
|
|
602 * 2 Advisory upgrade
|
|
603 * 3 System bulletin
|
|
604 * 4 Nothing's wrong ("top o the world" -- normal)
|
|
605 * 5 Lets-break-something.
|
|
606 *
|
|
607 */
|
|
608 id = aimbs_get16(bs);
|
|
609
|
|
610 /*
|
|
611 * TLVs follow
|
|
612 */
|
|
613 tlvlist = aim_readtlvchain(bs);
|
|
614
|
|
615 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
|
|
616
|
|
617 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
618 ret = userfunc(sess, rx, id, msg);
|
|
619
|
|
620 free(msg);
|
|
621
|
|
622 aim_freetlvchain(&tlvlist);
|
|
623
|
|
624 return ret;
|
|
625 }
|
|
626
|
|
627 /*
|
|
628 * Set privacy flags (group 1, type 0x14)
|
|
629 *
|
|
630 * Normally 0x03.
|
|
631 *
|
|
632 * Bit 1: Allows other AIM users to see how long you've been idle.
|
|
633 * Bit 2: Allows other AIM users to see how long you've been a member.
|
|
634 *
|
|
635 */
|
|
636 faim_export int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, fu32_t flags)
|
|
637 {
|
|
638 return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags);
|
|
639 }
|
|
640
|
|
641 /*
|
|
642 * No-op (group 1, type 0x16)
|
|
643 *
|
|
644 * WinAIM sends these every 4min or so to keep the connection alive. Its not
|
|
645 * real necessary.
|
|
646 *
|
|
647 */
|
|
648 faim_export int aim_nop(aim_session_t *sess, aim_conn_t *conn)
|
|
649 {
|
|
650 return aim_genericreq_n(sess, conn, 0x0001, 0x0016);
|
|
651 }
|
|
652
|
|
653 /*
|
|
654 * Set client versions (group 1, subtype 0x17)
|
|
655 *
|
|
656 * If you've seen the clientonline/clientready SNAC you're probably
|
|
657 * wondering what the point of this one is. And that point seems to be
|
|
658 * that the versions in the client online SNAC are sent too late for the
|
|
659 * server to be able to use them to change the protocol for the earlier
|
|
660 * login packets (client versions are sent right after Host Online is
|
|
661 * received, but client online versions aren't sent until quite a bit later).
|
|
662 * We can see them already making use of this by changing the format of
|
|
663 * the rate information based on what version of group 1 we advertise here.
|
|
664 *
|
|
665 */
|
|
666 faim_internal int aim_setversions(aim_session_t *sess, aim_conn_t *conn)
|
|
667 {
|
|
668 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
|
|
669 struct snacgroup *sg;
|
|
670 aim_frame_t *fr;
|
|
671 aim_snacid_t snacid;
|
|
672
|
|
673 if (!ins)
|
|
674 return -EINVAL;
|
|
675
|
|
676 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
|
|
677 return -ENOMEM;
|
|
678
|
|
679 snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0);
|
|
680 aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid);
|
|
681
|
|
682 /*
|
|
683 * Send only the versions that the server cares about (that it
|
|
684 * marked as supporting in the server ready SNAC).
|
|
685 */
|
|
686 for (sg = ins->groups; sg; sg = sg->next) {
|
|
687 aim_module_t *mod;
|
|
688
|
|
689 if ((mod = aim__findmodulebygroup(sess, sg->group))) {
|
|
690 aimbs_put16(&fr->data, mod->family);
|
|
691 aimbs_put16(&fr->data, mod->version);
|
|
692 } else
|
|
693 faimdprintf(sess, 1, "aim_setversions: server supports group 0x%04x but we don't!\n", sg->group);
|
|
694 }
|
|
695
|
|
696 aim_tx_enqueue(sess, fr);
|
|
697
|
|
698 return 0;
|
|
699 }
|
|
700
|
|
701 /* Host versions (group 1, subtype 0x18) */
|
|
702 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
703 {
|
|
704 int vercount;
|
|
705 fu8_t *versions;
|
|
706
|
|
707 /* This is frivolous. (Thank you SmarterChild.) */
|
|
708 vercount = aim_bstream_empty(bs)/4;
|
|
709 versions = aimbs_getraw(bs, aim_bstream_empty(bs));
|
|
710 free(versions);
|
|
711
|
|
712 /*
|
|
713 * Now request rates.
|
|
714 */
|
|
715 aim_reqrates(sess, rx->conn);
|
|
716
|
|
717 return 1;
|
|
718 }
|
|
719
|
|
720 /*
|
|
721 * Set Extended Status (group 1, type 0x1e)
|
|
722 *
|
|
723 * Currently only works if using ICQ.
|
|
724 *
|
|
725 */
|
|
726 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu16_t status)
|
|
727 {
|
|
728 aim_frame_t *fr;
|
|
729 aim_snacid_t snacid;
|
|
730 aim_tlvlist_t *tl = NULL;
|
|
731 fu32_t data;
|
|
732
|
|
733 data = 0x00030000 | status; /* yay for error checking ;^) */
|
|
734
|
|
735 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8)))
|
|
736 return -ENOMEM;
|
|
737
|
|
738 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
|
|
739 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
|
|
740
|
|
741 aim_addtlvtochain32(&tl, 0x0006, data);
|
|
742 aim_writetlvchain(&fr->data, &tl);
|
|
743 aim_freetlvchain(&tl);
|
|
744
|
|
745 aim_tx_enqueue(sess, fr);
|
|
746
|
|
747 return 0;
|
|
748 }
|
|
749
|
|
750 /*
|
|
751 * Starting this past week (26 Mar 2001, say), AOL has started sending
|
|
752 * this nice little extra SNAC. AFAIK, it has never been used until now.
|
|
753 *
|
|
754 * The request contains eight bytes. The first four are an offset, the
|
|
755 * second four are a length.
|
|
756 *
|
|
757 * The offset is an offset into aim.exe when it is mapped during execution
|
|
758 * on Win32. So far, AOL has only been requesting bytes in static regions
|
|
759 * of memory. (I won't put it past them to start requesting data in
|
|
760 * less static regions -- regions that are initialized at run time, but still
|
|
761 * before the client recieves this request.)
|
|
762 *
|
|
763 * When the client recieves the request, it adds it to the current ds
|
|
764 * (0x00400000) and dereferences it, copying the data into a buffer which
|
|
765 * it then runs directly through the MD5 hasher. The 16 byte output of
|
|
766 * the hash is then sent back to the server.
|
|
767 *
|
|
768 * If the client does not send any data back, or the data does not match
|
|
769 * the data that the specific client should have, the client will get the
|
|
770 * following message from "AOL Instant Messenger":
|
|
771 * "You have been disconnected from the AOL Instant Message Service (SM)
|
|
772 * for accessing the AOL network using unauthorized software. You can
|
|
773 * download a FREE, fully featured, and authorized client, here
|
|
774 * http://www.aol.com/aim/download2.html"
|
|
775 * The connection is then closed, recieving disconnect code 1, URL
|
|
776 * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.
|
|
777 *
|
|
778 * Note, however, that numerous inconsistencies can cause the above error,
|
|
779 * not just sending back a bad hash. Do not immediatly suspect this code
|
|
780 * if you get disconnected. AOL and the open/free software community have
|
|
781 * played this game for a couple years now, generating the above message
|
|
782 * on numerous ocassions.
|
|
783 *
|
|
784 * Anyway, neener. We win again.
|
|
785 *
|
|
786 */
|
|
787 /* Client verification (group 1, subtype 0x1f) */
|
|
788 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
789 {
|
|
790 aim_rxcallback_t userfunc;
|
|
791 fu32_t offset, len;
|
|
792 aim_tlvlist_t *list;
|
|
793 char *modname;
|
|
794
|
|
795 offset = aimbs_get32(bs);
|
|
796 len = aimbs_get32(bs);
|
|
797 list = aim_readtlvchain(bs);
|
|
798
|
|
799 modname = aim_gettlv_str(list, 0x0001, 1);
|
|
800
|
|
801 faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe");
|
|
802
|
|
803 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
804 return userfunc(sess, rx, offset, len, modname);
|
|
805
|
|
806 free(modname);
|
|
807 aim_freetlvchain(&list);
|
|
808
|
|
809 return 0;
|
|
810 }
|
|
811
|
|
812 #if 0
|
|
813 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)
|
|
814 {
|
|
815 int i;
|
|
816
|
|
817 if (!sess || !buf || !len)
|
|
818 return;
|
|
819
|
|
820 faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf);
|
|
821
|
|
822 for (i = 0; i < len; i++) {
|
|
823 if ((i % 8) == 0)
|
|
824 faimdprintf(sess, 1, "\n\t");
|
|
825
|
|
826 faimdprintf(sess, 1, "0x%2x ", buf[i]);
|
|
827 }
|
|
828
|
|
829 faimdprintf(sess, 1, "\n\n");
|
|
830
|
|
831 return;
|
|
832 }
|
|
833 #endif
|
|
834
|
|
835 /* Client verification reply (group 1, subtype 0x20) */
|
|
836 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)
|
|
837 {
|
|
838 aim_frame_t *fr;
|
|
839 aim_snacid_t snacid;
|
|
840
|
|
841 if (!sess || !conn)
|
|
842 return -EINVAL;
|
|
843
|
|
844 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16)))
|
|
845 return -ENOMEM;
|
|
846
|
|
847 snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0);
|
|
848
|
|
849 aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid);
|
|
850 aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */
|
|
851
|
|
852 if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */
|
|
853
|
|
854 aimbs_putraw(&fr->data, buf, 0x10);
|
|
855
|
|
856 } else if (buf && (len > 0)) { /* use input buffer */
|
|
857 md5_state_t state;
|
|
858 md5_byte_t digest[0x10];
|
|
859
|
|
860 md5_init(&state);
|
|
861 md5_append(&state, (const md5_byte_t *)buf, len);
|
|
862 md5_finish(&state, digest);
|
|
863
|
|
864 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
|
|
865
|
|
866 } else if (len == 0) { /* no length, just hash NULL (buf is optional) */
|
|
867 md5_state_t state;
|
|
868 fu8_t nil = '\0';
|
|
869 md5_byte_t digest[0x10];
|
|
870
|
|
871 /*
|
|
872 * These MD5 routines are stupid in that you have to have
|
|
873 * at least one append. So thats why this doesn't look
|
|
874 * real logical.
|
|
875 */
|
|
876 md5_init(&state);
|
|
877 md5_append(&state, (const md5_byte_t *)&nil, 0);
|
|
878 md5_finish(&state, digest);
|
|
879
|
|
880 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
|
|
881
|
|
882 } else {
|
|
883
|
|
884 /*
|
|
885 * This data is correct for AIM 3.5.1670.
|
|
886 *
|
|
887 * Using these blocks is as close to "legal" as you can get
|
|
888 * without using an AIM binary.
|
|
889 *
|
|
890 */
|
|
891 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) {
|
|
892
|
|
893 #if 1 /* with "AnrbnrAqhfzcd" */
|
|
894 aimbs_put32(&fr->data, 0x44a95d26);
|
|
895 aimbs_put32(&fr->data, 0xd2490423);
|
|
896 aimbs_put32(&fr->data, 0x93b8821f);
|
|
897 aimbs_put32(&fr->data, 0x51c54b01);
|
|
898 #else /* no filename */
|
|
899 aimbs_put32(&fr->data, 0x1df8cbae);
|
|
900 aimbs_put32(&fr->data, 0x5523b839);
|
|
901 aimbs_put32(&fr->data, 0xa0e10db3);
|
|
902 aimbs_put32(&fr->data, 0xa46d3b39);
|
|
903 #endif
|
|
904
|
|
905 } else if ((offset == 0x00001000) && (len == 0x00000000)) {
|
|
906
|
|
907 aimbs_put32(&fr->data, 0xd41d8cd9);
|
|
908 aimbs_put32(&fr->data, 0x8f00b204);
|
|
909 aimbs_put32(&fr->data, 0xe9800998);
|
|
910 aimbs_put32(&fr->data, 0xecf8427e);
|
|
911
|
|
912 } else
|
|
913 faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n");
|
|
914
|
|
915 }
|
|
916
|
|
917 aim_tx_enqueue(sess, fr);
|
|
918
|
|
919 return 0;
|
|
920 }
|
|
921
|
|
922 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
923 {
|
|
924
|
|
925 if (snac->subtype == 0x0003)
|
|
926 return hostonline(sess, mod, rx, snac, bs);
|
|
927 else if (snac->subtype == 0x0005)
|
|
928 return redirect(sess, mod, rx, snac, bs);
|
|
929 else if (snac->subtype == 0x0007)
|
|
930 return rateresp(sess, mod, rx, snac, bs);
|
|
931 else if (snac->subtype == 0x000a)
|
|
932 return ratechange(sess, mod, rx, snac, bs);
|
|
933 else if (snac->subtype == 0x000b)
|
|
934 return serverpause(sess, mod, rx, snac, bs);
|
|
935 else if (snac->subtype == 0x000d)
|
|
936 return serverresume(sess, mod, rx, snac, bs);
|
|
937 else if (snac->subtype == 0x000f)
|
|
938 return selfinfo(sess, mod, rx, snac, bs);
|
|
939 else if (snac->subtype == 0x0010)
|
|
940 return evilnotify(sess, mod, rx, snac, bs);
|
|
941 else if (snac->subtype == 0x0012)
|
|
942 return migrate(sess, mod, rx, snac, bs);
|
|
943 else if (snac->subtype == 0x0013)
|
|
944 return motd(sess, mod, rx, snac, bs);
|
|
945 else if (snac->subtype == 0x0018)
|
|
946 return hostversions(sess, mod, rx, snac, bs);
|
|
947 else if (snac->subtype == 0x001f)
|
|
948 return memrequest(sess, mod, rx, snac, bs);
|
|
949
|
|
950 return 0;
|
|
951 }
|
|
952
|
|
953 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod)
|
|
954 {
|
|
955
|
|
956 mod->family = 0x0001;
|
|
957 mod->version = 0x0003;
|
|
958 mod->toolid = 0x0110;
|
|
959 mod->toolversion = 0x047b;
|
|
960 mod->flags = 0;
|
|
961 strncpy(mod->name, "general", sizeof(mod->name));
|
|
962 mod->snachandler = snachandler;
|
|
963
|
|
964 return 0;
|
|
965 }
|
|
966
|