]> andersk Git - libfaim.git/blame_incremental - src/rxhandlers.c
- Fri Aug 3 14:19:37 EDT 2001
[libfaim.git] / src / 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#define FAIM_INTERNAL
11#include <aim.h>
12
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
51 faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
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
125/*
126 * Bleck functions get called when there's no non-bleck functions
127 * around to cleanup the mess...
128 */
129faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
130{
131 u_short family;
132 u_short subtype;
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))
290 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
291 else
292 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
293
294 return 1;
295}
296
297faim_export int aim_conn_addhandler(struct aim_session_t *sess,
298 struct aim_conn_t *conn,
299 u_short family,
300 u_short type,
301 aim_rxcallback_t newhandler,
302 u_short flags)
303{
304 struct aim_rxcblist_t *newcb;
305
306 if (!conn)
307 return -1;
308
309 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
310
311 if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
312 return -1;
313 newcb->family = family;
314 newcb->type = type;
315 newcb->flags = flags;
316 if (!newhandler)
317 newcb->handler = &bleck;
318 else
319 newcb->handler = newhandler;
320 newcb->next = NULL;
321
322 if (!conn->handlerlist)
323 conn->handlerlist = newcb;
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 }
333
334 return 0;
335}
336
337faim_export int aim_clearhandlers(struct aim_conn_t *conn)
338{
339 struct aim_rxcblist_t *cur;
340
341 if (!conn)
342 return -1;
343
344 for (cur = conn->handlerlist; cur; ) {
345 struct aim_rxcblist_t *tmp;
346
347 tmp = cur->next;
348 free(cur);
349 cur = tmp;
350 }
351 conn->handlerlist = NULL;
352
353 return 0;
354}
355
356faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess,
357 struct aim_conn_t *conn,
358 unsigned short family,
359 unsigned short type)
360{
361 struct aim_rxcblist_t *cur;
362
363 if (!conn)
364 return NULL;
365
366 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
367
368 for (cur = conn->handlerlist; cur; cur = cur->next) {
369 if ((cur->family == family) && (cur->type == type))
370 return cur->handler;
371 }
372
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);
379
380 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
381}
382
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)
388{
389 aim_rxcallback_t userfunc = NULL;
390 userfunc = aim_callhandler(sess, conn, family, type);
391 if (userfunc)
392 return userfunc(sess, ptr);
393 return 1; /* XXX */
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 */
419faim_export int aim_rxdispatch(struct aim_session_t *sess)
420{
421 int i = 0;
422 struct command_rx_struct *workingPtr = NULL;
423 static int critical = 0;
424
425 if (critical)
426 return 0; /* don't call recursively! */
427
428 critical = 1;
429
430 if (sess->queue_incoming == NULL) {
431 faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
432 } else {
433 workingPtr = sess->queue_incoming;
434 for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
435 unsigned short family,subtype;
436
437 /*
438 * XXX: This is still fairly ugly.
439 */
440 if (workingPtr->handled)
441 continue;
442
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))) {
451 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
452 workingPtr->handled = 1;
453 continue;
454 }
455
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 */
465 }
466 continue;
467 }
468
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 }
475
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 }
481
482 if (workingPtr->hdr.oscar.type == 0x04) {
483 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
484 continue;
485 }
486
487 if ((workingPtr->handled = consumesnac(sess, workingPtr)))
488 continue;
489
490 if (!workingPtr->handled) {
491 family = aimutil_get16(workingPtr->data);
492 subtype = aimutil_get16(workingPtr->data+2);
493
494 faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype);
495 consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */
496 workingPtr->handled = 1;
497 }
498 }
499 }
500
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);
508
509 critical = 0;
510
511 return 0;
512}
513
514faim_internal int aim_parse_unknown(struct aim_session_t *sess,
515 struct command_rx_struct *command, ...)
516{
517 u_int i = 0;
518
519 if (!sess || !command)
520 return 1;
521
522 faimdprintf(sess, 1, "\nRecieved unknown packet:");
523
524 for (i = 0; i < command->commandlen; i++)
525 {
526 if ((i % 8) == 0)
527 faimdprintf(sess, 1, "\n\t");
528
529 faimdprintf(sess, 1, "0x%2x ", command->data[i]);
530 }
531
532 faimdprintf(sess, 1, "\n\n");
533
534 return 1;
535}
536
537
538faim_internal int aim_negchan_middle(struct aim_session_t *sess,
539 struct command_rx_struct *command)
540{
541 struct aim_tlvlist_t *tlvlist;
542 char *msg = NULL;
543 unsigned short code = 0;
544 aim_rxcallback_t userfunc = NULL;
545 int ret = 1;
546
547 /* Used only by the older login protocol */
548 /* XXX remove this special case? */
549 if (command->conn->type == AIM_CONN_TYPE_AUTH)
550 return consumenonsnac(sess, command, 0x0017, 0x0003);
551
552 tlvlist = aim_readtlvchain(command->data, command->commandlen);
553
554 if (aim_gettlv(tlvlist, 0x0009, 1))
555 code = aim_gettlv16(tlvlist, 0x0009, 1);
556
557 if (aim_gettlv(tlvlist, 0x000b, 1))
558 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
559
560 if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
561 ret = userfunc(sess, command, code, msg);
562
563 aim_freetlvchain(&tlvlist);
564
565 if (msg)
566 free(msg);
567
568 return ret;
569}
570
This page took 0.044447 seconds and 5 git commands to generate.