diff options
author | irungentoo <irungentoo@gmail.com> | 2013-10-02 20:53:48 -0400 |
---|---|---|
committer | irungentoo <irungentoo@gmail.com> | 2013-10-02 20:53:48 -0400 |
commit | c014cebbe5753287c2d0657e0ebe002a520017b0 (patch) | |
tree | 5ac34c6c9e75bf35b90b464231cfb2e8ab7b83e0 /toxcore/Messenger.c | |
parent | efa3c79699c4d0af21b7fcdc30b6117adfdc1e9d (diff) | |
parent | fbd494a8b44d58911a6329761d48a85f71fc1718 (diff) |
Merge branch 'file-transfers'
File transfers are now working and in public api.
Diffstat (limited to 'toxcore/Messenger.c')
-rw-r--r-- | toxcore/Messenger.c | 357 |
1 files changed, 354 insertions, 3 deletions
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 | } |