]> andersk Git - libfaim.git/blame - src/rxhandlers.c
- Mon Mar 5 01:19:48 UTC 2001
[libfaim.git] / src / rxhandlers.c
CommitLineData
9de3ca7e 1/*
24286d93 2 * aim_rxhandlers.c
3 *
4 * This file contains most all of the incoming packet handlers, along
5 * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
6 * actually done in aim_rxqueue.c.
7 *
9de3ca7e 8 */
9
37ee990e 10#define FAIM_INTERNAL
dd60ff8b 11#include <aim.h>
9de3ca7e 12
24286d93 13/*
14 * Bleck functions get called when there's no non-bleck functions
15 * around to cleanup the mess...
16 */
78b3fb13 17faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
9de3ca7e 18{
19 u_short family;
20 u_short subtype;
01b59e1e 21
22 u_short maxf;
23 u_short maxs;
24
25 /* XXX: this is ugly. and big just for debugging. */
26 char *literals[14][25] = {
27 {"Invalid",
28 NULL
29 },
30 {"General",
31 "Invalid",
32 "Error",
33 "Client Ready",
34 "Server Ready",
35 "Service Request",
36 "Redirect",
37 "Rate Information Request",
38 "Rate Information",
39 "Rate Information Ack",
40 NULL,
41 "Rate Information Change",
42 "Server Pause",
43 NULL,
44 "Server Resume",
45 "Request Personal User Information",
46 "Personal User Information",
47 "Evil Notification",
48 NULL,
49 "Migration notice",
50 "Message of the Day",
51 "Set Privacy Flags",
52 "Well Known URL",
53 "NOP"
54 },
55 {"Location",
56 "Invalid",
57 "Error",
58 "Request Rights",
59 "Rights Information",
60 "Set user information",
61 "Request User Information",
62 "User Information",
63 "Watcher Sub Request",
64 "Watcher Notification"
65 },
66 {"Buddy List Management",
67 "Invalid",
68 "Error",
69 "Request Rights",
70 "Rights Information",
71 "Add Buddy",
72 "Remove Buddy",
73 "Watcher List Query",
74 "Watcher List Response",
75 "Watcher SubRequest",
76 "Watcher Notification",
77 "Reject Notification",
78 "Oncoming Buddy",
79 "Offgoing Buddy"
80 },
81 {"Messeging",
82 "Invalid",
83 "Error",
84 "Add ICBM Parameter",
85 "Remove ICBM Parameter",
86 "Request Parameter Information",
87 "Parameter Information",
88 "Outgoing Message",
89 "Incoming Message",
90 "Evil Request",
91 "Evil Reply",
92 "Missed Calls",
93 "Message Error",
94 "Host Ack"
95 },
96 {"Advertisements",
97 "Invalid",
98 "Error",
99 "Request Ad",
100 "Ad Data (GIFs)"
101 },
102 {"Invitation / Client-to-Client",
103 "Invalid",
104 "Error",
105 "Invite a Friend",
106 "Invitation Ack"
107 },
108 {"Administrative",
109 "Invalid",
110 "Error",
111 "Information Request",
112 "Information Reply",
113 "Information Change Request",
114 "Information Chat Reply",
115 "Account Confirm Request",
116 "Account Confirm Reply",
117 "Account Delete Request",
118 "Account Delete Reply"
119 },
120 {"Popups",
121 "Invalid",
122 "Error",
123 "Display Popup"
124 },
125 {"BOS",
126 "Invalid",
127 "Error",
128 "Request Rights",
129 "Rights Response",
130 "Set group permission mask",
131 "Add permission list entries",
132 "Delete permission list entries",
133 "Add deny list entries",
134 "Delete deny list entries",
135 "Server Error"
136 },
137 {"User Lookup",
138 "Invalid",
139 "Error",
140 "Search Request",
141 "Search Response"
142 },
143 {"Stats",
144 "Invalid",
145 "Error",
146 "Set minimum report interval",
147 "Report Events"
148 },
149 {"Translate",
150 "Invalid",
151 "Error",
152 "Translate Request",
153 "Translate Reply",
154 },
155 {"Chat Navigation",
156 "Invalid",
157 "Error",
158 "Request rights",
159 "Request Exchange Information",
160 "Request Room Information",
161 "Request Occupant List",
162 "Search for Room",
163 "Outgoing Message",
164 "Incoming Message",
165 "Evil Request",
166 "Evil Reply",
167 "Chat Error",
168 }
169 };
170
171 maxf = sizeof(literals) / sizeof(literals[0]);
172 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
173
174 family = aimutil_get16(workingPtr->data+0);
175 subtype= aimutil_get16(workingPtr->data+2);
176
177 if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
646c6b52 178 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
01b59e1e 179 else
646c6b52 180 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
01b59e1e 181
9de3ca7e 182 return 1;
183}
184
78b3fb13 185faim_export int aim_conn_addhandler(struct aim_session_t *sess,
a25832e6 186 struct aim_conn_t *conn,
9de3ca7e 187 u_short family,
188 u_short type,
189 rxcallback_t newhandler,
190 u_short flags)
191{
871e2fd0 192 struct aim_rxcblist_t *newcb;
9de3ca7e 193
194 if (!conn)
195 return -1;
196
646c6b52 197 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
9de3ca7e 198
871e2fd0 199 if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
200 return -1;
a15d82b1 201 newcb->family = family;
202 newcb->type = type;
203 newcb->flags = flags;
9de3ca7e 204 if (!newhandler)
a15d82b1 205 newcb->handler = &bleck;
9de3ca7e 206 else
a15d82b1 207 newcb->handler = newhandler;
208 newcb->next = NULL;
9de3ca7e 209
871e2fd0 210 if (!conn->handlerlist)
a15d82b1 211 conn->handlerlist = newcb;
871e2fd0 212 else {
213 struct aim_rxcblist_t *cur;
214
215 cur = conn->handlerlist;
216
217 while (cur->next)
218 cur = cur->next;
219 cur->next = newcb;
220 }
9de3ca7e 221
222 return 0;
223}
224
78b3fb13 225faim_export int aim_clearhandlers(struct aim_conn_t *conn)
9de3ca7e 226{
871e2fd0 227 struct aim_rxcblist_t *cur;
228
9de3ca7e 229 if (!conn)
230 return -1;
231
55e77c8a 232 for (cur = conn->handlerlist; cur; ) {
871e2fd0 233 struct aim_rxcblist_t *tmp;
234
235 tmp = cur->next;
236 free(cur);
237 cur = tmp;
238 }
55e77c8a 239 conn->handlerlist = NULL;
871e2fd0 240
9de3ca7e 241 return 0;
242}
243
646c6b52 244faim_internal rxcallback_t aim_callhandler(struct aim_session_t *sess,
245 struct aim_conn_t *conn,
246 unsigned short family,
247 unsigned short type)
9de3ca7e 248{
249 struct aim_rxcblist_t *cur;
250
251 if (!conn)
252 return NULL;
253
646c6b52 254 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
9de3ca7e 255
646c6b52 256 for (cur = conn->handlerlist; cur; cur = cur->next) {
257 if ((cur->family == family) && (cur->type == type))
258 return cur->handler;
259 }
9de3ca7e 260
646c6b52 261 if (type == AIM_CB_SPECIAL_DEFAULT) {
262 faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
263 return NULL; /* prevent infinite recursion */
264 }
265
266 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
871e2fd0 267
646c6b52 268 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
9de3ca7e 269}
270
78b3fb13 271faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
272 struct aim_conn_t *conn,
273 u_short family,
274 u_short type,
275 struct command_rx_struct *ptr)
9de3ca7e 276{
277 rxcallback_t userfunc = NULL;
646c6b52 278 userfunc = aim_callhandler(sess, conn, family, type);
9de3ca7e 279 if (userfunc)
a25832e6 280 return userfunc(sess, ptr);
b8d0da45 281 return 1; /* XXX */
9de3ca7e 282}
283
284/*
285 aim_rxdispatch()
286
287 Basically, heres what this should do:
288 1) Determine correct packet handler for this packet
289 2) Mark the packet handled (so it can be dequeued in purge_queue())
290 3) Send the packet to the packet handler
291 4) Go to next packet in the queue and start over
292 5) When done, run purge_queue() to purge handled commands
293
294 Note that any unhandlable packets should probably be left in the
295 queue. This is the best way to prevent data loss. This means
296 that a single packet may get looked at by this function multiple
297 times. This is more good than bad! This behavior may change.
298
299 Aren't queue's fun?
300
301 TODO: Get rid of all the ugly if's.
302 TODO: Clean up.
303 TODO: More support for mid-level handlers.
304 TODO: Allow for NULL handlers.
305
306 */
78b3fb13 307faim_export int aim_rxdispatch(struct aim_session_t *sess)
9de3ca7e 308{
309 int i = 0;
310 struct command_rx_struct *workingPtr = NULL;
311
b8d0da45 312 if (sess->queue_incoming == NULL) {
646c6b52 313 faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
b8d0da45 314 return 0;
315 } else {
316 workingPtr = sess->queue_incoming;
50443ea0 317 for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
b8d0da45 318 /*
319 * XXX: This is still fairly ugly.
320 */
50443ea0 321 if (workingPtr->handled)
322 continue;
323
b69540e3 324 /*
325 * This is a debugging/sanity check only and probably could/should be removed
326 * for stable code.
327 */
328 if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) &&
329 (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
330 ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) &&
331 (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
646c6b52 332 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
b69540e3 333 workingPtr->handled = 1;
334 continue;
335 }
336
b8d0da45 337 switch(workingPtr->conn->type) {
338 case -1:
339 /*
340 * This can happen if we have a queued command
341 * that was recieved after a connection has
342 * been terminated. In which case, the handler
343 * list has been cleared, and there's nothing we
344 * can do for it. We can only cancel it.
345 */
346 workingPtr->handled = 1;
347 break;
348 case AIM_CONN_TYPE_AUTH: {
5daacaa3 349 unsigned long head;
b8d0da45 350
351 head = aimutil_get32(workingPtr->data);
5daacaa3 352 if ((head == 0x00000001) && (workingPtr->commandlen == 4)) {
646c6b52 353 faimdprintf(sess, 1, "got connection ack on auth line\n");
22517493 354 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
5daacaa3 355 } else if (workingPtr->hdr.oscar.type == 0x04) {
356 /* Used only by the older login protocol */
f0a7908e 357 workingPtr->handled = aim_authparse(sess, workingPtr);
358 } else {
5daacaa3 359 unsigned short family,subtype;
b8d0da45 360
361 family = aimutil_get16(workingPtr->data);
362 subtype = aimutil_get16(workingPtr->data+2);
363
364 switch (family) {
365 /* New login protocol */
b8d0da45 366 case 0x0017:
367 if (subtype == 0x0001)
368 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
369 else if (subtype == 0x0003)
370 workingPtr->handled = aim_authparse(sess, workingPtr);
371 else if (subtype == 0x0007)
b5bc2a8c 372 workingPtr->handled = aim_authkeyparse(sess, workingPtr);
b8d0da45 373 else
374 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
375 break;
64c78745 376
ee49b735 377 case 0x0001:
378 if (subtype == 0x0003)
379 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
64c78745 380 else if (subtype == 0x0007)
381 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
382 else if (subtype == 0x0018)
383 workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
ee49b735 384 else
64c78745 385 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr);
ee49b735 386 break;
64c78745 387
ee49b735 388 case 0x0007:
64c78745 389 if (subtype == 0x0003)
390 workingPtr->handled = aim_parse_infochange(sess, workingPtr);
391 else if (subtype == 0x0005)
392 workingPtr->handled = aim_parse_infochange(sess, workingPtr);
393 else if (subtype == 0x0007)
394 workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr);
ee49b735 395 break;
64c78745 396
ee49b735 397 case AIM_CB_FAM_SPECIAL:
398 if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
399 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
400 break;
401 } else
402 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
403 break;
64c78745 404
ee49b735 405 default:
78b3fb13 406 break;
b8d0da45 407 }
408 }
409 break;
410 }
411 case AIM_CONN_TYPE_BOS: {
412 u_short family;
413 u_short subtype;
5e02cf44 414
b69540e3 415 if (workingPtr->hdr.oscar.type == 0x04) {
5e02cf44 416 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
417 break;
418 }
419
b8d0da45 420 family = aimutil_get16(workingPtr->data);
421 subtype = aimutil_get16(workingPtr->data+2);
422
423 switch (family) {
424 case 0x0000: /* not really a family, but it works */
425 if (subtype == 0x0001)
22517493 426 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
b8d0da45 427 else
428 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
429 break;
430 case 0x0001: /* Family: General */
431 switch (subtype) {
432 case 0x0001:
433 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
434 break;
435 case 0x0003:
ee49b735 436 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
b8d0da45 437 break;
438 case 0x0005:
439 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
440 break;
441 case 0x0007:
442 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
443 break;
444 case 0x000a:
1a8c261b 445 workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
b8d0da45 446 break;
447 case 0x000f:
448 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
449 break;
98c88242 450 case 0x0010:
451 workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
452 break;
b8d0da45 453 case 0x0013:
454 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
455 break;
ee49b735 456 case 0x0018:
457 workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
458 break;
b8d0da45 459 default:
460 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
461 break;
462 }
96f8b1ed 463 break;
b8d0da45 464 case 0x0002: /* Family: Location */
465 switch (subtype) {
466 case 0x0001:
96f8b1ed 467 workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
b8d0da45 468 break;
469 case 0x0003:
470 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
471 break;
472 case 0x0006:
473 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
474 break;
475 default:
476 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
477 break;
478 }
96f8b1ed 479 break;
b8d0da45 480 case 0x0003: /* Family: Buddy List */
481 switch (subtype) {
482 case 0x0001:
483 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
484 break;
485 case 0x0003:
96f8b1ed 486 workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
b8d0da45 487 break;
488 case 0x000b: /* oncoming buddy */
489 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
490 break;
491 case 0x000c: /* offgoing buddy */
492 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
493 break;
494 default:
495 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
496 }
497 break;
3e2c7bcf 498 case 0x0004: /* Family: Messaging */
b8d0da45 499 switch (subtype) {
500 case 0x0001:
501 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
502 break;
503 case 0x0005:
504 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
505 break;
e5012450 506 case 0x0006:
507 workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
508 break;
b8d0da45 509 case 0x0007:
510 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
511 break;
512 case 0x000a:
96f8b1ed 513 workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
b8d0da45 514 break;
1a8c261b 515 case 0x000c:
516 workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
517 break;
b8d0da45 518 default:
519 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
520 }
521 break;
522 case 0x0009:
523 if (subtype == 0x0001)
524 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
525 else if (subtype == 0x0003)
96f8b1ed 526 workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
b8d0da45 527 else
528 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
529 break;
530 case 0x000a: /* Family: User lookup */
531 switch (subtype) {
532 case 0x0001:
37ee990e 533 workingPtr->handled = aim_parse_searcherror(sess, workingPtr);
b8d0da45 534 break;
535 case 0x0003:
37ee990e 536 workingPtr->handled = aim_parse_searchreply(sess, workingPtr);
b8d0da45 537 break;
538 default:
539 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
540 }
541 break;
96f8b1ed 542 case 0x000b: {
b8d0da45 543 if (subtype == 0x0001)
544 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
545 else if (subtype == 0x0002)
546 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
547 else
548 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
549 break;
96f8b1ed 550 }
3e2c7bcf 551 case 0x0013: {
646c6b52 552 faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype);
3e2c7bcf 553 break;
554 }
96f8b1ed 555 case AIM_CB_FAM_SPECIAL:
556 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
557 break;
b8d0da45 558 default:
559 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
560 break;
96f8b1ed 561 } /* switch(family) */
b8d0da45 562 break;
96f8b1ed 563 } /* AIM_CONN_TYPE_BOS */
64c78745 564 case AIM_CONN_TYPE_ADS: {
565 unsigned short family;
566 unsigned short subtype;
567
568 family = aimutil_get16(workingPtr->data);
569 subtype= aimutil_get16(workingPtr->data+2);
570
571 if ((family == 0x0000) && (subtype == 0x00001)) {
572 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
573 } else if ((family == 0x0001) && (subtype == 0x0003)) {
574 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
575 } else {
576 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
577 }
578 break;
579 }
b8d0da45 580 case AIM_CONN_TYPE_CHATNAV: {
581 u_short family;
582 u_short subtype;
583 family = aimutil_get16(workingPtr->data);
584 subtype= aimutil_get16(workingPtr->data+2);
22517493 585
586 if ((family == 0x0000) && (subtype == 0x00001)) {
587 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
ee49b735 588 } else if ((family == 0x0001) && (subtype == 0x0003)) {
589 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
b8d0da45 590 } else if ((family == 0x000d) && (subtype == 0x0009)) {
591 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
592 } else {
593 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
9de3ca7e 594 }
b8d0da45 595 break;
596 }
597 case AIM_CONN_TYPE_CHAT: {
598 u_short family, subtype;
599
600 family = aimutil_get16(workingPtr->data);
601 subtype= aimutil_get16(workingPtr->data+2);
602
22517493 603 if ((family == 0x0000) && (subtype == 0x00001)) {
604 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
605 } else if (family == 0x0001) {
b8d0da45 606 if (subtype == 0x0001)
607 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
608 else if (subtype == 0x0003)
ee49b735 609 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
b8d0da45 610 else if (subtype == 0x0007)
611 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
275a2ff8 612 else if (subtype == 0x000a)
613 workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
b8d0da45 614 else
cd71e19b 615 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
b8d0da45 616 } else if (family == 0x000e) {
617 if (subtype == 0x0002)
618 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
619 else if (subtype == 0x0003)
620 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
621 else if (subtype == 0x0004)
622 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
623 else if (subtype == 0x0006)
624 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
625 else
646c6b52 626 faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype);
b8d0da45 627 } else {
646c6b52 628 faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype);
b8d0da45 629 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
630 }
631 break;
632 }
b69540e3 633 case AIM_CONN_TYPE_RENDEZVOUS: {
634 /* make sure that we only get OFT frames on these connections */
635 if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
646c6b52 636 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
b69540e3 637 workingPtr->handled = 1; /* get rid of it */
638 break;
639 }
640
641 /* XXX: implement this */
646c6b52 642 faimdprintf(sess, 0, "faim: OFT frame!\n");
b69540e3 643
644 break;
645 }
7392c79f 646 case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
647 /* not possible */
648 break;
649 }
b8d0da45 650 default:
646c6b52 651 faimdprintf(sess, 0, "internal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
b8d0da45 652 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
653 break;
654 }
9de3ca7e 655 }
b8d0da45 656 }
9de3ca7e 657
b8d0da45 658 /*
659 * This doesn't have to be called here. It could easily be done
660 * by a seperate thread or something. It's an administrative operation,
661 * and can take a while. Though the less you call it the less memory
662 * you'll have :)
663 */
664 aim_purge_rxqueue(sess);
9de3ca7e 665
666 return 0;
667}
668
78b3fb13 669faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
1a8c261b 670{
671 rxcallback_t userfunc = NULL;
672 char sn[MAXSNLEN];
673 unsigned short type;
674 int i = 10+8; /* skip SNAC and cookie */
675 int ret = 1;
676 unsigned char snlen;
677
678 type = aimutil_get16(command->data+i);
679 i += 2;
680
681 snlen = aimutil_get8(command->data+i);
682 i++;
683
684 memset(sn, 0, sizeof(sn));
78b3fb13 685 strncpy(sn, (char *)command->data+i, snlen);
1a8c261b 686
646c6b52 687 if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
1a8c261b 688 ret = userfunc(sess, command, type, sn);
689
690 return ret;
691}
692
d6c9fcf0 693/*
694 * The Rate Limiting System, An Abridged Guide to Nonsense.
695 *
696 * OSCAR defines several 'rate classes'. Each class has seperate
697 * rate limiting properties (limit level, alert level, disconnect
698 * level, etc), and a set of SNAC family/type pairs associated with
699 * it. The rate classes, their limiting properties, and the definitions
700 * of which SNACs are belong to which class, are defined in the
701 * Rate Response packet at login to each host.
702 *
703 * Logically, all rate offenses within one class count against further
704 * offenses for other SNACs in the same class (ie, sending messages
705 * too fast will limit the number of user info requests you can send,
706 * since those two SNACs are in the same rate class).
707 *
708 * Since the rate classes are defined dynamically at login, the values
709 * below may change. But they seem to be fairly constant.
710 *
711 * Currently, BOS defines five rate classes, with the commonly used
712 * members as follows...
713 *
714 * Rate class 0x0001:
715 * - Everything thats not in any of the other classes
716 *
717 * Rate class 0x0002:
718 * - Buddy list add/remove
719 * - Permit list add/remove
720 * - Deny list add/remove
721 *
722 * Rate class 0x0003:
723 * - User information requests
724 * - Outgoing ICBMs
725 *
726 * Rate class 0x0004:
727 * - A few unknowns: 2/9, 2/b, and f/2
728 *
729 * Rate class 0x0005:
730 * - Chat room create
731 * - Outgoing chat ICBMs
732 *
733 * The only other thing of note is that class 5 (chat) has slightly looser
734 * limiting properties than class 3 (normal messages). But thats just a
735 * small bit of trivia for you.
736 *
737 * The last thing that needs to be learned about the rate limiting
738 * system is how the actual numbers relate to the passing of time. This
739 * seems to be a big mystery.
740 *
741 */
78b3fb13 742faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
1a8c261b 743{
744 rxcallback_t userfunc = NULL;
1a8c261b 745 int ret = 1;
275a2ff8 746 int i;
747 int code;
d6c9fcf0 748 unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
275a2ff8 749 unsigned long currentavg, maxavg;
1a8c261b 750
275a2ff8 751 i = 10;
752
753 code = aimutil_get16(command->data+i);
754 i += 2;
755
d6c9fcf0 756 rateclass = aimutil_get16(command->data+i);
275a2ff8 757 i += 2;
758
759 windowsize = aimutil_get32(command->data+i);
760 i += 4;
761 clear = aimutil_get32(command->data+i);
762 i += 4;
763 alert = aimutil_get32(command->data+i);
764 i += 4;
765 limit = aimutil_get32(command->data+i);
766 i += 4;
767 disconnect = aimutil_get32(command->data+i);
768 i += 4;
769 currentavg = aimutil_get32(command->data+i);
770 i += 4;
771 maxavg = aimutil_get32(command->data+i);
772 i += 4;
1a8c261b 773
646c6b52 774 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
d6c9fcf0 775 ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
1a8c261b 776
777 return ret;
778}
779
78b3fb13 780faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
98c88242 781{
782 rxcallback_t userfunc = NULL;
06bc8607 783 int ret = 1;
784 int i;
785 unsigned short newevil;
786 struct aim_userinfo_s userinfo;
98c88242 787
06bc8607 788 i = 10;
789 newevil = aimutil_get16(command->data+10);
790 i += 2;
98c88242 791
06bc8607 792 memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
793 if (command->commandlen-i)
646c6b52 794 i += aim_extractuserinfo(sess, command->data+i, &userinfo);
98c88242 795
646c6b52 796 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
06bc8607 797 ret = userfunc(sess, command, newevil, &userinfo);
98c88242 798
799 return ret;
800}
801
78b3fb13 802faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
803 struct command_rx_struct *command, ...)
9de3ca7e 804{
805 rxcallback_t userfunc = NULL;
01b59e1e 806 char *msg;
807 int ret=1;
808 struct aim_tlvlist_t *tlvlist;
809 u_short id;
810
811 /*
98c88242 812 * Code.
813 *
814 * Valid values:
815 * 1 Mandatory upgrade
816 * 2 Advisory upgrade
817 * 3 System bulletin
818 * 4 Nothing's wrong ("top o the world" -- normal)
819 *
01b59e1e 820 */
821 id = aimutil_get16(command->data+10);
822
823 /*
824 * TLVs follow
825 */
b13c9e13 826 if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
827 return ret;
828
829 if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
830 aim_freetlvchain(&tlvlist);
831 return ret;
832 }
01b59e1e 833
646c6b52 834 userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
01b59e1e 835 if (userfunc)
836 ret = userfunc(sess, command, id, msg);
9de3ca7e 837
01b59e1e 838 aim_freetlvchain(&tlvlist);
b13c9e13 839 free(msg);
9de3ca7e 840
b13c9e13 841 return ret;
9de3ca7e 842}
843
ee49b735 844faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
845 struct command_rx_struct *command, ...)
846{
847 rxcallback_t userfunc = NULL;
848 int ret = 1;
849 unsigned short *families = NULL;
850 int famcount = 0, i;
851
852 famcount = (command->commandlen-10)/2;
853 if (!(families = malloc(command->commandlen-10)))
854 return ret;
855
856 for (i = 0; i < famcount; i++)
857 families[i] = aimutil_get16(command->data+((i*2)+10));
858
646c6b52 859 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
ee49b735 860 ret = userfunc(sess, command, famcount, families);
861
862 free(families);
863
864 return ret;
865}
866
64c78745 867faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess,
868 struct command_rx_struct *command)
869{
870 rxcallback_t userfunc = NULL;
871 int ret = 1;
872 int status = -1;
873
874 status = aimutil_get16(command->data+10);
875
646c6b52 876 if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007)))
64c78745 877 ret = userfunc(sess, command, status);
878
879 return ret;
880}
881
882faim_internal int aim_parse_infochange(struct aim_session_t *sess,
883 struct command_rx_struct *command)
884{
885 unsigned short subtype; /* called for both reply and change-reply */
886 int i;
887
888 subtype = aimutil_get16(command->data+2);
889
890 /*
891 * struct {
892 * unsigned short perms;
893 * unsigned short tlvcount;
894 * aim_tlv_t tlvs[tlvcount];
895 * } admin_info[n];
896 */
897 for (i = 10; i < command->commandlen; ) {
898 int perms, tlvcount;
899
900 perms = aimutil_get16(command->data+i);
901 i += 2;
902
903 tlvcount = aimutil_get16(command->data+i);
904 i += 2;
905
906 while (tlvcount) {
907 rxcallback_t userfunc;
908 struct aim_tlv_t *tlv;
909 int str = 0;
910
911 if ((aimutil_get16(command->data+i) == 0x0011) ||
912 (aimutil_get16(command->data+i) == 0x0004))
913 str = 1;
914
915 if (str)
916 tlv = aim_grabtlvstr(command->data+i);
917 else
918 tlv = aim_grabtlv(command->data+i);
919
920 /* XXX fix so its only called once for the entire packet */
646c6b52 921 if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype)))
64c78745 922 userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str);
923
924 if (tlv)
925 i += 2+2+tlv->length;
926
927 if (tlv && tlv->value)
928 free(tlv->value);
929 if (tlv)
930 free(tlv);
931
932 tlvcount--;
933 }
934 }
935
936 return 1;
937}
938
ee49b735 939faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
940 struct command_rx_struct *command, ...)
941{
942 rxcallback_t userfunc = NULL;
943 int ret = 1;
944 int vercount;
945
946 vercount = (command->commandlen-10)/4;
947
646c6b52 948 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
ee49b735 949 ret = userfunc(sess, command, vercount, command->data+10);
950
951 return ret;
952}
953
78b3fb13 954faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
ee49b735 955 struct command_rx_struct *command, ...)
9de3ca7e 956{
1ea867e3 957 int serviceid = 0;
958 unsigned char *cookie = NULL;
9de3ca7e 959 char *ip = NULL;
960 rxcallback_t userfunc = NULL;
01b59e1e 961 struct aim_tlvlist_t *tlvlist;
962 int ret = 1;
963
1ea867e3 964 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
965
966 if (aim_gettlv(tlvlist, 0x000d, 1))
967 serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
968 if (aim_gettlv(tlvlist, 0x0005, 1))
969 ip = aim_gettlv_str(tlvlist, 0x0005, 1);
970 if (aim_gettlv(tlvlist, 0x0006, 1))
971 cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
972
973 if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
974
975 /*
976 * Chat hack.
977 *
978 */
646c6b52 979 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
1ea867e3 980 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
0c20631f 981 free(sess->pendingjoin);
982 sess->pendingjoin = NULL;
9f20a4e3 983 sess->pendingjoinexchange = 0;
1ea867e3 984 } else if (!serviceid || !ip || !cookie) { /* yeep! */
985 ret = 1;
986 } else {
646c6b52 987 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
1ea867e3 988 ret = userfunc(sess, command, serviceid, ip, cookie);
989 }
990
991 if (ip)
992 free(ip);
993 if (cookie)
994 free(cookie);
0e2be272 995
01b59e1e 996 aim_freetlvchain(&tlvlist);
997
998 return ret;
9de3ca7e 999}
1000
78b3fb13 1001faim_internal int aim_parse_unknown(struct aim_session_t *sess,
1002 struct command_rx_struct *command, ...)
9de3ca7e 1003{
1004 u_int i = 0;
1005
22517493 1006 if (!sess || !command)
1007 return 1;
1008
646c6b52 1009 faimdprintf(sess, 1, "\nRecieved unknown packet:");
9de3ca7e 1010
1011 for (i = 0; i < command->commandlen; i++)
1012 {
1013 if ((i % 8) == 0)
646c6b52 1014 faimdprintf(sess, 1, "\n\t");
9de3ca7e 1015
646c6b52 1016 faimdprintf(sess, 1, "0x%2x ", command->data[i]);
9de3ca7e 1017 }
1018
646c6b52 1019 faimdprintf(sess, 1, "\n\n");
9de3ca7e 1020
1021 return 1;
1022}
1023
1024
78b3fb13 1025faim_internal int aim_negchan_middle(struct aim_session_t *sess,
1026 struct command_rx_struct *command)
5e02cf44 1027{
1028 struct aim_tlvlist_t *tlvlist;
1029 char *msg = NULL;
1030 unsigned short code = 0;
5e02cf44 1031 rxcallback_t userfunc = NULL;
1032 int ret = 1;
1033
1034 tlvlist = aim_readtlvchain(command->data, command->commandlen);
1035
1ea867e3 1036 if (aim_gettlv(tlvlist, 0x0009, 1))
1037 code = aim_gettlv16(tlvlist, 0x0009, 1);
5e02cf44 1038
1ea867e3 1039 if (aim_gettlv(tlvlist, 0x000b, 1))
5e02cf44 1040 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
1041
646c6b52 1042 if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
5e02cf44 1043 ret = userfunc(sess, command, code, msg);
1044
1045 aim_freetlvchain(&tlvlist);
1ea867e3 1046
1047 if (msg)
1048 free(msg);
5e02cf44 1049
1050 return ret;
1051}
1052
9de3ca7e 1053/*
1054 * aim_parse_generalerrs()
1055 *
1056 * Middle handler for 0x0001 snac of each family.
1057 *
1058 */
78b3fb13 1059faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
1060 struct command_rx_struct *command, ...)
9de3ca7e 1061{
1449ad2b 1062 unsigned short family;
1063 unsigned short subtype;
1064 int ret = 1;
1065 int error = 0;
1066 rxcallback_t userfunc = NULL;
a25832e6 1067
1068 family = aimutil_get16(command->data+0);
1069 subtype= aimutil_get16(command->data+2);
9de3ca7e 1070
1449ad2b 1071 if (command->commandlen > 10)
1072 error = aimutil_get16(command->data+10);
9de3ca7e 1073
646c6b52 1074 if ((userfunc = aim_callhandler(sess, command->conn, family, subtype)))
1449ad2b 1075 ret = userfunc(sess, command, error);
1076
1077 return ret;
9de3ca7e 1078}
1079
1080
1081
This page took 1.275106 seconds and 5 git commands to generate.