]> andersk Git - libfaim.git/blame - aim_rxhandlers.c
Initial revision
[libfaim.git] / aim_rxhandlers.c
CommitLineData
9de3ca7e 1
2/*
3 aim_rxhandlers.c
4
5 This file contains most all of the incoming packet handlers, along
6 with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
7 actually done in aim_rxqueue.c.
8
9 */
10
11
12#include "aim.h" /* for most everything */
13
14
15int bleck(struct command_rx_struct *workingPtr, ...)
16{
17 u_short family;
18 u_short subtype;
19 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
20 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
21#if debug > 0
22 fprintf(stderr, "bleck: null handler for %04x/%04x\n", family, subtype);
23#endif
24 return 1;
25}
26
27int bleck2(struct command_rx_struct *workingPtr, ...)
28{
29 u_short family;
30 u_short subtype;
31 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
32 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
33 printf("OLDbleck: called for %04x/%04x -- OBSOLETE\n", family, subtype);
34 return 1;
35}
36
37int aim_conn_addhandler(struct aim_conn_t *conn,
38 u_short family,
39 u_short type,
40 rxcallback_t newhandler,
41 u_short flags)
42{
43 struct aim_rxcblist_t *new,*cur;
44
45 if (!conn)
46 return -1;
47
48#if debug > 0
49 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
50#endif
51
52 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
53 new->family = family;
54 new->type = type;
55 new->flags = flags;
56 if (!newhandler)
57 new->handler = &bleck;
58 else
59 new->handler = newhandler;
60 new->next = NULL;
61
62 cur = conn->handlerlist;
63 if (!cur)
64 conn->handlerlist = new;
65 else
66 {
67 while (cur->next)
68 cur = cur->next;
69 cur->next = new;
70 }
71
72 return 0;
73}
74
75int aim_clearhandlers(struct aim_conn_t *conn)
76{
77 struct aim_rxcblist_t *cur,*tmp;
78 if (!conn)
79 return -1;
80
81 cur = conn->handlerlist;
82 while(cur)
83 {
84 tmp = cur->next;
85 free(cur);
86 cur = tmp;
87 }
88 return 0;
89}
90
91rxcallback_t aim_callhandler(struct aim_conn_t *conn,
92 u_short family,
93 u_short type)
94{
95 struct aim_rxcblist_t *cur;
96
97 if (!conn)
98 return NULL;
99
100#if debug > 0
101 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
102#endif
103
104 cur = conn->handlerlist;
105 while(cur)
106 {
107 if ( (cur->family == family) && (cur->type == type) )
108 return cur->handler;
109 cur = cur->next;
110 }
111
112 if (type==0xffff)
113 return NULL;
114 return aim_callhandler(conn, family, 0xffff);
115}
116
117int aim_callhandler_noparam(struct aim_conn_t *conn,
118 u_short family,
119 u_short type,
120 struct command_rx_struct *ptr)
121{
122 rxcallback_t userfunc = NULL;
123 userfunc = aim_callhandler(conn, family, type);
124 if (userfunc)
125 return userfunc(ptr);
126 return 0;
127}
128
129/*
130 aim_rxdispatch()
131
132 Basically, heres what this should do:
133 1) Determine correct packet handler for this packet
134 2) Mark the packet handled (so it can be dequeued in purge_queue())
135 3) Send the packet to the packet handler
136 4) Go to next packet in the queue and start over
137 5) When done, run purge_queue() to purge handled commands
138
139 Note that any unhandlable packets should probably be left in the
140 queue. This is the best way to prevent data loss. This means
141 that a single packet may get looked at by this function multiple
142 times. This is more good than bad! This behavior may change.
143
144 Aren't queue's fun?
145
146 TODO: Get rid of all the ugly if's.
147 TODO: Clean up.
148 TODO: More support for mid-level handlers.
149 TODO: Allow for NULL handlers.
150
151 */
152int aim_rxdispatch(void)
153{
154 int i = 0;
155 struct command_rx_struct *workingPtr = NULL;
156
157 if (aim_queue_incoming == NULL)
158 /* this shouldn't really happen, unless the main loop's select is broke */
159 printf("parse_generic: incoming packet queue empty.\n");
160 else
161 {
162 workingPtr = aim_queue_incoming;
163 for (i = 0; workingPtr != NULL; i++)
164 {
165 switch(workingPtr->conn->type)
166 {
167 case AIM_CONN_TYPE_AUTH:
168 if ( (workingPtr->data[0] == 0x00) &&
169 (workingPtr->data[1] == 0x00) &&
170 (workingPtr->data[2] == 0x00) &&
171 (workingPtr->data[3] == 0x01) )
172 {
173#if debug > 0
174 fprintf(stderr, "got connection ack on auth line\n");
175#endif
176 workingPtr->handled = 1;
177 }
178 else
179 {
180 /* any user callbacks will be called from here */
181 workingPtr->handled = aim_authparse(workingPtr);
182 }
183 break;
184 case AIM_CONN_TYPE_BOS:
185 {
186 u_short family;
187 u_short subtype;
188 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
189 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
190 switch (family)
191 {
192 case 0x0000: /* not really a family, but it works */
193 if (subtype == 0x0001)
194 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0000, 0x0001, workingPtr);
195 else
196 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
197 break;
198 case 0x0001: /* Family: General */
199 switch (subtype)
200 {
201 case 0x0001:
202 workingPtr->handled = aim_parse_generalerrs(workingPtr);
203 break;
204 case 0x0003:
205 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0003, workingPtr);
206 break;
207 case 0x0005:
208 workingPtr->handled = aim_handleredirect_middle(workingPtr);
209 break;
210 case 0x0007:
211 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0007, workingPtr);
212 break;
213 case 0x000a:
214 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000a, workingPtr);
215 break;
216 case 0x000f:
217 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000f, workingPtr);
218 break;
219 case 0x0013:
220 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0013, workingPtr);
221 break;
222 default:
223 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
224 }
225 break;
226 case 0x0002: /* Family: Location */
227 switch (subtype)
228 {
229 case 0x0001:
230 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0001, workingPtr);
231 break;
232 case 0x0003:
233 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0003, workingPtr);
234 break;
235 case 0x0006:
236 workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
237 break;
238 default:
239 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
240 }
241 break;
242 case 0x0003: /* Family: Buddy List */
243 switch (subtype)
244 {
245 case 0x0001:
246 workingPtr->handled = aim_parse_generalerrs(workingPtr);
247 break;
248 case 0x0003:
249 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x0003, workingPtr);
250 break;
251 case 0x000b: /* oncoming buddy */
252 workingPtr->handled = aim_parse_oncoming_middle(workingPtr);
253 break;
254 case 0x000c: /* offgoing buddy */
255 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x000c, workingPtr);
256 break;
257 default:
258 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
259 }
260 break;
261 case 0x0004: /* Family: Messeging */
262 switch (subtype)
263 {
264 case 0x0001:
265 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0001, workingPtr);
266 break;
267 case 0x0005:
268 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0005, workingPtr);
269 break;
270 case 0x0007:
271 workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
272 break;
273 case 0x000a:
274 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x000a, workingPtr);
275 break;
276 default:
277 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
278 }
279 break;
280 case 0x0009:
281 if (subtype == 0x0001)
282 workingPtr->handled = aim_parse_generalerrs(workingPtr);
283 else if (subtype == 0x0003)
284 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0009, 0x0003, workingPtr);
285 else
286 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
287 break;
288 case 0x000a: /* Family: User lookup */
289 switch (subtype)
290 {
291 case 0x0001:
292 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0001, workingPtr);
293 break;
294 case 0x0003:
295 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0003, workingPtr);
296 break;
297 default:
298 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
299 }
300 break;
301 case 0x000b:
302 if (subtype == 0x0001)
303 workingPtr->handled = aim_parse_generalerrs(workingPtr);
304 else if (subtype == 0x0002)
305 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000b, 0x0002, workingPtr);
306 else
307 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
308 break;
309 default:
310 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
311 break;
312 }
313 }
314 break;
315 case AIM_CONN_TYPE_CHATNAV:
316 {
317 u_short family;
318 u_short subtype;
319 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
320 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
321 if ( (workingPtr->data[0] == 0x00) &&
322 (workingPtr->data[1] == 0x02) &&
323 (workingPtr->data[2] == 0x00) &&
324 (workingPtr->data[3] == 0x06) )
325 {
326 workingPtr->handled = 1;
327 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
328 }
329 else
330 {
331 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, family, subtype, workingPtr);
332 }
333 }
334 break;
335 case AIM_CONN_TYPE_CHAT:
336 fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n");
337 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
338 break;
339 default:
340 fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
341 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
342 break;
343 }
344 /* move to next command */
345 workingPtr = workingPtr->next;
346 }
347 }
348
349 aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
350
351 return 0;
352}
353
354/*
355 * TODO: check and cure memory leakage in this function.
356 */
357int aim_authparse(struct command_rx_struct *command)
358{
359 rxcallback_t userfunc = NULL;
360 int iserror = 0;
361 struct aim_tlv_t *tlv = NULL;
362 char *errorurl = NULL;
363 short errorcode = 0x00;
364 u_int z = 0;
365
366 if ( (command->data[0] == 0x00) &&
367 (command->data[1] == 0x01) &&
368 (command->data[2] == 0x00) &&
369 (command->data[3] == 0x03) )
370 {
371 /* "server ready" -- can be ignored */
372 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
373 }
374 else if ( (command->data[0] == 0x00) &&
375 (command->data[1] == 0x07) &&
376 (command->data[2] == 0x00) &&
377 (command->data[3] == 0x05) )
378 {
379 /* "information change reply" */
380 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
381 }
382 else
383 {
384 /* anything else -- usually used for login; just parse as pure TLVs */
385
386 /*
387 * Free up the loginstruct first.
388 */
389 if (aim_logininfo.screen_name)
390 {
391 free(aim_logininfo.screen_name);
392 aim_logininfo.screen_name = NULL;
393 }
394 if (aim_logininfo.BOSIP)
395 {
396 free(aim_logininfo.BOSIP);
397 aim_logininfo.BOSIP = NULL;
398 }
399 if (aim_logininfo.cookie)
400 {
401 free(aim_logininfo.cookie);
402 aim_logininfo.cookie = NULL;
403 }
404 if (aim_logininfo.email)
405 {
406 free(aim_logininfo.email);
407 aim_logininfo.email = NULL;
408 }
409 aim_logininfo.regstatus = 0;
410
411 /* all this block does is figure out if it's an
412 error or a success, nothing more */
413 while (z < command->commandlen)
414 {
415 tlv = aim_grabtlvstr(&(command->data[z]));
416 switch(tlv->type)
417 {
418 case 0x0001: /* screen name */
419 aim_logininfo.screen_name = tlv->value;
420 z += 2 + 2 + tlv->length;
421 free(tlv);
422 tlv = NULL;
423 break;
424 case 0x0004: /* error URL */
425 errorurl = tlv->value;
426 z += 2 + 2 + tlv->length;
427 free(tlv);
428 tlv = NULL;
429 break;
430 case 0x0005: /* BOS IP */
431 aim_logininfo.BOSIP = tlv->value;
432 z += 2 + 2 + tlv->length;
433 free(tlv);
434 tlv = NULL;
435 break;
436 case 0x0006: /* auth cookie */
437 aim_logininfo.cookie = tlv->value;
438 z += 2 + 2 + tlv->length;
439 free(tlv);
440 tlv=NULL;
441 break;
442 case 0x0011: /* email addy */
443 aim_logininfo.email = tlv->value;
444 z += 2 + 2 + tlv->length;
445 free(tlv);
446 tlv = NULL;
447 break;
448 case 0x0013: /* registration status */
449 aim_logininfo.regstatus = *(tlv->value);
450 z += 2 + 2 + tlv->length;
451 aim_freetlv(&tlv);
452 break;
453 case 0x0008: /* error code */
454 errorcode = *(tlv->value);
455 z += 2 + 2 + tlv->length;
456 aim_freetlv(&tlv);
457 iserror = 1;
458 break;
459 default:
460 z += 2 + 2 + tlv->length;
461 aim_freetlv(&tlv);
462 /* dunno */
463 }
464 }
465
466 if (iserror &&
467 errorurl)
468 {
469 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
470 if (userfunc)
471 return userfunc(command, &aim_logininfo, errorurl, errorcode);
472 return 0;
473 }
474 else if (aim_logininfo.screen_name &&
475 aim_logininfo.cookie && aim_logininfo.BOSIP)
476 {
477 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
478 if (userfunc)
479 return userfunc(command, &aim_logininfo);
480 return 0;
481 }
482 else
483 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
484 }
485
486 if (userfunc)
487 return userfunc(command);
488 printf("handler not available!\n");
489 return 0;
490}
491
492/*
493 * TODO: check for and cure any memory leaks here.
494 */
495int aim_handleredirect_middle(struct command_rx_struct *command, ...)
496{
497 struct aim_tlv_t *tlv = NULL;
498 u_int z = 10;
499 int serviceid = 0x00;
500 char *cookie = NULL;
501 char *ip = NULL;
502 rxcallback_t userfunc = NULL;
503
504 while (z < command->commandlen)
505 {
506 tlv = aim_grabtlvstr(&(command->data[z]));
507 switch(tlv->type)
508 {
509 case 0x000d: /* service id */
510 aim_freetlv(&tlv);
511 /* regrab as an int */
512 tlv = aim_grabtlv(&(command->data[z]));
513 serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
514 z += 2 + 2 + tlv->length;
515 aim_freetlv(&tlv);
516 break;
517 case 0x0005: /* service server IP */
518 ip = tlv->value;
519 z += 2 + 2 + tlv->length;
520 free(tlv);
521 tlv = NULL;
522 break;
523 case 0x0006: /* auth cookie */
524 cookie = tlv->value;
525 z += 2 + 2 + tlv->length;
526 free(tlv);
527 tlv = NULL;
528 break;
529 default:
530 /* dunno */
531 z += 2 + 2 + tlv->length;
532 aim_freetlv(&tlv);
533 }
534 }
535 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
536 if (userfunc)
537 return userfunc(command, serviceid, ip, cookie);
538 return 0;
539}
540
541int aim_parse_unknown(struct command_rx_struct *command, ...)
542{
543 u_int i = 0;
544
545 printf("\nRecieved unknown packet:");
546
547 for (i = 0; i < command->commandlen; i++)
548 {
549 if ((i % 8) == 0)
550 printf("\n\t");
551
552 printf("0x%2x ", command->data[i]);
553 }
554
555 printf("\n\n");
556
557 return 1;
558}
559
560
561/*
562 * aim_parse_generalerrs()
563 *
564 * Middle handler for 0x0001 snac of each family.
565 *
566 */
567int aim_parse_generalerrs(struct command_rx_struct *command, ...)
568{
569 u_short family;
570 u_short subtype;
571 family = (command->data[0] << 8) + command->data[1];
572 subtype = (command->data[2] << 8) + command->data[3];
573
574 switch(family)
575 {
576 default:
577 /* Unknown family */
578 return aim_callhandler_noparam(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
579 }
580
581 return 1;
582}
583
584
585
This page took 0.120004 seconds and 5 git commands to generate.