]> andersk Git - libfaim.git/blame - src/rxhandlers.c
- Sat Mar 24 03:16:32 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
9f1a4013 13static aim_module_t *findmodule(struct aim_session_t *sess, const char *name)
14{
15 aim_module_t *cur;
16
17 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
18 if (strcmp(name, cur->name) == 0)
19 return cur;
20 }
21
22 return NULL;
23}
24
25faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *))
26{
27 aim_module_t *mod;
28
29 if (!sess || !modfirst)
30 return -1;
31
32 if (!(mod = malloc(sizeof(aim_module_t))))
33 return -1;
34 memset(mod, 0, sizeof(aim_module_t));
35
36 if (modfirst(sess, mod) == -1) {
37 free(mod);
38 return -1;
39 }
40
41 if (findmodule(sess, mod->name)) {
42 if (mod->shutdown)
43 mod->shutdown(sess, mod);
44 free(mod);
45 return -1;
46 }
47
48 mod->next = (aim_module_t *)sess->modlistv;
49 (aim_module_t *)sess->modlistv = mod;
50
00ef5271 51 faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
9f1a4013 52
53 return 0;
54}
55
56faim_internal void aim__shutdownmodules(struct aim_session_t *sess)
57{
58 aim_module_t *cur;
59
60 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
61 aim_module_t *tmp;
62
63 tmp = cur->next;
64
65 if (cur->shutdown)
66 cur->shutdown(sess, cur);
67
68 free(cur);
69
70 cur = tmp;
71 }
72
73 sess->modlistv = NULL;
74
75 return;
76}
77
78static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx)
79{
80 aim_module_t *cur;
81 aim_modsnac_t snac;
82
83 snac.family = aimutil_get16(rx->data+0);
84 snac.subtype = aimutil_get16(rx->data+2);
85 snac.flags = aimutil_get16(rx->data+4);
86 snac.id = aimutil_get32(rx->data+6);
87
88 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
89
90 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
91 (cur->family != snac.family))
92 continue;
93
94 if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10))
95 return 1;
96
97 }
98
99 return 0;
100}
101
102static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype)
103{
104 aim_module_t *cur;
105 aim_modsnac_t snac;
106
107 snac.family = family;
108 snac.subtype = subtype;
109 snac.flags = snac.id = 0;
110
111 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
112
113 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
114 (cur->family != snac.family))
115 continue;
116
117 if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen))
118 return 1;
119
120 }
121
122 return 0;
123}
124
24286d93 125/*
126 * Bleck functions get called when there's no non-bleck functions
127 * around to cleanup the mess...
128 */
78b3fb13 129faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
9de3ca7e 130{
131 u_short family;
132 u_short subtype;
01b59e1e 133
134 u_short maxf;
135 u_short maxs;
136
137 /* XXX: this is ugly. and big just for debugging. */
138 char *literals[14][25] = {
139 {"Invalid",
140 NULL
141 },
142 {"General",
143 "Invalid",
144 "Error",
145 "Client Ready",
146 "Server Ready",
147 "Service Request",
148 "Redirect",
149 "Rate Information Request",
150 "Rate Information",
151 "Rate Information Ack",
152 NULL,
153 "Rate Information Change",
154 "Server Pause",
155 NULL,
156 "Server Resume",
157 "Request Personal User Information",
158 "Personal User Information",
159 "Evil Notification",
160 NULL,
161 "Migration notice",
162 "Message of the Day",
163 "Set Privacy Flags",
164 "Well Known URL",
165 "NOP"
166 },
167 {"Location",
168 "Invalid",
169 "Error",
170 "Request Rights",
171 "Rights Information",
172 "Set user information",
173 "Request User Information",
174 "User Information",
175 "Watcher Sub Request",
176 "Watcher Notification"
177 },
178 {"Buddy List Management",
179 "Invalid",
180 "Error",
181 "Request Rights",
182 "Rights Information",
183 "Add Buddy",
184 "Remove Buddy",
185 "Watcher List Query",
186 "Watcher List Response",
187 "Watcher SubRequest",
188 "Watcher Notification",
189 "Reject Notification",
190 "Oncoming Buddy",
191 "Offgoing Buddy"
192 },
193 {"Messeging",
194 "Invalid",
195 "Error",
196 "Add ICBM Parameter",
197 "Remove ICBM Parameter",
198 "Request Parameter Information",
199 "Parameter Information",
200 "Outgoing Message",
201 "Incoming Message",
202 "Evil Request",
203 "Evil Reply",
204 "Missed Calls",
205 "Message Error",
206 "Host Ack"
207 },
208 {"Advertisements",
209 "Invalid",
210 "Error",
211 "Request Ad",
212 "Ad Data (GIFs)"
213 },
214 {"Invitation / Client-to-Client",
215 "Invalid",
216 "Error",
217 "Invite a Friend",
218 "Invitation Ack"
219 },
220 {"Administrative",
221 "Invalid",
222 "Error",
223 "Information Request",
224 "Information Reply",
225 "Information Change Request",
226 "Information Chat Reply",
227 "Account Confirm Request",
228 "Account Confirm Reply",
229 "Account Delete Request",
230 "Account Delete Reply"
231 },
232 {"Popups",
233 "Invalid",
234 "Error",
235 "Display Popup"
236 },
237 {"BOS",
238 "Invalid",
239 "Error",
240 "Request Rights",
241 "Rights Response",
242 "Set group permission mask",
243 "Add permission list entries",
244 "Delete permission list entries",
245 "Add deny list entries",
246 "Delete deny list entries",
247 "Server Error"
248 },
249 {"User Lookup",
250 "Invalid",
251 "Error",
252 "Search Request",
253 "Search Response"
254 },
255 {"Stats",
256 "Invalid",
257 "Error",
258 "Set minimum report interval",
259 "Report Events"
260 },
261 {"Translate",
262 "Invalid",
263 "Error",
264 "Translate Request",
265 "Translate Reply",
266 },
267 {"Chat Navigation",
268 "Invalid",
269 "Error",
270 "Request rights",
271 "Request Exchange Information",
272 "Request Room Information",
273 "Request Occupant List",
274 "Search for Room",
275 "Outgoing Message",
276 "Incoming Message",
277 "Evil Request",
278 "Evil Reply",
279 "Chat Error",
280 }
281 };
282
283 maxf = sizeof(literals) / sizeof(literals[0]);
284 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
285
286 family = aimutil_get16(workingPtr->data+0);
287 subtype= aimutil_get16(workingPtr->data+2);
288
289 if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
646c6b52 290 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
01b59e1e 291 else
646c6b52 292 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
01b59e1e 293
9de3ca7e 294 return 1;
295}
296
78b3fb13 297faim_export int aim_conn_addhandler(struct aim_session_t *sess,
a25832e6 298 struct aim_conn_t *conn,
9de3ca7e 299 u_short family,
300 u_short type,
301 rxcallback_t newhandler,
302 u_short flags)
303{
871e2fd0 304 struct aim_rxcblist_t *newcb;
9de3ca7e 305
306 if (!conn)
307 return -1;
308
646c6b52 309 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
9de3ca7e 310
871e2fd0 311 if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
312 return -1;
a15d82b1 313 newcb->family = family;
314 newcb->type = type;
315 newcb->flags = flags;
9de3ca7e 316 if (!newhandler)
a15d82b1 317 newcb->handler = &bleck;
9de3ca7e 318 else
a15d82b1 319 newcb->handler = newhandler;
320 newcb->next = NULL;
9de3ca7e 321
871e2fd0 322 if (!conn->handlerlist)
a15d82b1 323 conn->handlerlist = newcb;
871e2fd0 324 else {
325 struct aim_rxcblist_t *cur;
326
327 cur = conn->handlerlist;
328
329 while (cur->next)
330 cur = cur->next;
331 cur->next = newcb;
332 }
9de3ca7e 333
334 return 0;
335}
336
78b3fb13 337faim_export int aim_clearhandlers(struct aim_conn_t *conn)
9de3ca7e 338{
871e2fd0 339 struct aim_rxcblist_t *cur;
340
9de3ca7e 341 if (!conn)
342 return -1;
343
55e77c8a 344 for (cur = conn->handlerlist; cur; ) {
871e2fd0 345 struct aim_rxcblist_t *tmp;
346
347 tmp = cur->next;
348 free(cur);
349 cur = tmp;
350 }
55e77c8a 351 conn->handlerlist = NULL;
871e2fd0 352
9de3ca7e 353 return 0;
354}
355
646c6b52 356faim_internal rxcallback_t aim_callhandler(struct aim_session_t *sess,
357 struct aim_conn_t *conn,
358 unsigned short family,
359 unsigned short type)
9de3ca7e 360{
361 struct aim_rxcblist_t *cur;
362
363 if (!conn)
364 return NULL;
365
646c6b52 366 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
9de3ca7e 367
646c6b52 368 for (cur = conn->handlerlist; cur; cur = cur->next) {
369 if ((cur->family == family) && (cur->type == type))
370 return cur->handler;
371 }
9de3ca7e 372
646c6b52 373 if (type == AIM_CB_SPECIAL_DEFAULT) {
374 faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
375 return NULL; /* prevent infinite recursion */
376 }
377
378 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
871e2fd0 379
646c6b52 380 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
9de3ca7e 381}
382
78b3fb13 383faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
384 struct aim_conn_t *conn,
385 u_short family,
386 u_short type,
387 struct command_rx_struct *ptr)
9de3ca7e 388{
389 rxcallback_t userfunc = NULL;
646c6b52 390 userfunc = aim_callhandler(sess, conn, family, type);
9de3ca7e 391 if (userfunc)
a25832e6 392 return userfunc(sess, ptr);
b8d0da45 393 return 1; /* XXX */
9de3ca7e 394}
395
396/*
397 aim_rxdispatch()
398
399 Basically, heres what this should do:
400 1) Determine correct packet handler for this packet
401 2) Mark the packet handled (so it can be dequeued in purge_queue())
402 3) Send the packet to the packet handler
403 4) Go to next packet in the queue and start over
404 5) When done, run purge_queue() to purge handled commands
405
406 Note that any unhandlable packets should probably be left in the
407 queue. This is the best way to prevent data loss. This means
408 that a single packet may get looked at by this function multiple
409 times. This is more good than bad! This behavior may change.
410
411 Aren't queue's fun?
412
413 TODO: Get rid of all the ugly if's.
414 TODO: Clean up.
415 TODO: More support for mid-level handlers.
416 TODO: Allow for NULL handlers.
417
418 */
78b3fb13 419faim_export int aim_rxdispatch(struct aim_session_t *sess)
9de3ca7e 420{
421 int i = 0;
422 struct command_rx_struct *workingPtr = NULL;
154b4093 423 static int critical = 0;
9de3ca7e 424
154b4093 425 if (critical)
426 return 0; /* don't call recursively! */
427
428 critical = 1;
429
b8d0da45 430 if (sess->queue_incoming == NULL) {
646c6b52 431 faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
b8d0da45 432 } else {
433 workingPtr = sess->queue_incoming;
50443ea0 434 for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
bb010ae0 435 unsigned short family,subtype;
436
b8d0da45 437 /*
438 * XXX: This is still fairly ugly.
439 */
50443ea0 440 if (workingPtr->handled)
441 continue;
442
b69540e3 443 /*
444 * This is a debugging/sanity check only and probably could/should be removed
445 * for stable code.
446 */
447 if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) &&
448 (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
449 ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) &&
450 (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
646c6b52 451 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
b69540e3 452 workingPtr->handled = 1;
453 continue;
454 }
455
bb010ae0 456 if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
457 /* make sure that we only get OFT frames on these connections */
458 if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
459 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
460 workingPtr->handled = 1; /* get rid of it */
461 } else {
462 /* XXX: implement this */
463 faimdprintf(sess, 0, "faim: OFT frame!\n");
464 workingPtr->handled = 1; /* get rid of it */
b8d0da45 465 }
bb010ae0 466 continue;
b8d0da45 467 }
5e02cf44 468
bb010ae0 469 if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
470 /* not possible */
471 faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
472 workingPtr->handled = 1;
473 continue;
474 }
5e02cf44 475
bb010ae0 476 if ((workingPtr->commandlen == 4) &&
477 (aimutil_get32(workingPtr->data) == 0x00000001)) {
478 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
479 continue;
480 }
64c78745 481
bb010ae0 482 if (workingPtr->hdr.oscar.type == 0x04) {
483 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
484 continue;
485 }
9f1a4013 486
487 if ((workingPtr->handled = consumesnac(sess, workingPtr)))
488 continue;
bb010ae0 489
00ef5271 490 if (!workingPtr->handled) {
491 family = aimutil_get16(workingPtr->data);
492 subtype = aimutil_get16(workingPtr->data+2);
bb010ae0 493
00ef5271 494 faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype);
495 consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */
496 workingPtr->handled = 1;
7392c79f 497 }
9de3ca7e 498 }
b8d0da45 499 }
9de3ca7e 500
b8d0da45 501 /*
502 * This doesn't have to be called here. It could easily be done
503 * by a seperate thread or something. It's an administrative operation,
504 * and can take a while. Though the less you call it the less memory
505 * you'll have :)
506 */
507 aim_purge_rxqueue(sess);
154b4093 508
509 critical = 0;
9de3ca7e 510
511 return 0;
512}
513
78b3fb13 514faim_internal int aim_parse_unknown(struct aim_session_t *sess,
515 struct command_rx_struct *command, ...)
9de3ca7e 516{
517 u_int i = 0;
518
22517493 519 if (!sess || !command)
520 return 1;
521
646c6b52 522 faimdprintf(sess, 1, "\nRecieved unknown packet:");
9de3ca7e 523
524 for (i = 0; i < command->commandlen; i++)
525 {
526 if ((i % 8) == 0)
646c6b52 527 faimdprintf(sess, 1, "\n\t");
9de3ca7e 528
646c6b52 529 faimdprintf(sess, 1, "0x%2x ", command->data[i]);
9de3ca7e 530 }
531
646c6b52 532 faimdprintf(sess, 1, "\n\n");
9de3ca7e 533
534 return 1;
535}
536
537
78b3fb13 538faim_internal int aim_negchan_middle(struct aim_session_t *sess,
539 struct command_rx_struct *command)
5e02cf44 540{
541 struct aim_tlvlist_t *tlvlist;
542 char *msg = NULL;
543 unsigned short code = 0;
5e02cf44 544 rxcallback_t userfunc = NULL;
545 int ret = 1;
546
bb010ae0 547 /* Used only by the older login protocol */
548 /* XXX remove this special case? */
549 if (command->conn->type == AIM_CONN_TYPE_AUTH)
9f1a4013 550 return consumenonsnac(sess, command, 0x0017, 0x0003);
bb010ae0 551
5e02cf44 552 tlvlist = aim_readtlvchain(command->data, command->commandlen);
553
1ea867e3 554 if (aim_gettlv(tlvlist, 0x0009, 1))
555 code = aim_gettlv16(tlvlist, 0x0009, 1);
5e02cf44 556
1ea867e3 557 if (aim_gettlv(tlvlist, 0x000b, 1))
5e02cf44 558 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
559
646c6b52 560 if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
9f1a4013 561 ret = userfunc(sess, command, code, msg);
5e02cf44 562
563 aim_freetlvchain(&tlvlist);
1ea867e3 564
565 if (msg)
566 free(msg);
5e02cf44 567
568 return ret;
569}
570
This page took 2.532768 seconds and 5 git commands to generate.