diff options
-rw-r--r-- | testing/nTox.c | 125 | ||||
-rw-r--r-- | toxcore/Lossless_UDP.c | 8 | ||||
-rw-r--r-- | toxcore/Messenger.c | 357 | ||||
-rw-r--r-- | toxcore/Messenger.h | 95 | ||||
-rw-r--r-- | toxcore/tox.c | 85 | ||||
-rw-r--r-- | toxcore/tox.h | 90 |
6 files changed, 753 insertions, 7 deletions
diff --git a/testing/nTox.c b/testing/nTox.c index 6ac663a6..f82c0fba 100644 --- a/testing/nTox.c +++ b/testing/nTox.c | |||
@@ -67,6 +67,68 @@ typedef struct { | |||
67 | Friend_request pending_requests[256]; | 67 | Friend_request pending_requests[256]; |
68 | uint8_t num_requests = 0; | 68 | uint8_t num_requests = 0; |
69 | 69 | ||
70 | #define NUM_FILE_SENDERS 256 | ||
71 | typedef struct { | ||
72 | FILE *file; | ||
73 | uint16_t friendnum; | ||
74 | uint8_t filenumber; | ||
75 | uint8_t nextpiece[1024]; | ||
76 | uint16_t piecelength; | ||
77 | } File_Sender; | ||
78 | File_Sender file_senders[NUM_FILE_SENDERS]; | ||
79 | uint8_t numfilesenders; | ||
80 | |||
81 | void send_filesenders(Tox *m) | ||
82 | { | ||
83 | uint32_t i; | ||
84 | |||
85 | for (i = 0; i < NUM_FILE_SENDERS; ++i) { | ||
86 | if (file_senders[i].file == 0) | ||
87 | continue; | ||
88 | |||
89 | while (1) { | ||
90 | if (!tox_file_senddata(m, file_senders[i].friendnum, file_senders[i].filenumber, file_senders[i].nextpiece, | ||
91 | file_senders[i].piecelength)) | ||
92 | break; | ||
93 | |||
94 | file_senders[i].piecelength = fread(file_senders[i].nextpiece, 1, 1000, file_senders[i].file); | ||
95 | |||
96 | if (file_senders[i].piecelength == 0) { | ||
97 | fclose(file_senders[i].file); | ||
98 | file_senders[i].file = 0; | ||
99 | tox_file_sendcontrol(m, file_senders[i].friendnum, 0, file_senders[i].filenumber, 3, 0, 0); | ||
100 | char msg[512]; | ||
101 | sprintf(msg, "[t] %u file transfer: %u completed", file_senders[i].friendnum, file_senders[i].filenumber); | ||
102 | new_lines(msg); | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | int add_filesender(Tox *m, uint16_t friendnum, char *filename) | ||
109 | { | ||
110 | FILE *tempfile = fopen(filename, "r"); | ||
111 | |||
112 | if (tempfile == 0) | ||
113 | return -1; | ||
114 | |||
115 | fseek(tempfile, 0, SEEK_END); | ||
116 | uint64_t filesize = ftell(tempfile); | ||
117 | fseek(tempfile, 0, SEEK_SET); | ||
118 | int filenum = tox_new_filesender(m, friendnum, filesize, (uint8_t *)filename, strlen(filename) + 1); | ||
119 | |||
120 | if (filenum == -1) | ||
121 | return -1; | ||
122 | |||
123 | file_senders[numfilesenders].file = tempfile; | ||
124 | file_senders[numfilesenders].piecelength = fread(file_senders[numfilesenders].nextpiece, 1, 1000, | ||
125 | file_senders[numfilesenders].file); | ||
126 | file_senders[numfilesenders].friendnum = friendnum; | ||
127 | file_senders[numfilesenders].filenumber = filenum; | ||
128 | ++numfilesenders; | ||
129 | return filenum; | ||
130 | } | ||
131 | |||
70 | /* | 132 | /* |
71 | resolve_addr(): | 133 | resolve_addr(): |
72 | address should represent IPv4 or a hostname with A record | 134 | address should represent IPv4 or a hostname with A record |
@@ -366,6 +428,16 @@ void line_eval(Tox *m, char *line) | |||
366 | tox_group_message_send(m, groupnumber, (uint8_t *)*posi + 1, strlen(*posi + 1) + 1)); | 428 | tox_group_message_send(m, groupnumber, (uint8_t *)*posi + 1, strlen(*posi + 1) + 1)); |
367 | new_lines(msg); | 429 | new_lines(msg); |
368 | } | 430 | } |
431 | } else if (inpt_command == 't') { | ||
432 | char msg[512]; | ||
433 | char *posi[1]; | ||
434 | int friendnum = strtoul(line + prompt_offset, posi, 0); | ||
435 | |||
436 | if (**posi != 0) { | ||
437 | sprintf(msg, "[t] Sending file %s to friendnum %u filenumber is %i (-1 means failure)", *posi + 1, friendnum, | ||
438 | add_filesender(m, friendnum, *posi + 1)); | ||
439 | new_lines(msg); | ||
440 | } | ||
369 | } else if (inpt_command == 'q') { //exit | 441 | } else if (inpt_command == 'q') { //exit |
370 | save_data(m); | 442 | save_data(m); |
371 | endwin(); | 443 | endwin(); |
@@ -586,6 +658,53 @@ void print_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *messag | |||
586 | new_lines(msg); | 658 | new_lines(msg); |
587 | } | 659 | } |
588 | 660 | ||
661 | void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, | ||
662 | uint16_t filename_length, void *userdata) | ||
663 | { | ||
664 | char msg[512]; | ||
665 | sprintf(msg, "[t] %u is sending us: %s of size %llu", friendnumber, filename, filesize); | ||
666 | new_lines(msg); | ||
667 | |||
668 | if (tox_file_sendcontrol(m, friendnumber, 1, filenumber, 0, 0, 0)) { | ||
669 | sprintf(msg, "Accepted file transfer. (saving file as: %u.%u.bin)", friendnumber, filenumber); | ||
670 | new_lines(msg); | ||
671 | } else | ||
672 | new_lines("Could not accept file transfer."); | ||
673 | } | ||
674 | |||
675 | void file_print_control(Tox *m, int friendnumber, uint8_t send_recieve, uint8_t filenumber, uint8_t control_type, | ||
676 | uint8_t *data, | ||
677 | uint16_t length, void *userdata) | ||
678 | { | ||
679 | char msg[512] = {0}; | ||
680 | |||
681 | if (control_type == 0) | ||
682 | sprintf(msg, "[t] %u accepted file transfer: %u", friendnumber, filenumber); | ||
683 | else if (control_type == 3) | ||
684 | sprintf(msg, "[t] %u file transfer: %u completed", friendnumber, filenumber); | ||
685 | else | ||
686 | sprintf(msg, "[t] control %u received", control_type); | ||
687 | |||
688 | new_lines(msg); | ||
689 | } | ||
690 | |||
691 | void write_file(Tox *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
692 | { | ||
693 | char filename[256]; | ||
694 | sprintf(filename, "%u.%u.bin", friendnumber, filenumber); | ||
695 | FILE *pFile = fopen(filename, "a"); | ||
696 | |||
697 | if (tox_file_dataremaining(m, friendnumber, filenumber, 1) == 0) { | ||
698 | //file_control(m, friendnumber, 1, filenumber, 3, 0, 0); | ||
699 | char msg[512]; | ||
700 | sprintf(msg, "[t] %u file transfer: %u completed", friendnumber, filenumber); | ||
701 | new_lines(msg); | ||
702 | } | ||
703 | |||
704 | fwrite(data, length, 1, pFile); | ||
705 | fclose(pFile); | ||
706 | } | ||
707 | |||
589 | 708 | ||
590 | int main(int argc, char *argv[]) | 709 | int main(int argc, char *argv[]) |
591 | { | 710 | { |
@@ -633,6 +752,9 @@ int main(int argc, char *argv[]) | |||
633 | tox_callback_statusmessage(m, print_statuschange, NULL); | 752 | tox_callback_statusmessage(m, print_statuschange, NULL); |
634 | tox_callback_group_invite(m, print_invite, NULL); | 753 | tox_callback_group_invite(m, print_invite, NULL); |
635 | tox_callback_group_message(m, print_groupmessage, NULL); | 754 | tox_callback_group_message(m, print_groupmessage, NULL); |
755 | tox_callback_file_data(m, write_file, NULL); | ||
756 | tox_callback_file_control(m, file_print_control, NULL); | ||
757 | tox_callback_file_sendrequest(m, file_request_accept, NULL); | ||
636 | 758 | ||
637 | initscr(); | 759 | initscr(); |
638 | noecho(); | 760 | noecho(); |
@@ -668,6 +790,7 @@ int main(int argc, char *argv[]) | |||
668 | } | 790 | } |
669 | 791 | ||
670 | time_t timestamp0 = time(NULL); | 792 | time_t timestamp0 = time(NULL); |
793 | |||
671 | while (1) { | 794 | while (1) { |
672 | if (on == 0) { | 795 | if (on == 0) { |
673 | if (tox_isconnected(m)) { | 796 | if (tox_isconnected(m)) { |
@@ -675,6 +798,7 @@ int main(int argc, char *argv[]) | |||
675 | on = 1; | 798 | on = 1; |
676 | } else { | 799 | } else { |
677 | time_t timestamp1 = time(NULL); | 800 | time_t timestamp1 = time(NULL); |
801 | |||
678 | if (timestamp0 + 10 < timestamp1) { | 802 | if (timestamp0 + 10 < timestamp1) { |
679 | timestamp0 = timestamp1; | 803 | timestamp0 = timestamp1; |
680 | tox_bootstrap_from_address(m, argv[argvoffset + 1], ipv6enabled, port, binary_string); | 804 | tox_bootstrap_from_address(m, argv[argvoffset + 1], ipv6enabled, port, binary_string); |
@@ -682,6 +806,7 @@ int main(int argc, char *argv[]) | |||
682 | } | 806 | } |
683 | } | 807 | } |
684 | 808 | ||
809 | send_filesenders(m); | ||
685 | tox_do(m); | 810 | tox_do(m); |
686 | c_sleep(1); | 811 | c_sleep(1); |
687 | do_refresh(); | 812 | do_refresh(); |
diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c index 53cdea09..bdf5cd4c 100644 --- a/toxcore/Lossless_UDP.c +++ b/toxcore/Lossless_UDP.c | |||
@@ -547,6 +547,8 @@ int discard_packet(Lossless_UDP *ludp, int connection_id) | |||
547 | return 0; | 547 | return 0; |
548 | } | 548 | } |
549 | 549 | ||
550 | #define MAX_SYNC_RATE 20 | ||
551 | |||
550 | /* return 0 if data could not be put in packet queue. | 552 | /* return 0 if data could not be put in packet queue. |
551 | * return 1 if data was put into the queue. | 553 | * return 1 if data was put into the queue. |
552 | */ | 554 | */ |
@@ -564,6 +566,8 @@ int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t | |||
564 | return 0; | 566 | return 0; |
565 | 567 | ||
566 | if (sendqueue(ludp, connection_id) >= connection->sendbuffer_length && connection->sendbuffer_length != 0) { | 568 | if (sendqueue(ludp, connection_id) >= connection->sendbuffer_length && connection->sendbuffer_length != 0) { |
569 | if (sendqueue(ludp, connection_id) > connection->data_rate/MAX_SYNC_RATE) | ||
570 | return 0; | ||
567 | uint32_t newlen = connection->sendbuffer_length = resize_queue(&connection->sendbuffer, connection->sendbuffer_length, | 571 | uint32_t newlen = connection->sendbuffer_length = resize_queue(&connection->sendbuffer, connection->sendbuffer_length, |
568 | connection->sendbuffer_length * 2, connection->successful_sent, connection->sendbuff_packetnum); | 572 | connection->sendbuffer_length * 2, connection->successful_sent, connection->sendbuff_packetnum); |
569 | 573 | ||
@@ -829,7 +833,7 @@ static void adjust_datasendspeed(Connection *connection, uint32_t req_packets) | |||
829 | return; | 833 | return; |
830 | } | 834 | } |
831 | 835 | ||
832 | if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 20 || req_packets <= 1) { | 836 | if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 5 || req_packets <= 10) { |
833 | connection->data_rate += (connection->data_rate / 8) + 1; | 837 | connection->data_rate += (connection->data_rate / 8) + 1; |
834 | 838 | ||
835 | if (connection->data_rate > connection->sendbuffer_length * connection->SYNC_rate) | 839 | if (connection->data_rate > connection->sendbuffer_length * connection->SYNC_rate) |
@@ -1084,7 +1088,7 @@ static void do_data(Lossless_UDP *ludp) | |||
1084 | } | 1088 | } |
1085 | } | 1089 | } |
1086 | 1090 | ||
1087 | #define MAX_SYNC_RATE 20 | 1091 | |
1088 | 1092 | ||
1089 | /* | 1093 | /* |
1090 | * Automatically adjusts send rates of packets for optimal transmission. | 1094 | * Automatically adjusts send rates of packets for optimal transmission. |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index c8d69494..ac79cde1 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -606,7 +606,7 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in | |||
606 | m->friend_connectionstatuschange = function; | 606 | m->friend_connectionstatuschange = function; |
607 | m->friend_connectionstatuschange_userdata = userdata; | 607 | m->friend_connectionstatuschange_userdata = userdata; |
608 | } | 608 | } |
609 | 609 | static void break_files(Messenger *m, int friendnumber); | |
610 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) | 610 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) |
611 | { | 611 | { |
612 | if (!m->friend_connectionstatuschange) | 612 | if (!m->friend_connectionstatuschange) |
@@ -618,8 +618,12 @@ static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_ | |||
618 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; | 618 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; |
619 | const uint8_t is_online = status == FRIEND_ONLINE; | 619 | const uint8_t is_online = status == FRIEND_ONLINE; |
620 | 620 | ||
621 | if (is_online != was_online) | 621 | if (is_online != was_online) { |
622 | if (was_online) | ||
623 | break_files(m, friendnumber); | ||
624 | |||
622 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | 625 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); |
626 | } | ||
623 | } | 627 | } |
624 | 628 | ||
625 | void set_friend_status(Messenger *m, int friendnumber, uint8_t status) | 629 | void set_friend_status(Messenger *m, int friendnumber, uint8_t status) |
@@ -928,7 +932,300 @@ static void do_allgroupchats(Messenger *m) | |||
928 | } | 932 | } |
929 | } | 933 | } |
930 | 934 | ||
931 | /*********************************/ | 935 | /****************FILE SENDING*****************/ |
936 | |||
937 | |||
938 | /* Set the callback for file send requests. | ||
939 | * | ||
940 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | ||
941 | */ | ||
942 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, | ||
943 | void *), void *userdata) | ||
944 | { | ||
945 | m->file_sendrequest = function; | ||
946 | m->file_sendrequest_userdata = userdata; | ||
947 | } | ||
948 | |||
949 | /* Set the callback for file control requests. | ||
950 | * | ||
951 | * Function(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | ||
952 | * | ||
953 | */ | ||
954 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint8_t, uint8_t, uint8_t *, | ||
955 | uint16_t, | ||
956 | void *), void *userdata) | ||
957 | { | ||
958 | m->file_filecontrol = function; | ||
959 | m->file_filecontrol_userdata = userdata; | ||
960 | } | ||
961 | |||
962 | /* Set the callback for file data. | ||
963 | * | ||
964 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
965 | * | ||
966 | */ | ||
967 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint8_t *, uint16_t length, void *), | ||
968 | void *userdata) | ||
969 | { | ||
970 | m->file_filedata = function; | ||
971 | m->file_filedata_userdata = userdata; | ||
972 | } | ||
973 | |||
974 | #define MAX_FILENAME_LENGTH 255 | ||
975 | |||
976 | /* Send a file send request. | ||
977 | * Maximum filename length is 255 bytes. | ||
978 | * return 1 on success | ||
979 | * return 0 on failure | ||
980 | */ | ||
981 | int file_sendrequest(Messenger *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, | ||
982 | uint16_t filename_length) | ||
983 | { | ||
984 | if (friend_not_valid(m, friendnumber)) | ||
985 | return 0; | ||
986 | |||
987 | if (filename_length > MAX_FILENAME_LENGTH) | ||
988 | return 0; | ||
989 | |||
990 | uint8_t packet[MAX_FILENAME_LENGTH + 1 + sizeof(filesize)]; | ||
991 | packet[0] = filenumber; | ||
992 | //TODO: | ||
993 | //filesize = htonll(filesize); | ||
994 | memcpy(packet + 1, &filesize, sizeof(filesize)); | ||
995 | memcpy(packet + 1 + sizeof(filesize), filename, filename_length); | ||
996 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, | ||
997 | 1 + sizeof(filesize) + filename_length); | ||
998 | } | ||
999 | |||
1000 | /* Send a file send request. | ||
1001 | * Maximum filename length is 255 bytes. | ||
1002 | * return file number on success | ||
1003 | * return -1 on failure | ||
1004 | */ | ||
1005 | int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) | ||
1006 | { | ||
1007 | if (friend_not_valid(m, friendnumber)) | ||
1008 | return 0; | ||
1009 | |||
1010 | uint32_t i; | ||
1011 | |||
1012 | for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { | ||
1013 | if (m->friendlist[friendnumber].file_sending[i].status == 0) | ||
1014 | break; | ||
1015 | } | ||
1016 | |||
1017 | if (i == MAX_CONCURRENT_FILE_PIPES) | ||
1018 | return -1; | ||
1019 | |||
1020 | if (file_sendrequest(m, friendnumber, i, filesize, filename, filename_length) == 0) | ||
1021 | return -1; | ||
1022 | |||
1023 | m->friendlist[friendnumber].file_sending[i].status = 1; | ||
1024 | m->friendlist[friendnumber].file_sending[i].size = filesize; | ||
1025 | m->friendlist[friendnumber].file_sending[i].transferred = 0; | ||
1026 | return i; | ||
1027 | } | ||
1028 | |||
1029 | /* Send a file control request. | ||
1030 | * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. | ||
1031 | * | ||
1032 | * return 1 on success | ||
1033 | * return 0 on failure | ||
1034 | */ | ||
1035 | int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | ||
1036 | uint8_t *data, uint16_t length) | ||
1037 | { | ||
1038 | if (length > MAX_DATA_SIZE - 3) | ||
1039 | return 0; | ||
1040 | |||
1041 | if (friend_not_valid(m, friendnumber)) | ||
1042 | return 0; | ||
1043 | |||
1044 | if (m->friendlist[friendnumber].file_receiving[filenumber].status == 0) | ||
1045 | return 0; | ||
1046 | |||
1047 | if (send_receive > 1) | ||
1048 | return 0; | ||
1049 | |||
1050 | uint8_t packet[MAX_DATA_SIZE]; | ||
1051 | packet[0] = send_receive; | ||
1052 | packet[1] = filenumber; | ||
1053 | packet[2] = message_id; | ||
1054 | memcpy(packet + 3, data, length); | ||
1055 | |||
1056 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3)) { | ||
1057 | if (send_receive == 1) | ||
1058 | switch (message_id) { | ||
1059 | case FILECONTROL_ACCEPT: | ||
1060 | m->friendlist[friendnumber].file_receiving[filenumber].status = 3; | ||
1061 | break; | ||
1062 | |||
1063 | case FILECONTROL_PAUSE: | ||
1064 | m->friendlist[friendnumber].file_receiving[filenumber].status = 5; | ||
1065 | break; | ||
1066 | |||
1067 | case FILECONTROL_KILL: | ||
1068 | case FILECONTROL_FINISHED: | ||
1069 | m->friendlist[friendnumber].file_receiving[filenumber].status = 0; | ||
1070 | break; | ||
1071 | } | ||
1072 | else | ||
1073 | switch (message_id) { | ||
1074 | case FILECONTROL_ACCEPT: | ||
1075 | m->friendlist[friendnumber].file_sending[filenumber].status = 3; | ||
1076 | break; | ||
1077 | |||
1078 | case FILECONTROL_PAUSE: | ||
1079 | m->friendlist[friendnumber].file_sending[filenumber].status = 5; | ||
1080 | break; | ||
1081 | |||
1082 | case FILECONTROL_KILL: | ||
1083 | case FILECONTROL_FINISHED: | ||
1084 | m->friendlist[friendnumber].file_sending[filenumber].status = 0; | ||
1085 | break; | ||
1086 | } | ||
1087 | |||
1088 | return 1; | ||
1089 | } else { | ||
1090 | return 0; | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | |||
1095 | /* Send file data. | ||
1096 | * | ||
1097 | * return 1 on success | ||
1098 | * return 0 on failure | ||
1099 | */ | ||
1100 | int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) | ||
1101 | { | ||
1102 | if (length > MAX_DATA_SIZE - 1) | ||
1103 | return 0; | ||
1104 | |||
1105 | if (friend_not_valid(m, friendnumber)) | ||
1106 | return 0; | ||
1107 | |||
1108 | if (m->friendlist[friendnumber].file_sending[filenumber].status != 3) | ||
1109 | return 0; | ||
1110 | |||
1111 | uint8_t packet[MAX_DATA_SIZE]; | ||
1112 | packet[0] = filenumber; | ||
1113 | memcpy(packet + 1, data, length); | ||
1114 | |||
1115 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1)) { | ||
1116 | m->friendlist[friendnumber].file_sending[filenumber].transferred += length; | ||
1117 | return 1; | ||
1118 | } | ||
1119 | |||
1120 | return 0; | ||
1121 | |||
1122 | } | ||
1123 | |||
1124 | /* Give the number of bytes left to be sent/received. | ||
1125 | * | ||
1126 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | ||
1127 | * | ||
1128 | * return number of bytes remaining to be sent/received on success | ||
1129 | * return 0 on failure | ||
1130 | */ | ||
1131 | uint64_t file_dataremaining(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t send_receive) | ||
1132 | { | ||
1133 | if (friend_not_valid(m, friendnumber)) | ||
1134 | return 0; | ||
1135 | |||
1136 | if (send_receive == 0) { | ||
1137 | if (m->friendlist[friendnumber].file_sending[filenumber].status == 0) | ||
1138 | return 0; | ||
1139 | |||
1140 | return m->friendlist[friendnumber].file_sending[filenumber].size - | ||
1141 | m->friendlist[friendnumber].file_sending[filenumber].transferred; | ||
1142 | } else { | ||
1143 | if (m->friendlist[friendnumber].file_receiving[filenumber].status == 0) | ||
1144 | return 0; | ||
1145 | |||
1146 | return m->friendlist[friendnumber].file_receiving[filenumber].size - | ||
1147 | m->friendlist[friendnumber].file_receiving[filenumber].transferred; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | /* Run this when the friend disconnects. | ||
1152 | * Sets all current file transfers to broken. | ||
1153 | */ | ||
1154 | static void break_files(Messenger *m, int friendnumber) | ||
1155 | { | ||
1156 | uint32_t i; | ||
1157 | |||
1158 | for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { | ||
1159 | if (m->friendlist[friendnumber].file_sending[i].status != 0) | ||
1160 | m->friendlist[friendnumber].file_sending[i].status = 4; | ||
1161 | |||
1162 | if (m->friendlist[friendnumber].file_receiving[i].status != 0) | ||
1163 | m->friendlist[friendnumber].file_receiving[i].status = 4; | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | static int handle_filecontrol(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, | ||
1168 | uint8_t message_id, uint8_t *data, | ||
1169 | uint16_t length) | ||
1170 | { | ||
1171 | if (send_receive > 1) | ||
1172 | return -1; | ||
1173 | |||
1174 | if (send_receive == 0) { | ||
1175 | if (m->friendlist[friendnumber].file_receiving[filenumber].status == 0) | ||
1176 | return -1; | ||
1177 | |||
1178 | switch (message_id) { | ||
1179 | case FILECONTROL_ACCEPT: | ||
1180 | if (m->friendlist[friendnumber].file_receiving[filenumber].status != 5) { | ||
1181 | m->friendlist[friendnumber].file_receiving[filenumber].status = 3; | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | return -1; | ||
1186 | |||
1187 | case FILECONTROL_PAUSE: | ||
1188 | if (m->friendlist[friendnumber].file_receiving[filenumber].status != 5) { | ||
1189 | m->friendlist[friendnumber].file_receiving[filenumber].status = 2; | ||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | return -1; | ||
1194 | |||
1195 | case FILECONTROL_KILL: | ||
1196 | case FILECONTROL_FINISHED: | ||
1197 | m->friendlist[friendnumber].file_receiving[filenumber].status = 0; | ||
1198 | return 0; | ||
1199 | } | ||
1200 | } else { | ||
1201 | if (m->friendlist[friendnumber].file_sending[filenumber].status == 0) | ||
1202 | return -1; | ||
1203 | |||
1204 | switch (message_id) { | ||
1205 | case FILECONTROL_ACCEPT: | ||
1206 | if (m->friendlist[friendnumber].file_sending[filenumber].status != 5) { | ||
1207 | m->friendlist[friendnumber].file_sending[filenumber].status = 3; | ||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | return -1; | ||
1212 | |||
1213 | case FILECONTROL_PAUSE: | ||
1214 | m->friendlist[friendnumber].file_sending[filenumber].status = 2; | ||
1215 | return 0; | ||
1216 | |||
1217 | case FILECONTROL_KILL: | ||
1218 | case FILECONTROL_FINISHED: | ||
1219 | m->friendlist[friendnumber].file_sending[filenumber].status = 0; | ||
1220 | return 0; | ||
1221 | } | ||
1222 | } | ||
1223 | |||
1224 | return -1; | ||
1225 | } | ||
1226 | |||
1227 | /**************************************/ | ||
1228 | |||
932 | 1229 | ||
933 | /* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ | 1230 | /* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ |
934 | static void LANdiscovery(Messenger *m) | 1231 | static void LANdiscovery(Messenger *m) |
@@ -1210,6 +1507,60 @@ void doFriends(Messenger *m) | |||
1210 | break; | 1507 | break; |
1211 | } | 1508 | } |
1212 | 1509 | ||
1510 | case PACKET_ID_FILE_SENDREQUEST: { | ||
1511 | if (data_length < 1 + sizeof(uint64_t) + 1) | ||
1512 | break; | ||
1513 | |||
1514 | uint8_t filenumber = data[0]; | ||
1515 | uint64_t filesize; | ||
1516 | memcpy(&filesize, data + 1, sizeof(filesize)); | ||
1517 | //TODO: | ||
1518 | //filesize = ntohll(filesize); | ||
1519 | m->friendlist[i].file_receiving[filenumber].status = 1; | ||
1520 | m->friendlist[i].file_receiving[filenumber].size = filesize; | ||
1521 | m->friendlist[i].file_receiving[filenumber].transferred = 0; | ||
1522 | if (m->file_sendrequest) | ||
1523 | (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), | ||
1524 | m->file_sendrequest_userdata); | ||
1525 | |||
1526 | break; | ||
1527 | } | ||
1528 | |||
1529 | case PACKET_ID_FILE_CONTROL: { | ||
1530 | if (data_length < 3) | ||
1531 | break; | ||
1532 | |||
1533 | uint8_t send_receive = data[0]; | ||
1534 | uint8_t filenumber = data[1]; | ||
1535 | uint8_t control_type = data[2]; | ||
1536 | |||
1537 | if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) | ||
1538 | break; | ||
1539 | |||
1540 | if (m->file_filecontrol) | ||
1541 | (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, | ||
1542 | m->file_filecontrol_userdata); | ||
1543 | |||
1544 | break; | ||
1545 | } | ||
1546 | |||
1547 | case PACKET_ID_FILE_DATA: { | ||
1548 | if (data_length < 2) | ||
1549 | break; | ||
1550 | |||
1551 | uint8_t filenumber = data[0]; | ||
1552 | |||
1553 | if (m->friendlist[i].file_receiving[filenumber].status == 0) | ||
1554 | break; | ||
1555 | |||
1556 | m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); | ||
1557 | |||
1558 | if (m->file_filedata) | ||
1559 | (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); | ||
1560 | |||
1561 | break; | ||
1562 | } | ||
1563 | |||
1213 | default: { | 1564 | default: { |
1214 | break; | 1565 | break; |
1215 | } | 1566 | } |
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 0ff14de4..5d31e15b 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -44,6 +44,9 @@ | |||
44 | #define PACKET_ID_RECEIPT 65 | 44 | #define PACKET_ID_RECEIPT 65 |
45 | #define PACKET_ID_MESSAGE 64 | 45 | #define PACKET_ID_MESSAGE 64 |
46 | #define PACKET_ID_ACTION 63 | 46 | #define PACKET_ID_ACTION 63 |
47 | #define PACKET_ID_FILE_SENDREQUEST 80 | ||
48 | #define PACKET_ID_FILE_CONTROL 81 | ||
49 | #define PACKET_ID_FILE_DATA 82 | ||
47 | #define PACKET_ID_INVITE_GROUPCHAT 144 | 50 | #define PACKET_ID_INVITE_GROUPCHAT 144 |
48 | #define PACKET_ID_JOIN_GROUPCHAT 145 | 51 | #define PACKET_ID_JOIN_GROUPCHAT 145 |
49 | #define PACKET_ID_ACCEPT_GROUPCHAT 146 | 52 | #define PACKET_ID_ACCEPT_GROUPCHAT 146 |
@@ -96,6 +99,22 @@ typedef enum { | |||
96 | } | 99 | } |
97 | USERSTATUS; | 100 | USERSTATUS; |
98 | 101 | ||
102 | struct File_Transfers { | ||
103 | uint64_t size; | ||
104 | uint64_t transferred; | ||
105 | uint8_t status; /* 0 == no transfer, 1 = not accepted, 2 = paused by the other, 3 = transferring, 4 = broken, 5 = paused by us */ | ||
106 | }; | ||
107 | |||
108 | /* This cannot be bigger than 256 */ | ||
109 | #define MAX_CONCURRENT_FILE_PIPES 256 | ||
110 | |||
111 | enum { | ||
112 | FILECONTROL_ACCEPT, | ||
113 | FILECONTROL_PAUSE, | ||
114 | FILECONTROL_KILL, | ||
115 | FILECONTROL_FINISHED | ||
116 | }; | ||
117 | |||
99 | typedef struct { | 118 | typedef struct { |
100 | uint8_t client_id[CLIENT_ID_SIZE]; | 119 | uint8_t client_id[CLIENT_ID_SIZE]; |
101 | int crypt_connection_id; | 120 | int crypt_connection_id; |
@@ -117,6 +136,8 @@ typedef struct { | |||
117 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. | 136 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. |
118 | uint64_t ping_lastrecv; | 137 | uint64_t ping_lastrecv; |
119 | uint64_t ping_lastsent; | 138 | uint64_t ping_lastsent; |
139 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; | ||
140 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | ||
120 | } Friend; | 141 | } Friend; |
121 | 142 | ||
122 | typedef struct Messenger { | 143 | typedef struct Messenger { |
@@ -157,11 +178,19 @@ typedef struct Messenger { | |||
157 | void *friend_statuschange_userdata; | 178 | void *friend_statuschange_userdata; |
158 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); | 179 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); |
159 | void *friend_connectionstatuschange_userdata; | 180 | void *friend_connectionstatuschange_userdata; |
181 | |||
160 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); | 182 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); |
161 | void *group_invite_userdata; | 183 | void *group_invite_userdata; |
162 | void (*group_message)(struct Messenger *m, int, int, uint8_t *, uint16_t, void *); | 184 | void (*group_message)(struct Messenger *m, int, int, uint8_t *, uint16_t, void *); |
163 | void *group_message_userdata; | 185 | void *group_message_userdata; |
164 | 186 | ||
187 | void (*file_sendrequest)(struct Messenger *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, void *); | ||
188 | void *file_sendrequest_userdata; | ||
189 | void (*file_filecontrol)(struct Messenger *m, int, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t, void *); | ||
190 | void *file_filecontrol_userdata; | ||
191 | void (*file_filedata)(struct Messenger *m, int, uint8_t, uint8_t *, uint16_t length, void *); | ||
192 | void *file_filedata_userdata; | ||
193 | |||
165 | } Messenger; | 194 | } Messenger; |
166 | 195 | ||
167 | /* Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 196 | /* Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] |
@@ -439,6 +468,72 @@ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_ | |||
439 | 468 | ||
440 | int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); | 469 | int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); |
441 | 470 | ||
471 | /****************FILE SENDING*****************/ | ||
472 | |||
473 | |||
474 | /* Set the callback for file send requests. | ||
475 | * | ||
476 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | ||
477 | */ | ||
478 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, | ||
479 | void *), void *userdata); | ||
480 | |||
481 | /* Set the callback for file control requests. | ||
482 | * | ||
483 | * Function(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | ||
484 | * | ||
485 | */ | ||
486 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint8_t, uint8_t, uint8_t *, | ||
487 | uint16_t, void *), void *userdata); | ||
488 | |||
489 | /* Set the callback for file data. | ||
490 | * | ||
491 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
492 | * | ||
493 | */ | ||
494 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, int, uint8_t, uint8_t *, uint16_t length, void *), | ||
495 | void *userdata); | ||
496 | |||
497 | /* Send a file send request. | ||
498 | * Maximum filename length is 255 bytes. | ||
499 | * return 1 on success | ||
500 | * return 0 on failure | ||
501 | */ | ||
502 | int file_sendrequest(Messenger *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, | ||
503 | uint16_t filename_length); | ||
504 | |||
505 | /* Send a file send request. | ||
506 | * Maximum filename length is 255 bytes. | ||
507 | * return file number on success | ||
508 | * return -1 on failure | ||
509 | */ | ||
510 | int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length); | ||
511 | |||
512 | /* Send a file control request. | ||
513 | * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. | ||
514 | * | ||
515 | * return 1 on success | ||
516 | * return 0 on failure | ||
517 | */ | ||
518 | int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | ||
519 | uint8_t *data, uint16_t length); | ||
520 | |||
521 | /* Send file data. | ||
522 | * | ||
523 | * return 1 on success | ||
524 | * return 0 on failure | ||
525 | */ | ||
526 | int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length); | ||
527 | |||
528 | /* Give the number of bytes left to be sent/received. | ||
529 | * | ||
530 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | ||
531 | * | ||
532 | * return number of bytes remaining to be sent/received on success | ||
533 | * return 0 on failure | ||
534 | */ | ||
535 | uint64_t file_dataremaining(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t send_receive); | ||
536 | |||
442 | /*********************************/ | 537 | /*********************************/ |
443 | 538 | ||
444 | /* Run this at startup. | 539 | /* Run this at startup. |
diff --git a/toxcore/tox.c b/toxcore/tox.c index 1d7118be..21e8bf75 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -473,7 +473,90 @@ int tox_group_message_send(void *tox, int groupnumber, uint8_t *message, uint32_ | |||
473 | 473 | ||
474 | 474 | ||
475 | 475 | ||
476 | /******************END OF GROUP CHAT FUNCTIONS************************/ | 476 | /****************FILE SENDING FUNCTIONS*****************/ |
477 | |||
478 | |||
479 | /* Set the callback for file send requests. | ||
480 | * | ||
481 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | ||
482 | */ | ||
483 | void tox_callback_file_sendrequest(void *tox, void (*function)(Messenger *tox, int, uint8_t, uint64_t, uint8_t *, | ||
484 | uint16_t, | ||
485 | void *), void *userdata) | ||
486 | { | ||
487 | Messenger *m = tox; | ||
488 | callback_file_sendrequest(m, function, userdata); | ||
489 | } | ||
490 | /* Set the callback for file control requests. | ||
491 | * | ||
492 | * Function(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | ||
493 | * | ||
494 | */ | ||
495 | void tox_callback_file_control(void *tox, void (*function)(Messenger *tox, int, uint8_t, uint8_t, uint8_t, uint8_t *, | ||
496 | uint16_t, void *), void *userdata) | ||
497 | { | ||
498 | Messenger *m = tox; | ||
499 | callback_file_control(m, function, userdata); | ||
500 | } | ||
501 | /* Set the callback for file data. | ||
502 | * | ||
503 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
504 | * | ||
505 | */ | ||
506 | void tox_callback_file_data(void *tox, void (*function)(Messenger *tox, int, uint8_t, uint8_t *, uint16_t length, | ||
507 | void *), | ||
508 | void *userdata) | ||
509 | |||
510 | { | ||
511 | Messenger *m = tox; | ||
512 | callback_file_data(m, function, userdata); | ||
513 | } | ||
514 | /* Send a file send request. | ||
515 | * Maximum filename length is 255 bytes. | ||
516 | * return file number on success | ||
517 | * return -1 on failure | ||
518 | */ | ||
519 | int tox_new_filesender(void *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) | ||
520 | { | ||
521 | Messenger *m = tox; | ||
522 | return new_filesender(m, friendnumber, filesize, filename, filename_length); | ||
523 | } | ||
524 | /* Send a file control request. | ||
525 | * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. | ||
526 | * | ||
527 | * return 1 on success | ||
528 | * return 0 on failure | ||
529 | */ | ||
530 | int tox_file_sendcontrol(void *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | ||
531 | uint8_t *data, uint16_t length) | ||
532 | { | ||
533 | Messenger *m = tox; | ||
534 | return file_control(m, friendnumber, send_receive, filenumber, message_id, data, length); | ||
535 | } | ||
536 | /* Send file data. | ||
537 | * | ||
538 | * return 1 on success | ||
539 | * return 0 on failure | ||
540 | */ | ||
541 | int tox_file_senddata(void *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) | ||
542 | { | ||
543 | Messenger *m = tox; | ||
544 | return file_data(m, friendnumber, filenumber, data, length); | ||
545 | } | ||
546 | /* Give the number of bytes left to be sent/received. | ||
547 | * | ||
548 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | ||
549 | * | ||
550 | * return number of bytes remaining to be sent/received on success | ||
551 | * return 0 on failure | ||
552 | */ | ||
553 | uint64_t tox_file_dataremaining(void *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive) | ||
554 | { | ||
555 | Messenger *m = tox; | ||
556 | return file_dataremaining(m, friendnumber, filenumber, send_receive); | ||
557 | } | ||
558 | |||
559 | /***************END OF FILE SENDING FUNCTIONS******************/ | ||
477 | 560 | ||
478 | /* Use these functions to bootstrap the client. | 561 | /* Use these functions to bootstrap the client. |
479 | * Sends a get nodes request to the given node with ip port and public_key. | 562 | * Sends a get nodes request to the given node with ip port and public_key. |
diff --git a/toxcore/tox.h b/toxcore/tox.h index eabbb1af..b1f18515 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -426,8 +426,96 @@ int tox_join_groupchat(Tox *tox, int friendnumber, uint8_t *friend_group_public_ | |||
426 | int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length); | 426 | int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length); |
427 | 427 | ||
428 | 428 | ||
429 | /****************FILE SENDING FUNCTIONS*****************/ | ||
430 | /* NOTE: This how to will be updated. | ||
431 | * | ||
432 | * HOW TO SEND FILES CORRECTLY: | ||
433 | * 1. Use tox_new_filesender(...) to create a new file sender. | ||
434 | * 2. Wait for the callback set with tox_callback_file_control(...) to be called with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT | ||
435 | * 3. Send the data with tox_file_senddata(...) | ||
436 | * 4. When sending is done, send a tox_file_sendcontrol(...) with send_receive = 0 and message_id = TOX_FILECONTROL_FINISHED | ||
437 | * | ||
438 | * HOW TO RECEIVE FILES CORRECTLY: | ||
439 | * 1. wait for the callback set with tox_callback_file_sendrequest(...) | ||
440 | * 2. accept or refuse the connection with tox_file_sendcontrol(...) with send_receive = 1 and message_id = TOX_FILECONTROL_ACCEPT or TOX_FILECONTROL_KILL | ||
441 | * 3. save all the data received with the callback set with tox_callback_file_data(...) to a file. | ||
442 | * 4. when the callback set with tox_callback_file_control(...) is called with receive_send == 0 and control_type == TOX_FILECONTROL_FINISHED | ||
443 | * the file is done transferring. | ||
444 | * | ||
445 | * tox_file_dataremaining(...) can be used to know how many bytes are left to send/receive. | ||
446 | * | ||
447 | * More to come... | ||
448 | */ | ||
449 | |||
450 | enum { | ||
451 | TOX_FILECONTROL_ACCEPT, | ||
452 | TOX_FILECONTROL_PAUSE, | ||
453 | TOX_FILECONTROL_KILL, | ||
454 | TOX_FILECONTROL_FINISHED | ||
455 | }; | ||
456 | /* Set the callback for file send requests. | ||
457 | * | ||
458 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | ||
459 | */ | ||
460 | void tox_callback_file_sendrequest(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, | ||
461 | void *), void *userdata); | ||
462 | |||
463 | /* Set the callback for file control requests. | ||
464 | * | ||
465 | * receive_send is 1 if the message is for a slot on which we are currently sending a file and 0 if the message | ||
466 | * is for a slot on which we are receiving the file | ||
467 | * | ||
468 | * Function(Tox *tox, int friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | ||
469 | * | ||
470 | */ | ||
471 | void tox_callback_file_control(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint8_t, uint8_t, uint8_t *, | ||
472 | uint16_t, void *), void *userdata); | ||
473 | |||
474 | /* Set the callback for file data. | ||
475 | * | ||
476 | * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
477 | * | ||
478 | */ | ||
479 | void tox_callback_file_data(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint8_t *, uint16_t length, void *), | ||
480 | void *userdata); | ||
481 | |||
482 | |||
483 | /* Send a file send request. | ||
484 | * Maximum filename length is 255 bytes. | ||
485 | * return file number on success | ||
486 | * return -1 on failure | ||
487 | */ | ||
488 | int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length); | ||
489 | |||
490 | /* Send a file control request. | ||
491 | * | ||
492 | * send_receive is 0 if we want the control packet to target a file we are currently sending, | ||
493 | * 1 if it targets a file we are currently receiving. | ||
494 | * | ||
495 | * return 1 on success | ||
496 | * return 0 on failure | ||
497 | */ | ||
498 | int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | ||
499 | uint8_t *data, uint16_t length); | ||
500 | |||
501 | /* Send file data. | ||
502 | * | ||
503 | * return 1 on success | ||
504 | * return 0 on failure | ||
505 | */ | ||
506 | int tox_file_senddata(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length); | ||
507 | |||
508 | /* Give the number of bytes left to be sent/received. | ||
509 | * | ||
510 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | ||
511 | * | ||
512 | * return number of bytes remaining to be sent/received on success | ||
513 | * return 0 on failure | ||
514 | */ | ||
515 | uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive); | ||
516 | |||
517 | /***************END OF FILE SENDING FUNCTIONS******************/ | ||
429 | 518 | ||
430 | /******************END OF GROUP CHAT FUNCTIONS************************/ | ||
431 | 519 | ||
432 | /* | 520 | /* |
433 | * Use these two functions to bootstrap the client. | 521 | * Use these two functions to bootstrap the client. |