| 241 j += 2; |
238 j += 2; |
| 242 |
239 |
| 243 msg = msgblock+j; |
240 msg = msgblock+j; |
| 244 } |
241 } |
| 245 |
242 |
| 246 if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0006)) || (i = 0)) |
243 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| 247 i = userfunc(sess, command, channel, sn, msg, icbmflags, flag1, flag2); |
244 ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2); |
| 248 |
245 |
| 249 if (msgblock) |
246 if (msgblock) |
| 250 free(msgblock); |
247 free(msgblock); |
| 251 aim_freetlvchain(&tlvlist); |
248 aim_freetlvchain(&tlvlist); |
| 252 |
249 |
| 253 return 0; |
250 return ret; |
| |
251 } |
| |
252 |
| |
253 static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) |
| |
254 { |
| |
255 rxcallback_t userfunc; |
| |
256 int i, j = 0, y = 0, z = 0, ret = 0; |
| |
257 char *msg = NULL; |
| |
258 unsigned long icbmflags = 0; |
| |
259 struct aim_tlv_t *msgblocktlv; |
| |
260 unsigned char *msgblock; |
| |
261 unsigned short flag1, flag2; |
| |
262 int finlen = 0; |
| |
263 unsigned char fingerprint[10]; |
| |
264 unsigned short wastebits; |
| |
265 |
| |
266 /* |
| |
267 * Check Autoresponse status. If it is an autoresponse, |
| |
268 * it will contain a type 0x0004 TLV, with zero length. |
| |
269 */ |
| |
270 if (aim_gettlv(tlvlist, 0x0004, 1)) |
| |
271 icbmflags |= AIM_IMFLAGS_AWAY; |
| |
272 |
| |
273 /* |
| |
274 * Check Ack Request status. |
| |
275 */ |
| |
276 if (aim_gettlv(tlvlist, 0x0003, 1)) |
| |
277 icbmflags |= AIM_IMFLAGS_ACK; |
| |
278 |
| |
279 /* |
| |
280 * Message block. |
| |
281 */ |
| |
282 msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); |
| |
283 if (!msgblocktlv || !(msgblock = msgblocktlv->value)) { |
| |
284 faimdprintf(sess, 0, "icbm: major error! no message block TLV found!\n"); |
| |
285 return 0; |
| |
286 } |
| |
287 |
| |
288 /* |
| |
289 * Extracting the message from the unknown cruft. |
| |
290 * |
| |
291 * This is a bit messy, and I'm not really qualified, |
| |
292 * even as the author, to comment on it. At least |
| |
293 * its not as bad as a while loop shooting into infinity. |
| |
294 * |
| |
295 * "Do you believe in magic?" |
| |
296 * |
| |
297 */ |
| |
298 |
| |
299 wastebits = aimutil_get8(msgblock+j++); |
| |
300 wastebits = aimutil_get8(msgblock+j++); |
| |
301 |
| |
302 y = aimutil_get16(msgblock+j); |
| |
303 j += 2; |
| |
304 for (z = 0; z < y; z++) |
| |
305 wastebits = aimutil_get8(msgblock+j++); |
| |
306 wastebits = aimutil_get8(msgblock+j++); |
| |
307 wastebits = aimutil_get8(msgblock+j++); |
| |
308 |
| |
309 finlen = j; |
| |
310 if (finlen > sizeof(fingerprint)) |
| |
311 finlen = sizeof(fingerprint); |
| |
312 memcpy(fingerprint, msgblocktlv->value, finlen); |
| |
313 |
| |
314 /* |
| |
315 * Message string length, including flag words. |
| |
316 */ |
| |
317 i = aimutil_get16(msgblock+j); |
| |
318 j += 2; |
| |
319 |
| |
320 /* |
| |
321 * Flag words. |
| |
322 * |
| |
323 * Its rumored that these can kick in some funky |
| |
324 * 16bit-wide char stuff that used to really kill |
| |
325 * libfaim. Hopefully the latter is no longer true. |
| |
326 * |
| |
327 * Though someone should investiagte the former. |
| |
328 * |
| |
329 */ |
| |
330 flag1 = aimutil_get16(msgblock+j); |
| |
331 j += 2; |
| |
332 flag2 = aimutil_get16(msgblock+j); |
| |
333 j += 2; |
| |
334 |
| |
335 if (flag1 || flag2) |
| |
336 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); |
| |
337 |
| |
338 /* |
| |
339 * Message string. |
| |
340 */ |
| |
341 i -= 4; |
| |
342 msg = (char *)malloc(i+1); |
| |
343 memcpy(msg, msgblock+j, i); |
| |
344 msg[i] = '\0'; |
| |
345 |
| |
346 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
347 ret = userfunc(sess, rx, channel, userinfo, msg, icbmflags, flag1, flag2, finlen, fingerprint); |
| |
348 |
| |
349 free(msg); |
| |
350 |
| |
351 return ret; |
| |
352 } |
| |
353 |
| |
354 static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) |
| |
355 { |
| |
356 rxcallback_t userfunc; |
| |
357 struct aim_tlv_t *block1; |
| |
358 struct aim_tlvlist_t *list2; |
| |
359 unsigned short reqclass = 0; |
| |
360 unsigned short status = 0; |
| |
361 int ret = 0; |
| |
362 |
| |
363 /* |
| |
364 * There's another block of TLVs embedded in the type 5 here. |
| |
365 */ |
| |
366 block1 = aim_gettlv(tlvlist, 0x0005, 1); |
| |
367 if (!block1 || !block1->value) { |
| |
368 faimdprintf(sess, 0, "no tlv 0x0005 in rendezvous transaction!\n"); |
| |
369 return 0; |
| |
370 } |
| |
371 |
| |
372 /* |
| |
373 * First two bytes represent the status of the connection. |
| |
374 * |
| |
375 * 0 is a request, 2 is an accept |
| |
376 */ |
| |
377 status = aimutil_get16(block1->value+0); |
| |
378 |
| |
379 /* |
| |
380 * Next comes the cookie. Should match the ICBM cookie. |
| |
381 */ |
| |
382 if (memcmp(block1->value+2, cookie, 8) != 0) |
| |
383 faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); |
| |
384 |
| |
385 /* |
| |
386 * The next 16bytes are a capability block so we can |
| |
387 * identify what type of rendezvous this is. |
| |
388 * |
| |
389 * Thanks to Eric Warmenhoven <warmenhoven@linux.com> (of GAIM) |
| |
390 * for pointing some of this out to me. In fact, a lot of |
| |
391 * the client-to-client info comes from the work of the GAIM |
| |
392 * developers. Thanks! |
| |
393 * |
| |
394 * Read off one capability string and we should have it ID'd. |
| |
395 * |
| |
396 */ |
| |
397 reqclass = aim_getcap(sess, block1->value+2+8, 0x10); |
| |
398 if (reqclass == 0x0000) { |
| |
399 faimdprintf(sess, 0, "rend: no ID block\n"); |
| |
400 return 0; |
| |
401 } |
| |
402 |
| |
403 /* |
| |
404 * What follows may be TLVs or nothing, depending on the |
| |
405 * purpose of the message. |
| |
406 * |
| |
407 * Ack packets for instance have nothing more to them. |
| |
408 */ |
| |
409 list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); |
| |
410 |
| |
411 if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { |
| |
412 struct aim_msgcookie_t *cook; |
| |
413 int type; |
| |
414 |
| |
415 type = aim_msgcookie_gettype(reqclass); /* XXX: fix this shitty code */ |
| |
416 |
| |
417 if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { |
| |
418 faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie); |
| |
419 aim_freetlvchain(&list2); |
| |
420 return 0; |
| |
421 } |
| |
422 |
| |
423 if (cook->type == AIM_COOKIETYPE_OFTGET) { |
| |
424 struct aim_filetransfer_priv *ft; |
| |
425 |
| |
426 if (cook->data) { |
| |
427 int errorcode = -1; /* XXX shouldnt this be 0? */ |
| |
428 |
| |
429 ft = (struct aim_filetransfer_priv *)cook->data; |
| |
430 |
| |
431 if(status != 0x0002) { |
| |
432 if (aim_gettlv(list2, 0x000b, 1)) |
| |
433 errorcode = aim_gettlv16(list2, 0x000b, 1); |
| |
434 |
| |
435 /* XXX this should make it up to the client, you know.. */ |
| |
436 if (errorcode) |
| |
437 faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); |
| |
438 } |
| |
439 } else { |
| |
440 faimdprintf(sess, 0, "no data attached to file transfer\n"); |
| |
441 } |
| |
442 } else if (cook->type == AIM_CAPS_VOICE) { |
| |
443 faimdprintf(sess, 0, "voice request cancelled\n"); |
| |
444 } else { |
| |
445 faimdprintf(sess, 0, "unknown cookie cache type %d\n", cook->type); |
| |
446 } |
| |
447 |
| |
448 aim_freetlvchain(&list2); |
| |
449 |
| |
450 return 1; |
| |
451 } |
| |
452 |
| |
453 /* |
| |
454 * The rest of the handling depends on what type it is. |
| |
455 */ |
| |
456 if (reqclass & AIM_CAPS_BUDDYICON) { |
| |
457 |
| |
458 /* XXX implement this (its in ActiveBuddy...) */ |
| |
459 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
460 ret = userfunc(sess, rx, channel, reqclass, userinfo); |
| |
461 |
| |
462 } else if (reqclass & AIM_CAPS_VOICE) { |
| |
463 struct aim_msgcookie_t *cachedcook; |
| |
464 |
| |
465 faimdprintf(sess, 0, "rend: voice!\n"); |
| |
466 |
| |
467 if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) { |
| |
468 aim_freetlvchain(&list2); |
| |
469 return 0; |
| |
470 } |
| |
471 |
| |
472 memcpy(cachedcook->cookie, cookie, 8); |
| |
473 cachedcook->type = AIM_COOKIETYPE_OFTVOICE; |
| |
474 cachedcook->data = NULL; |
| |
475 |
| |
476 if (aim_cachecookie(sess, cachedcook) == -1) |
| |
477 faimdprintf(sess, 0, "ERROR caching message cookie\n"); |
| |
478 |
| |
479 /* XXX: implement all this */ |
| |
480 |
| |
481 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
482 ret = userfunc(sess, rx, channel, reqclass, &userinfo); |
| |
483 |
| |
484 } else if ((reqclass & AIM_CAPS_IMIMAGE) || |
| |
485 (reqclass & AIM_CAPS_BUDDYICON)) { |
| |
486 char ip[30]; |
| |
487 struct aim_directim_priv *priv; |
| |
488 |
| |
489 memset(ip, 0, sizeof(ip)); |
| |
490 |
| |
491 if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { |
| |
492 struct aim_tlv_t *iptlv, *porttlv; |
| |
493 |
| |
494 iptlv = aim_gettlv(list2, 0x0003, 1); |
| |
495 porttlv = aim_gettlv(list2, 0x0005, 1); |
| |
496 |
| |
497 snprintf(ip, 30, "%d.%d.%d.%d:%d", |
| |
498 aimutil_get8(iptlv->value+0), |
| |
499 aimutil_get8(iptlv->value+1), |
| |
500 aimutil_get8(iptlv->value+2), |
| |
501 aimutil_get8(iptlv->value+3), |
| |
502 4443 /*aimutil_get16(porttlv->value)*/); |
| |
503 } |
| |
504 |
| |
505 faimdprintf(sess, 0, "rend: directIM request from %s (%s)\n", |
| |
506 userinfo->sn, ip); |
| |
507 |
| |
508 /* |
| |
509 * XXX: there are a couple of different request packets for |
| |
510 * different things |
| |
511 */ |
| |
512 |
| |
513 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); |
| |
514 memcpy(priv->ip, ip, sizeof(priv->ip)); |
| |
515 memcpy(priv->sn, userinfo->sn, sizeof(priv->sn)); |
| |
516 memcpy(priv->cookie, cookie, sizeof(priv->cookie)); |
| |
517 |
| |
518 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
519 ret = userfunc(sess, rx, channel, reqclass, userinfo, priv); |
| |
520 |
| |
521 } else if (reqclass & AIM_CAPS_CHAT) { |
| |
522 struct aim_tlv_t *miscinfo; |
| |
523 struct aim_chat_roominfo roominfo; |
| |
524 char *msg=NULL,*encoding=NULL,*lang=NULL; |
| |
525 |
| |
526 miscinfo = aim_gettlv(list2, 0x2711, 1); |
| |
527 aim_chat_readroominfo(miscinfo->value, &roominfo); |
| |
528 |
| |
529 if (aim_gettlv(list2, 0x000c, 1)) |
| |
530 msg = aim_gettlv_str(list2, 0x000c, 1); |
| |
531 |
| |
532 if (aim_gettlv(list2, 0x000d, 1)) |
| |
533 encoding = aim_gettlv_str(list2, 0x000d, 1); |
| |
534 |
| |
535 if (aim_gettlv(list2, 0x000e, 1)) |
| |
536 lang = aim_gettlv_str(list2, 0x000e, 1); |
| |
537 |
| |
538 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
539 ret = userfunc(sess, rx, channel, reqclass, userinfo, &roominfo, msg, encoding?encoding+1:NULL, lang?lang+1:NULL); |
| |
540 |
| |
541 free(roominfo.name); |
| |
542 free(msg); |
| |
543 free(encoding); |
| |
544 free(lang); |
| |
545 |
| |
546 } else if (reqclass & AIM_CAPS_GETFILE) { |
| |
547 char ip[30]; |
| |
548 struct aim_msgcookie_t *cachedcook; |
| |
549 struct aim_tlv_t *miscinfo; |
| |
550 struct aim_tlv_t *iptlv, *porttlv; |
| |
551 |
| |
552 memset(ip, 0, 30); |
| |
553 |
| |
554 if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { |
| |
555 aim_freetlvchain(&list2); |
| |
556 return 0; |
| |
557 } |
| |
558 |
| |
559 if (!(miscinfo = aim_gettlv(list2, 0x2711, 1)) || |
| |
560 !(iptlv = aim_gettlv(list2, 0x0003, 1)) || |
| |
561 !(porttlv = aim_gettlv(list2, 0x0005, 1))) { |
| |
562 faimdprintf(sess, 0, "rend: badly damaged file get request from %s...\n", userinfo->sn); |
| |
563 aim_cookie_free(sess, cachedcook); |
| |
564 aim_freetlvchain(&list2); |
| |
565 return 0; |
| |
566 } |
| |
567 |
| |
568 snprintf(ip, 30, "%d.%d.%d.%d:%d", |
| |
569 aimutil_get8(iptlv->value+0), |
| |
570 aimutil_get8(iptlv->value+1), |
| |
571 aimutil_get8(iptlv->value+2), |
| |
572 aimutil_get8(iptlv->value+3), |
| |
573 aimutil_get16(porttlv->value)); |
| |
574 |
| |
575 faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo->sn, ip); |
| |
576 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
577 ret = userfunc(sess, rx, channel, reqclass, userinfo, ip, cookie); |
| |
578 |
| |
579 } else if (reqclass & AIM_CAPS_SENDFILE) { |
| |
580 #if 0 |
| |
581 char ip[30]; |
| |
582 struct aim_msgcookie_t *cachedcook; |
| |
583 struct aim_tlv_t *miscinfo; |
| |
584 struct aim_tlv_t *iptlv, *porttlv; |
| |
585 |
| |
586 memset(ip, 0, 30); |
| |
587 |
| |
588 if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { |
| |
589 aim_freetlvchain(&list2); |
| |
590 return 0; |
| |
591 } |
| |
592 |
| |
593 if (!(miscinfo = aim_gettlv(list2, 0x2711, 1)) || |
| |
594 !(iptlv = aim_gettlv(list2, 0x0003, 1)) || |
| |
595 !(porttlv = aim_gettlv(list2, 0x0005, 1))) { |
| |
596 faimdprintf(sess, 0, "rend: badly damaged file get request from %s...\n", userinfo->sn); |
| |
597 aim_cookie_free(sess, cachedcook); |
| |
598 aim_freetlvchain(&list2); |
| |
599 return 0; |
| |
600 } |
| |
601 |
| |
602 snprintf(ip, 30, "%d.%d.%d.%d:%d", |
| |
603 aimutil_get8(iptlv->value+0), |
| |
604 aimutil_get8(iptlv->value+1), |
| |
605 aimutil_get8(iptlv->value+2), |
| |
606 aimutil_get8(iptlv->value+3), |
| |
607 aimutil_get16(porttlv->value)); |
| |
608 |
| |
609 if (aim_gettlv(list2, 0x000c, 1)) |
| |
610 desc = aim_gettlv_str(list2, 0x000c, 1); |
| |
611 |
| |
612 faimdprintf(sess, 0, "rend: file transfer request from %s for %s: %s (%s)\n", |
| |
613 userinfo->sn, miscinfo->value+8, |
| |
614 desc, ip); |
| |
615 |
| |
616 memcpy(cachedcook->cookie, cookie, 8); |
| |
617 |
| |
618 ft = malloc(sizeof(struct aim_filetransfer_priv)); |
| |
619 strncpy(ft->sn, userinfo.sn, sizeof(ft->sn)); |
| |
620 strncpy(ft->ip, ip, sizeof(ft->ip)); |
| |
621 strncpy(ft->fh.name, miscinfo->value+8, sizeof(ft->fh.name)); |
| |
622 cachedcook->type = AIM_COOKIETYPE_OFTSEND; |
| |
623 cachedcook->data = ft; |
| |
624 |
| |
625 if (aim_cachecookie(sess, cachedcook) == -1) |
| |
626 faimdprintf(sess, 0, "ERROR caching message cookie\n"); |
| |
627 |
| |
628 aim_accepttransfer(sess, rx->conn, ft->sn, cookie, AIM_CAPS_SENDFILE); |
| |
629 |
| |
630 if (desc) |
| |
631 free(desc); |
| |
632 |
| |
633 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
634 ret = userfunc(sess, rx, channel, reqclass, userinfo); |
| |
635 |
| |
636 #endif |
| |
637 } else |
| |
638 faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", reqclass); |
| |
639 |
| |
640 aim_freetlvchain(&list2); |
| |
641 |
| |
642 return ret; |
| 254 } |
643 } |
| 255 |
644 |
| 256 /* |
645 /* |
| 257 * It can easily be said that parsing ICBMs is THE single |
646 * It can easily be said that parsing ICBMs is THE single |
| 258 * most difficult thing to do in the in AIM protocol. In |
647 * most difficult thing to do in the in AIM protocol. In |
| 326 * That also means that TLV types can be duplicated between the |
707 * That also means that TLV types can be duplicated between the |
| 327 * userinfo block and the rest of the message, however there should |
708 * userinfo block and the rest of the message, however there should |
| 328 * never be two TLVs of the same type in one block. |
709 * never be two TLVs of the same type in one block. |
| 329 * |
710 * |
| 330 */ |
711 */ |
| 331 i += aim_extractuserinfo(sess, command->data+i, &userinfo); |
712 i += aim_extractuserinfo(sess, data+i, &userinfo); |
| 332 |
713 |
| 333 /* |
714 /* |
| 334 * Read block of TLVs (not including the userinfo data). All |
715 * Read block of TLVs (not including the userinfo data). All |
| 335 * further data is derived from what is parsed here. |
716 * further data is derived from what is parsed here. |
| 336 */ |
717 */ |
| 337 tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); |
718 tlvlist = aim_readtlvchain(data+i, datalen-i); |
| 338 |
719 |
| 339 /* |
720 /* |
| 340 * From here on, its depends on what channel we're on. |
721 * From here on, its depends on what channel we're on. |
| 341 */ |
722 */ |
| 342 if (channel == 1) |
723 if (channel == 1) |
| 343 { |
724 ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); |
| 344 u_int j = 0, y = 0, z = 0; |
|
| 345 char *msg = NULL; |
|
| 346 u_int icbmflags = 0; |
|
| 347 struct aim_tlv_t *msgblocktlv; |
|
| 348 u_char *msgblock; |
|
| 349 u_short flag1,flag2; |
|
| 350 int finlen = 0; |
|
| 351 unsigned char fingerprint[10]; |
|
| 352 u_short wastebits; |
|
| 353 |
|
| 354 /* |
|
| 355 * Check Autoresponse status. If it is an autoresponse, |
|
| 356 * it will contain a type 0x0004 TLV, with zero length. |
|
| 357 */ |
|
| 358 if (aim_gettlv(tlvlist, 0x0004, 1)) |
|
| 359 icbmflags |= AIM_IMFLAGS_AWAY; |
|
| 360 |
|
| 361 /* |
|
| 362 * Check Ack Request status. |
|
| 363 */ |
|
| 364 if (aim_gettlv(tlvlist, 0x0003, 1)) |
|
| 365 icbmflags |= AIM_IMFLAGS_ACK; |
|
| 366 |
|
| 367 /* |
|
| 368 * Message block. |
|
| 369 */ |
|
| 370 msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); |
|
| 371 if (!msgblocktlv || !msgblocktlv->value) { |
|
| 372 faimdprintf(sess, 0, "icbm: major error! no message block TLV found!\n"); |
|
| 373 aim_freetlvchain(&tlvlist); |
|
| 374 return 1; |
|
| 375 } |
|
| 376 |
|
| 377 /* |
|
| 378 * Extracting the message from the unknown cruft. |
|
| 379 * |
|
| 380 * This is a bit messy, and I'm not really qualified, |
|
| 381 * even as the author, to comment on it. At least |
|
| 382 * its not as bad as a while loop shooting into infinity. |
|
| 383 * |
|
| 384 * "Do you believe in magic?" |
|
| 385 * |
|
| 386 */ |
|
| 387 msgblock = msgblocktlv->value; |
|
| 388 j = 0; |
|
| 389 |
|
| 390 wastebits = aimutil_get8(msgblock+j++); |
|
| 391 wastebits = aimutil_get8(msgblock+j++); |
|
| 392 |
|
| 393 y = aimutil_get16(msgblock+j); |
|
| 394 j += 2; |
|
| 395 for (z = 0; z < y; z++) |
|
| 396 wastebits = aimutil_get8(msgblock+j++); |
|
| 397 wastebits = aimutil_get8(msgblock+j++); |
|
| 398 wastebits = aimutil_get8(msgblock+j++); |
|
| 399 |
|
| 400 finlen = j; |
|
| 401 if (finlen > sizeof(fingerprint)) |
|
| 402 finlen = sizeof(fingerprint); |
|
| 403 memcpy(fingerprint, msgblocktlv->value, finlen); |
|
| 404 |
|
| 405 /* |
|
| 406 * Message string length, including flag words. |
|
| 407 */ |
|
| 408 i = aimutil_get16(msgblock+j); |
|
| 409 j += 2; |
|
| 410 |
|
| 411 /* |
|
| 412 * Flag words. |
|
| 413 * |
|
| 414 * Its rumored that these can kick in some funky |
|
| 415 * 16bit-wide char stuff that used to really kill |
|
| 416 * libfaim. Hopefully the latter is no longer true. |
|
| 417 * |
|
| 418 * Though someone should investiagte the former. |
|
| 419 * |
|
| 420 */ |
|
| 421 flag1 = aimutil_get16(msgblock+j); |
|
| 422 j += 2; |
|
| 423 flag2 = aimutil_get16(msgblock+j); |
|
| 424 j += 2; |
|
| 425 |
|
| 426 if (flag1 || flag2) |
|
| 427 faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); |
|
| 428 |
|
| 429 /* |
|
| 430 * Message string. |
|
| 431 */ |
|
| 432 i -= 4; |
|
| 433 msg = (char *)malloc(i+1); |
|
| 434 memcpy(msg, msgblock+j, i); |
|
| 435 msg[i] = '\0'; |
|
| 436 |
|
| 437 /* |
|
| 438 * Call client. |
|
| 439 */ |
|
| 440 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 441 if (userfunc) |
|
| 442 i = userfunc(sess, command, channel, &userinfo, msg, icbmflags, flag1, flag2, finlen, fingerprint); |
|
| 443 else |
|
| 444 i = 0; |
|
| 445 |
|
| 446 free(msg); |
|
| 447 } |
|
| 448 else if (channel == 0x0002) |
725 else if (channel == 0x0002) |
| 449 { |
726 ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); |
| 450 struct aim_tlv_t *block1; |
|
| 451 struct aim_tlvlist_t *list2; |
|
| 452 unsigned short reqclass = 0; |
|
| 453 unsigned short status = 0; |
|
| 454 |
|
| 455 /* |
|
| 456 * There's another block of TLVs embedded in the type 5 here. |
|
| 457 */ |
|
| 458 block1 = aim_gettlv(tlvlist, 0x0005, 1); |
|
| 459 if (!block1) { |
|
| 460 faimdprintf(sess, 0, "no tlv 0x0005 in rendezvous transaction!\n"); |
|
| 461 aim_freetlvchain(&tlvlist); |
|
| 462 return 1; /* major problem */ |
|
| 463 } |
|
| 464 |
|
| 465 /* |
|
| 466 * First two bytes represent the status of the connection. |
|
| 467 * |
|
| 468 * 0 is a request, 2 is an accept |
|
| 469 */ |
|
| 470 status = aimutil_get16(block1->value+0); |
|
| 471 |
|
| 472 /* |
|
| 473 * Next comes the cookie. Should match the ICBM cookie. |
|
| 474 */ |
|
| 475 if (memcmp(block1->value+2, cookie, 8) != 0) |
|
| 476 faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); |
|
| 477 |
|
| 478 /* |
|
| 479 * The next 16bytes are a capability block so we can |
|
| 480 * identify what type of rendezvous this is. |
|
| 481 * |
|
| 482 * Thanks to Eric Warmenhoven <warmenhoven@linux.com> (of GAIM) |
|
| 483 * for pointing some of this out to me. In fact, a lot of |
|
| 484 * the client-to-client info comes from the work of the GAIM |
|
| 485 * developers. Thanks! |
|
| 486 * |
|
| 487 * Read off one capability string and we should have it ID'd. |
|
| 488 * |
|
| 489 */ |
|
| 490 reqclass = aim_getcap(sess, block1->value+2+8, 0x10); |
|
| 491 if (reqclass == 0x0000) { |
|
| 492 faimdprintf(sess, 0, "rend: no ID block\n"); |
|
| 493 aim_freetlvchain(&tlvlist); |
|
| 494 return 1; |
|
| 495 } |
|
| 496 |
|
| 497 /* |
|
| 498 * What follows may be TLVs or nothing, depending on the |
|
| 499 * purpose of the message. |
|
| 500 * |
|
| 501 * Ack packets for instance have nothing more to them. |
|
| 502 */ |
|
| 503 list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); |
|
| 504 |
|
| 505 if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { |
|
| 506 struct aim_msgcookie_t *cook; |
|
| 507 int type; |
|
| 508 |
|
| 509 type = aim_msgcookie_gettype(reqclass); /* XXX: fix this shitty code */ |
|
| 510 |
|
| 511 if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { |
|
| 512 faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie); |
|
| 513 aim_freetlvchain(&list2); |
|
| 514 aim_freetlvchain(&tlvlist); |
|
| 515 return 1; |
|
| 516 } |
|
| 517 |
|
| 518 if (cook->type == AIM_COOKIETYPE_OFTGET) { |
|
| 519 struct aim_filetransfer_priv *ft; |
|
| 520 |
|
| 521 if (cook->data) { |
|
| 522 int errorcode = -1; /* XXX shouldnt this be 0? */ |
|
| 523 |
|
| 524 ft = (struct aim_filetransfer_priv *)cook->data; |
|
| 525 |
|
| 526 if(status != 0x0002) { |
|
| 527 if (aim_gettlv(list2, 0x000b, 1)) |
|
| 528 errorcode = aim_gettlv16(list2, 0x000b, 1); |
|
| 529 |
|
| 530 if (errorcode) |
|
| 531 faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); |
|
| 532 } |
|
| 533 } else { |
|
| 534 faimdprintf(sess, 0, "no data attached to file transfer\n"); |
|
| 535 } |
|
| 536 } else if (cook->type == AIM_CAPS_VOICE) { |
|
| 537 faimdprintf(sess, 0, "voice request cancelled\n"); |
|
| 538 } else { |
|
| 539 faimdprintf(sess, 0, "unknown cookie cache type %d\n", cook->type); |
|
| 540 } |
|
| 541 |
|
| 542 if (list2) |
|
| 543 aim_freetlvchain(&list2); |
|
| 544 aim_freetlvchain(&tlvlist); |
|
| 545 return 1; |
|
| 546 } |
|
| 547 |
|
| 548 /* |
|
| 549 * The rest of the handling depends on what type it is. |
|
| 550 */ |
|
| 551 if (reqclass & AIM_CAPS_BUDDYICON) { |
|
| 552 |
|
| 553 /* |
|
| 554 * Call client. |
|
| 555 */ |
|
| 556 #if 0 |
|
| 557 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 558 if (userfunc || (i = 0)) |
|
| 559 i = userfunc(sess, |
|
| 560 command, |
|
| 561 channel, |
|
| 562 reqclass, |
|
| 563 &userinfo, |
|
| 564 ip, |
|
| 565 cookie); |
|
| 566 #endif |
|
| 567 |
|
| 568 } else if (reqclass & AIM_CAPS_VOICE) { |
|
| 569 struct aim_msgcookie_t *cachedcook; |
|
| 570 |
|
| 571 faimdprintf(sess, 0, "rend: voice!\n"); |
|
| 572 |
|
| 573 if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) |
|
| 574 return 1; |
|
| 575 |
|
| 576 memcpy(cachedcook->cookie, cookie, 8); |
|
| 577 cachedcook->type = AIM_COOKIETYPE_OFTVOICE; |
|
| 578 cachedcook->data = NULL; |
|
| 579 |
|
| 580 if (aim_cachecookie(sess, cachedcook) == -1) |
|
| 581 faimdprintf(sess, 0, "ERROR caching message cookie\n"); |
|
| 582 |
|
| 583 /* XXX: implement all this */ |
|
| 584 |
|
| 585 /* |
|
| 586 * Call client. |
|
| 587 */ |
|
| 588 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 589 if (userfunc || (i = 0)) { |
|
| 590 i = userfunc(sess, command, channel, reqclass, &userinfo); |
|
| 591 } |
|
| 592 } else if ((reqclass & AIM_CAPS_IMIMAGE) || (reqclass & AIM_CAPS_BUDDYICON)) { |
|
| 593 char ip[30]; |
|
| 594 struct aim_directim_priv *priv; |
|
| 595 |
|
| 596 memset(ip, 0, 30); |
|
| 597 |
|
| 598 if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { |
|
| 599 struct aim_tlv_t *iptlv, *porttlv; |
|
| 600 |
|
| 601 iptlv = aim_gettlv(list2, 0x0003, 1); |
|
| 602 porttlv = aim_gettlv(list2, 0x0005, 1); |
|
| 603 |
|
| 604 snprintf(ip, 30, "%d.%d.%d.%d:%d", |
|
| 605 aimutil_get8(iptlv->value+0), |
|
| 606 aimutil_get8(iptlv->value+1), |
|
| 607 aimutil_get8(iptlv->value+2), |
|
| 608 aimutil_get8(iptlv->value+3), |
|
| 609 4443 /*aimutil_get16(porttlv->value)*/); |
|
| 610 } |
|
| 611 |
|
| 612 faimdprintf(sess, 0, "rend: directIM request from %s (%s)\n", |
|
| 613 userinfo.sn, ip); |
|
| 614 |
|
| 615 /* XXX: there are a couple of different request packets for |
|
| 616 * different things */ |
|
| 617 |
|
| 618 priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); |
|
| 619 memcpy(priv->ip, ip, sizeof(priv->ip)); |
|
| 620 memcpy(priv->sn, userinfo.sn, sizeof(priv->sn)); |
|
| 621 memcpy(priv->cookie, cookie, sizeof(priv->cookie)); |
|
| 622 |
|
| 623 /* |
|
| 624 * Call client. |
|
| 625 */ |
|
| 626 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 627 if (userfunc || (i = 0)) |
|
| 628 i = userfunc(sess, |
|
| 629 command, |
|
| 630 channel, |
|
| 631 reqclass, |
|
| 632 &userinfo, priv); |
|
| 633 |
|
| 634 } else if (reqclass & AIM_CAPS_CHAT) { |
|
| 635 struct aim_tlv_t *miscinfo; |
|
| 636 struct aim_chat_roominfo roominfo; |
|
| 637 char *msg=NULL,*encoding=NULL,*lang=NULL; |
|
| 638 |
|
| 639 miscinfo = aim_gettlv(list2, 0x2711, 1); |
|
| 640 aim_chat_readroominfo(miscinfo->value, &roominfo); |
|
| 641 |
|
| 642 if (aim_gettlv(list2, 0x000c, 1)) |
|
| 643 msg = aim_gettlv_str(list2, 0x000c, 1); |
|
| 644 |
|
| 645 if (aim_gettlv(list2, 0x000d, 1)) |
|
| 646 encoding = aim_gettlv_str(list2, 0x000d, 1); |
|
| 647 |
|
| 648 if (aim_gettlv(list2, 0x000e, 1)) |
|
| 649 lang = aim_gettlv_str(list2, 0x000e, 1); |
|
| 650 |
|
| 651 /* |
|
| 652 * Call client. |
|
| 653 */ |
|
| 654 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 655 if (userfunc || (i = 0)) |
|
| 656 i = userfunc(sess, |
|
| 657 command, |
|
| 658 channel, |
|
| 659 reqclass, |
|
| 660 &userinfo, |
|
| 661 &roominfo, |
|
| 662 msg, |
|
| 663 encoding?encoding+1:NULL, |
|
| 664 lang?lang+1:NULL); |
|
| 665 free(roominfo.name); |
|
| 666 free(msg); |
|
| 667 free(encoding); |
|
| 668 free(lang); |
|
| 669 } else if (reqclass & AIM_CAPS_GETFILE) { |
|
| 670 char ip[30]; |
|
| 671 struct aim_msgcookie_t *cachedcook; |
|
| 672 struct aim_tlv_t *miscinfo; |
|
| 673 |
|
| 674 if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) |
|
| 675 return 0; |
|
| 676 |
|
| 677 memset(ip, 0, 30); |
|
| 678 |
|
| 679 if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) { |
|
| 680 aim_cookie_free(sess, cachedcook); |
|
| 681 return 0; |
|
| 682 } |
|
| 683 |
|
| 684 if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { |
|
| 685 struct aim_tlv_t *iptlv, *porttlv; |
|
| 686 |
|
| 687 if (!(iptlv = aim_gettlv(list2, 0x0003, 1)) || !(porttlv = aim_gettlv(list2, 0x0005, 1))) { |
|
| 688 aim_cookie_free(sess, cachedcook); |
|
| 689 return 0; |
|
| 690 } |
|
| 691 |
|
| 692 snprintf(ip, 30, "%d.%d.%d.%d:%d", |
|
| 693 aimutil_get8(iptlv->value+0), |
|
| 694 aimutil_get8(iptlv->value+1), |
|
| 695 aimutil_get8(iptlv->value+2), |
|
| 696 aimutil_get8(iptlv->value+3), |
|
| 697 aimutil_get16(porttlv->value)); |
|
| 698 } |
|
| 699 |
|
| 700 faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo.sn, ip); |
|
| 701 |
|
| 702 /* |
|
| 703 * Call client. |
|
| 704 */ |
|
| 705 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 706 if (userfunc || (i = 0)) |
|
| 707 i = userfunc(sess, |
|
| 708 command, |
|
| 709 channel, |
|
| 710 reqclass, |
|
| 711 &userinfo, |
|
| 712 ip, |
|
| 713 cookie); |
|
| 714 |
|
| 715 } else if (reqclass & AIM_CAPS_SENDFILE) { |
|
| 716 #if 0 |
|
| 717 char ip[30]; |
|
| 718 char *desc = NULL; |
|
| 719 struct aim_msgcookie_t *cachedcook; |
|
| 720 struct aim_filetransfer_priv *ft; |
|
| 721 struct aim_tlv_t *miscinfo; |
|
| 722 |
|
| 723 memset(ip, 0, sizeof(ip)); |
|
| 724 |
|
| 725 if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) |
|
| 726 return 0; |
|
| 727 |
|
| 728 if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0003, 1)) { |
|
| 729 struct aim_tlv_t *iptlv, *porttlv; |
|
| 730 |
|
| 731 iptlv = aim_gettlv(list2, 0x0003, 1); |
|
| 732 porttlv = aim_gettlv(list2, 0x0005, 1); |
|
| 733 |
|
| 734 snprintf(ip, sizeof(ip)-1, "%d.%d.%d.%d:%d", |
|
| 735 aimutil_get8(iptlv->value+0), |
|
| 736 aimutil_get8(iptlv->value+1), |
|
| 737 aimutil_get8(iptlv->value+2), |
|
| 738 aimutil_get8(iptlv->value+3), |
|
| 739 aimutil_get16(porttlv->value)); |
|
| 740 } |
|
| 741 |
|
| 742 if (aim_gettlv(list2, 0x000c, 1)) { |
|
| 743 desc = aim_gettlv_str(list2, 0x000c, 1); |
|
| 744 } |
|
| 745 |
|
| 746 faimdprintf(sess, 0, "rend: file transfer request from %s for %s: %s (%s)\n", |
|
| 747 userinfo.sn, |
|
| 748 miscinfo->value+8, |
|
| 749 desc, |
|
| 750 ip); |
|
| 751 |
|
| 752 memcpy(cachedcook->cookie, cookie, 8); |
|
| 753 |
|
| 754 ft = malloc(sizeof(struct aim_filetransfer_priv)); |
|
| 755 strncpy(ft->sn, userinfo.sn, sizeof(ft->sn)); |
|
| 756 strncpy(ft->ip, ip, sizeof(ft->ip)); |
|
| 757 strncpy(ft->fh.name, miscinfo->value+8, sizeof(ft->fh.name)); |
|
| 758 cachedcook->type = AIM_COOKIETYPE_OFTSEND; |
|
| 759 cachedcook->data = ft; |
|
| 760 |
|
| 761 if (aim_cachecookie(sess, cachedcook) == -1) |
|
| 762 faimdprintf(sess, 0, "ERROR caching message cookie\n"); |
|
| 763 |
|
| 764 |
|
| 765 aim_accepttransfer(sess, command->conn, ft->sn, cookie, AIM_CAPS_SENDFILE); |
|
| 766 |
|
| 767 if (desc) |
|
| 768 free(desc); |
|
| 769 #endif |
|
| 770 /* |
|
| 771 * Call client. |
|
| 772 */ |
|
| 773 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); |
|
| 774 if (userfunc || (i = 0)) |
|
| 775 i = userfunc(sess, |
|
| 776 command, |
|
| 777 channel, |
|
| 778 reqclass, |
|
| 779 &userinfo); |
|
| 780 } else |
|
| 781 faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", reqclass); |
|
| 782 |
|
| 783 aim_freetlvchain(&list2); |
|
| 784 } |
|
| 785 |
727 |
| 786 /* |
728 /* |
| 787 * Free up the TLV chain. |
729 * Free up the TLV chain. |
| 788 */ |
730 */ |
| 789 aim_freetlvchain(&tlvlist); |
731 aim_freetlvchain(&tlvlist); |
| 790 |
732 |
| 791 |
733 return ret; |
| 792 return i; |
|
| 793 } |
734 } |
| 794 |
735 |
| 795 /* |
736 /* |
| 796 * Possible codes: |
737 * Possible codes: |
| 797 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" |
738 * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" |
| 846 newpacket->lock = 1; |
787 newpacket->lock = 1; |
| 847 |
788 |
| 848 curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid); |
789 curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid); |
| 849 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
790 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
| 850 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000003); |
791 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000003); |
| 851 curbyte += aimutil_put8(newpacket->data+curbyte, 0x1f); |
792 curbyte += aimutil_put16(newpacket->data+curbyte, 0x1f40); |
| 852 curbyte += aimutil_put8(newpacket->data+curbyte, 0x40); |
793 curbyte += aimutil_put16(newpacket->data+curbyte, 0x03e7); |
| 853 curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); |
794 curbyte += aimutil_put16(newpacket->data+curbyte, 0x03e7); |
| 854 curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); |
795 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000000); |
| 855 curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); |
|
| 856 curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); |
|
| 857 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
|
| 858 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
|
| 859 |
796 |
| 860 newpacket->lock = 0; |
797 newpacket->lock = 0; |
| 861 aim_tx_enqueue(sess, newpacket); |
798 aim_tx_enqueue(sess, newpacket); |
| 862 |
799 |
| 863 return (sess->snac_nextid++); |
800 return (sess->snac_nextid++); |
| 864 } |
801 } |
| 865 |
802 |
| 866 faim_internal int aim_parse_msgerror_middle(struct aim_session_t *sess, |
803 static int paraminfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) |
| 867 struct command_rx_struct *command) |
804 { |
| 868 { |
805 unsigned long defflags, minmsginterval; |
| 869 u_long snacid = 0x000000000; |
806 unsigned short maxicbmlen, maxsenderwarn, maxrecverwarn, maxchannel; |
| 870 struct aim_snac_t *snac = NULL; |
807 rxcallback_t userfunc; |
| 871 int ret = 0; |
808 int i = 0; |
| 872 rxcallback_t userfunc = NULL; |
809 |
| 873 char *dest; |
810 maxchannel = aimutil_get16(data+i); |
| 874 unsigned short reason = 0; |
811 i += 2; |
| 875 |
812 |
| 876 /* |
813 defflags = aimutil_get32(data+i); |
| 877 * Get SNAC from packet and look it up |
814 i += 4; |
| 878 * the list of unrepliedto/outstanding |
815 |
| 879 * SNACs. |
816 maxicbmlen = aimutil_get16(data+i); |
| 880 * |
817 i += 2; |
| 881 * After its looked up, the SN that the |
818 |
| 882 * message should've gone to will be |
819 maxsenderwarn = aimutil_get16(data+i); |
| 883 * in the ->data element of the snac struct. |
820 i += 2; |
| 884 * |
821 |
| 885 */ |
822 maxrecverwarn = aimutil_get16(data+i); |
| 886 snacid = aimutil_get32(command->data+6); |
823 i += 2; |
| 887 snac = aim_remsnac(sess, snacid); |
824 |
| 888 |
825 minmsginterval = aimutil_get32(data+i); |
| 889 if (!snac) { |
826 i += 4; |
| 890 faimdprintf(sess, 0, "msgerr: got an ICBM-failed error on an unknown SNAC ID! (%08lx)\n", snacid); |
827 |
| 891 dest = NULL; |
828 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| 892 } else |
829 return userfunc(sess, rx, maxchannel, defflags, maxicbmlen, maxsenderwarn, maxrecverwarn, minmsginterval); |
| 893 dest = snac->data; |
830 |
| 894 |
831 return 0; |
| 895 reason = aimutil_get16(command->data+10); |
832 } |
| 896 |
833 |
| 897 /* |
834 static int missedcall(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) |
| 898 * Call client. |
835 { |
| 899 */ |
836 int i = 0; |
| 900 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0001); |
837 rxcallback_t userfunc; |
| 901 if (userfunc) |
|
| 902 ret = userfunc(sess, command, dest, reason); |
|
| 903 else |
|
| 904 ret = 0; |
|
| 905 |
|
| 906 if (snac) { |
|
| 907 free(snac->data); |
|
| 908 free(snac); |
|
| 909 } |
|
| 910 |
|
| 911 return ret; |
|
| 912 } |
|
| 913 |
|
| 914 |
|
| 915 faim_internal int aim_parse_missedcall(struct aim_session_t *sess, |
|
| 916 struct command_rx_struct *command) |
|
| 917 { |
|
| 918 int i, ret = 1; |
|
| 919 rxcallback_t userfunc = NULL; |
|
| 920 unsigned short channel, nummissed, reason; |
838 unsigned short channel, nummissed, reason; |
| 921 struct aim_userinfo_s userinfo; |
839 struct aim_userinfo_s userinfo; |
| 922 |
840 |
| 923 i = 10; /* Skip SNAC header */ |
|
| 924 |
|
| 925 |
|
| 926 /* |
841 /* |
| 927 * XXX: supposedly, this entire packet can repeat as many times |
842 * XXX: supposedly, this entire packet can repeat as many times |
| 928 * as necessary. Should implement that. |
843 * as necessary. Should implement that. |
| 929 */ |
844 */ |
| 930 |
845 |
| 931 /* |
846 /* |
| 932 * Channel ID. |
847 * Channel ID. |
| 933 */ |
848 */ |
| 934 channel = aimutil_get16(command->data+i); |
849 channel = aimutil_get16(data+i); |
| 935 i += 2; |
850 i += 2; |
| 936 |
851 |
| 937 /* |
852 /* |
| 938 * Extract the standard user info block. |
853 * Extract the standard user info block. |
| 939 */ |
854 */ |
| 940 i += aim_extractuserinfo(sess, command->data+i, &userinfo); |
855 i += aim_extractuserinfo(sess, data+i, &userinfo); |
| 941 |
856 |
| 942 nummissed = aimutil_get16(command->data+i); |
857 nummissed = aimutil_get16(data+i); |
| 943 i += 2; |
858 i += 2; |
| 944 |
859 |
| 945 reason = aimutil_get16(command->data+i); |
860 reason = aimutil_get16(data+i); |
| 946 i += 2; |
861 i += 2; |
| 947 |
862 |
| 948 /* |
863 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| 949 * Call client. |
864 return userfunc(sess, rx, channel, &userinfo, nummissed, reason); |
| 950 */ |
865 |
| 951 userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000a); |
866 return 0; |
| 952 if (userfunc) |
867 } |
| 953 ret = userfunc(sess, command, channel, &userinfo, nummissed, reason); |
868 |
| 954 else |
869 static int msgack(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) |
| 955 ret = 0; |
870 { |
| 956 |
871 rxcallback_t userfunc; |
| 957 return ret; |
872 char sn[MAXSNLEN]; |
| 958 } |
873 unsigned char ck[8]; |
| |
874 unsigned short type; |
| |
875 int i = 0; |
| |
876 unsigned char snlen; |
| |
877 |
| |
878 memcpy(ck, data, 8); |
| |
879 i += 8; |
| |
880 |
| |
881 type = aimutil_get16(data+i); |
| |
882 i += 2; |
| |
883 |
| |
884 snlen = aimutil_get8(data+i); |
| |
885 i++; |
| |
886 |
| |
887 memset(sn, 0, sizeof(sn)); |
| |
888 strncpy(sn, (char *)data+i, snlen); |
| |
889 |
| |
890 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
| |
891 return userfunc(sess, rx, type, sn); |
| |
892 |
| |
893 return 0; |
| |
894 } |
| |
895 |
| |
896 static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) |
| |
897 { |
| |
898 |
| |
899 if (snac->subtype == 0x0005) |
| |
900 return paraminfo(sess, mod, rx, snac, data, datalen); |
| |
901 else if (snac->subtype == 0x0006) |
| |
902 return outgoingim(sess, mod, rx, snac, data, datalen); |
| |
903 else if (snac->subtype == 0x0007) |
| |
904 return incomingim(sess, mod, rx, snac, data, datalen); |
| |
905 else if (snac->subtype == 0x000a) |
| |
906 return missedcall(sess, mod, rx, snac, data, datalen); |
| |
907 else if (snac->subtype == 0x000c) |
| |
908 return msgack(sess, mod, rx, snac, data, datalen); |
| |
909 |
| |
910 return 0; |
| |
911 } |
| |
912 |
| |
913 faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod) |
| |
914 { |
| |
915 |
| |
916 mod->family = 0x0004; |
| |
917 mod->version = 0x0000; |
| |
918 mod->flags = 0; |
| |
919 strncpy(mod->name, "messaging", sizeof(mod->name)); |
| |
920 mod->snachandler = snachandler; |
| |
921 |
| |
922 return 0; |
| |
923 } |