summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2013-10-02 20:53:48 -0400
committerirungentoo <irungentoo@gmail.com>2013-10-02 20:53:48 -0400
commitc014cebbe5753287c2d0657e0ebe002a520017b0 (patch)
tree5ac34c6c9e75bf35b90b464231cfb2e8ab7b83e0
parentefa3c79699c4d0af21b7fcdc30b6117adfdc1e9d (diff)
parentfbd494a8b44d58911a6329761d48a85f71fc1718 (diff)
Merge branch 'file-transfers'
File transfers are now working and in public api.
-rw-r--r--testing/nTox.c125
-rw-r--r--toxcore/Lossless_UDP.c8
-rw-r--r--toxcore/Messenger.c357
-rw-r--r--toxcore/Messenger.h95
-rw-r--r--toxcore/tox.c85
-rw-r--r--toxcore/tox.h90
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 {
67Friend_request pending_requests[256]; 67Friend_request pending_requests[256];
68uint8_t num_requests = 0; 68uint8_t num_requests = 0;
69 69
70#define NUM_FILE_SENDERS 256
71typedef struct {
72 FILE *file;
73 uint16_t friendnum;
74 uint8_t filenumber;
75 uint8_t nextpiece[1024];
76 uint16_t piecelength;
77} File_Sender;
78File_Sender file_senders[NUM_FILE_SENDERS];
79uint8_t numfilesenders;
80
81void 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}
108int 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
661void 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
675void 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
691void 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
590int main(int argc, char *argv[]) 709int 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 609static void break_files(Messenger *m, int friendnumber);
610static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) 610static 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
625void set_friend_status(Messenger *m, int friendnumber, uint8_t status) 629void 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 */
942void 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 */
954void 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 */
967void 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 */
981int 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 */
1005int 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 */
1035int 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 */
1100int 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 */
1131uint64_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 */
1154static 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
1167static 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. */
934static void LANdiscovery(Messenger *m) 1231static 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}
97USERSTATUS; 100USERSTATUS;
98 101
102struct 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
111enum {
112 FILECONTROL_ACCEPT,
113 FILECONTROL_PAUSE,
114 FILECONTROL_KILL,
115 FILECONTROL_FINISHED
116};
117
99typedef struct { 118typedef 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
122typedef struct Messenger { 143typedef 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
440int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); 469int 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 */
478void 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 */
486void 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 */
494void 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 */
502int 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 */
510int 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 */
518int 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 */
526int 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 */
535uint64_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 */
483void 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 */
495void 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 */
506void 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 */
519int 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 */
530int 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 */
541int 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 */
553uint64_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_
426int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length); 426int 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
450enum {
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 */
460void 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 */
471void 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 */
479void 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 */
488int 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 */
498int 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 */
506int 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 */
515uint64_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.