| 1 /* |
1 /* |
| 2 * Family 0x0004 - Routines for sending/receiving Instant Messages. |
2 * Family 0x0004 - Routines for sending/receiving Instant Messages. |
| 3 * |
3 * |
| 4 * Note the term ICBM (Inter-Client Basic Message) which blankets |
4 * Note the term ICBM (Inter-Client Basic Message) which blankets |
| 5 * all types of genericly routed through-server messages. Within |
5 * all types of genericly routed through-server messages. Within |
| 6 * the ICBM types (family 4), a channel is defined. Each channel |
6 * the ICBM types (family 4), a channel is defined. Each channel |
| 7 * represents a different type of message. Channel 1 is used for |
7 * represents a different type of message. Channel 1 is used for |
| 8 * what would commonly be called an "instant message". Channel 2 |
8 * what would commonly be called an "instant message". Channel 2 |
| 9 * is used for negotiating "rendezvous". These transactions end in |
9 * is used for negotiating "rendezvous". These transactions end in |
| 10 * something more complex happening, such as a chat invitation, or |
10 * something more complex happening, such as a chat invitation, or |
| 11 * a file transfer. Channel 3 is used for chat messages (not in |
11 * a file transfer. Channel 3 is used for chat messages (not in |
| 12 * the same family as these channels). Channel 4 is used for |
12 * the same family as these channels). Channel 4 is used for |
| 13 * various ICQ messages. Examples are normal messages, URLs, and |
13 * various ICQ messages. Examples are normal messages, URLs, and |
| 14 * old-style authorization. |
14 * old-style authorization. |
| 15 * |
15 * |
| 16 * In addition to the channel, every ICBM contains a cookie. For |
16 * In addition to the channel, every ICBM contains a cookie. For |
| 17 * standard IMs, these are only used for error messages. However, |
17 * standard IMs, these are only used for error messages. However, |
| 18 * the more complex rendezvous messages make suitably more complex |
18 * the more complex rendezvous messages make suitably more complex |
| 19 * use of this field. |
19 * use of this field. |
| 20 * |
20 * |
| |
21 * TODO: Split this up into an im.c file an an icbm.c file. It |
| |
22 * will be beautiful, you'll see. |
| |
23 * |
| |
24 * Need to rename all the mpmsg messages to aim_im_bleh. |
| |
25 * |
| |
26 * Make sure aim_conn_findbygroup is used by all functions. |
| 21 */ |
27 */ |
| 22 |
28 |
| 23 #define FAIM_INTERNAL |
29 #define FAIM_INTERNAL |
| 24 #include <aim.h> |
30 #include <aim.h> |
| 25 |
31 |
| 26 #ifdef _WIN32 |
32 #ifdef _WIN32 |
| 27 #include "win32dep.h" |
33 #include "win32dep.h" |
| 28 #endif |
34 #endif |
| |
35 |
| |
36 /** |
| |
37 * Add a standard ICBM header to the given bstream with the given |
| |
38 * information. |
| |
39 * |
| |
40 * @param bs The bstream to write the ICBM header to. |
| |
41 * @param c c is for cookie, and cookie is for me. |
| |
42 * @param ch The ICBM channel (1 through 4). |
| |
43 * @param sn Null-terminated scrizeen nizame. |
| |
44 * @return The number of bytes written. It's really not useful. |
| |
45 */ |
| |
46 static int aim_im_puticbm(aim_bstream_t *bs, const fu8_t *c, fu16_t ch, const char *sn) |
| |
47 { |
| |
48 aimbs_putraw(bs, c, 8); |
| |
49 aimbs_put16(bs, ch); |
| |
50 aimbs_put8(bs, strlen(sn)); |
| |
51 aimbs_putraw(bs, sn, strlen(sn)); |
| |
52 return 8+2+1+strlen(sn); |
| |
53 } |
| 29 |
54 |
| 30 /* |
55 /* |
| 31 * Takes a msghdr (and a length) and returns a client type |
56 * Takes a msghdr (and a length) and returns a client type |
| 32 * code. Note that this is *only a guess* and has a low likelihood |
57 * code. Note that this is *only a guess* and has a low likelihood |
| 33 * of actually being accurate. |
58 * of actually being accurate. |
| 273 } |
287 } |
| 274 |
288 |
| 275 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) |
289 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) |
| 276 return -ENOMEM; |
290 return -ENOMEM; |
| 277 |
291 |
| 278 /* XXX should be optional */ |
292 /* XXX - should be optional */ |
| 279 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); |
293 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); |
| 280 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
294 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| 281 |
295 |
| 282 /* |
296 /* |
| 283 * Generate a random message cookie |
297 * Generate a random message cookie |
| 284 * |
298 * |
| 285 * We could cache these like we do SNAC IDs. (In fact, it |
299 * We could cache these like we do SNAC IDs. (In fact, it |
| 286 * might be a good idea.) In the message error functions, |
300 * might be a good idea.) In the message error functions, |
| 287 * the 8byte message cookie is returned as well as the |
301 * the 8byte message cookie is returned as well as the |
| 288 * SNAC ID. |
302 * SNAC ID. |
| 289 * |
303 * |
| 290 */ |
304 */ |
| 291 for (i = 0; i < 8; i++) |
305 for (i = 0; i < 8; i++) |
| 292 aimbs_put8(&fr->data, (fu8_t) rand()); |
306 ck[i] = (fu8_t)rand(); |
| 293 |
307 |
| 294 /* |
308 /* ICBM header */ |
| 295 * Channel ID |
309 aim_im_puticbm(&fr->data, ck, 0x0001, args->destsn); |
| 296 */ |
310 |
| 297 aimbs_put16(&fr->data, 0x0001); |
311 /* Message TLV (type 0x0002) */ |
| 298 |
|
| 299 /* |
|
| 300 * Destination SN (prepended with byte length) |
|
| 301 */ |
|
| 302 aimbs_put8(&fr->data, strlen(args->destsn)); |
|
| 303 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); |
|
| 304 |
|
| 305 /* |
|
| 306 * Message TLV (type 2). |
|
| 307 */ |
|
| 308 aimbs_put16(&fr->data, 0x0002); |
312 aimbs_put16(&fr->data, 0x0002); |
| 309 aimbs_put16(&fr->data, msgtlvlen); |
313 aimbs_put16(&fr->data, msgtlvlen); |
| 310 |
314 |
| 311 /* |
315 /* Features TLV (type 0x0501) */ |
| 312 * Features |
316 aimbs_put16(&fr->data, 0x0501); |
| 313 * |
|
| 314 */ |
|
| 315 aimbs_put8(&fr->data, 0x05); |
|
| 316 aimbs_put8(&fr->data, 0x01); |
|
| 317 |
|
| 318 if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { |
317 if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { |
| 319 aimbs_put16(&fr->data, args->featureslen); |
318 aimbs_put16(&fr->data, args->featureslen); |
| 320 aimbs_putraw(&fr->data, args->features, args->featureslen); |
319 aimbs_putraw(&fr->data, args->features, args->featureslen); |
| 321 } else { |
320 } else { |
| 322 aimbs_put16(&fr->data, sizeof(deffeatures)); |
321 aimbs_put16(&fr->data, sizeof(deffeatures)); |
| 324 } |
323 } |
| 325 |
324 |
| 326 if (args->flags & AIM_IMFLAGS_MULTIPART) { |
325 if (args->flags & AIM_IMFLAGS_MULTIPART) { |
| 327 aim_mpmsg_section_t *sec; |
326 aim_mpmsg_section_t *sec; |
| 328 |
327 |
| |
328 /* Insert each message part in a TLV (type 0x0101) */ |
| 329 for (sec = args->mpmsg->parts; sec; sec = sec->next) { |
329 for (sec = args->mpmsg->parts; sec; sec = sec->next) { |
| 330 aimbs_put16(&fr->data, 0x0101); |
330 aimbs_put16(&fr->data, 0x0101); |
| 331 aimbs_put16(&fr->data, sec->datalen + 4); |
331 aimbs_put16(&fr->data, sec->datalen + 4); |
| 332 aimbs_put16(&fr->data, sec->charset); |
332 aimbs_put16(&fr->data, sec->charset); |
| 333 aimbs_put16(&fr->data, sec->charsubset); |
333 aimbs_put16(&fr->data, sec->charsubset); |
| 334 aimbs_putraw(&fr->data, sec->data, sec->datalen); |
334 aimbs_putraw(&fr->data, sec->data, sec->datalen); |
| 335 } |
335 } |
| 336 |
336 |
| 337 } else { |
337 } else { |
| 338 |
338 |
| |
339 /* Insert message text in a TLV (type 0x0101) */ |
| 339 aimbs_put16(&fr->data, 0x0101); |
340 aimbs_put16(&fr->data, 0x0101); |
| 340 |
341 |
| 341 /* |
342 /* Message block length */ |
| 342 * Message block length. |
|
| 343 */ |
|
| 344 aimbs_put16(&fr->data, args->msglen + 0x04); |
343 aimbs_put16(&fr->data, args->msglen + 0x04); |
| 345 |
344 |
| 346 /* |
345 /* Character set */ |
| 347 * Character set. |
|
| 348 */ |
|
| 349 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) { |
346 if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) { |
| 350 |
|
| 351 aimbs_put16(&fr->data, args->charset); |
347 aimbs_put16(&fr->data, args->charset); |
| 352 aimbs_put16(&fr->data, args->charsubset); |
348 aimbs_put16(&fr->data, args->charsubset); |
| 353 |
|
| 354 } else { |
349 } else { |
| 355 if (args->flags & AIM_IMFLAGS_UNICODE) |
350 if (args->flags & AIM_IMFLAGS_UNICODE) |
| 356 aimbs_put16(&fr->data, 0x0002); |
351 aimbs_put16(&fr->data, 0x0002); |
| 357 else if (args->flags & AIM_IMFLAGS_ISO_8859_1) |
352 else if (args->flags & AIM_IMFLAGS_ISO_8859_1) |
| 358 aimbs_put16(&fr->data, 0x0003); |
353 aimbs_put16(&fr->data, 0x0003); |
| 412 aimbs_put16(&fr->data, 0x0000); |
401 aimbs_put16(&fr->data, 0x0000); |
| 413 } |
402 } |
| 414 |
403 |
| 415 aim_tx_enqueue(sess, fr); |
404 aim_tx_enqueue(sess, fr); |
| 416 |
405 |
| |
406 /* Move this to receive aim_flap_nop and send aim_flap_nop */ |
| 417 if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) |
407 if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) |
| 418 aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */ |
408 aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */ |
| 419 |
409 |
| 420 return 0; |
410 return 0; |
| 421 } |
411 } |
| 422 |
412 |
| 423 /* |
413 /* |
| 424 * Simple wrapper for aim_send_im_ext() |
414 * Simple wrapper for aim_im_sendch1_ext() |
| 425 * |
415 * |
| 426 * You cannot use aim_send_im if you need the HASICON flag. You must |
416 * You cannot use aim_send_im if you need the HASICON flag. You must |
| 427 * use aim_send_im_ext directly for that. |
417 * use aim_im_sendch1_ext directly for that. |
| 428 * |
418 * |
| 429 * aim_send_im also cannot be used if you require UNICODE messages, because |
419 * aim_send_im also cannot be used if you require UNICODE messages, because |
| 430 * that requires an explicit message length. Use aim_send_im_ext(). |
420 * that requires an explicit message length. Use aim_im_sendch1_ext(). |
| 431 * |
421 * |
| 432 */ |
422 */ |
| 433 faim_export int aim_send_im(aim_session_t *sess, const char *destsn, fu16_t flags, const char *msg) |
423 faim_export int aim_im_sendch1(aim_session_t *sess, const char *sn, fu16_t flags, const char *msg) |
| 434 { |
424 { |
| 435 struct aim_sendimext_args args; |
425 struct aim_sendimext_args args; |
| 436 |
426 |
| 437 args.destsn = destsn; |
427 args.destsn = sn; |
| 438 args.flags = flags; |
428 args.flags = flags; |
| 439 args.msg = msg; |
429 args.msg = msg; |
| 440 args.msglen = strlen(msg); |
430 args.msglen = strlen(msg); |
| 441 |
431 |
| 442 /* Make these don't get set by accident -- they need aim_send_im_ext */ |
432 /* Make these don't get set by accident -- they need aim_im_sendch1_ext */ |
| 443 args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART); |
433 args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART); |
| 444 |
434 |
| 445 return aim_send_im_ext(sess, &args); |
435 return aim_im_sendch1_ext(sess, &args); |
| 446 } |
436 } |
| 447 |
437 |
| 448 /* |
438 /** |
| 449 * Subtype 0x0006 |
439 * Subtype 0x0006 - Send your icon to a given user. |
| 450 * |
440 * |
| 451 * This is also performance sensitive. (If you can believe it...) |
441 * This is also performance sensitive. (If you can believe it...) |
| 452 * |
442 * |
| 453 */ |
443 */ |
| 454 faim_export int aim_send_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum) |
444 faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum) |
| 455 { |
445 { |
| 456 aim_conn_t *conn; |
446 aim_conn_t *conn; |
| 457 int i; |
|
| 458 fu8_t ck[8]; |
|
| 459 aim_frame_t *fr; |
447 aim_frame_t *fr; |
| 460 aim_snacid_t snacid; |
448 aim_snacid_t snacid; |
| |
449 fu8_t ck[8]; |
| |
450 int i; |
| 461 |
451 |
| 462 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
452 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
| 463 return -EINVAL; |
453 return -EINVAL; |
| 464 |
454 |
| 465 if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) |
455 if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) |
| 466 return -EINVAL; |
456 return -EINVAL; |
| 467 |
457 |
| 468 for (i = 0; i < 8; i++) |
458 for (i = 0; i < 8; i++) |
| 469 aimutil_put8(ck+i, (fu8_t) rand()); |
459 ck[i] = (fu8_t)rand(); |
| 470 |
460 |
| 471 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) |
461 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) |
| 472 return -ENOMEM; |
462 return -ENOMEM; |
| 473 |
463 |
| 474 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
464 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
| 475 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
465 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| 476 |
466 |
| 477 /* |
467 /* ICBM header */ |
| 478 * Cookie |
468 aim_im_puticbm(&fr->data, ck, 0x0002, sn); |
| 479 */ |
|
| 480 aimbs_putraw(&fr->data, ck, 8); |
|
| 481 |
|
| 482 /* |
|
| 483 * Channel (2) |
|
| 484 */ |
|
| 485 aimbs_put16(&fr->data, 0x0002); |
|
| 486 |
|
| 487 /* |
|
| 488 * Dest sn |
|
| 489 */ |
|
| 490 aimbs_put8(&fr->data, strlen(sn)); |
|
| 491 aimbs_putraw(&fr->data, sn, strlen(sn)); |
|
| 492 |
469 |
| 493 /* |
470 /* |
| 494 * TLV t(0005) |
471 * TLV t(0005) |
| 495 * |
472 * |
| 496 * Encompasses everything below. |
473 * Encompasses everything below. |
| 543 * be an exception, since Rendezvous IMs are external of the Oscar core, |
520 * be an exception, since Rendezvous IMs are external of the Oscar core, |
| 544 * and therefore are undefined. Really I just need to think of a good way to |
521 * and therefore are undefined. Really I just need to think of a good way to |
| 545 * make an interface similar to what AOL actually uses. But I'm not using COM. |
522 * make an interface similar to what AOL actually uses. But I'm not using COM. |
| 546 * |
523 * |
| 547 */ |
524 */ |
| 548 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args) |
525 faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args) |
| 549 { |
526 { |
| 550 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */ |
|
| 551 aim_conn_t *conn; |
527 aim_conn_t *conn; |
| 552 int i; |
|
| 553 fu8_t ck[8]; |
|
| 554 aim_frame_t *fr; |
528 aim_frame_t *fr; |
| 555 aim_snacid_t snacid; |
529 aim_snacid_t snacid; |
| 556 int servdatalen; |
530 fu8_t ck[8]; |
| |
531 const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */ |
| |
532 int i, servdatalen; |
| 557 |
533 |
| 558 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
534 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
| 559 return -EINVAL; |
535 return -EINVAL; |
| 560 |
536 |
| 561 if (!args || !args->destsn || !args->rtfmsg) |
537 if (!args || !args->destsn || !args->rtfmsg) |
| 562 return -EINVAL; |
538 return -EINVAL; |
| 563 |
539 |
| 564 servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1; |
540 servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1; |
| 565 |
541 |
| 566 for (i = 0; i < 8; i++) |
542 for (i = 0; i < 8; i++) |
| 567 aimutil_put8(ck+i, (fu8_t) rand()); |
543 ck[i] = (fu8_t)rand(); |
| 568 |
544 |
| 569 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen))) |
545 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen))) |
| 570 return -ENOMEM; |
546 return -ENOMEM; |
| 571 |
547 |
| 572 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
548 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
| 573 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
549 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| 574 |
550 |
| 575 /* |
551 /* ICBM header */ |
| 576 * Cookie |
552 aim_im_puticbm(&fr->data, ck, 0x0002, args->destsn); |
| 577 */ |
553 |
| 578 aimbs_putraw(&fr->data, ck, 8); |
554 /* TLV t(0005) - Encompasses everything below. */ |
| 579 |
|
| 580 /* |
|
| 581 * Channel (2) |
|
| 582 */ |
|
| 583 aimbs_put16(&fr->data, 0x0002); |
|
| 584 |
|
| 585 /* |
|
| 586 * Dest sn |
|
| 587 */ |
|
| 588 aimbs_put8(&fr->data, strlen(args->destsn)); |
|
| 589 aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); |
|
| 590 |
|
| 591 /* |
|
| 592 * TLV t(0005) |
|
| 593 * |
|
| 594 * Encompasses everything below. |
|
| 595 */ |
|
| 596 aimbs_put16(&fr->data, 0x0005); |
555 aimbs_put16(&fr->data, 0x0005); |
| 597 aimbs_put16(&fr->data, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen); |
556 aimbs_put16(&fr->data, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen); |
| 598 |
557 |
| 599 aimbs_put16(&fr->data, 0x0000); |
558 aimbs_put16(&fr->data, 0x0000); |
| 600 aimbs_putraw(&fr->data, ck, 8); |
559 aimbs_putraw(&fr->data, ck, 8); |
| 601 aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY); |
560 aim_putcap(&fr->data, AIM_CAPS_ICQSERVERRELAY); |
| 602 |
561 |
| 603 /* |
562 /* t(000a) l(0002) v(0001) */ |
| 604 * t(000a) l(0002) v(0001) |
|
| 605 */ |
|
| 606 aimbs_put16(&fr->data, 0x000a); |
563 aimbs_put16(&fr->data, 0x000a); |
| 607 aimbs_put16(&fr->data, 0x0002); |
564 aimbs_put16(&fr->data, 0x0002); |
| 608 aimbs_put16(&fr->data, 0x0001); |
565 aimbs_put16(&fr->data, 0x0001); |
| 609 |
566 |
| 610 /* |
567 /* t(000f) l(0000) v() */ |
| 611 * t(000f) l(0000) v() |
|
| 612 */ |
|
| 613 aimbs_put16(&fr->data, 0x000f); |
568 aimbs_put16(&fr->data, 0x000f); |
| 614 aimbs_put16(&fr->data, 0x0000); |
569 aimbs_put16(&fr->data, 0x0000); |
| 615 |
570 |
| 616 /* |
571 /* Service Data TLV */ |
| 617 * Service Data TLV |
|
| 618 */ |
|
| 619 aimbs_put16(&fr->data, 0x2711); |
572 aimbs_put16(&fr->data, 0x2711); |
| 620 aimbs_put16(&fr->data, servdatalen); |
573 aimbs_put16(&fr->data, servdatalen); |
| 621 |
574 |
| 622 aimbs_putle16(&fr->data, 11 + 16 /* 11 + (sizeof CLSID) */); |
575 aimbs_putle16(&fr->data, 11 + 16 /* 11 + (sizeof CLSID) */); |
| 623 aimbs_putle16(&fr->data, 9); |
576 aimbs_putle16(&fr->data, 9); |
| 723 aim_tx_enqueue(sess, fr); |
672 aim_tx_enqueue(sess, fr); |
| 724 |
673 |
| 725 return 0; |
674 return 0; |
| 726 } |
675 } |
| 727 |
676 |
| 728 /* Subtype 0x0006 */ |
677 /** |
| 729 faim_internal int aim_request_sendfile(aim_session_t *sess, const char *sn, const char *filename, fu16_t numfiles, fu32_t totsize, fu8_t *ip, fu16_t port, fu8_t *ckret) |
678 * Subtype 0x0006 - Send an "I want to send you this file" message |
| |
679 * |
| |
680 */ |
| |
681 faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port, const char *filename, fu16_t numfiles, fu32_t totsize) |
| 730 { |
682 { |
| 731 aim_conn_t *conn; |
683 aim_conn_t *conn; |
| 732 int i; |
|
| 733 fu8_t ck[8]; |
|
| 734 aim_frame_t *fr; |
684 aim_frame_t *fr; |
| 735 aim_snacid_t snacid; |
685 aim_snacid_t snacid; |
| 736 struct aim_snac_destructor snacdest; |
686 aim_tlvlist_t *tl=NULL, *subtl=NULL; |
| |
687 fu8_t *ck; |
| |
688 int i; |
| 737 |
689 |
| 738 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
690 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
| 739 return -EINVAL; |
691 return -EINVAL; |
| 740 |
692 |
| 741 if (!sn || !filename) |
693 if (!sn || !filename) |
| 742 return -EINVAL; |
694 return -EINVAL; |
| 743 |
695 |
| 744 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4))) |
696 /* XXX - Should be like "21CBF95" and null terminated */ |
| |
697 ck = (fu8_t *)malloc(8*sizeof(fu8_t)); |
| |
698 for (i = 0; i < 7; i++) |
| |
699 ck[i] = 0x30 + ((fu8_t)rand() % 10); |
| |
700 ck[7] = '\0'; |
| |
701 if (cookie) |
| |
702 memcpy(cookie, ck, 8); |
| |
703 |
| |
704 { /* Create the subTLV chain */ |
| |
705 fu8_t *buf; |
| |
706 int buflen; |
| |
707 aim_bstream_t bs; |
| |
708 |
| |
709 aim_addtlvtochain16(&subtl, 0x000a, 0x0001); |
| |
710 aim_addtlvtochain_noval(&subtl, 0x000f); |
| |
711 /* aim_addtlvtochain_raw(&subtl, 0x000e, 2, "en"); |
| |
712 aim_addtlvtochain_raw(&subtl, 0x000d, 8, "us-ascii"); |
| |
713 aim_addtlvtochain_raw(&subtl, 0x000c, 24, "Please accept this file."); */ |
| |
714 aim_addtlvtochain_raw(&subtl, 0x0003, 4, ip); |
| |
715 aim_addtlvtochain16(&subtl, 0x0005, port); |
| |
716 |
| |
717 /* TLV t(2711) */ |
| |
718 buflen = 2+2+4+63; |
| |
719 buf = malloc(buflen); |
| |
720 aim_bstream_init(&bs, buf, buflen); |
| |
721 aimbs_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001); |
| |
722 aimbs_put16(&bs, numfiles); |
| |
723 aimbs_put32(&bs, totsize); |
| |
724 |
| |
725 /* Filename is a fixed size of 63 bytes, so pad with 0's */ |
| |
726 aimbs_putraw(&bs, filename, strlen(filename)); |
| |
727 for (i=0; i<(63-strlen(filename)); i++) |
| |
728 aimbs_put8(&bs, 0x00); |
| |
729 |
| |
730 aim_addtlvtochain_raw(&subtl, 0x2711, bs.len, bs.data); |
| |
731 free(buf); |
| |
732 } |
| |
733 |
| |
734 { /* Create the main TLV chain */ |
| |
735 fu8_t *buf; |
| |
736 int buflen; |
| |
737 aim_bstream_t bs; |
| |
738 |
| |
739 /* TLV t(0005) - Encompasses everything from above. Gee. */ |
| |
740 buflen = 2+8+16+aim_sizetlvchain(&subtl); |
| |
741 buf = malloc(buflen); |
| |
742 aim_bstream_init(&bs, buf, buflen); |
| |
743 aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE); |
| |
744 aimbs_putraw(&bs, ck, 8); |
| |
745 aim_putcap(&bs, AIM_CAPS_SENDFILE); |
| |
746 aim_writetlvchain(&bs, &subtl); |
| |
747 aim_freetlvchain(&subtl); |
| |
748 aim_addtlvtochain_raw(&tl, 0x0005, bs.len, bs.data); |
| |
749 free(buf); |
| |
750 |
| |
751 /* TLV t(0003) - Request an ack */ |
| |
752 aim_addtlvtochain_noval(&tl, 0x0003); |
| |
753 } |
| |
754 |
| |
755 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + aim_sizetlvchain(&tl)))) |
| 745 return -ENOMEM; |
756 return -ENOMEM; |
| 746 |
757 |
| 747 for (i = 0; i < 7; i++) |
758 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, ck, sizeof(ck)); |
| 748 aimutil_put8(ck+i, 0x30 + ((fu8_t) rand() % 10)); |
|
| 749 ck[7] = '\0'; |
|
| 750 |
|
| 751 if (ckret) |
|
| 752 memcpy(ckret, ck, 8); |
|
| 753 |
|
| 754 /* Fill in the snac destructor so we know if the request |
|
| 755 * times out. Use the cookie in the data field, so we |
|
| 756 * know what request to cancel if there is an error. |
|
| 757 */ |
|
| 758 snacdest.data = malloc(8); |
|
| 759 memcpy(snacdest.data, ck, 8); |
|
| 760 snacdest.conn = conn; |
|
| 761 snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, &snacdest, sizeof(snacdest)); |
|
| 762 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
759 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| 763 |
760 |
| 764 /* |
761 /* ICBM header */ |
| 765 * Cookie |
762 aim_im_puticbm(&fr->data, ck, 0x0002, sn); |
| 766 */ |
763 |
| 767 aimbs_putraw(&fr->data, ck, 8); |
764 /* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */ |
| 768 |
765 aim_writetlvchain(&fr->data, &tl); |
| 769 /* |
766 aim_freetlvchain(&tl); |
| 770 * Channel (2) |
767 |
| 771 */ |
768 aim_tx_enqueue(sess, fr); |
| 772 aimbs_put16(&fr->data, 0x0002); |
769 |
| 773 |
770 return 0; |
| 774 /* |
771 } |
| 775 * Dest sn |
772 |
| 776 */ |
773 /** |
| 777 aimbs_put8(&fr->data, strlen(sn)); |
774 * Subtype 0x0006 - Send an "I will accept this file" message? |
| 778 aimbs_putraw(&fr->data, sn, strlen(sn)); |
775 * |
| 779 |
776 * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE) |
| 780 /* |
777 */ |
| 781 * TLV t(0005) |
778 faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid) |
| 782 * |
779 { |
| 783 * Encompasses everything below. Gee. |
780 aim_conn_t *conn; |
| 784 */ |
781 aim_frame_t *fr; |
| |
782 aim_snacid_t snacid; |
| |
783 |
| |
784 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn) |
| |
785 return -EINVAL; |
| |
786 |
| |
787 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16))) |
| |
788 return -ENOMEM; |
| |
789 |
| |
790 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
| |
791 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| |
792 |
| |
793 /* ICBM header */ |
| |
794 aim_im_puticbm(&fr->data, cookie, 0x0002, sn); |
| |
795 |
| 785 aimbs_put16(&fr->data, 0x0005); |
796 aimbs_put16(&fr->data, 0x0005); |
| 786 aimbs_put16(&fr->data, 2+8+16+6+8+6+4+2+2+2+2+4+strlen(filename)+4); |
797 aimbs_put16(&fr->data, 0x001a); |
| 787 |
798 aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT); |
| 788 aimbs_put16(&fr->data, 0x0000); |
799 aimbs_putraw(&fr->data, cookie, 8); |
| 789 aimbs_putraw(&fr->data, ck, 8); |
800 aim_putcap(&fr->data, rendid); |
| 790 aim_putcap(&fr->data, AIM_CAPS_SENDFILE); |
801 |
| 791 |
802 aim_tx_enqueue(sess, fr); |
| 792 /* TLV t(000a) */ |
803 |
| 793 aimbs_put16(&fr->data, 0x000a); |
804 return 0; |
| 794 aimbs_put16(&fr->data, 0x0002); |
805 } |
| 795 aimbs_put16(&fr->data, 0x0001); |
806 |
| 796 |
807 /** |
| 797 /* TLV t(0003) (IP) */ |
808 * Subtype 0x0006 - Send a "cancel this file transfer" message? |
| 798 aimbs_put16(&fr->data, 0x0003); |
809 * |
| 799 aimbs_put16(&fr->data, 0x0004); |
810 */ |
| 800 aimbs_putraw(&fr->data, ip, 4); |
811 faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid) |
| 801 |
812 { |
| 802 /* TLV t(0005) (port) */ |
813 aim_conn_t *conn; |
| |
814 aim_frame_t *fr; |
| |
815 aim_snacid_t snacid; |
| |
816 |
| |
817 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn) |
| |
818 return -EINVAL; |
| |
819 |
| |
820 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16))) |
| |
821 return -ENOMEM; |
| |
822 |
| |
823 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
| |
824 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| |
825 |
| |
826 /* ICBM header */ |
| |
827 aim_im_puticbm(&fr->data, cookie, 0x0002, sn); |
| |
828 |
| 803 aimbs_put16(&fr->data, 0x0005); |
829 aimbs_put16(&fr->data, 0x0005); |
| 804 aimbs_put16(&fr->data, 0x0002); |
830 aimbs_put16(&fr->data, 0x001a); |
| 805 aimbs_put16(&fr->data, port); |
831 aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL); |
| 806 |
832 aimbs_putraw(&fr->data, cookie, 8); |
| 807 /* TLV t(000f) */ |
833 aim_putcap(&fr->data, rendid); |
| 808 aimbs_put16(&fr->data, 0x000f); |
|
| 809 aimbs_put16(&fr->data, 0x0000); |
|
| 810 |
|
| 811 /* TLV t(2711) */ |
|
| 812 aimbs_put16(&fr->data, 0x2711); |
|
| 813 aimbs_put16(&fr->data, 2+2+4+strlen(filename)+4); |
|
| 814 |
|
| 815 /* ? */ |
|
| 816 aimbs_put16(&fr->data, (numfiles > 1) ? 0x0002 : 0x0001); |
|
| 817 aimbs_put16(&fr->data, numfiles); |
|
| 818 aimbs_put32(&fr->data, totsize); |
|
| 819 aimbs_putraw(&fr->data, filename, strlen(filename)); |
|
| 820 |
|
| 821 /* ? */ |
|
| 822 aimbs_put32(&fr->data, 0x00000000); |
|
| 823 |
|
| 824 #if 0 |
|
| 825 /* Newer clients seem to send this (?) -- wtm */ |
|
| 826 aimbs_put32(&fr->data, 0x00030000); |
|
| 827 #endif |
|
| 828 |
834 |
| 829 aim_tx_enqueue(sess, fr); |
835 aim_tx_enqueue(sess, fr); |
| 830 |
836 |
| 831 return 0; |
837 return 0; |
| 832 } |
838 } |
| 838 * @param sn The UIN of the user of whom you wish to request info. |
844 * @param sn The UIN of the user of whom you wish to request info. |
| 839 * @param type The type of info you wish to request. This should be the current |
845 * @param type The type of info you wish to request. This should be the current |
| 840 * state of the user, as one of the AIM_ICQ_STATE_* defines. |
846 * state of the user, as one of the AIM_ICQ_STATE_* defines. |
| 841 * @return Return 0 if no errors, otherwise return the error number. |
847 * @return Return 0 if no errors, otherwise return the error number. |
| 842 */ |
848 */ |
| 843 faim_export int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type) |
849 faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type) |
| 844 { |
850 { |
| 845 aim_conn_t *conn; |
851 aim_conn_t *conn; |
| |
852 aim_frame_t *fr; |
| |
853 aim_snacid_t snacid; |
| 846 int i; |
854 int i; |
| 847 fu8_t ck[8]; |
855 fu8_t ck[8]; |
| 848 aim_frame_t *fr; |
|
| 849 aim_snacid_t snacid; |
|
| 850 |
856 |
| 851 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn) |
857 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn) |
| 852 return -EINVAL; |
858 return -EINVAL; |
| 853 |
859 |
| 854 for (i = 0; i < 8; i++) |
860 for (i = 0; i < 8; i++) |
| 855 aimutil_put8(ck+i, (fu8_t) rand()); |
861 ck[i] = (fu8_t)rand(); |
| 856 |
862 |
| 857 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4))) |
863 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4))) |
| 858 return -ENOMEM; |
864 return -ENOMEM; |
| 859 |
865 |
| 860 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
866 snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); |
| 861 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
867 aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); |
| 862 |
868 |
| 863 /* Cookie */ |
869 /* ICBM header */ |
| 864 aimbs_putraw(&fr->data, ck, 8); |
870 aim_im_puticbm(&fr->data, ck, 0x0002, sn); |
| 865 |
|
| 866 /* Channel (2) */ |
|
| 867 aimbs_put16(&fr->data, 0x0002); |
|
| 868 |
|
| 869 /* Dest sn */ |
|
| 870 aimbs_put8(&fr->data, strlen(sn)); |
|
| 871 aimbs_putraw(&fr->data, sn, strlen(sn)); |
|
| 872 |
871 |
| 873 /* TLV t(0005) - Encompasses almost everything below. */ |
872 /* TLV t(0005) - Encompasses almost everything below. */ |
| 874 aimbs_put16(&fr->data, 0x0005); /* T */ |
873 aimbs_put16(&fr->data, 0x0005); /* T */ |
| 875 aimbs_put16(&fr->data, 0x005e); /* L */ |
874 aimbs_put16(&fr->data, 0x005e); /* L */ |
| 876 { /* V */ |
875 { /* V */ |
| 1629 static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata) |
1610 static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata) |
| 1630 { |
1611 { |
| 1631 |
1612 |
| 1632 args->destructor = (void *)incomingim_ch2_sendfile_free; |
1613 args->destructor = (void *)incomingim_ch2_sendfile_free; |
| 1633 |
1614 |
| 1634 if (servdata) { |
1615 /* Maybe there is a better way to tell what kind of sendfile |
| |
1616 * this is? Maybe TLV t(000a)? */ |
| |
1617 if (servdata) { /* Someone is sending us a file */ |
| 1635 int flen; |
1618 int flen; |
| 1636 |
1619 |
| 1637 /* subtype is one of AIM_OFT_SUBTYPE_* */ |
1620 /* subtype is one of AIM_OFT_SUBTYPE_* */ |
| 1638 args->info.sendfile.subtype = aimbs_get16(servdata); |
1621 args->info.sendfile.subtype = aimbs_get16(servdata); |
| 1639 args->info.sendfile.totfiles = aimbs_get16(servdata); |
1622 args->info.sendfile.totfiles = aimbs_get16(servdata); |
| 1640 args->info.sendfile.totsize = aimbs_get32(servdata); |
1623 args->info.sendfile.totsize = aimbs_get32(servdata); |
| 1641 |
1624 |
| 1642 /* XXX - create an aimbs_getnullstr function */ |
1625 /* |
| |
1626 * I hope to God I'm right when I guess that there is a |
| |
1627 * 32 char max filename length for single files. I think |
| |
1628 * OFT tends to do that. Gotta love inconsistency. I saw |
| |
1629 * a 26 byte filename? |
| |
1630 */ |
| |
1631 /* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */ |
| 1643 /* Use an inelegant way of getting the null-terminated filename, |
1632 /* Use an inelegant way of getting the null-terminated filename, |
| 1644 * since there's no easy bstream routine. */ |
1633 * since there's no easy bstream routine. */ |
| 1645 for (flen = 0; aimbs_get8(servdata); flen++); |
1634 for (flen = 0; aimbs_get8(servdata); flen++); |
| 1646 aim_bstream_advance(servdata, -flen -1); |
1635 aim_bstream_advance(servdata, -flen -1); |
| 1647 args->info.sendfile.filename = aimbs_getstr(servdata, flen); |
1636 args->info.sendfile.filename = aimbs_getstr(servdata, flen); |
| 1648 |
1637 |
| 1649 /* There is sometimes more after the null-terminated filename, |
1638 /* There is sometimes more after the null-terminated filename, |
| 1650 * but I'm unsure of its format. */ |
1639 * but I'm unsure of its format. */ |
| |
1640 /* I don't believe him. */ |
| 1651 } |
1641 } |
| 1652 |
1642 |
| 1653 return; |
1643 return; |
| 1654 } |
1644 } |
| 1655 |
1645 |
| 1977 |
1973 |
| 1978 return ret; |
1974 return ret; |
| 1979 } |
1975 } |
| 1980 |
1976 |
| 1981 /* |
1977 /* |
| 1982 * Subtype 0x0008 - Send a warning to destsn. |
1978 * Subtype 0x0008 - Send a warning to sn. |
| 1983 * |
1979 * |
| 1984 * Flags: |
1980 * Flags: |
| 1985 * AIM_WARN_ANON Send as an anonymous (doesn't count as much) |
1981 * AIM_WARN_ANON Send as an anonymous (doesn't count as much) |
| 1986 * |
1982 * |
| 1987 * returns -1 on error (couldn't alloc packet), 0 on success. |
1983 * returns -1 on error (couldn't alloc packet), 0 on success. |
| 1988 * |
1984 * |
| 1989 */ |
1985 */ |
| 1990 faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags) |
1986 faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu32_t flags) |
| 1991 { |
1987 { |
| 1992 aim_frame_t *fr; |
1988 aim_frame_t *fr; |
| 1993 aim_snacid_t snacid; |
1989 aim_snacid_t snacid; |
| 1994 fu16_t outflags = 0x0000; |
1990 |
| 1995 |
1991 if (!sess || !conn || !sn) |
| 1996 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13))) |
1992 return -EINVAL; |
| |
1993 |
| |
1994 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13))) |
| 1997 return -ENOMEM; |
1995 return -ENOMEM; |
| 1998 |
1996 |
| 1999 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); |
1997 snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1); |
| 2000 |
|
| 2001 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); |
1998 aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); |
| 2002 |
1999 |
| 2003 if (flags & AIM_WARN_ANON) |
2000 aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); |
| 2004 outflags |= 0x0001; |
2001 aimbs_put8(&fr->data, strlen(sn)); |
| 2005 |
2002 aimbs_putraw(&fr->data, sn, strlen(sn)); |
| 2006 aimbs_put16(&fr->data, outflags); |
|
| 2007 aimbs_put8(&fr->data, strlen(destsn)); |
|
| 2008 aimbs_putraw(&fr->data, destsn, strlen(destsn)); |
|
| 2009 |
2003 |
| 2010 aim_tx_enqueue(sess, fr); |
2004 aim_tx_enqueue(sess, fr); |
| 2011 |
2005 |
| 2012 return 0; |
2006 return 0; |
| 2013 } |
2007 } |