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