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