src/protocols/oscar/rxhandlers.c

branch
gaim
changeset 20470
77693555855f
parent 13071
b98e72d4089a
parent 20469
b2836a24d81e
child 20471
1966704b3e42
equal deleted inserted replaced
13071:b98e72d4089a 20470:77693555855f
1 /*
2 * 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
13 struct aim_rxcblist_s {
14 fu16_t family;
15 fu16_t type;
16 aim_rxcallback_t handler;
17 fu16_t flags;
18 struct aim_rxcblist_s *next;
19 };
20
21 faim_internal aim_module_t *aim__findmodulebygroup(aim_session_t *sess, fu16_t group)
22 {
23 aim_module_t *cur;
24
25 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
26 if (cur->family == group)
27 return cur;
28 }
29
30 return NULL;
31 }
32
33 faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name)
34 {
35 aim_module_t *cur;
36
37 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
38 if (strcmp(name, cur->name) == 0)
39 return cur;
40 }
41
42 return NULL;
43 }
44
45 faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
46 {
47 aim_module_t *mod;
48
49 if (!sess || !modfirst)
50 return -1;
51
52 if (!(mod = malloc(sizeof(aim_module_t))))
53 return -1;
54 memset(mod, 0, sizeof(aim_module_t));
55
56 if (modfirst(sess, mod) == -1) {
57 free(mod);
58 return -1;
59 }
60
61 if (aim__findmodule(sess, mod->name)) {
62 if (mod->shutdown)
63 mod->shutdown(sess, mod);
64 free(mod);
65 return -1;
66 }
67
68 mod->next = (aim_module_t *)sess->modlistv;
69 sess->modlistv = mod;
70
71 gaim_debug_misc("oscar", "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion);
72
73 return 0;
74 }
75
76 faim_internal void aim__shutdownmodules(aim_session_t *sess)
77 {
78 aim_module_t *cur;
79
80 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
81 aim_module_t *tmp;
82
83 tmp = cur->next;
84
85 if (cur->shutdown)
86 cur->shutdown(sess, cur);
87
88 free(cur);
89
90 cur = tmp;
91 }
92
93 sess->modlistv = NULL;
94
95 return;
96 }
97
98 static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
99 {
100 aim_module_t *cur;
101 aim_modsnac_t snac;
102
103 if (aim_bstream_empty(&rx->data) < 10)
104 return 0;
105
106 snac.family = aimbs_get16(&rx->data);
107 snac.subtype = aimbs_get16(&rx->data);
108 snac.flags = aimbs_get16(&rx->data);
109 snac.id = aimbs_get32(&rx->data);
110
111 /* SNAC flags are apparently uniform across all SNACs, so we handle them here */
112 if (snac.flags & 0x0001) {
113 /*
114 * This means the SNAC will be followed by another SNAC with
115 * related information. We don't need to do anything about
116 * this here.
117 */
118 }
119 if (snac.flags & 0x8000) {
120 /*
121 * This packet contains the version of the family that this SNAC is
122 * in. You get this when your SSI module is version 2 or higher.
123 * For now we have no need for this, but you could always save
124 * it as a part of aim_modnsac_t, or something. The format is...
125 * 2 byte length of total mini-header (which is 6 bytes), then TLV
126 * of type 0x0001, length 0x0002, value is the 2 byte version
127 * number
128 */
129 aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
130 }
131
132 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
133
134 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
135 (cur->family != snac.family))
136 continue;
137
138 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
139 return 1;
140
141 }
142
143 return 0;
144 }
145
146 static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
147 {
148 aim_module_t *cur;
149 aim_modsnac_t snac;
150
151 snac.family = family;
152 snac.subtype = subtype;
153 snac.flags = snac.id = 0;
154
155 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
156
157 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
158 (cur->family != snac.family))
159 continue;
160
161 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
162 return 1;
163
164 }
165
166 return 0;
167 }
168
169 static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
170 {
171 aim_tlvlist_t *tlvlist;
172 char *msg = NULL;
173 fu16_t code = 0;
174 aim_rxcallback_t userfunc;
175 int ret = 1;
176
177 if (aim_bstream_empty(&fr->data) == 0) {
178 /* XXX should do something with this */
179 return 1;
180 }
181
182 /* Used only by the older login protocol */
183 /* XXX remove this special case? */
184 if (fr->conn->type == AIM_CONN_TYPE_AUTH)
185 return consumenonsnac(sess, fr, 0x0017, 0x0003);
186
187 tlvlist = aim_tlvlist_read(&fr->data);
188
189 if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
190 code = aim_tlv_get16(tlvlist, 0x0009, 1);
191
192 if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
193 msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
194
195 if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
196 ret = userfunc(sess, fr, code, msg);
197
198 aim_tlvlist_free(&tlvlist);
199
200 free(msg);
201
202 return ret;
203 }
204
205 /*
206 * Bleck functions get called when there's no non-bleck functions
207 * around to cleanup the mess...
208 */
209 static int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
210 {
211 fu16_t family, subtype;
212 fu16_t maxf, maxs;
213
214 static const char *channels[6] = {
215 "Invalid (0)",
216 "FLAP Version",
217 "SNAC",
218 "Invalid (3)",
219 "Negotiation",
220 "FLAP NOP"
221 };
222 static const int maxchannels = 5;
223
224 /* XXX: this is ugly. and big just for debugging. */
225 static const char *literals[14][25] = {
226 {"Invalid",
227 NULL
228 },
229 {"General",
230 "Invalid",
231 "Error",
232 "Client Ready",
233 "Server Ready",
234 "Service Request",
235 "Redirect",
236 "Rate Information Request",
237 "Rate Information",
238 "Rate Information Ack",
239 NULL,
240 "Rate Information Change",
241 "Server Pause",
242 NULL,
243 "Server Resume",
244 "Request Personal User Information",
245 "Personal User Information",
246 "Evil Notification",
247 NULL,
248 "Migration notice",
249 "Message of the Day",
250 "Set Privacy Flags",
251 "Well Known URL",
252 "NOP"
253 },
254 {"Location",
255 "Invalid",
256 "Error",
257 "Request Rights",
258 "Rights Information",
259 "Set user information",
260 "Request User Information",
261 "User Information",
262 "Watcher Sub Request",
263 "Watcher Notification"
264 },
265 {"Buddy List Management",
266 "Invalid",
267 "Error",
268 "Request Rights",
269 "Rights Information",
270 "Add Buddy",
271 "Remove Buddy",
272 "Watcher List Query",
273 "Watcher List Response",
274 "Watcher SubRequest",
275 "Watcher Notification",
276 "Reject Notification",
277 "Oncoming Buddy",
278 "Offgoing Buddy"
279 },
280 {"Messeging",
281 "Invalid",
282 "Error",
283 "Add ICBM Parameter",
284 "Remove ICBM Parameter",
285 "Request Parameter Information",
286 "Parameter Information",
287 "Outgoing Message",
288 "Incoming Message",
289 "Evil Request",
290 "Evil Reply",
291 "Missed Calls",
292 "Message Error",
293 "Host Ack"
294 },
295 {"Advertisements",
296 "Invalid",
297 "Error",
298 "Request Ad",
299 "Ad Data (GIFs)"
300 },
301 {"Invitation / Client-to-Client",
302 "Invalid",
303 "Error",
304 "Invite a Friend",
305 "Invitation Ack"
306 },
307 {"Administrative",
308 "Invalid",
309 "Error",
310 "Information Request",
311 "Information Reply",
312 "Information Change Request",
313 "Information Chat Reply",
314 "Account Confirm Request",
315 "Account Confirm Reply",
316 "Account Delete Request",
317 "Account Delete Reply"
318 },
319 {"Popups",
320 "Invalid",
321 "Error",
322 "Display Popup"
323 },
324 {"BOS",
325 "Invalid",
326 "Error",
327 "Request Rights",
328 "Rights Response",
329 "Set group permission mask",
330 "Add permission list entries",
331 "Delete permission list entries",
332 "Add deny list entries",
333 "Delete deny list entries",
334 "Server Error"
335 },
336 {"User Lookup",
337 "Invalid",
338 "Error",
339 "Search Request",
340 "Search Response"
341 },
342 {"Stats",
343 "Invalid",
344 "Error",
345 "Set minimum report interval",
346 "Report Events"
347 },
348 {"Translate",
349 "Invalid",
350 "Error",
351 "Translate Request",
352 "Translate Reply",
353 },
354 {"Chat Navigation",
355 "Invalid",
356 "Error",
357 "Request rights",
358 "Request Exchange Information",
359 "Request Room Information",
360 "Request Occupant List",
361 "Search for Room",
362 "Outgoing Message",
363 "Incoming Message",
364 "Evil Request",
365 "Evil Reply",
366 "Chat Error",
367 }
368 };
369
370 maxf = sizeof(literals) / sizeof(literals[0]);
371 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
372
373 if (frame->hdr.flap.channel == 0x02) {
374
375 family = aimbs_get16(&frame->data);
376 subtype = aimbs_get16(&frame->data);
377
378 if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
379 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.channel], family, subtype, literals[family][subtype+1]);
380 else
381 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.channel], family, subtype);
382 } else {
383
384 if (frame->hdr.flap.channel <= maxchannels)
385 gaim_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.channel], frame->hdr.flap.channel);
386 else
387 gaim_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->hdr.flap.channel);
388
389 }
390
391 return 1;
392 }
393
394 faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags)
395 {
396 struct aim_rxcblist_s *newcb;
397
398 if (!conn)
399 return -1;
400
401 gaim_debug_misc("oscar", "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
402
403 if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
404 return -1;
405
406 newcb->family = family;
407 newcb->type = type;
408 newcb->flags = flags;
409 newcb->handler = newhandler ? newhandler : bleck;
410 newcb->next = NULL;
411
412 if (!conn->handlerlist)
413 conn->handlerlist = (void *)newcb;
414 else {
415 struct aim_rxcblist_s *cur;
416
417 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
418 ;
419 cur->next = newcb;
420 }
421
422 return 0;
423 }
424
425 faim_export int aim_clearhandlers(aim_conn_t *conn)
426 {
427 struct aim_rxcblist_s *cur;
428
429 if (!conn)
430 return -1;
431
432 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
433 struct aim_rxcblist_s *tmp;
434
435 tmp = cur->next;
436 free(cur);
437 cur = tmp;
438 }
439 conn->handlerlist = NULL;
440
441 return 0;
442 }
443
444 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
445 {
446 struct aim_rxcblist_s *cur;
447
448 if (!conn)
449 return NULL;
450
451 /* gaim_debug_misc("oscar", "aim_callhandler: calling for %04x/%04x\n", family, type); */
452
453 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
454 if ((cur->family == family) && (cur->type == type))
455 return cur->handler;
456 }
457
458 if (type == AIM_CB_SPECIAL_DEFAULT) {
459 /* gaim_debug_misc("oscar", "aim_callhandler: no default handler for family 0x%04x\n", family); */
460 return NULL; /* prevent infinite recursion */
461 }
462
463 /* gaim_debug_misc("oscar", "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type); */
464
465 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
466 }
467
468 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
469 {
470 struct aim_rxcblist_s *cur;
471
472 for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
473 aim_conn_addhandler(sess, dest, cur->family, cur->type,
474 cur->handler, cur->flags);
475 }
476
477 return;
478 }
479
480 faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
481 {
482 aim_rxcallback_t userfunc;
483
484 if ((userfunc = aim_callhandler(sess, conn, family, type)))
485 return userfunc(sess, ptr);
486
487 return 1; /* XXX */
488 }
489
490 /*
491 * aim_rxdispatch()
492 *
493 * Basically, heres what this should do:
494 * 1) Determine correct packet handler for this packet
495 * 2) Mark the packet handled (so it can be dequeued in purge_queue())
496 * 3) Send the packet to the packet handler
497 * 4) Go to next packet in the queue and start over
498 * 5) When done, run purge_queue() to purge handled commands
499 *
500 * TODO: Clean up.
501 * TODO: More support for mid-level handlers.
502 * TODO: Allow for NULL handlers.
503 *
504 */
505 faim_export void aim_rxdispatch(aim_session_t *sess)
506 {
507 int i;
508 aim_frame_t *cur;
509
510 for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
511
512 /*
513 * XXX: This is still fairly ugly.
514 */
515
516 if (cur->handled)
517 continue;
518
519 if (cur->hdrtype == AIM_FRAMETYPE_FLAP) {
520 if (cur->hdr.flap.channel == 0x01) {
521 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
522 continue;
523
524 } else if (cur->hdr.flap.channel == 0x02) {
525 if ((cur->handled = consumesnac(sess, cur)))
526 continue;
527
528 } else if (cur->hdr.flap.channel == 0x04) {
529 cur->handled = negchan_middle(sess, cur);
530 continue;
531
532 } else if (cur->hdr.flap.channel == 0x05) {
533
534 }
535
536 } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
537 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
538 aim_rxdispatch_rendezvous(sess, cur);
539 cur->handled = 1;
540 continue;
541
542 } else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) {
543 /* not possible */
544 gaim_debug_misc("oscar", "rxdispatch called on LISTENER connection!\n");
545 cur->handled = 1;
546 continue;
547 }
548 }
549
550 if (!cur->handled) {
551 consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
552 cur->handled = 1;
553 }
554 }
555
556 /*
557 * This doesn't have to be called here. It could easily be done
558 * by a separate thread or something. It's an administrative operation,
559 * and can take a while. Though the less you call it the less memory
560 * you'll have :)
561 */
562 aim_purge_rxqueue(sess);
563
564 return;
565 }
566
567 faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
568 {
569 int i;
570
571 gaim_debug_misc("oscar", "\nRecieved unknown packet:");
572
573 for (i = 0; aim_bstream_empty(&frame->data); i++) {
574 if ((i % 8) == 0)
575 gaim_debug_misc("oscar", "\n\t");
576
577 gaim_debug_misc("oscar", "0x%2x ", aimbs_get8(&frame->data));
578 }
579
580 gaim_debug_misc("oscar", "\n\n");
581
582 return 1;
583 }

mercurial