]> andersk Git - libfaim.git/blame_incremental - aim_rxhandlers.c
Implemented chat and some chatnav. Nearly a 2000line diff.
[libfaim.git] / aim_rxhandlers.c
... / ...
CommitLineData
1/*
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 *
8 */
9
10#include <faim/aim.h>
11
12/*
13 * Bleck functions get called when there's no non-bleck functions
14 * around to cleanup the mess...
15 */
16int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
17{
18 u_short family;
19 u_short subtype;
20
21 u_short maxf;
22 u_short maxs;
23
24 /* XXX: this is ugly. and big just for debugging. */
25 char *literals[14][25] = {
26 {"Invalid",
27 NULL
28 },
29 {"General",
30 "Invalid",
31 "Error",
32 "Client Ready",
33 "Server Ready",
34 "Service Request",
35 "Redirect",
36 "Rate Information Request",
37 "Rate Information",
38 "Rate Information Ack",
39 NULL,
40 "Rate Information Change",
41 "Server Pause",
42 NULL,
43 "Server Resume",
44 "Request Personal User Information",
45 "Personal User Information",
46 "Evil Notification",
47 NULL,
48 "Migration notice",
49 "Message of the Day",
50 "Set Privacy Flags",
51 "Well Known URL",
52 "NOP"
53 },
54 {"Location",
55 "Invalid",
56 "Error",
57 "Request Rights",
58 "Rights Information",
59 "Set user information",
60 "Request User Information",
61 "User Information",
62 "Watcher Sub Request",
63 "Watcher Notification"
64 },
65 {"Buddy List Management",
66 "Invalid",
67 "Error",
68 "Request Rights",
69 "Rights Information",
70 "Add Buddy",
71 "Remove Buddy",
72 "Watcher List Query",
73 "Watcher List Response",
74 "Watcher SubRequest",
75 "Watcher Notification",
76 "Reject Notification",
77 "Oncoming Buddy",
78 "Offgoing Buddy"
79 },
80 {"Messeging",
81 "Invalid",
82 "Error",
83 "Add ICBM Parameter",
84 "Remove ICBM Parameter",
85 "Request Parameter Information",
86 "Parameter Information",
87 "Outgoing Message",
88 "Incoming Message",
89 "Evil Request",
90 "Evil Reply",
91 "Missed Calls",
92 "Message Error",
93 "Host Ack"
94 },
95 {"Advertisements",
96 "Invalid",
97 "Error",
98 "Request Ad",
99 "Ad Data (GIFs)"
100 },
101 {"Invitation / Client-to-Client",
102 "Invalid",
103 "Error",
104 "Invite a Friend",
105 "Invitation Ack"
106 },
107 {"Administrative",
108 "Invalid",
109 "Error",
110 "Information Request",
111 "Information Reply",
112 "Information Change Request",
113 "Information Chat Reply",
114 "Account Confirm Request",
115 "Account Confirm Reply",
116 "Account Delete Request",
117 "Account Delete Reply"
118 },
119 {"Popups",
120 "Invalid",
121 "Error",
122 "Display Popup"
123 },
124 {"BOS",
125 "Invalid",
126 "Error",
127 "Request Rights",
128 "Rights Response",
129 "Set group permission mask",
130 "Add permission list entries",
131 "Delete permission list entries",
132 "Add deny list entries",
133 "Delete deny list entries",
134 "Server Error"
135 },
136 {"User Lookup",
137 "Invalid",
138 "Error",
139 "Search Request",
140 "Search Response"
141 },
142 {"Stats",
143 "Invalid",
144 "Error",
145 "Set minimum report interval",
146 "Report Events"
147 },
148 {"Translate",
149 "Invalid",
150 "Error",
151 "Translate Request",
152 "Translate Reply",
153 },
154 {"Chat Navigation",
155 "Invalid",
156 "Error",
157 "Request rights",
158 "Request Exchange Information",
159 "Request Room Information",
160 "Request Occupant List",
161 "Search for Room",
162 "Outgoing Message",
163 "Incoming Message",
164 "Evil Request",
165 "Evil Reply",
166 "Chat Error",
167 }
168 };
169
170 maxf = sizeof(literals) / sizeof(literals[0]);
171 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
172
173 family = aimutil_get16(workingPtr->data+0);
174 subtype= aimutil_get16(workingPtr->data+2);
175
176 if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
177 printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
178 else
179 printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
180
181 return 1;
182}
183
184int aim_conn_addhandler(struct aim_session_t *sess,
185 struct aim_conn_t *conn,
186 u_short family,
187 u_short type,
188 rxcallback_t newhandler,
189 u_short flags)
190{
191 struct aim_rxcblist_t *new,*cur;
192
193 if (!conn)
194 return -1;
195
196#if debug > 0
197 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
198#endif
199
200 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
201 new->family = family;
202 new->type = type;
203 new->flags = flags;
204 if (!newhandler)
205 new->handler = &bleck;
206 else
207 new->handler = newhandler;
208 new->next = NULL;
209
210 cur = conn->handlerlist;
211 if (!cur)
212 conn->handlerlist = new;
213 else
214 {
215 while (cur->next)
216 cur = cur->next;
217 cur->next = new;
218 }
219
220 return 0;
221}
222
223int aim_clearhandlers(struct aim_conn_t *conn)
224{
225 struct aim_rxcblist_t *cur,*tmp;
226 if (!conn)
227 return -1;
228
229 cur = conn->handlerlist;
230 while(cur)
231 {
232 tmp = cur->next;
233 free(cur);
234 cur = tmp;
235 }
236 return 0;
237}
238
239rxcallback_t aim_callhandler(struct aim_conn_t *conn,
240 u_short family,
241 u_short type)
242{
243 struct aim_rxcblist_t *cur;
244
245 if (!conn)
246 return NULL;
247
248#if debug > 0
249 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
250#endif
251
252 cur = conn->handlerlist;
253 while(cur)
254 {
255 if ( (cur->family == family) && (cur->type == type) )
256 return cur->handler;
257 cur = cur->next;
258 }
259
260 if (type==0xffff)
261 return NULL;
262 return aim_callhandler(conn, family, 0xffff);
263}
264
265int aim_callhandler_noparam(struct aim_session_t *sess,
266 struct aim_conn_t *conn,
267 u_short family,
268 u_short type,
269 struct command_rx_struct *ptr)
270{
271 rxcallback_t userfunc = NULL;
272 userfunc = aim_callhandler(conn, family, type);
273 if (userfunc)
274 return userfunc(sess, ptr);
275 return 0;
276}
277
278/*
279 aim_rxdispatch()
280
281 Basically, heres what this should do:
282 1) Determine correct packet handler for this packet
283 2) Mark the packet handled (so it can be dequeued in purge_queue())
284 3) Send the packet to the packet handler
285 4) Go to next packet in the queue and start over
286 5) When done, run purge_queue() to purge handled commands
287
288 Note that any unhandlable packets should probably be left in the
289 queue. This is the best way to prevent data loss. This means
290 that a single packet may get looked at by this function multiple
291 times. This is more good than bad! This behavior may change.
292
293 Aren't queue's fun?
294
295 TODO: Get rid of all the ugly if's.
296 TODO: Clean up.
297 TODO: More support for mid-level handlers.
298 TODO: Allow for NULL handlers.
299
300 */
301int aim_rxdispatch(struct aim_session_t *sess)
302{
303 int i = 0;
304 struct command_rx_struct *workingPtr = NULL;
305
306 if (sess->queue_incoming == NULL)
307 /* this shouldn't really happen, unless the main loop's select is broke */
308 printf("parse_generic: incoming packet queue empty.\n");
309 else
310 {
311 workingPtr = sess->queue_incoming;
312 for (i = 0; workingPtr != NULL; i++)
313 {
314 switch(workingPtr->conn->type)
315 {
316 case AIM_CONN_TYPE_AUTH:
317 {
318 u_long head;
319
320 head = aimutil_get32(workingPtr->data);
321 if (head == 0x00000001)
322 {
323#if debug > 0
324 printf("got connection ack on auth line\n");
325#endif
326 workingPtr->handled = 1;
327 }
328 else
329 {
330 u_short family,subtype;
331
332 family = aimutil_get16(workingPtr->data);
333 subtype = aimutil_get16(workingPtr->data+2);
334
335 switch (family)
336 {
337 /* New login protocol */
338#ifdef SNACLOGIN
339 case 0x0017:
340 if (subtype == 0x0001)
341 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
342 else if (subtype == 0x0003)
343 workingPtr->handled = aim_authparse(sess, workingPtr);
344 else if (subtype == 0x0007)
345 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
346 else
347 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
348 break;
349#else
350 /* XXX: this isnt foolproof */
351 case 0x0001:
352 if (subtype == 0x0003)
353 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
354 else
355 workingPtr->handled = aim_authparse(sess, workingPtr);
356 break;
357 case 0x0007:
358 if (subtype == 0x0005)
359 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
360 break;
361 default:
362 /* Old login protocol */
363 /* any user callbacks will be called from here */
364 workingPtr->handled = aim_authparse(sess, workingPtr);
365#endif
366 }
367 }
368 }
369 break;
370 case AIM_CONN_TYPE_BOS:
371 {
372 u_short family;
373 u_short subtype;
374
375 family = aimutil_get16(workingPtr->data);
376 subtype = aimutil_get16(workingPtr->data+2);
377
378 switch (family)
379 {
380 case 0x0000: /* not really a family, but it works */
381 if (subtype == 0x0001)
382 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
383 else
384 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
385 break;
386 case 0x0001: /* Family: General */
387 switch (subtype)
388 {
389 case 0x0001:
390 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
391 break;
392 case 0x0003:
393 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
394 break;
395 case 0x0005:
396 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
397 break;
398 case 0x0007:
399 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
400 break;
401 case 0x000a:
402 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
403 break;
404 case 0x000f:
405 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
406 break;
407 case 0x0013:
408 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
409 break;
410 default:
411 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
412 }
413 break;
414 case 0x0002: /* Family: Location */
415 switch (subtype)
416 {
417 case 0x0001:
418 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
419 break;
420 case 0x0003:
421 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
422 break;
423 case 0x0006:
424 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
425 break;
426 default:
427 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
428 }
429 break;
430 case 0x0003: /* Family: Buddy List */
431 switch (subtype)
432 {
433 case 0x0001:
434 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
435 break;
436 case 0x0003:
437 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
438 break;
439 case 0x000b: /* oncoming buddy */
440 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
441 break;
442 case 0x000c: /* offgoing buddy */
443 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
444 break;
445 default:
446 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
447 }
448 break;
449 case 0x0004: /* Family: Messeging */
450 switch (subtype)
451 {
452 case 0x0001:
453 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
454 break;
455 case 0x0005:
456 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
457 break;
458 case 0x0007:
459 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
460 break;
461 case 0x000a:
462 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
463 break;
464 default:
465 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
466 }
467 break;
468 case 0x0009:
469 if (subtype == 0x0001)
470 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
471 else if (subtype == 0x0003)
472 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
473 else
474 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
475 break;
476 case 0x000a: /* Family: User lookup */
477 switch (subtype)
478 {
479 case 0x0001:
480 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
481 break;
482 case 0x0003:
483 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
484 break;
485 default:
486 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
487 }
488 break;
489 case 0x000b:
490 if (subtype == 0x0001)
491 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
492 else if (subtype == 0x0002)
493 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
494 else
495 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
496 break;
497 default:
498 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
499 break;
500 }
501 }
502 break;
503 case AIM_CONN_TYPE_CHATNAV:
504 {
505 u_short family;
506 u_short subtype;
507 family = aimutil_get16(workingPtr->data);
508 subtype= aimutil_get16(workingPtr->data+2);
509
510 if ((family == 0x0002) && (subtype == 0x0006))
511 {
512 workingPtr->handled = 1;
513 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
514 }
515 else if ((family == 0x000d) && (subtype == 0x0009))
516 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
517 else
518 {
519 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
520 }
521 }
522 break;
523 case AIM_CONN_TYPE_CHAT:
524 {
525 u_short family, subtype;
526
527 family = aimutil_get16(workingPtr->data);
528 subtype= aimutil_get16(workingPtr->data+2);
529
530 if ((family == 0x0000) && (subtype == 0x00001))
531 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
532 else if (family == 0x0001)
533 {
534 if (subtype == 0x0001)
535 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
536 else if (subtype == 0x0003)
537 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
538 else if (subtype == 0x0007)
539 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
540 else
541 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
542 }
543 else if (family == 0x000e)
544 {
545 if (subtype == 0x0002)
546 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
547 else if (subtype == 0x0003)
548 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
549 else if (subtype == 0x0004)
550 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
551 else if (subtype == 0x0006)
552 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
553 else
554 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
555 }
556 else
557 {
558 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
559 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
560 }
561 }
562 break;
563 default:
564 printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
565 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
566 break;
567 }
568 /* move to next command */
569 workingPtr = workingPtr->next;
570 }
571 }
572
573 sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
574
575 return 0;
576}
577
578int aim_parsemotd_middle(struct aim_session_t *sess,
579 struct command_rx_struct *command, ...)
580{
581 rxcallback_t userfunc = NULL;
582 char *msg;
583 int ret=1;
584 struct aim_tlvlist_t *tlvlist;
585 u_short id;
586
587 /*
588 * Dunno.
589 */
590 id = aimutil_get16(command->data+10);
591
592 /*
593 * TLVs follow
594 */
595 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
596
597 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
598
599 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
600 if (userfunc)
601 ret = userfunc(sess, command, id, msg);
602
603 aim_freetlvchain(&tlvlist);
604
605 return ret;
606
607}
608
609int aim_handleredirect_middle(struct aim_session_t *sess,
610 struct command_rx_struct *command, ...)
611{
612 struct aim_tlv_t *tmptlv = NULL;
613 int serviceid = 0x00;
614 char cookie[AIM_COOKIELEN];
615 char *ip = NULL;
616 rxcallback_t userfunc = NULL;
617 struct aim_tlvlist_t *tlvlist;
618 int ret = 1;
619
620 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
621
622 tmptlv = aim_gettlv(tlvlist, 0x000d, 1);
623 serviceid = aimutil_get16(tmptlv->value);
624
625 ip = aim_gettlv_str(tlvlist, 0x0005, 1);
626
627 tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
628 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
629
630 if (serviceid == AIM_CONN_TYPE_CHAT)
631 {
632 /*
633 * Chat hack.
634 *
635 */
636 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
637 if (userfunc)
638 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
639 free(sess->pendingjoin);
640 sess->pendingjoin = NULL;
641 }
642 else
643 {
644 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
645 if (userfunc)
646 ret = userfunc(sess, command, serviceid, ip, cookie);
647 }
648 aim_freetlvchain(&tlvlist);
649
650 return ret;
651}
652
653int aim_parse_unknown(struct aim_session_t *sess,
654 struct command_rx_struct *command, ...)
655{
656 u_int i = 0;
657
658 printf("\nRecieved unknown packet:");
659
660 for (i = 0; i < command->commandlen; i++)
661 {
662 if ((i % 8) == 0)
663 printf("\n\t");
664
665 printf("0x%2x ", command->data[i]);
666 }
667
668 printf("\n\n");
669
670 return 1;
671}
672
673
674/*
675 * aim_parse_generalerrs()
676 *
677 * Middle handler for 0x0001 snac of each family.
678 *
679 */
680int aim_parse_generalerrs(struct aim_session_t *sess,
681 struct command_rx_struct *command, ...)
682{
683 u_short family;
684 u_short subtype;
685
686 family = aimutil_get16(command->data+0);
687 subtype= aimutil_get16(command->data+2);
688
689 switch(family)
690 {
691 default:
692 /* Unknown family */
693 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
694 }
695
696 return 1;
697}
698
699
700
This page took 0.040031 seconds and 5 git commands to generate.