comparison libpurple/protocols/msn/slplink.c @ 31292:47b6eda87723

propagate from branch 'im.pidgin.pidgin' (head 07d0765c444a097af45c2650f54323afb900a07b) to branch 'im.pidgin.soc.2010.msn-tlc' (head f3998422a4724ab424e4e2328f58fc0504856557)
author masca@cpw.pidgin.im
date Mon, 19 Jul 2010 21:11:32 +0000
parents 8c1a2ef5a713 e0c374ad8fd3
children 6814678f3c63
comparison
equal deleted inserted replaced
30698:e874875a74a7 31292:47b6eda87723
19 * 19 *
20 * You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 */ 23 */
24
25 #include "internal.h"
26 #include "debug.h"
27
24 #include "msn.h" 28 #include "msn.h"
25 #include "slplink.h" 29 #include "slplink.h"
26 30 #include "slpmsg_part.h"
31
32 #include "sbconn.h"
27 #include "switchboard.h" 33 #include "switchboard.h"
28 #include "slp.h" 34 #include "slp.h"
35 #include "p2p.h"
29 36
30 #ifdef MSN_DEBUG_SLP_FILES 37 #ifdef MSN_DEBUG_SLP_FILES
31 static int m_sc = 0; 38 static int m_sc = 0;
32 static int m_rc = 0; 39 static int m_rc = 0;
33 40
34 static void 41 static void
35 debug_msg_to_file(MsnMessage *msg, gboolean send) 42 debug_part_to_file(MsnSlpMessage *msg, gboolean send)
36 { 43 {
37 char *tmp; 44 char *tmp;
38 char *dir; 45 char *dir;
39 char *pload; 46 char *data;
40 int c; 47 int c;
41 gsize pload_size; 48 gsize data_size;
42 49
43 dir = send ? "send" : "recv"; 50 dir = send ? "send" : "recv";
44 c = send ? m_sc++ : m_rc++; 51 c = send ? m_sc++ : m_rc++;
45 tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c); 52 tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c);
46 pload = msn_message_gen_payload(msg, &pload_size); 53 data = msn_slpmsg_serialize(msg, &data_size);
47 if (!purple_util_write_data_to_file_absolute(tmp, pload, pload_size)) 54 if (!purple_util_write_data_to_file_absolute(tmp, data, data_size))
48 { 55 {
49 purple_debug_error("msn", "could not save debug file\n"); 56 purple_debug_error("msn", "could not save debug file\n");
50 } 57 }
51 g_free(tmp); 58 g_free(tmp);
52 } 59 }
79 g_list_append(session->slplinks, slplink); 86 g_list_append(session->slplinks, slplink);
80 87
81 return msn_slplink_ref(slplink); 88 return msn_slplink_ref(slplink);
82 } 89 }
83 90
84 void 91 static void
85 msn_slplink_destroy(MsnSlpLink *slplink) 92 msn_slplink_destroy(MsnSlpLink *slplink)
86 { 93 {
87 MsnSession *session; 94 MsnSession *session;
88 95
89 if (purple_debug_is_verbose()) 96 if (purple_debug_is_verbose())
263 270
264 return NULL; 271 return NULL;
265 } 272 }
266 273
267 void 274 void
268 msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg) 275 msn_slplink_send_part(MsnSlpLink *slplink, MsnSlpMessagePart *part)
269 { 276 {
270 if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED) 277 if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
271 { 278 {
272 msn_dc_enqueue_msg(slplink->dc, msg); 279 msn_dc_enqueue_part(slplink->dc, part);
273 } 280 }
274 else 281 else
275 { 282 {
276 if (slplink->swboard == NULL) 283 msn_sbconn_send_part(slplink, part);
277 {
278 slplink->swboard = msn_session_get_swboard(slplink->session,
279 slplink->remote_user, MSN_SB_FLAG_FT);
280
281 g_return_if_fail(slplink->swboard != NULL);
282
283 /* If swboard is destroyed we will be too */
284 slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
285 }
286
287 msn_switchboard_send_msg(slplink->swboard, msg, TRUE);
288 } 284 }
289 } 285 }
290 286
291 void 287 void
292 msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) 288 msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
293 { 289 {
294 MsnMessage *msg; 290 MsnSlpMessagePart *part;
295 long long real_size; 291 long long real_size;
296 size_t len = 0; 292 size_t len = 0;
297 293
298 /* Maybe we will want to create a new msg for this slpmsg instead of 294 /* Maybe we will want to create a new msg for this slpmsg instead of
299 * reusing the same one all the time. */ 295 * reusing the same one all the time. */
300 msg = slpmsg->msg; 296 part = msn_slpmsgpart_new(slpmsg->header, slpmsg->footer);
301 297 part->ack_data = slpmsg;
302 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; 298
299 real_size = (slpmsg->flags == P2P_ACK) ? 0 : slpmsg->size;
303 300
304 if (slpmsg->offset < real_size) 301 if (slpmsg->offset < real_size)
305 { 302 {
306 if (slpmsg->slpcall && slpmsg->slpcall->xfer && purple_xfer_get_type(slpmsg->slpcall->xfer) == PURPLE_XFER_SEND && 303 if (slpmsg->slpcall && slpmsg->slpcall->xfer && purple_xfer_get_type(slpmsg->slpcall->xfer) == PURPLE_XFER_SEND &&
307 purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED) 304 purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED)
308 { 305 {
309 len = MIN(1202, slpmsg->slpcall->u.outgoing.len); 306 len = MIN(MSN_SBCONN_MAX_SIZE, slpmsg->slpcall->u.outgoing.len);
310 msn_message_set_bin_data(msg, slpmsg->slpcall->u.outgoing.data, len); 307 msn_slpmsgpart_set_bin_data(part, slpmsg->slpcall->u.outgoing.data, len);
311 } 308 }
312 else 309 else
313 { 310 {
314 len = slpmsg->size - slpmsg->offset; 311 len = slpmsg->size - slpmsg->offset;
315 312
316 if (len > 1202) 313 if (len > MSN_SBCONN_MAX_SIZE)
317 len = 1202; 314 len = MSN_SBCONN_MAX_SIZE;
318 315
319 msn_message_set_bin_data(msg, slpmsg->buffer + slpmsg->offset, len); 316 msn_slpmsgpart_set_bin_data(part, slpmsg->buffer + slpmsg->offset, len);
320 } 317 }
321 318
322 msg->msnslp_header.offset = slpmsg->offset; 319 slpmsg->header->offset = slpmsg->offset;
323 msg->msnslp_header.length = len; 320 slpmsg->header->length = len;
324 } 321 }
325 322
323 #if 0
324 /* TODO: port this function to SlpMessageParts */
326 if (purple_debug_is_verbose()) 325 if (purple_debug_is_verbose())
327 msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body); 326 msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body);
327 #endif
328 328
329 #ifdef MSN_DEBUG_SLP_FILES 329 #ifdef MSN_DEBUG_SLP_FILES
330 debug_msg_to_file(msg, TRUE); 330 debug_part_to_file(slpmsg, TRUE);
331 #endif 331 #endif
332 332
333 slpmsg->msgs = 333 slpmsg->parts = g_list_append(slpmsg->parts, part);
334 g_list_append(slpmsg->msgs, msn_message_ref(msg)); 334 msn_slplink_send_part(slplink, part);
335 msn_slplink_send_msg(slplink, msg); 335
336 336 if ((slpmsg->flags == P2P_MSN_OBJ_DATA ||
337 if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 || 337 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
338 slpmsg->flags == 0x1000030) && 338 slpmsg->flags == P2P_FILE_DATA) &&
339 (slpmsg->slpcall != NULL)) 339 (slpmsg->slpcall != NULL))
340 { 340 {
341 slpmsg->slpcall->progress = TRUE; 341 slpmsg->slpcall->progress = TRUE;
342 342
343 if (slpmsg->slpcall->progress_cb != NULL) 343 if (slpmsg->slpcall->progress_cb != NULL)
348 } 348 }
349 349
350 /* slpmsg->offset += len; */ 350 /* slpmsg->offset += len; */
351 } 351 }
352 352
353 /* We have received the message ack */
354 static void
355 msg_ack(MsnMessage *msg, void *data)
356 {
357 MsnSlpMessage *slpmsg;
358 long long real_size;
359
360 slpmsg = data;
361
362 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size;
363
364 slpmsg->offset += msg->msnslp_header.length;
365
366 slpmsg->msgs = g_list_remove(slpmsg->msgs, msg);
367
368 if (slpmsg->offset < real_size)
369 {
370 if (slpmsg->slpcall->xfer && purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED)
371 {
372 slpmsg->slpcall->xfer_msg = slpmsg;
373 msn_message_ref(msg);
374 purple_xfer_prpl_ready(slpmsg->slpcall->xfer);
375 }
376 else
377 msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
378 }
379 else
380 {
381 /* The whole message has been sent */
382 if (slpmsg->flags == 0x20 ||
383 slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030)
384 {
385 if (slpmsg->slpcall != NULL)
386 {
387 if (slpmsg->slpcall->cb)
388 slpmsg->slpcall->cb(slpmsg->slpcall,
389 NULL, 0);
390 }
391 }
392 }
393
394 msn_message_unref(msg);
395 }
396
397 /* We have received the message nak. */
398 static void
399 msg_nak(MsnMessage *msg, void *data)
400 {
401 MsnSlpMessage *slpmsg;
402
403 slpmsg = data;
404
405 msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
406
407 slpmsg->msgs = g_list_remove(slpmsg->msgs, msg);
408 msn_message_unref(msg);
409 }
410
411 static void 353 static void
412 msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) 354 msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
413 { 355 {
414 MsnMessage *msg; 356 slpmsg = slpmsg;
415 const char *passport; 357 slpmsg->header = g_new0(MsnP2PHeader, 1);
416 358 slpmsg->footer = g_new0(MsnP2PFooter, 1);
417 slpmsg->msg = msg = msn_message_new_msnslp(); 359
418 360 if (slpmsg->flags == P2P_NO_FLAG)
419 if (slpmsg->flags == 0x0) 361 {
420 { 362 slpmsg->header->session_id = slpmsg->session_id;
421 msg->msnslp_header.session_id = slpmsg->session_id; 363 slpmsg->header->ack_id = rand() % 0xFFFFFF00;
422 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; 364 }
423 } 365 else if (slpmsg->flags == P2P_ACK)
424 else if (slpmsg->flags == 0x2) 366 {
425 { 367 slpmsg->header->session_id = slpmsg->session_id;
426 msg->msnslp_header.session_id = slpmsg->session_id; 368 slpmsg->header->ack_id = slpmsg->ack_id;
427 msg->msnslp_header.ack_id = slpmsg->ack_id; 369 slpmsg->header->ack_size = slpmsg->ack_size;
428 msg->msnslp_header.ack_size = slpmsg->ack_size; 370 slpmsg->header->ack_sub_id = slpmsg->ack_sub_id;
429 msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; 371 }
430 } 372 else if (slpmsg->flags == P2P_MSN_OBJ_DATA ||
431 else if (slpmsg->flags == 0x20 || 373 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
432 slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) 374 slpmsg->flags == P2P_FILE_DATA)
433 { 375 {
434 MsnSlpCall *slpcall; 376 MsnSlpCall *slpcall;
435 slpcall = slpmsg->slpcall; 377 slpcall = slpmsg->slpcall;
436 378
437 g_return_if_fail(slpcall != NULL); 379 g_return_if_fail(slpcall != NULL);
438 msg->msnslp_header.session_id = slpcall->session_id; 380 slpmsg->header->session_id = slpcall->session_id;
439 msg->msnslp_footer.value = slpcall->app_id; 381 slpmsg->footer->value = slpcall->app_id;
440 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; 382 slpmsg->header->ack_id = rand() % 0xFFFFFF00;
441 } 383 }
442 else if (slpmsg->flags == 0x100) 384 else if (slpmsg->flags == 0x100)
443 { 385 {
444 msg->msnslp_header.ack_id = slpmsg->ack_id; 386 slpmsg->header->ack_id = slpmsg->ack_id;
445 msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; 387 slpmsg->header->ack_sub_id = slpmsg->ack_sub_id;
446 msg->msnslp_header.ack_size = slpmsg->ack_size; 388 slpmsg->header->ack_size = slpmsg->ack_size;
447 } 389 }
448 390
449 msg->msnslp_header.id = slpmsg->id; 391 slpmsg->header->id = slpmsg->id;
450 msg->msnslp_header.flags = slpmsg->flags; 392 slpmsg->header->flags = (guint32)slpmsg->flags;
451 393
452 msg->msnslp_header.total_size = slpmsg->size; 394 slpmsg->header->total_size = slpmsg->size;
453
454 passport = purple_normalize(slplink->session->account, slplink->remote_user);
455 msn_message_set_attr(msg, "P2P-Dest", passport);
456
457 msg->ack_cb = msg_ack;
458 msg->nak_cb = msg_nak;
459 msg->ack_data = slpmsg;
460 395
461 msn_slplink_send_msgpart(slplink, slpmsg); 396 msn_slplink_send_msgpart(slplink, slpmsg);
462
463 msn_message_destroy(msg);
464 } 397 }
465 398
466 void 399 void
467 msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) 400 msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
468 { 401 {
492 msn_slplink_release_slpmsg(slplink, slpmsg); 425 msn_slplink_release_slpmsg(slplink, slpmsg);
493 } 426 }
494 } 427 }
495 428
496 static MsnSlpMessage * 429 static MsnSlpMessage *
497 msn_slplink_create_ack(MsnSlpLink *slplink, MsnSlpHeader *header) 430 msn_slplink_create_ack(MsnSlpLink *slplink, MsnP2PHeader *header)
498 { 431 {
499 MsnSlpMessage *slpmsg; 432 MsnSlpMessage *slpmsg;
500 433
501 slpmsg = msn_slpmsg_new(slplink); 434 slpmsg = msn_slpmsg_ack_new(header);
502 435 msn_slpmsg_set_slplink(slpmsg, slplink);
503 slpmsg->session_id = header->session_id;
504 slpmsg->size = header->total_size;
505 slpmsg->flags = 0x02;
506 slpmsg->ack_id = header->id;
507 slpmsg->ack_sub_id = header->ack_id;
508 slpmsg->ack_size = header->total_size;
509 slpmsg->info = "SLP ACK";
510 436
511 return slpmsg; 437 return slpmsg;
512 } 438 }
513 439
514 static void 440 static void
515 msn_slplink_send_ack(MsnSlpLink *slplink, MsnSlpHeader *header) 441 msn_slplink_send_ack(MsnSlpLink *slplink, MsnP2PHeader *header)
516 { 442 {
517 MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, header); 443 MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, header);
518 444
519 msn_slplink_send_slpmsg(slplink, slpmsg); 445 msn_slplink_send_slpmsg(slplink, slpmsg);
520 msn_slpmsg_destroy(slpmsg); 446 msn_slpmsg_destroy(slpmsg);
521 } 447 }
522 448
523 static void
524 send_file_cb(MsnSlpCall *slpcall)
525 {
526 MsnSlpMessage *slpmsg;
527 PurpleXfer *xfer;
528
529 xfer = (PurpleXfer *)slpcall->xfer;
530 if (purple_xfer_get_status(xfer) >= PURPLE_XFER_STATUS_STARTED)
531 return;
532
533 purple_xfer_ref(xfer);
534 purple_xfer_start(xfer, -1, NULL, 0);
535 if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_STARTED) {
536 purple_xfer_unref(xfer);
537 return;
538 }
539 purple_xfer_unref(xfer);
540
541 slpmsg = msn_slpmsg_new(slpcall->slplink);
542 slpmsg->slpcall = slpcall;
543 slpmsg->flags = 0x1000030;
544 slpmsg->info = "SLP FILE";
545 slpmsg->size = purple_xfer_get_size(xfer);
546
547 msn_slplink_send_slpmsg(slpcall->slplink, slpmsg);
548 }
549
550 static MsnSlpMessage * 449 static MsnSlpMessage *
551 msn_slplink_message_find(MsnSlpLink *slplink, long session_id, long id) 450 msn_slplink_message_find(MsnSlpLink *slplink, long session_id, long id)
552 { 451 {
553 GList *e; 452 GList *e;
554 453
562 461
563 return NULL; 462 return NULL;
564 } 463 }
565 464
566 void 465 void
567 msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpHeader *header, const char *data, gsize len) 466 msn_slplink_process_msg(MsnSlpLink *slplink, MsnP2PHeader *header, const char *data, gsize len)
568 { 467 {
569 MsnSlpMessage *slpmsg; 468 MsnSlpMessage *slpmsg;
570 guint64 offset; 469 guint64 offset;
571 PurpleXfer *xfer = NULL;
572 470
573 if (header->total_size < header->length) 471 if (header->total_size < header->length)
574 { 472 {
575 purple_debug_error("msn", "This can't be good\n"); 473 /* We seem to have received a bad header */
576 g_return_if_reached(); 474 purple_debug_warning("msn", "Total size listed in SLP binary header "
475 "was less than length of this particular message. This "
476 "should not happen. Dropping message.\n");
477 return;
577 } 478 }
578 479
579 offset = header->offset; 480 offset = header->offset;
580 481
581 if (offset == 0) 482 if (offset == 0)
586 slpmsg->size = header->total_size; 487 slpmsg->size = header->total_size;
587 slpmsg->flags = header->flags; 488 slpmsg->flags = header->flags;
588 489
589 if (slpmsg->session_id) 490 if (slpmsg->session_id)
590 { 491 {
591 if (slpmsg->slpcall == NULL) 492 slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
592 slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
593
594 if (slpmsg->slpcall != NULL) 493 if (slpmsg->slpcall != NULL)
595 { 494 {
596 if (slpmsg->flags == 0x20 || 495 if (slpmsg->flags == P2P_MSN_OBJ_DATA ||
597 slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) 496 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
497 slpmsg->flags == P2P_FILE_DATA)
598 { 498 {
599 xfer = slpmsg->slpcall->xfer; 499 PurpleXfer *xfer = slpmsg->slpcall->xfer;
600 if (xfer != NULL) 500 if (xfer != NULL)
601 { 501 {
602 slpmsg->ft = TRUE; 502 slpmsg->ft = TRUE;
603 slpmsg->slpcall->xfer_msg = slpmsg; 503 slpmsg->slpcall->xfer_msg = slpmsg;
604 504
638 } 538 }
639 } 539 }
640 540
641 if (slpmsg->ft) 541 if (slpmsg->ft)
642 { 542 {
643 xfer = slpmsg->slpcall->xfer;
644 slpmsg->slpcall->u.incoming_data = 543 slpmsg->slpcall->u.incoming_data =
645 g_byte_array_append(slpmsg->slpcall->u.incoming_data, (const guchar *)data, len); 544 g_byte_array_append(slpmsg->slpcall->u.incoming_data, (const guchar *)data, len);
646 purple_xfer_prpl_ready(xfer); 545 purple_xfer_prpl_ready(slpmsg->slpcall->xfer);
647 } 546 }
648 else if (slpmsg->size && slpmsg->buffer) 547 else if (slpmsg->size && slpmsg->buffer)
649 { 548 {
650 if (G_MAXSIZE - len < offset || (offset + len) > slpmsg->size || slpmsg->offset != offset) 549 if (G_MAXSIZE - len < offset || (offset + len) > slpmsg->size || slpmsg->offset != offset)
651 { 550 {
657 memcpy(slpmsg->buffer + offset, data, len); 556 memcpy(slpmsg->buffer + offset, data, len);
658 slpmsg->offset += len; 557 slpmsg->offset += len;
659 } 558 }
660 } 559 }
661 560
662 if ((slpmsg->flags == 0x20 || 561 if ((slpmsg->flags == P2P_MSN_OBJ_DATA ||
663 slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) && 562 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
563 slpmsg->flags == P2P_FILE_DATA) &&
664 (slpmsg->slpcall != NULL)) 564 (slpmsg->slpcall != NULL))
665 { 565 {
666 slpmsg->slpcall->progress = TRUE; 566 slpmsg->slpcall->progress = TRUE;
667 567
668 if (slpmsg->slpcall->progress_cb != NULL) 568 if (slpmsg->slpcall->progress_cb != NULL)
699 directconn = slplink->directconn; 599 directconn = slplink->directconn;
700 if (!directconn->acked) 600 if (!directconn->acked)
701 msn_directconn_send_handshake(directconn); 601 msn_directconn_send_handshake(directconn);
702 #endif 602 #endif
703 } 603 }
704 else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 || 604 else if (slpmsg->flags == P2P_NO_FLAG || slpmsg->flags == P2P_WML2009_COMP ||
705 slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 || 605 slpmsg->flags == P2P_MSN_OBJ_DATA ||
706 slpmsg->flags == 0x1000030) 606 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
607 slpmsg->flags == P2P_FILE_DATA)
707 { 608 {
708 /* Release all the messages and send the ACK */ 609 /* Release all the messages and send the ACK */
709 610
710 if (slpcall->wait_for_socket) { 611 if (slpcall->wait_for_socket) {
711 /* 612 /*
730 if (!slpcall->wait_for_socket && slpcall->wasted) 631 if (!slpcall->wait_for_socket && slpcall->wasted)
731 msn_slpcall_destroy(slpcall); 632 msn_slpcall_destroy(slpcall);
732 } 633 }
733 } 634 }
734 635
735 static gchar *
736 gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
737 {
738 gsize size = 0;
739 MsnFileContext *header;
740 gchar *u8 = NULL;
741 gchar *ret;
742 gunichar2 *uni = NULL;
743 glong currentChar = 0;
744 glong len = 0;
745 const char *preview;
746 gsize preview_len;
747
748 size = purple_xfer_get_size(xfer);
749
750 purple_xfer_prepare_thumbnail(xfer, "png");
751
752 if (!file_name) {
753 gchar *basename = g_path_get_basename(file_path);
754 u8 = purple_utf8_try_convert(basename);
755 g_free(basename);
756 file_name = u8;
757 }
758
759 uni = g_utf8_to_utf16(file_name, -1, NULL, &len, NULL);
760
761 if (u8) {
762 g_free(u8);
763 file_name = NULL;
764 u8 = NULL;
765 }
766
767 preview = purple_xfer_get_thumbnail(xfer, &preview_len);
768 header = g_malloc(sizeof(MsnFileContext) + preview_len);
769
770 header->length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1);
771 header->version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */
772 header->file_size = GUINT64_TO_LE(size);
773 if (preview)
774 header->type = GUINT32_TO_LE(0);
775 else
776 header->type = GUINT32_TO_LE(1);
777
778 len = MIN(len, MAX_FILE_NAME_LEN);
779 for (currentChar = 0; currentChar < len; currentChar++) {
780 header->file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
781 }
782 memset(&header->file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
783
784 memset(&header->unknown1, 0, sizeof(header->unknown1));
785 header->unknown2 = GUINT32_TO_LE(0xffffffff);
786 if (preview) {
787 memcpy(&header->preview, preview, preview_len);
788 }
789 header->preview[preview_len] = '\0';
790
791 g_free(uni);
792 ret = purple_base64_encode((const guchar *)header, sizeof(MsnFileContext) + preview_len);
793 g_free(header);
794 return ret;
795 }
796
797 void
798 msn_slplink_request_ft(MsnSlpLink *slplink, PurpleXfer *xfer)
799 {
800 MsnSlpCall *slpcall;
801 char *context;
802 const char *fn;
803 const char *fp;
804
805 fn = purple_xfer_get_filename(xfer);
806 fp = purple_xfer_get_local_filename(xfer);
807
808 g_return_if_fail(slplink != NULL);
809 g_return_if_fail(fp != NULL);
810
811 slpcall = msn_slpcall_new(slplink);
812 msn_slpcall_init(slpcall, MSN_SLPCALL_DC);
813
814 slpcall->session_init_cb = send_file_cb;
815 slpcall->end_cb = msn_xfer_end_cb;
816 slpcall->cb = msn_xfer_completed_cb;
817 slpcall->xfer = xfer;
818 purple_xfer_ref(slpcall->xfer);
819
820 slpcall->pending = TRUE;
821
822 purple_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel);
823 purple_xfer_set_read_fnc(xfer, msn_xfer_read);
824 purple_xfer_set_write_fnc(xfer, msn_xfer_write);
825
826 xfer->data = slpcall;
827
828 context = gen_context(xfer, fn, fp);
829
830 msn_slpcall_invite(slpcall, MSN_FT_GUID, 2, context);
831
832 g_free(context);
833 }
834
835 void 636 void
836 msn_slplink_request_object(MsnSlpLink *slplink, 637 msn_slplink_request_object(MsnSlpLink *slplink,
837 const char *info, 638 const char *info,
838 MsnSlpCb cb, 639 MsnSlpCb cb,
839 MsnSlpEndCb end_cb, 640 MsnSlpEndCb end_cb,
855 656
856 slpcall->data_info = g_strdup(info); 657 slpcall->data_info = g_strdup(info);
857 slpcall->cb = cb; 658 slpcall->cb = cb;
858 slpcall->end_cb = end_cb; 659 slpcall->end_cb = end_cb;
859 660
860 msn_slpcall_invite(slpcall, MSN_OBJ_GUID, 1, msnobj_base64); 661 msn_slpcall_invite(slpcall, MSN_OBJ_GUID, P2P_APPID_OBJ, msnobj_base64);
861 662
862 g_free(msnobj_base64); 663 g_free(msnobj_base64);
863 } 664 }