]> andersk Git - libfaim.git/blame - aim_rxhandlers.c
Added stubs for those capability TLVs in userinfo.
[libfaim.git] / aim_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
a25832e6 10#include <faim/aim.h>
9de3ca7e 11
24286d93 12/*
13 * Bleck functions get called when there's no non-bleck functions
14 * around to cleanup the mess...
15 */
a25832e6 16int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
9de3ca7e 17{
18 u_short family;
19 u_short subtype;
01b59e1e 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
9de3ca7e 181 return 1;
182}
183
a25832e6 184int aim_conn_addhandler(struct aim_session_t *sess,
185 struct aim_conn_t *conn,
9de3ca7e 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
a25832e6 265int aim_callhandler_noparam(struct aim_session_t *sess,
266 struct aim_conn_t *conn,
9de3ca7e 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)
a25832e6 274 return userfunc(sess, ptr);
9de3ca7e 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 */
a25832e6 301int aim_rxdispatch(struct aim_session_t *sess)
9de3ca7e 302{
303 int i = 0;
304 struct command_rx_struct *workingPtr = NULL;
305
a25832e6 306 if (sess->queue_incoming == NULL)
9de3ca7e 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 {
a25832e6 311 workingPtr = sess->queue_incoming;
9de3ca7e 312 for (i = 0; workingPtr != NULL; i++)
313 {
314 switch(workingPtr->conn->type)
315 {
316 case AIM_CONN_TYPE_AUTH:
a25832e6 317 {
318 u_long head;
319
320 head = aimutil_get32(workingPtr->data);
321 if (head == 0x00000001)
322 {
9de3ca7e 323#if debug > 0
a25832e6 324 printf("got connection ack on auth line\n");
9de3ca7e 325#endif
a25832e6 326 workingPtr->handled = 1;
327 }
328 else
329 {
01b59e1e 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 }
a25832e6 367 }
368 }
9de3ca7e 369 break;
370 case AIM_CONN_TYPE_BOS:
371 {
372 u_short family;
373 u_short subtype;
a25832e6 374
375 family = aimutil_get16(workingPtr->data);
376 subtype = aimutil_get16(workingPtr->data+2);
377
9de3ca7e 378 switch (family)
379 {
380 case 0x0000: /* not really a family, but it works */
381 if (subtype == 0x0001)
a25832e6 382 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
9de3ca7e 383 else
a25832e6 384 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
9de3ca7e 385 break;
386 case 0x0001: /* Family: General */
387 switch (subtype)
388 {
389 case 0x0001:
a25832e6 390 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
9de3ca7e 391 break;
392 case 0x0003:
a25832e6 393 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
9de3ca7e 394 break;
395 case 0x0005:
a25832e6 396 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
9de3ca7e 397 break;
398 case 0x0007:
a25832e6 399 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
9de3ca7e 400 break;
401 case 0x000a:
a25832e6 402 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
9de3ca7e 403 break;
404 case 0x000f:
a25832e6 405 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
9de3ca7e 406 break;
407 case 0x0013:
01b59e1e 408 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
9de3ca7e 409 break;
410 default:
a25832e6 411 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
9de3ca7e 412 }
413 break;
414 case 0x0002: /* Family: Location */
415 switch (subtype)
416 {
417 case 0x0001:
a25832e6 418 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
9de3ca7e 419 break;
420 case 0x0003:
a25832e6 421 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
9de3ca7e 422 break;
423 case 0x0006:
a25832e6 424 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
9de3ca7e 425 break;
426 default:
a25832e6 427 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
9de3ca7e 428 }
429 break;
430 case 0x0003: /* Family: Buddy List */
431 switch (subtype)
432 {
433 case 0x0001:
a25832e6 434 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
9de3ca7e 435 break;
436 case 0x0003:
a25832e6 437 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
9de3ca7e 438 break;
439 case 0x000b: /* oncoming buddy */
a25832e6 440 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
9de3ca7e 441 break;
442 case 0x000c: /* offgoing buddy */
a25832e6 443 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
9de3ca7e 444 break;
445 default:
a25832e6 446 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
9de3ca7e 447 }
448 break;
449 case 0x0004: /* Family: Messeging */
450 switch (subtype)
451 {
452 case 0x0001:
a25832e6 453 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
9de3ca7e 454 break;
455 case 0x0005:
a25832e6 456 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
9de3ca7e 457 break;
458 case 0x0007:
a25832e6 459 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
9de3ca7e 460 break;
461 case 0x000a:
a25832e6 462 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
9de3ca7e 463 break;
464 default:
a25832e6 465 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
9de3ca7e 466 }
467 break;
468 case 0x0009:
469 if (subtype == 0x0001)
a25832e6 470 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
9de3ca7e 471 else if (subtype == 0x0003)
a25832e6 472 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
9de3ca7e 473 else
a25832e6 474 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
9de3ca7e 475 break;
476 case 0x000a: /* Family: User lookup */
477 switch (subtype)
478 {
479 case 0x0001:
a25832e6 480 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
9de3ca7e 481 break;
482 case 0x0003:
a25832e6 483 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
9de3ca7e 484 break;
485 default:
a25832e6 486 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
9de3ca7e 487 }
488 break;
489 case 0x000b:
490 if (subtype == 0x0001)
a25832e6 491 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
9de3ca7e 492 else if (subtype == 0x0002)
a25832e6 493 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
9de3ca7e 494 else
a25832e6 495 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
9de3ca7e 496 break;
497 default:
a25832e6 498 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
9de3ca7e 499 break;
500 }
501 }
502 break;
503 case AIM_CONN_TYPE_CHATNAV:
504 {
505 u_short family;
506 u_short subtype;
a25832e6 507 family = aimutil_get16(workingPtr->data);
508 subtype= aimutil_get16(workingPtr->data+2);
509
510 if ((family == 0x0002) && (subtype == 0x0006))
9de3ca7e 511 {
512 workingPtr->handled = 1;
513 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
514 }
515 else
516 {
a25832e6 517 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
9de3ca7e 518 }
519 }
520 break;
521 case AIM_CONN_TYPE_CHAT:
24286d93 522 printf("\nAHH! Dont know what to do with CHAT stuff yet!\n");
a25832e6 523 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
9de3ca7e 524 break;
525 default:
24286d93 526 printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
a25832e6 527 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
9de3ca7e 528 break;
529 }
a25832e6 530 /* move to next command */
9de3ca7e 531 workingPtr = workingPtr->next;
532 }
533 }
534
a25832e6 535 sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
9de3ca7e 536
537 return 0;
538}
539
01b59e1e 540int aim_parsemotd_middle(struct aim_session_t *sess,
541 struct command_rx_struct *command, ...)
9de3ca7e 542{
543 rxcallback_t userfunc = NULL;
01b59e1e 544 char *msg;
545 int ret=1;
546 struct aim_tlvlist_t *tlvlist;
547 u_short id;
548
549 /*
550 * Dunno.
551 */
552 id = aimutil_get16(command->data+10);
553
554 /*
555 * TLVs follow
556 */
557 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
a25832e6 558
01b59e1e 559 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
560
561 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
562 if (userfunc)
563 ret = userfunc(sess, command, id, msg);
9de3ca7e 564
01b59e1e 565 aim_freetlvchain(&tlvlist);
9de3ca7e 566
01b59e1e 567 return ret;
568
9de3ca7e 569}
570
a25832e6 571int aim_handleredirect_middle(struct aim_session_t *sess,
572 struct command_rx_struct *command, ...)
9de3ca7e 573{
01b59e1e 574 struct aim_tlv_t *tmptlv = NULL;
9de3ca7e 575 int serviceid = 0x00;
01b59e1e 576 char cookie[AIM_COOKIELEN];
9de3ca7e 577 char *ip = NULL;
578 rxcallback_t userfunc = NULL;
01b59e1e 579 struct aim_tlvlist_t *tlvlist;
580 int ret = 1;
581
582 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
583
584 tmptlv = aim_gettlv(tlvlist, 0x000d, 1);
585 serviceid = aimutil_get16(tmptlv->value);
586
587 ip = aim_gettlv_str(tlvlist, 0x0005, 1);
588
589 tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
590 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
9de3ca7e 591
9de3ca7e 592 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
593 if (userfunc)
01b59e1e 594 ret = userfunc(sess, command, serviceid, ip, cookie);
595
596 aim_freetlvchain(&tlvlist);
597
598 return ret;
9de3ca7e 599}
600
a25832e6 601int aim_parse_unknown(struct aim_session_t *sess,
602 struct command_rx_struct *command, ...)
9de3ca7e 603{
604 u_int i = 0;
605
606 printf("\nRecieved unknown packet:");
607
608 for (i = 0; i < command->commandlen; i++)
609 {
610 if ((i % 8) == 0)
611 printf("\n\t");
612
613 printf("0x%2x ", command->data[i]);
614 }
615
616 printf("\n\n");
617
618 return 1;
619}
620
621
622/*
623 * aim_parse_generalerrs()
624 *
625 * Middle handler for 0x0001 snac of each family.
626 *
627 */
a25832e6 628int aim_parse_generalerrs(struct aim_session_t *sess,
629 struct command_rx_struct *command, ...)
9de3ca7e 630{
631 u_short family;
632 u_short subtype;
a25832e6 633
634 family = aimutil_get16(command->data+0);
635 subtype= aimutil_get16(command->data+2);
9de3ca7e 636
637 switch(family)
638 {
639 default:
640 /* Unknown family */
a25832e6 641 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
9de3ca7e 642 }
643
644 return 1;
645}
646
647
648
This page took 0.159184 seconds and 5 git commands to generate.