summaryrefslogtreecommitdiff
path: root/toxcore/Messenger.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/Messenger.c')
-rw-r--r--toxcore/Messenger.c357
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 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 }