| 159 int fd; |
159 int fd; |
| 160 if (method[0] == 'r') { |
160 if (method[0] == 'r') { |
| 161 fd = open(purple_xfer_get_local_filename(xfer), O_RDONLY); |
161 fd = open(purple_xfer_get_local_filename(xfer), O_RDONLY); |
| 162 info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ, MAP_PRIVATE, fd, 0); |
162 info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ, MAP_PRIVATE, fd, 0); |
| 163 } |
163 } |
| 164 else |
164 else |
| 165 { |
165 { |
| 166 fd = open(purple_xfer_get_local_filename(xfer), O_RDWR|O_CREAT, 0644); |
166 fd = open(purple_xfer_get_local_filename(xfer), O_RDWR|O_CREAT, 0644); |
| 167 info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0); |
167 info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0); |
| 168 } |
168 } |
| 169 |
169 |
| 246 |
246 |
| 247 raw_data = g_newa(guint8, MAX_PACKET_SIZE); |
247 raw_data = g_newa(guint8, MAX_PACKET_SIZE); |
| 248 file_key = _gen_file_key(); |
248 file_key = _gen_file_key(); |
| 249 |
249 |
| 250 bytes += qq_put8(raw_data + bytes, packet_type); |
250 bytes += qq_put8(raw_data + bytes, packet_type); |
| 251 bytes += qq_put16(raw_data + bytes, QQ_CLIENT); |
251 bytes += qq_put16(raw_data + bytes, qd->client_version); |
| 252 bytes += qq_put8(raw_data + bytes, file_key & 0xff); |
252 bytes += qq_put8(raw_data + bytes, file_key & 0xff); |
| 253 bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key)); |
253 bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key)); |
| 254 bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key)); |
254 bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key)); |
| 255 bytes += qq_putdata(raw_data + bytes, data, len); |
255 bytes += qq_putdata(raw_data + bytes, data, len); |
| 256 |
256 |
| 362 purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); |
362 purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); |
| 363 _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); |
363 _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); |
| 364 } |
364 } |
| 365 |
365 |
| 366 /* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */ |
366 /* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */ |
| 367 static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type, |
367 static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type, |
| 368 guint32 fragment_index, guint16 seq, guint8 *data, gint len) |
368 guint32 fragment_index, guint16 seq, guint8 *data, gint len) |
| 369 { |
369 { |
| 370 guint8 *raw_data, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH]; |
370 guint8 *raw_data, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH]; |
| 371 gint bytes; |
371 gint bytes; |
| 372 guint32 fragment_size = 1000; |
372 guint32 fragment_size = 1000; |
| 400 filename_len = strlen(filename); |
400 filename_len = strlen(filename); |
| 401 qq_get_md5(filename_md5, sizeof(filename_md5), (guint8 *)filename, filename_len); |
401 qq_get_md5(filename_md5, sizeof(filename_md5), (guint8 *)filename, filename_len); |
| 402 _fill_file_md5(purple_xfer_get_local_filename(qd->xfer), |
402 _fill_file_md5(purple_xfer_get_local_filename(qd->xfer), |
| 403 purple_xfer_get_size(qd->xfer), |
403 purple_xfer_get_size(qd->xfer), |
| 404 file_md5); |
404 file_md5); |
| 405 |
405 |
| 406 info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1; |
406 info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1; |
| 407 info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN; |
407 info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN; |
| 408 |
408 |
| 409 purple_debug_info("QQ", |
409 purple_debug_info("QQ", |
| 410 "start transfering data, %d fragments with %d length each\n", |
410 "start transfering data, %d fragments with %d length each\n", |
| 411 info->fragment_num, info->fragment_len); |
411 info->fragment_num, info->fragment_len); |
| 412 /* Unknown */ |
412 /* Unknown */ |
| 413 bytes += qq_put16(raw_data + bytes, 0x0000); |
413 bytes += qq_put16(raw_data + bytes, 0x0000); |
| 414 /* Sub-operation type */ |
414 /* Sub-operation type */ |
| 429 /* filename */ |
429 /* filename */ |
| 430 bytes += qq_putdata(raw_data + bytes, (guint8 *) filename, |
430 bytes += qq_putdata(raw_data + bytes, (guint8 *) filename, |
| 431 filename_len); |
431 filename_len); |
| 432 break; |
432 break; |
| 433 case QQ_FILE_DATA_INFO: |
433 case QQ_FILE_DATA_INFO: |
| 434 purple_debug_info("QQ", |
434 purple_debug_info("QQ", |
| 435 "sending %dth fragment with length %d, offset %d\n", |
435 "sending %dth fragment with length %d, offset %d\n", |
| 436 fragment_index, len, (fragment_index-1)*fragment_size); |
436 fragment_index, len, (fragment_index-1)*fragment_size); |
| 437 /* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */ |
437 /* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */ |
| 438 bytes += qq_put16(raw_data + bytes, info->send_seq); |
438 bytes += qq_put16(raw_data + bytes, info->send_seq); |
| 439 bytes += qq_put8(raw_data + bytes, sub_type); |
439 bytes += qq_put8(raw_data + bytes, sub_type); |
| 530 switch (packet_type) { |
530 switch (packet_type) { |
| 531 case QQ_FILE_CMD_NOTIFY_IP_ACK: |
531 case QQ_FILE_CMD_NOTIFY_IP_ACK: |
| 532 decryped_bytes = 0; |
532 decryped_bytes = 0; |
| 533 qq_get_conn_info(info, decrypted_data + decryped_bytes); |
533 qq_get_conn_info(info, decrypted_data + decryped_bytes); |
| 534 /* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */ |
534 /* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */ |
| 535 qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); |
535 qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); |
| 536 break; |
536 break; |
| 537 case QQ_FILE_CMD_SENDER_SAY_HELLO: |
537 case QQ_FILE_CMD_SENDER_SAY_HELLO: |
| 538 /* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */ |
538 /* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */ |
| 539 decryped_bytes += 47; |
539 decryped_bytes += 47; |
| 540 decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes); |
540 decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes); |
| 571 qq_data *qd = (qq_data *) gc->proto_data; |
571 qq_data *qd = (qq_data *) gc->proto_data; |
| 572 PurpleXfer *xfer = qd->xfer; |
572 PurpleXfer *xfer = qd->xfer; |
| 573 ft_info *info = (ft_info *) xfer->data; |
573 ft_info *info = (ft_info *) xfer->data; |
| 574 guint32 mask; |
574 guint32 mask; |
| 575 |
575 |
| 576 purple_debug_info("QQ", |
576 purple_debug_info("QQ", |
| 577 "receiving %dth fragment with length %d, slide window status %o, max_fragment_index %d\n", |
577 "receiving %dth fragment with length %d, slide window status %o, max_fragment_index %d\n", |
| 578 index, len, info->window, info->max_fragment_index); |
578 index, len, info->window, info->max_fragment_index); |
| 579 if (info->window == 0 && info->max_fragment_index == 0) { |
579 if (info->window == 0 && info->max_fragment_index == 0) { |
| 580 if (_qq_xfer_open_file(purple_xfer_get_local_filename(xfer), "wb", xfer) == -1) { |
580 if (_qq_xfer_open_file(purple_xfer_get_local_filename(xfer), "wb", xfer) == -1) { |
| 581 purple_xfer_cancel_local(xfer); |
581 purple_xfer_cancel_local(xfer); |
| 582 return; |
582 return; |
| 603 info->window &= ~mask; |
603 info->window &= ~mask; |
| 604 info->max_fragment_index ++; |
604 info->max_fragment_index ++; |
| 605 if (mask & 0x8000) mask = 0x0001; |
605 if (mask & 0x8000) mask = 0x0001; |
| 606 else mask = mask << 1; |
606 else mask = mask << 1; |
| 607 } |
607 } |
| 608 purple_debug_info("QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n", |
608 purple_debug_info("QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n", |
| 609 index, info->window, info->max_fragment_index); |
609 index, info->window, info->max_fragment_index); |
| 610 } |
610 } |
| 611 |
611 |
| 612 static void _qq_send_file_progess(PurpleConnection *gc) |
612 static void _qq_send_file_progess(PurpleConnection *gc) |
| 613 { |
613 { |
| 648 gint readbytes; |
648 gint readbytes; |
| 649 qq_data *qd = (qq_data *) gc->proto_data; |
649 qq_data *qd = (qq_data *) gc->proto_data; |
| 650 PurpleXfer *xfer = qd->xfer; |
650 PurpleXfer *xfer = qd->xfer; |
| 651 ft_info *info = (ft_info *) xfer->data; |
651 ft_info *info = (ft_info *) xfer->data; |
| 652 |
652 |
| 653 purple_debug_info("QQ", |
653 purple_debug_info("QQ", |
| 654 "receiving %dth fragment ack, slide window status %o, max_fragment_index %d\n", |
654 "receiving %dth fragment ack, slide window status %o, max_fragment_index %d\n", |
| 655 fragment_index, info->window, info->max_fragment_index); |
655 fragment_index, info->window, info->max_fragment_index); |
| 656 if (fragment_index < info->max_fragment_index || |
656 if (fragment_index < info->max_fragment_index || |
| 657 fragment_index >= info->max_fragment_index + sizeof(info->window)) { |
657 fragment_index >= info->max_fragment_index + sizeof(info->window)) { |
| 658 purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); |
658 purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); |
| 659 return; |
659 return; |
| 660 } |
660 } |
| 661 mask = 0x1 << (fragment_index % sizeof(info->window)); |
661 mask = 0x1 << (fragment_index % sizeof(info->window)); |
| 679 { |
679 { |
| 680 /* move the slide window */ |
680 /* move the slide window */ |
| 681 info->window &= ~mask; |
681 info->window &= ~mask; |
| 682 |
682 |
| 683 buffer = g_newa(guint8, info->fragment_len); |
683 buffer = g_newa(guint8, info->fragment_len); |
| 684 readbytes = _qq_xfer_read_file(buffer, info->max_fragment_index + sizeof(info->window), |
684 readbytes = _qq_xfer_read_file(buffer, info->max_fragment_index + sizeof(info->window), |
| 685 info->fragment_len, xfer); |
685 info->fragment_len, xfer); |
| 686 if (readbytes > 0) |
686 if (readbytes > 0) |
| 687 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_DATA_INFO, |
687 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_DATA_INFO, |
| 688 info->max_fragment_index + sizeof(info->window) + 1, 0, buffer, readbytes); |
688 info->max_fragment_index + sizeof(info->window) + 1, 0, buffer, readbytes); |
| 689 |
689 |
| 690 info->max_fragment_index ++; |
690 info->max_fragment_index ++; |
| 691 if (mask & 0x8000) mask = 0x0001; |
691 if (mask & 0x8000) mask = 0x0001; |
| 692 else mask = mask << 1; |
692 else mask = mask << 1; |
| 693 } |
693 } |
| 694 } |
694 } |
| 695 purple_debug_info("QQ", |
695 purple_debug_info("QQ", |
| 696 "procceed %dth fragment ack, slide window status %o, max_fragment_index %d\n", |
696 "procceed %dth fragment ack, slide window status %o, max_fragment_index %d\n", |
| 697 fragment_index, info->window, info->max_fragment_index); |
697 fragment_index, info->window, info->max_fragment_index); |
| 698 } |
698 } |
| 699 |
699 |
| 700 static void _qq_process_recv_file_data(PurpleConnection *gc, guint8 *data, gint len) |
700 static void _qq_process_recv_file_data(PurpleConnection *gc, guint8 *data, gint len) |
| 701 { |
701 { |
| 725 case QQ_FILE_BASIC_INFO: |
725 case QQ_FILE_BASIC_INFO: |
| 726 bytes += 4; /* file length, we have already known it from xfer */ |
726 bytes += 4; /* file length, we have already known it from xfer */ |
| 727 bytes += qq_get32(&info->fragment_num, data + bytes); |
727 bytes += qq_get32(&info->fragment_num, data + bytes); |
| 728 bytes += qq_get32(&info->fragment_len, data + bytes); |
728 bytes += qq_get32(&info->fragment_len, data + bytes); |
| 729 |
729 |
| 730 /* FIXME: We must check the md5 here, |
730 /* FIXME: We must check the md5 here, |
| 731 * if md5 doesn't match we will ignore |
731 * if md5 doesn't match we will ignore |
| 732 * the packet or send sth as error number */ |
732 * the packet or send sth as error number */ |
| 733 |
733 |
| 734 info->max_fragment_index = 0; |
734 info->max_fragment_index = 0; |
| 735 info->window = 0; |
735 info->window = 0; |
| 736 purple_debug_info("QQ", |
736 purple_debug_info("QQ", |
| 737 "start receiving data, %d fragments with %d length each\n", |
737 "start receiving data, %d fragments with %d length each\n", |
| 738 info->fragment_num, info->fragment_len); |
738 info->fragment_num, info->fragment_len); |
| 739 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, |
739 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, |
| 740 0, 0, NULL, 0); |
740 0, 0, NULL, 0); |
| 741 break; |
741 break; |
| 742 case QQ_FILE_DATA_INFO: |
742 case QQ_FILE_DATA_INFO: |
| 743 bytes += qq_get32(&fragment_index, data + bytes); |
743 bytes += qq_get32(&fragment_index, data + bytes); |
| 744 bytes += qq_get32(&fragment_offset, data + bytes); |
744 bytes += qq_get32(&fragment_offset, data + bytes); |
| 745 bytes += qq_get16(&fragment_len, data + bytes); |
745 bytes += qq_get16(&fragment_len, data + bytes); |
| 746 purple_debug_info("QQ", |
746 purple_debug_info("QQ", |
| 747 "received %dth fragment with length %d, offset %d\n", |
747 "received %dth fragment with length %d, offset %d\n", |
| 748 fragment_index, fragment_len, fragment_offset); |
748 fragment_index, fragment_len, fragment_offset); |
| 749 |
749 |
| 750 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, |
750 _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, |
| 751 fragment_index, packet_seq, NULL, 0); |
751 fragment_index, packet_seq, NULL, 0); |