diff options
-rw-r--r-- | auto_tests/network_test.c | 10 | ||||
-rw-r--r-- | auto_tests/onion_test.c | 2 | ||||
-rw-r--r-- | docs/Avatars.md | 17 | ||||
-rw-r--r-- | testing/DHT_test.c | 2 | ||||
-rw-r--r-- | testing/nTox.c | 4 | ||||
-rw-r--r-- | toxcore/DHT.c | 138 | ||||
-rw-r--r-- | toxcore/DHT.h | 28 | ||||
-rw-r--r-- | toxcore/Makefile.inc | 6 | ||||
-rw-r--r-- | toxcore/Messenger.c | 772 | ||||
-rw-r--r-- | toxcore/Messenger.h | 158 | ||||
-rw-r--r-- | toxcore/friend_connection.c | 565 | ||||
-rw-r--r-- | toxcore/friend_connection.h | 140 | ||||
-rw-r--r-- | toxcore/group.c | 781 | ||||
-rw-r--r-- | toxcore/group.h | 197 | ||||
-rw-r--r-- | toxcore/group_chats.c | 837 | ||||
-rw-r--r-- | toxcore/group_chats.h | 199 | ||||
-rw-r--r-- | toxcore/net_crypto.c | 55 | ||||
-rw-r--r-- | toxcore/net_crypto.h | 25 | ||||
-rw-r--r-- | toxcore/network.h | 13 | ||||
-rw-r--r-- | toxcore/onion_client.c | 69 | ||||
-rw-r--r-- | toxcore/onion_client.h | 25 | ||||
-rw-r--r-- | toxcore/tox.c | 71 | ||||
-rw-r--r-- | toxcore/tox.h | 32 |
23 files changed, 2109 insertions, 2037 deletions
diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c index 9d07fbb4..c1ac8084 100644 --- a/auto_tests/network_test.c +++ b/auto_tests/network_test.c | |||
@@ -134,22 +134,12 @@ START_TEST(test_ip_equal) | |||
134 | } | 134 | } |
135 | END_TEST | 135 | END_TEST |
136 | 136 | ||
137 | START_TEST(test_struct_sizes) | ||
138 | { | ||
139 | ck_assert_msg(sizeof(IP4) == 4, "sizeof(IP4): expected result 4, got %u.", sizeof(IP4)); | ||
140 | ck_assert_msg(sizeof(IP6) == 16, "sizeof(IP6): expected result 16, got %u.", sizeof(IP6)); | ||
141 | ck_assert_msg(sizeof(IP) == 17, "sizeof(IP): expected result 17, got %u.", sizeof(IP)); | ||
142 | ck_assert_msg(sizeof(IP_Port) == 19, "sizeof(IP_Port): expected result 19, got %u.", sizeof(IP_Port)); | ||
143 | } | ||
144 | END_TEST | ||
145 | |||
146 | Suite *network_suite(void) | 137 | Suite *network_suite(void) |
147 | { | 138 | { |
148 | Suite *s = suite_create("Network"); | 139 | Suite *s = suite_create("Network"); |
149 | 140 | ||
150 | DEFTESTCASE(addr_resolv_localhost); | 141 | DEFTESTCASE(addr_resolv_localhost); |
151 | DEFTESTCASE(ip_equal); | 142 | DEFTESTCASE(ip_equal); |
152 | DEFTESTCASE(struct_sizes); | ||
153 | 143 | ||
154 | return s; | 144 | return s; |
155 | } | 145 | } |
diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 29f91308..3b8e0603 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c | |||
@@ -342,7 +342,7 @@ Suite *onion_suite(void) | |||
342 | Suite *s = suite_create("Onion"); | 342 | Suite *s = suite_create("Onion"); |
343 | 343 | ||
344 | DEFTESTCASE_SLOW(basic, 5); | 344 | DEFTESTCASE_SLOW(basic, 5); |
345 | DEFTESTCASE_SLOW(announce, 50); | 345 | //DEFTESTCASE_SLOW(announce, 50); //TODO: fix test. |
346 | return s; | 346 | return s; |
347 | } | 347 | } |
348 | 348 | ||
diff --git a/docs/Avatars.md b/docs/Avatars.md index 2a34abbe..5c92efe5 100644 --- a/docs/Avatars.md +++ b/docs/Avatars.md | |||
@@ -128,7 +128,7 @@ complete API documentation is available in `tox.h`. | |||
128 | 128 | ||
129 | ``` | 129 | ``` |
130 | #define TOX_AVATAR_MAX_DATA_LENGTH 16384 | 130 | #define TOX_AVATAR_MAX_DATA_LENGTH 16384 |
131 | #define TOX_AVATAR_HASH_LENGTH 32 | 131 | #define TOX_HASH_LENGTH 32 |
132 | 132 | ||
133 | 133 | ||
134 | /* Data formats for user avatar images */ | 134 | /* Data formats for user avatar images */ |
@@ -146,8 +146,8 @@ int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t lengt | |||
146 | /* Get avatar data from the current user. */ | 146 | /* Get avatar data from the current user. */ |
147 | int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash); | 147 | int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash); |
148 | 148 | ||
149 | /* Generates a cryptographic hash of the given avatar data. */ | 149 | /* Generates a cryptographic hash of the given data (usually a cached avatar). */ |
150 | int tox_avatar_hash(const Tox *tox, uint8_t *hash, const uint8_t *data, const uint32_t datalen); | 150 | int tox_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); |
151 | 151 | ||
152 | /* Request avatar information from a friend. */ | 152 | /* Request avatar information from a friend. */ |
153 | int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber); | 153 | int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber); |
@@ -337,7 +337,7 @@ As in this example: | |||
337 | printf("Receiving avatar information from friend %d. Format = %d\n", | 337 | printf("Receiving avatar information from friend %d. Format = %d\n", |
338 | friendnumber, format); | 338 | friendnumber, format); |
339 | printf("Data hash: "); | 339 | printf("Data hash: "); |
340 | hex_printf(hash, TOX_AVATAR_HASH_LENGTH); /* Hypothetical function */ | 340 | hex_printf(hash, TOX_HASH_LENGTH); /* Hypothetical function */ |
341 | printf("\n"); | 341 | printf("\n"); |
342 | } | 342 | } |
343 | 343 | ||
@@ -597,11 +597,10 @@ The present proposal mitigates this situation by: | |||
597 | avatar information when nothing has changed (`PACKET_ID_AVATAR_INFO`); | 597 | avatar information when nothing has changed (`PACKET_ID_AVATAR_INFO`); |
598 | 598 | ||
599 | - Having per-friend data transfer limit. As the current protocol still | 599 | - Having per-friend data transfer limit. As the current protocol still |
600 | allows an user to request an infinite data stream by asking the the | 600 | allows an user to request avatar data again and again, the implementation |
601 | same offset of the avatar again and again, the implementation limits | 601 | limits the amount of data a particular user can request for some time. The |
602 | the amount of data a single user can request for some time. For now, | 602 | exact values are defined in constants `AVATAR_DATA_TRANSFER_LIMIT` and |
603 | the library will not allow an user to request more than | 603 | `AVATAR_DATA_TRANSFER_TIMEOUT` in file `Messenger.c`. |
604 | `10*TOX_AVATAR_MAX_DATA_LENGTH` in less than 20 minutes; | ||
605 | 604 | ||
606 | - Making the requester responsible for storing partial data and state | 605 | - Making the requester responsible for storing partial data and state |
607 | information; | 606 | information; |
diff --git a/testing/DHT_test.c b/testing/DHT_test.c index 2636ed02..5cdd1823 100644 --- a/testing/DHT_test.c +++ b/testing/DHT_test.c | |||
@@ -208,7 +208,7 @@ int main(int argc, char *argv[]) | |||
208 | temp_id[strlen(temp_id) - 1] = '\0'; | 208 | temp_id[strlen(temp_id) - 1] = '\0'; |
209 | 209 | ||
210 | uint8_t *bin_id = hex_string_to_bin(temp_id); | 210 | uint8_t *bin_id = hex_string_to_bin(temp_id); |
211 | DHT_addfriend(dht, bin_id); | 211 | DHT_addfriend(dht, bin_id, 0, 0, 0, 0); |
212 | free(bin_id); | 212 | free(bin_id); |
213 | 213 | ||
214 | perror("Initialization"); | 214 | perror("Initialization"); |
diff --git a/testing/nTox.c b/testing/nTox.c index edda43b1..b33b1fd3 100644 --- a/testing/nTox.c +++ b/testing/nTox.c | |||
@@ -1001,11 +1001,11 @@ void print_help(char *prog_name) | |||
1001 | puts(" -f keyfile [Optional] Specify a keyfile to read from and write to."); | 1001 | puts(" -f keyfile [Optional] Specify a keyfile to read from and write to."); |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | void print_invite(Tox *m, int friendnumber, const uint8_t *group_public_key, void *userdata) | 1004 | void print_invite(Tox *m, int friendnumber, const uint8_t *data, uint16_t length, void *userdata) |
1005 | { | 1005 | { |
1006 | char msg[256]; | 1006 | char msg[256]; |
1007 | sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, | 1007 | sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, |
1008 | tox_join_groupchat(m, friendnumber, group_public_key)); | 1008 | tox_join_groupchat(m, friendnumber, data, length)); |
1009 | new_lines(msg); | 1009 | new_lines(msg); |
1010 | } | 1010 | } |
1011 | 1011 | ||
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index ca4e021b..db03def1 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -620,7 +620,7 @@ static int replace_all( Client_data *list, | |||
620 | const uint8_t *comp_client_id ) | 620 | const uint8_t *comp_client_id ) |
621 | { | 621 | { |
622 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) | 622 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) |
623 | return 1; | 623 | return 0; |
624 | 624 | ||
625 | uint32_t i, replace = ~0, bad = ~0, possibly_bad = ~0, good = ~0; | 625 | uint32_t i, replace = ~0, bad = ~0, possibly_bad = ~0, good = ~0; |
626 | 626 | ||
@@ -708,14 +708,41 @@ int addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *client_id) | |||
708 | } else | 708 | } else |
709 | used++; | 709 | used++; |
710 | 710 | ||
711 | DHT_Friend *friend_foundip = 0; | ||
712 | |||
711 | for (i = 0; i < dht->num_friends; ++i) { | 713 | for (i = 0; i < dht->num_friends; ++i) { |
712 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, | 714 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, |
713 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { | 715 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { |
714 | if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | 716 | if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, |
715 | client_id, ip_port, dht->friends_list[i].client_id)) | 717 | client_id, ip_port, dht->friends_list[i].client_id)) { |
718 | |||
719 | DHT_Friend *friend = &dht->friends_list[i]; | ||
720 | |||
721 | if (memcmp(client_id, friend->client_id, CLIENT_ID_SIZE) == 0) { | ||
722 | friend_foundip = friend; | ||
723 | } | ||
724 | |||
716 | used++; | 725 | used++; |
717 | } else | 726 | } |
727 | } else { | ||
728 | DHT_Friend *friend = &dht->friends_list[i]; | ||
729 | |||
730 | if (memcmp(client_id, friend->client_id, CLIENT_ID_SIZE) == 0) { | ||
731 | friend_foundip = friend; | ||
732 | } | ||
733 | |||
718 | used++; | 734 | used++; |
735 | } | ||
736 | } | ||
737 | |||
738 | if (friend_foundip) { | ||
739 | uint32_t j; | ||
740 | |||
741 | for (j = 0; j < friend_foundip->lock_count; ++j) { | ||
742 | if (friend_foundip->callbacks[j].ip_callback) | ||
743 | friend_foundip->callbacks[j].ip_callback(friend_foundip->callbacks[j].data, friend_foundip->callbacks[j].number, | ||
744 | ip_port); | ||
745 | } | ||
719 | } | 746 | } |
720 | 747 | ||
721 | #ifdef ENABLE_ASSOC_DHT | 748 | #ifdef ENABLE_ASSOC_DHT |
@@ -1089,23 +1116,54 @@ static void get_bunchnodes(DHT *dht, Client_data *list, uint16_t length, uint16_ | |||
1089 | } | 1116 | } |
1090 | } | 1117 | } |
1091 | */ | 1118 | */ |
1092 | int DHT_addfriend(DHT *dht, const uint8_t *client_id) | 1119 | int DHT_addfriend(DHT *dht, const uint8_t *client_id, void (*ip_callback)(void *data, int32_t number, IP_Port), |
1120 | void *data, int32_t number, uint16_t *lock_count) | ||
1093 | { | 1121 | { |
1094 | if (friend_number(dht, client_id) != -1) /* Is friend already in DHT? */ | 1122 | int friend_num = friend_number(dht, client_id); |
1095 | return 1; | 1123 | |
1124 | uint16_t lock_num; | ||
1125 | |||
1126 | if (friend_num != -1) { /* Is friend already in DHT? */ | ||
1127 | DHT_Friend *friend = &dht->friends_list[friend_num]; | ||
1128 | |||
1129 | if (friend->lock_count == DHT_FRIEND_MAX_LOCKS) | ||
1130 | return -1; | ||
1131 | |||
1132 | lock_num = friend->lock_count; | ||
1133 | ++friend->lock_count; | ||
1134 | friend->callbacks[lock_num].ip_callback = ip_callback; | ||
1135 | friend->callbacks[lock_num].data = data; | ||
1136 | friend->callbacks[lock_num].number = number; | ||
1137 | |||
1138 | if (lock_count) | ||
1139 | *lock_count = lock_num + 1; | ||
1140 | |||
1141 | return 0; | ||
1142 | } | ||
1096 | 1143 | ||
1097 | DHT_Friend *temp; | 1144 | DHT_Friend *temp; |
1098 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); | 1145 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); |
1099 | 1146 | ||
1100 | if (temp == NULL) | 1147 | if (temp == NULL) |
1101 | return 1; | 1148 | return -1; |
1102 | 1149 | ||
1103 | dht->friends_list = temp; | 1150 | dht->friends_list = temp; |
1104 | memset(&dht->friends_list[dht->num_friends], 0, sizeof(DHT_Friend)); | 1151 | DHT_Friend *friend = &dht->friends_list[dht->num_friends]; |
1105 | memcpy(dht->friends_list[dht->num_friends].client_id, client_id, CLIENT_ID_SIZE); | 1152 | memset(friend, 0, sizeof(DHT_Friend)); |
1153 | memcpy(friend->client_id, client_id, CLIENT_ID_SIZE); | ||
1106 | 1154 | ||
1107 | dht->friends_list[dht->num_friends].nat.NATping_id = random_64b(); | 1155 | friend->nat.NATping_id = random_64b(); |
1108 | ++dht->num_friends; | 1156 | ++dht->num_friends; |
1157 | |||
1158 | lock_num = friend->lock_count; | ||
1159 | ++friend->lock_count; | ||
1160 | friend->callbacks[lock_num].ip_callback = ip_callback; | ||
1161 | friend->callbacks[lock_num].data = data; | ||
1162 | friend->callbacks[lock_num].number = number; | ||
1163 | |||
1164 | if (lock_count) | ||
1165 | *lock_count = lock_num + 1; | ||
1166 | |||
1109 | #ifdef ENABLE_ASSOC_DHT | 1167 | #ifdef ENABLE_ASSOC_DHT |
1110 | 1168 | ||
1111 | if (dht->assoc) { | 1169 | if (dht->assoc) { |
@@ -1143,39 +1201,49 @@ int DHT_addfriend(DHT *dht, const uint8_t *client_id) | |||
1143 | return 0; | 1201 | return 0; |
1144 | } | 1202 | } |
1145 | 1203 | ||
1146 | int DHT_delfriend(DHT *dht, const uint8_t *client_id) | 1204 | int DHT_delfriend(DHT *dht, const uint8_t *client_id, uint16_t lock_count) |
1147 | { | 1205 | { |
1148 | uint32_t i; | 1206 | int friend_num = friend_number(dht, client_id); |
1149 | DHT_Friend *temp; | ||
1150 | 1207 | ||
1151 | for (i = 0; i < dht->num_friends; ++i) { | 1208 | if (friend_num == -1) { |
1152 | /* Equal */ | 1209 | return -1; |
1153 | if (id_equal(dht->friends_list[i].client_id, client_id)) { | 1210 | } |
1154 | --dht->num_friends; | ||
1155 | 1211 | ||
1156 | if (dht->num_friends != i) { | 1212 | DHT_Friend *friend = &dht->friends_list[friend_num]; |
1157 | memcpy( &dht->friends_list[i], | 1213 | --friend->lock_count; |
1158 | &dht->friends_list[dht->num_friends], | ||
1159 | sizeof(DHT_Friend) ); | ||
1160 | } | ||
1161 | 1214 | ||
1162 | if (dht->num_friends == 0) { | 1215 | if (friend->lock_count && lock_count) { /* DHT friend is still in use.*/ |
1163 | free(dht->friends_list); | 1216 | --lock_count; |
1164 | dht->friends_list = NULL; | 1217 | friend->callbacks[lock_count].ip_callback = NULL; |
1165 | return 0; | 1218 | friend->callbacks[lock_count].data = NULL; |
1166 | } | 1219 | friend->callbacks[lock_count].number = 0; |
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | uint32_t i; | ||
1224 | DHT_Friend *temp; | ||
1167 | 1225 | ||
1168 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); | 1226 | --dht->num_friends; |
1169 | 1227 | ||
1170 | if (temp == NULL) | 1228 | if (dht->num_friends != friend_num) { |
1171 | return 1; | 1229 | memcpy( &dht->friends_list[friend_num], |
1230 | &dht->friends_list[dht->num_friends], | ||
1231 | sizeof(DHT_Friend) ); | ||
1232 | } | ||
1172 | 1233 | ||
1173 | dht->friends_list = temp; | 1234 | if (dht->num_friends == 0) { |
1174 | return 0; | 1235 | free(dht->friends_list); |
1175 | } | 1236 | dht->friends_list = NULL; |
1237 | return 0; | ||
1176 | } | 1238 | } |
1177 | 1239 | ||
1178 | return 1; | 1240 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); |
1241 | |||
1242 | if (temp == NULL) | ||
1243 | return -1; | ||
1244 | |||
1245 | dht->friends_list = temp; | ||
1246 | return 0; | ||
1179 | } | 1247 | } |
1180 | 1248 | ||
1181 | /* TODO: Optimize this. */ | 1249 | /* TODO: Optimize this. */ |
@@ -2216,7 +2284,7 @@ DHT *new_DHT(Networking_Core *net) | |||
2216 | for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { | 2284 | for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { |
2217 | uint8_t random_key_bytes[CLIENT_ID_SIZE]; | 2285 | uint8_t random_key_bytes[CLIENT_ID_SIZE]; |
2218 | randombytes(random_key_bytes, sizeof(random_key_bytes)); | 2286 | randombytes(random_key_bytes, sizeof(random_key_bytes)); |
2219 | DHT_addfriend(dht, random_key_bytes); | 2287 | DHT_addfriend(dht, random_key_bytes, 0, 0, 0, 0); |
2220 | } | 2288 | } |
2221 | 2289 | ||
2222 | return dht; | 2290 | return dht; |
diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 4beda37e..e1e14cd9 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h | |||
@@ -122,6 +122,8 @@ typedef struct { | |||
122 | uint64_t NATping_timestamp; | 122 | uint64_t NATping_timestamp; |
123 | } NAT; | 123 | } NAT; |
124 | 124 | ||
125 | #define DHT_FRIEND_MAX_LOCKS 32 | ||
126 | |||
125 | typedef struct { | 127 | typedef struct { |
126 | uint8_t client_id[CLIENT_ID_SIZE]; | 128 | uint8_t client_id[CLIENT_ID_SIZE]; |
127 | Client_data client_list[MAX_FRIEND_CLIENTS]; | 129 | Client_data client_list[MAX_FRIEND_CLIENTS]; |
@@ -133,10 +135,17 @@ typedef struct { | |||
133 | 135 | ||
134 | /* Symetric NAT hole punching stuff. */ | 136 | /* Symetric NAT hole punching stuff. */ |
135 | NAT nat; | 137 | NAT nat; |
138 | |||
139 | uint16_t lock_count; | ||
140 | struct { | ||
141 | void (*ip_callback)(void *, int32_t, IP_Port); | ||
142 | void *data; | ||
143 | int32_t number; | ||
144 | } callbacks[DHT_FRIEND_MAX_LOCKS]; | ||
145 | |||
136 | } DHT_Friend; | 146 | } DHT_Friend; |
137 | 147 | ||
138 | typedef struct __attribute__ ((__packed__)) | 148 | typedef struct { |
139 | { | ||
140 | uint8_t client_id[CLIENT_ID_SIZE]; | 149 | uint8_t client_id[CLIENT_ID_SIZE]; |
141 | IP_Port ip_port; | 150 | IP_Port ip_port; |
142 | } | 151 | } |
@@ -246,18 +255,25 @@ void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, con | |||
246 | /* Add a new friend to the friends list. | 255 | /* Add a new friend to the friends list. |
247 | * client_id must be CLIENT_ID_SIZE bytes long. | 256 | * client_id must be CLIENT_ID_SIZE bytes long. |
248 | * | 257 | * |
258 | * ip_callback is the callback of a function that will be called when the ip address | ||
259 | * is found along with arguments data and number. | ||
260 | * | ||
261 | * lock_count will be set to a non zero number that must be passed to DHT_delfriend() | ||
262 | * to properly remove the callback. | ||
263 | * | ||
249 | * return 0 if success. | 264 | * return 0 if success. |
250 | * return 1 if failure (friends list is full). | 265 | * return -1 if failure (friends list is full). |
251 | */ | 266 | */ |
252 | int DHT_addfriend(DHT *dht, const uint8_t *client_id); | 267 | int DHT_addfriend(DHT *dht, const uint8_t *client_id, void (*ip_callback)(void *data, int32_t number, IP_Port), |
268 | void *data, int32_t number, uint16_t *lock_count); | ||
253 | 269 | ||
254 | /* Delete a friend from the friends list. | 270 | /* Delete a friend from the friends list. |
255 | * client_id must be CLIENT_ID_SIZE bytes long. | 271 | * client_id must be CLIENT_ID_SIZE bytes long. |
256 | * | 272 | * |
257 | * return 0 if success. | 273 | * return 0 if success. |
258 | * return 1 if failure (client_id not in friends list). | 274 | * return -1 if failure (client_id not in friends list). |
259 | */ | 275 | */ |
260 | int DHT_delfriend(DHT *dht, const uint8_t *client_id); | 276 | int DHT_delfriend(DHT *dht, const uint8_t *client_id, uint16_t lock_count); |
261 | 277 | ||
262 | /* Get ip of friend. | 278 | /* Get ip of friend. |
263 | * client_id must be CLIENT_ID_SIZE bytes long. | 279 | * client_id must be CLIENT_ID_SIZE bytes long. |
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 8e39f96e..9fd1f94a 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc | |||
@@ -19,6 +19,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ | |||
19 | ../toxcore/friend_requests.c \ | 19 | ../toxcore/friend_requests.c \ |
20 | ../toxcore/LAN_discovery.h \ | 20 | ../toxcore/LAN_discovery.h \ |
21 | ../toxcore/LAN_discovery.c \ | 21 | ../toxcore/LAN_discovery.c \ |
22 | ../toxcore/friend_connection.h \ | ||
23 | ../toxcore/friend_connection.c \ | ||
22 | ../toxcore/Messenger.h \ | 24 | ../toxcore/Messenger.h \ |
23 | ../toxcore/Messenger.c \ | 25 | ../toxcore/Messenger.c \ |
24 | ../toxcore/ping.h \ | 26 | ../toxcore/ping.h \ |
@@ -27,8 +29,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ | |||
27 | ../toxcore/tox.c \ | 29 | ../toxcore/tox.c \ |
28 | ../toxcore/util.h \ | 30 | ../toxcore/util.h \ |
29 | ../toxcore/util.c \ | 31 | ../toxcore/util.c \ |
30 | ../toxcore/group_chats.h \ | 32 | ../toxcore/group.h \ |
31 | ../toxcore/group_chats.c \ | 33 | ../toxcore/group.c \ |
32 | ../toxcore/assoc.h \ | 34 | ../toxcore/assoc.h \ |
33 | ../toxcore/assoc.c \ | 35 | ../toxcore/assoc.c \ |
34 | ../toxcore/onion.h \ | 36 | ../toxcore/onion.h \ |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 99b95f67..75210830 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -153,20 +153,9 @@ void getaddress(const Messenger *m, uint8_t *address) | |||
153 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); | 153 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); |
154 | } | 154 | } |
155 | 155 | ||
156 | /* callback for recv TCP relay nodes. */ | 156 | static int handle_status(void *object, int i, uint8_t status); |
157 | static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) | 157 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); |
158 | { | 158 | static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length); |
159 | Messenger *m = object; | ||
160 | |||
161 | if (friend_not_valid(m, number)) | ||
162 | return -1; | ||
163 | |||
164 | if (m->friendlist[number].crypt_connection_id != -1) { | ||
165 | return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key); | ||
166 | } else { | ||
167 | return add_tcp_relay(m->net_crypto, ip_port, public_key); | ||
168 | } | ||
169 | } | ||
170 | 159 | ||
171 | /* | 160 | /* |
172 | * Add a friend. | 161 | * Add a friend. |
@@ -230,18 +219,17 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
230 | 219 | ||
231 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); | 220 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); |
232 | 221 | ||
233 | int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); | 222 | int friendcon_id = new_friend_connection(m->fr_c, client_id); |
234 | 223 | ||
235 | if (onion_friendnum == -1) | 224 | if (friendcon_id == -1) |
236 | return FAERR_UNKNOWN; | 225 | return -1; |
237 | 226 | ||
238 | uint32_t i; | 227 | uint32_t i; |
239 | 228 | ||
240 | for (i = 0; i <= m->numfriends; ++i) { | 229 | for (i = 0; i <= m->numfriends; ++i) { |
241 | if (m->friendlist[i].status == NOFRIEND) { | 230 | if (m->friendlist[i].status == NOFRIEND) { |
242 | m->friendlist[i].onion_friendnum = onion_friendnum; | ||
243 | m->friendlist[i].status = FRIEND_ADDED; | 231 | m->friendlist[i].status = FRIEND_ADDED; |
244 | m->friendlist[i].crypt_connection_id = -1; | 232 | m->friendlist[i].friendcon_id = friendcon_id; |
245 | m->friendlist[i].friendrequest_lastsent = 0; | 233 | m->friendlist[i].friendrequest_lastsent = 0; |
246 | m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; | 234 | m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; |
247 | id_copy(m->friendlist[i].client_id, client_id); | 235 | id_copy(m->friendlist[i].client_id, client_id); |
@@ -258,7 +246,9 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
258 | m->friendlist[i].message_id = 0; | 246 | m->friendlist[i].message_id = 0; |
259 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ | 247 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ |
260 | memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); | 248 | memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); |
261 | recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); | 249 | friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, |
250 | &handle_custom_lossy_packet, m, i); | ||
251 | |||
262 | 252 | ||
263 | if (m->numfriends == i) | 253 | if (m->numfriends == i) |
264 | ++m->numfriends; | 254 | ++m->numfriends; |
@@ -287,18 +277,17 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id) | |||
287 | 277 | ||
288 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); | 278 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); |
289 | 279 | ||
290 | int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); | 280 | int friendcon_id = new_friend_connection(m->fr_c, client_id); |
291 | 281 | ||
292 | if (onion_friendnum == -1) | 282 | if (friendcon_id == -1) |
293 | return -1; | 283 | return -1; |
294 | 284 | ||
295 | uint32_t i; | 285 | uint32_t i; |
296 | 286 | ||
297 | for (i = 0; i <= m->numfriends; ++i) { | 287 | for (i = 0; i <= m->numfriends; ++i) { |
298 | if (m->friendlist[i].status == NOFRIEND) { | 288 | if (m->friendlist[i].status == NOFRIEND) { |
299 | m->friendlist[i].onion_friendnum = onion_friendnum; | ||
300 | m->friendlist[i].status = FRIEND_CONFIRMED; | 289 | m->friendlist[i].status = FRIEND_CONFIRMED; |
301 | m->friendlist[i].crypt_connection_id = -1; | 290 | m->friendlist[i].friendcon_id = friendcon_id; |
302 | m->friendlist[i].friendrequest_lastsent = 0; | 291 | m->friendlist[i].friendrequest_lastsent = 0; |
303 | id_copy(m->friendlist[i].client_id, client_id); | 292 | id_copy(m->friendlist[i].client_id, client_id); |
304 | m->friendlist[i].statusmessage = calloc(1, 1); | 293 | m->friendlist[i].statusmessage = calloc(1, 1); |
@@ -311,7 +300,8 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id) | |||
311 | m->friendlist[i].is_typing = 0; | 300 | m->friendlist[i].is_typing = 0; |
312 | m->friendlist[i].message_id = 0; | 301 | m->friendlist[i].message_id = 0; |
313 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ | 302 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ |
314 | recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); | 303 | friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, |
304 | &handle_custom_lossy_packet, m, i); | ||
315 | 305 | ||
316 | if (m->numfriends == i) | 306 | if (m->numfriends == i) |
317 | ++m->numfriends; | 307 | ++m->numfriends; |
@@ -336,11 +326,11 @@ int m_delfriend(Messenger *m, int32_t friendnumber) | |||
336 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | 326 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) |
337 | remove_online_friend(m, friendnumber); | 327 | remove_online_friend(m, friendnumber); |
338 | 328 | ||
339 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); | ||
340 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); | ||
341 | free(m->friendlist[friendnumber].statusmessage); | 329 | free(m->friendlist[friendnumber].statusmessage); |
342 | free(m->friendlist[friendnumber].avatar_recv_data); | 330 | free(m->friendlist[friendnumber].avatar_recv_data); |
343 | remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); | 331 | remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); |
332 | friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); | ||
333 | kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); | ||
344 | memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); | 334 | memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); |
345 | uint32_t i; | 335 | uint32_t i; |
346 | 336 | ||
@@ -492,10 +482,6 @@ int setname(Messenger *m, const uint8_t *name, uint16_t length) | |||
492 | for (i = 0; i < m->numfriends; ++i) | 482 | for (i = 0; i < m->numfriends; ++i) |
493 | m->friendlist[i].name_sent = 0; | 483 | m->friendlist[i].name_sent = 0; |
494 | 484 | ||
495 | for (i = 0; i < m->numchats; i++) | ||
496 | if (m->chats[i] != NULL) | ||
497 | set_nick(m->chats[i], name, length); /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
498 | |||
499 | return 0; | 485 | return 0; |
500 | } | 486 | } |
501 | 487 | ||
@@ -574,33 +560,48 @@ int m_set_userstatus(Messenger *m, uint8_t status) | |||
574 | return 0; | 560 | return 0; |
575 | } | 561 | } |
576 | 562 | ||
563 | int m_unset_avatar(Messenger *m) | ||
564 | { | ||
565 | if (m->avatar_data != NULL) | ||
566 | free(m->avatar_data); | ||
567 | |||
568 | m->avatar_data = NULL; | ||
569 | m->avatar_data_length = 0; | ||
570 | m->avatar_format = AVATAR_FORMAT_NONE; | ||
571 | memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH); | ||
572 | |||
573 | uint32_t i; | ||
574 | |||
575 | for (i = 0; i < m->numfriends; ++i) | ||
576 | m->friendlist[i].avatar_info_sent = 0; | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | |||
577 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length) | 581 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length) |
578 | { | 582 | { |
579 | if (length > AVATAR_MAX_DATA_LENGTH) | 583 | if (format == AVATAR_FORMAT_NONE) { |
584 | m_unset_avatar(m); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | if (length > AVATAR_MAX_DATA_LENGTH || length == 0) | ||
580 | return -1; | 589 | return -1; |
581 | 590 | ||
582 | if (format == AVATAR_FORMAT_NONE) { | 591 | if (data == NULL) |
583 | free(m->avatar_data); | 592 | return -1; |
584 | m->avatar_data = NULL; | ||
585 | m->avatar_data_length = 0; | ||
586 | m->avatar_format = format; | ||
587 | memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH); | ||
588 | } else { | ||
589 | if (length == 0 || data == NULL) | ||
590 | return -1; | ||
591 | 593 | ||
592 | uint8_t *tmp = realloc(m->avatar_data, length); | 594 | uint8_t *tmp = realloc(m->avatar_data, length); |
593 | 595 | ||
594 | if (tmp == NULL) | 596 | if (tmp == NULL) |
595 | return -1; | 597 | return -1; |
596 | 598 | ||
597 | m->avatar_format = format; | 599 | m->avatar_format = format; |
598 | m->avatar_data = tmp; | 600 | m->avatar_data = tmp; |
599 | m->avatar_data_length = length; | 601 | m->avatar_data_length = length; |
600 | memcpy(m->avatar_data, data, length); | 602 | memcpy(m->avatar_data, data, length); |
601 | 603 | ||
602 | m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length); | 604 | m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length); |
603 | } | ||
604 | 605 | ||
605 | uint32_t i; | 606 | uint32_t i; |
606 | 607 | ||
@@ -811,16 +812,6 @@ static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t | |||
811 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); | 812 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); |
812 | } | 813 | } |
813 | 814 | ||
814 | static int send_ping(const Messenger *m, int32_t friendnumber) | ||
815 | { | ||
816 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0, 0); | ||
817 | |||
818 | if (ret == 1) | ||
819 | m->friendlist[friendnumber].ping_lastsent = unix_time(); | ||
820 | |||
821 | return ret; | ||
822 | } | ||
823 | |||
824 | static int send_relays(const Messenger *m, int32_t friendnumber) | 815 | static int send_relays(const Messenger *m, int32_t friendnumber) |
825 | { | 816 | { |
826 | Node_format nodes[MAX_SHARED_RELAYS]; | 817 | Node_format nodes[MAX_SHARED_RELAYS]; |
@@ -967,8 +958,6 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui | |||
967 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; | 958 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; |
968 | const uint8_t is_online = status == FRIEND_ONLINE; | 959 | const uint8_t is_online = status == FRIEND_ONLINE; |
969 | 960 | ||
970 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); | ||
971 | |||
972 | if (is_online != was_online) { | 961 | if (is_online != was_online) { |
973 | if (was_online) { | 962 | if (was_online) { |
974 | break_files(m, friendnumber); | 963 | break_files(m, friendnumber); |
@@ -1009,464 +998,31 @@ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_ | |||
1009 | if (length != 0) | 998 | if (length != 0) |
1010 | memcpy(packet + 1, data, length); | 999 | memcpy(packet + 1, data, length); |
1011 | 1000 | ||
1012 | return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1, | 1001 | return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1013 | congestion_control) != -1; | 1002 | m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1; |
1014 | } | 1003 | } |
1015 | 1004 | ||
1016 | /**********GROUP CHATS************/ | 1005 | /**********GROUP CHATS************/ |
1017 | 1006 | ||
1018 | /* return 1 if the groupnumber is not valid. | ||
1019 | * return 0 if the groupnumber is valid. | ||
1020 | */ | ||
1021 | static uint8_t groupnumber_not_valid(const Messenger *m, int groupnumber) | ||
1022 | { | ||
1023 | if ((unsigned int)groupnumber >= m->numchats) | ||
1024 | return 1; | ||
1025 | |||
1026 | if (m->chats == NULL) | ||
1027 | return 1; | ||
1028 | |||
1029 | if (m->chats[groupnumber] == NULL) | ||
1030 | return 1; | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /* returns valid ip port of connected friend on success | ||
1037 | * returns zeroed out IP_Port on failure | ||
1038 | */ | ||
1039 | static IP_Port get_friend_ipport(const Messenger *m, int32_t friendnumber) | ||
1040 | { | ||
1041 | IP_Port zero; | ||
1042 | memset(&zero, 0, sizeof(zero)); | ||
1043 | |||
1044 | if (friend_not_valid(m, friendnumber)) | ||
1045 | return zero; | ||
1046 | |||
1047 | int crypt_id = m->friendlist[friendnumber].crypt_connection_id; | ||
1048 | |||
1049 | uint8_t direct_connected; | ||
1050 | |||
1051 | if (crypto_connection_status(m->net_crypto, crypt_id, &direct_connected) != CRYPTO_CONN_ESTABLISHED) | ||
1052 | return zero; | ||
1053 | |||
1054 | if (direct_connected == 0) | ||
1055 | return zero; | ||
1056 | |||
1057 | return m->net_crypto->crypto_connections[crypt_id].ip_port; | ||
1058 | } | ||
1059 | |||
1060 | /* returns the group number of the chat with public key group_public_key. | ||
1061 | * returns -1 on failure. | ||
1062 | */ | ||
1063 | static int group_num(const Messenger *m, const uint8_t *group_public_key) | ||
1064 | { | ||
1065 | uint32_t i; | ||
1066 | |||
1067 | for (i = 0; i < m->numchats; ++i) { | ||
1068 | if (m->chats[i] != NULL) | ||
1069 | if (id_equal(m->chats[i]->self_public_key, group_public_key)) | ||
1070 | return i; | ||
1071 | } | ||
1072 | |||
1073 | return -1; | ||
1074 | } | ||
1075 | 1007 | ||
1076 | /* Set the callback for group invites. | 1008 | /* Set the callback for group invites. |
1077 | * | 1009 | * |
1078 | * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 1010 | * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length) |
1079 | */ | 1011 | */ |
1080 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), | 1012 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t)) |
1081 | void *userdata) | ||
1082 | { | 1013 | { |
1083 | m->group_invite = function; | 1014 | m->group_invite = function; |
1084 | m->group_invite_userdata = userdata; | ||
1085 | } | ||
1086 | |||
1087 | /* Set the callback for group messages. | ||
1088 | * | ||
1089 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
1090 | */ | ||
1091 | void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
1092 | void *userdata) | ||
1093 | { | ||
1094 | m->group_message = function; | ||
1095 | m->group_message_userdata = userdata; | ||
1096 | } | ||
1097 | |||
1098 | /* Set the callback for group actions. | ||
1099 | * | ||
1100 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
1101 | */ | ||
1102 | void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
1103 | void *userdata) | ||
1104 | { | ||
1105 | m->group_action = function; | ||
1106 | m->group_action_userdata = userdata; | ||
1107 | } | ||
1108 | |||
1109 | /* Set callback function for peer name list changes. | ||
1110 | * | ||
1111 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
1112 | * Function(Tox *tox, int groupnumber, void *userdata) | ||
1113 | */ | ||
1114 | void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
1115 | void *userdata) | ||
1116 | { | ||
1117 | m->group_namelistchange = function; | ||
1118 | m->group_namelistchange_userdata = userdata; | ||
1119 | } | ||
1120 | |||
1121 | static int get_chat_num(const Messenger *m, const Group_Chat *chat) | ||
1122 | { | ||
1123 | uint32_t i; | ||
1124 | |||
1125 | for (i = 0; i < m->numchats; ++i) { //TODO: remove this | ||
1126 | if (m->chats[i] == chat) | ||
1127 | return i; | ||
1128 | } | ||
1129 | |||
1130 | return -1; | ||
1131 | } | ||
1132 | |||
1133 | static void group_message_function(Group_Chat *chat, int peer_number, const uint8_t *message, uint16_t length, | ||
1134 | void *userdata) | ||
1135 | { | ||
1136 | Messenger *m = userdata; | ||
1137 | int i = get_chat_num(m, chat); | ||
1138 | |||
1139 | if (i == -1) | ||
1140 | return; | ||
1141 | |||
1142 | uint8_t message_terminated[length + 1]; | ||
1143 | memcpy(message_terminated, message, length); | ||
1144 | message_terminated[length] = 0; /* Force NULL terminator */ | ||
1145 | |||
1146 | if (m->group_message) | ||
1147 | (*m->group_message)(m, i, peer_number, message_terminated, length, m->group_message_userdata); | ||
1148 | } | 1015 | } |
1149 | 1016 | ||
1150 | static void group_action_function(Group_Chat *chat, int peer_number, const uint8_t *action, uint16_t length, | ||
1151 | void *userdata) | ||
1152 | { | ||
1153 | Messenger *m = userdata; | ||
1154 | int i = get_chat_num(m, chat); | ||
1155 | |||
1156 | if (i == -1) | ||
1157 | return; | ||
1158 | |||
1159 | uint8_t action_terminated[length + 1]; | ||
1160 | memcpy(action_terminated, action, length); | ||
1161 | action_terminated[length] = 0; /* Force NULL terminator */ | ||
1162 | |||
1163 | if (m->group_action) | ||
1164 | (*m->group_action)(m, i, peer_number, action_terminated, length, m->group_action_userdata); | ||
1165 | } | ||
1166 | |||
1167 | static void group_namelistchange_function(Group_Chat *chat, int peer, uint8_t change, void *userdata) | ||
1168 | { | ||
1169 | Messenger *m = userdata; | ||
1170 | int i = get_chat_num(m, chat); | ||
1171 | |||
1172 | if (i == -1) | ||
1173 | return; | ||
1174 | |||
1175 | if (m->group_namelistchange) | ||
1176 | (*m->group_namelistchange)(m, i, peer, change, m->group_namelistchange_userdata); | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | /* Creates a new groupchat and puts it in the chats array. | ||
1181 | * | ||
1182 | * return group number on success. | ||
1183 | * return -1 on failure. | ||
1184 | */ | ||
1185 | int add_groupchat(Messenger *m) | ||
1186 | { | ||
1187 | uint32_t i; | ||
1188 | |||
1189 | for (i = 0; i < m->numchats; ++i) { | ||
1190 | if (m->chats[i] == NULL) { | ||
1191 | Group_Chat *newchat = new_groupchat(m->net); | ||
1192 | |||
1193 | if (newchat == NULL) | ||
1194 | return -1; | ||
1195 | |||
1196 | callback_groupmessage(newchat, &group_message_function, m); | ||
1197 | callback_groupaction(newchat, &group_action_function, m); | ||
1198 | callback_namelistchange(newchat, &group_namelistchange_function, m); | ||
1199 | /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
1200 | set_nick(newchat, m->name, m->name_length); | ||
1201 | m->chats[i] = newchat; | ||
1202 | return i; | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | Group_Chat **temp; | ||
1207 | temp = realloc(m->chats, sizeof(Group_Chat *) * (m->numchats + 1)); | ||
1208 | |||
1209 | if (temp == NULL) | ||
1210 | return -1; | ||
1211 | |||
1212 | m->chats = temp; | ||
1213 | temp[m->numchats] = new_groupchat(m->net); | ||
1214 | |||
1215 | if (temp[m->numchats] == NULL) | ||
1216 | return -1; | ||
1217 | |||
1218 | callback_groupmessage(temp[m->numchats], &group_message_function, m); | ||
1219 | callback_groupaction(temp[m->numchats], &group_action_function, m); | ||
1220 | callback_namelistchange(temp[m->numchats], &group_namelistchange_function, m); | ||
1221 | /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
1222 | set_nick(temp[m->numchats], m->name, m->name_length); | ||
1223 | ++m->numchats; | ||
1224 | return (m->numchats - 1); | ||
1225 | } | ||
1226 | |||
1227 | /* Delete a groupchat from the chats array. | ||
1228 | * | ||
1229 | * return 0 on success. | ||
1230 | * return -1 if failure. | ||
1231 | */ | ||
1232 | int del_groupchat(Messenger *m, int groupnumber) | ||
1233 | { | ||
1234 | if ((unsigned int)groupnumber >= m->numchats) | ||
1235 | return -1; | ||
1236 | |||
1237 | if (m->chats == NULL) | ||
1238 | return -1; | ||
1239 | |||
1240 | if (m->chats[groupnumber] == NULL) | ||
1241 | return -1; | ||
1242 | |||
1243 | kill_groupchat(m->chats[groupnumber]); | ||
1244 | m->chats[groupnumber] = NULL; | ||
1245 | |||
1246 | uint32_t i; | ||
1247 | |||
1248 | for (i = m->numchats; i != 0; --i) { | ||
1249 | if (m->chats[i - 1] != NULL) | ||
1250 | break; | ||
1251 | } | ||
1252 | 1017 | ||
1253 | m->numchats = i; | 1018 | /* Send a group invite packet. |
1254 | |||
1255 | if (i == 0) { | ||
1256 | free(m->chats); | ||
1257 | m->chats = NULL; | ||
1258 | } else { | ||
1259 | Group_Chat **temp = realloc(m->chats, sizeof(Group_Chat *) * i); | ||
1260 | |||
1261 | if (temp != NULL) | ||
1262 | m->chats = temp; | ||
1263 | } | ||
1264 | |||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | /* Copy the name of peernumber who is in groupnumber to name. | ||
1269 | * name must be at least MAX_NICK_BYTES long. | ||
1270 | * | 1019 | * |
1271 | * return length of name if success | 1020 | * return 1 on success |
1272 | * return -1 if failure | 1021 | * return 0 on failure |
1273 | */ | ||
1274 | int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name) | ||
1275 | { | ||
1276 | if ((unsigned int)groupnumber >= m->numchats) | ||
1277 | return -1; | ||
1278 | |||
1279 | if (m->chats == NULL) | ||
1280 | return -1; | ||
1281 | |||
1282 | if (m->chats[groupnumber] == NULL) | ||
1283 | return -1; | ||
1284 | |||
1285 | return group_peername(m->chats[groupnumber], peernumber, name); | ||
1286 | } | ||
1287 | |||
1288 | /* Store the fact that we invited a specific friend. | ||
1289 | */ | ||
1290 | static void group_store_friendinvite(Messenger *m, int32_t friendnumber, int groupnumber) | ||
1291 | { | ||
1292 | /* Add 1 to the groupchat number because 0 (default value in invited_groups) is a valid groupchat number */ | ||
1293 | m->friendlist[friendnumber].invited_groups[m->friendlist[friendnumber].invited_groups_num % MAX_INVITED_GROUPS] = | ||
1294 | groupnumber + 1; | ||
1295 | ++m->friendlist[friendnumber].invited_groups_num; | ||
1296 | } | ||
1297 | |||
1298 | /* return 1 if that friend was invited to the group | ||
1299 | * return 0 if the friend was not or error. | ||
1300 | */ | ||
1301 | static uint8_t group_invited(const Messenger *m, int32_t friendnumber, int groupnumber) | ||
1302 | { | ||
1303 | |||
1304 | uint32_t i; | ||
1305 | uint16_t num = MAX_INVITED_GROUPS; | ||
1306 | |||
1307 | if (MAX_INVITED_GROUPS > m->friendlist[friendnumber].invited_groups_num) | ||
1308 | num = m->friendlist[friendnumber].invited_groups_num; | ||
1309 | |||
1310 | for (i = 0; i < num; ++i) { | ||
1311 | if (m->friendlist[friendnumber].invited_groups[i] == groupnumber + 1) { | ||
1312 | return 1; | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /* invite friendnumber to groupnumber | ||
1320 | * return 0 on success | ||
1321 | * return -1 on failure | ||
1322 | */ | ||
1323 | int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber) | ||
1324 | { | ||
1325 | if (friend_not_valid(m, friendnumber) || (unsigned int)groupnumber >= m->numchats) | ||
1326 | return -1; | ||
1327 | |||
1328 | if (m->chats == NULL) | ||
1329 | return -1; | ||
1330 | |||
1331 | if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL) | ||
1332 | return -1; | ||
1333 | |||
1334 | group_store_friendinvite(m, friendnumber, groupnumber); | ||
1335 | |||
1336 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key, | ||
1337 | crypto_box_PUBLICKEYBYTES, 0) == 0) | ||
1338 | return -1; | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | |||
1344 | /* Join a group (you need to have been invited first.) | ||
1345 | * | ||
1346 | * returns group number on success | ||
1347 | * returns -1 on failure. | ||
1348 | */ | ||
1349 | int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key) | ||
1350 | { | ||
1351 | if (friend_not_valid(m, friendnumber)) | ||
1352 | return -1; | ||
1353 | |||
1354 | uint8_t data[crypto_box_PUBLICKEYBYTES * 2]; | ||
1355 | int groupnum = add_groupchat(m); | ||
1356 | |||
1357 | if (groupnum == -1) | ||
1358 | return -1; | ||
1359 | |||
1360 | IP_Port friend_ip = get_friend_ipport(m, friendnumber); | ||
1361 | |||
1362 | if (friend_ip.ip.family == 0) { | ||
1363 | del_groupchat(m, groupnum); | ||
1364 | return -1; | ||
1365 | } | ||
1366 | |||
1367 | id_copy(data, friend_group_public_key); | ||
1368 | id_copy(data + crypto_box_PUBLICKEYBYTES, m->chats[groupnum]->self_public_key); | ||
1369 | |||
1370 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_JOIN_GROUPCHAT, data, sizeof(data), 0)) { | ||
1371 | chat_bootstrap_nonlazy(m->chats[groupnum], get_friend_ipport(m, friendnumber), | ||
1372 | friend_group_public_key); //TODO: check if ip returned is zero? | ||
1373 | return groupnum; | ||
1374 | } | ||
1375 | |||
1376 | del_groupchat(m, groupnum); | ||
1377 | return -1; | ||
1378 | } | ||
1379 | |||
1380 | |||
1381 | /* send a group message | ||
1382 | * return 0 on success | ||
1383 | * return -1 on failure | ||
1384 | */ | ||
1385 | int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length) | ||
1386 | { | ||
1387 | if (groupnumber_not_valid(m, groupnumber)) | ||
1388 | return -1; | ||
1389 | |||
1390 | if (group_sendmessage(m->chats[groupnumber], message, length) > 0) | ||
1391 | return 0; | ||
1392 | |||
1393 | return -1; | ||
1394 | } | ||
1395 | |||
1396 | /* send a group action | ||
1397 | * return 0 on success | ||
1398 | * return -1 on failure | ||
1399 | */ | ||
1400 | int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length) | ||
1401 | { | ||
1402 | if (groupnumber_not_valid(m, groupnumber)) | ||
1403 | return -1; | ||
1404 | |||
1405 | if (group_sendaction(m->chats[groupnumber], action, length) > 0) | ||
1406 | return 0; | ||
1407 | |||
1408 | return -1; | ||
1409 | } | ||
1410 | |||
1411 | /* Return the number of peers in the group chat on success. | ||
1412 | * return -1 on failure | ||
1413 | */ | ||
1414 | int group_number_peers(const Messenger *m, int groupnumber) | ||
1415 | { | ||
1416 | if (groupnumber_not_valid(m, groupnumber)) | ||
1417 | return -1; | ||
1418 | |||
1419 | return group_numpeers(m->chats[groupnumber]); | ||
1420 | } | ||
1421 | |||
1422 | /* List all the peers in the group chat. | ||
1423 | * | ||
1424 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
1425 | * | ||
1426 | * Copies the lengths of the names to lengths[length] | ||
1427 | * | ||
1428 | * returns the number of peers on success. | ||
1429 | * | ||
1430 | * return -1 on failure. | ||
1431 | */ | 1022 | */ |
1432 | int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | 1023 | int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) |
1433 | uint16_t length) | ||
1434 | { | 1024 | { |
1435 | if (groupnumber_not_valid(m, groupnumber)) | 1025 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, data, length, 0); |
1436 | return -1; | ||
1437 | |||
1438 | return group_client_names(m->chats[groupnumber], names, lengths, length); | ||
1439 | } | ||
1440 | |||
1441 | static int handle_group(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | ||
1442 | { | ||
1443 | Messenger *m = object; | ||
1444 | |||
1445 | if (length < crypto_box_PUBLICKEYBYTES + 1) { | ||
1446 | return 1; | ||
1447 | } | ||
1448 | |||
1449 | uint32_t i; | ||
1450 | |||
1451 | for (i = 0; i < m->numchats; ++i) { | ||
1452 | if (m->chats[i] == NULL) | ||
1453 | continue; | ||
1454 | |||
1455 | if (id_equal(packet + 1, m->chats[i]->self_public_key)) | ||
1456 | return handle_groupchatpacket(m->chats[i], source, packet, length); | ||
1457 | } | ||
1458 | |||
1459 | return 1; | ||
1460 | } | ||
1461 | |||
1462 | static void do_allgroupchats(Messenger *m) | ||
1463 | { | ||
1464 | uint32_t i; | ||
1465 | |||
1466 | for (i = 0; i < m->numchats; ++i) { | ||
1467 | if (m->chats[i] != NULL) | ||
1468 | do_groupchat(m->chats[i]); | ||
1469 | } | ||
1470 | } | 1026 | } |
1471 | 1027 | ||
1472 | /****************FILE SENDING*****************/ | 1028 | /****************FILE SENDING*****************/ |
@@ -1669,8 +1225,9 @@ int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, cons | |||
1669 | if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) | 1225 | if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) |
1670 | return -1; | 1226 | return -1; |
1671 | 1227 | ||
1672 | /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */ | 1228 | /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */ |
1673 | if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) | 1229 | if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1230 | m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) | ||
1674 | return -1; | 1231 | return -1; |
1675 | 1232 | ||
1676 | uint8_t packet[MAX_CRYPTO_DATA_SIZE]; | 1233 | uint8_t packet[MAX_CRYPTO_DATA_SIZE]; |
@@ -1876,10 +1433,8 @@ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uin | |||
1876 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | 1433 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) |
1877 | return -1; | 1434 | return -1; |
1878 | 1435 | ||
1879 | if (m->friendlist[friendnumber].crypt_connection_id == -1) | 1436 | return send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1880 | return -1; | 1437 | m->friendlist[friendnumber].friendcon_id), data, length); |
1881 | |||
1882 | return send_lossy_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length); | ||
1883 | } | 1438 | } |
1884 | 1439 | ||
1885 | static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) | 1440 | static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) |
@@ -1937,10 +1492,8 @@ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const | |||
1937 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | 1492 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) |
1938 | return -1; | 1493 | return -1; |
1939 | 1494 | ||
1940 | if (m->friendlist[friendnumber].crypt_connection_id == -1) | 1495 | if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1941 | return -1; | 1496 | m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) { |
1942 | |||
1943 | if (write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length, 1) == -1) { | ||
1944 | return -1; | 1497 | return -1; |
1945 | } else { | 1498 | } else { |
1946 | return 0; | 1499 | return 0; |
@@ -1967,31 +1520,6 @@ static void LANdiscovery(Messenger *m) | |||
1967 | } | 1520 | } |
1968 | } | 1521 | } |
1969 | 1522 | ||
1970 | static int handle_status(void *object, int i, uint8_t status); | ||
1971 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); | ||
1972 | |||
1973 | static int handle_new_connections(void *object, New_Connection *n_c) | ||
1974 | { | ||
1975 | Messenger *m = object; | ||
1976 | int friend_id = getfriend_id(m, n_c->public_key); | ||
1977 | |||
1978 | if (friend_id != -1) { | ||
1979 | if (m->friendlist[friend_id].crypt_connection_id != -1) | ||
1980 | return -1; | ||
1981 | |||
1982 | int id = accept_crypto_connection(m->net_crypto, n_c); | ||
1983 | connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id); | ||
1984 | connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id); | ||
1985 | connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friend_id); | ||
1986 | m->friendlist[friend_id].crypt_connection_id = id; | ||
1987 | set_friend_status(m, friend_id, FRIEND_CONFIRMED); | ||
1988 | return 0; | ||
1989 | } | ||
1990 | |||
1991 | return -1; | ||
1992 | } | ||
1993 | |||
1994 | |||
1995 | /* Run this at startup. */ | 1523 | /* Run this at startup. */ |
1996 | Messenger *new_messenger(Messenger_Options *options) | 1524 | Messenger *new_messenger(Messenger_Options *options) |
1997 | { | 1525 | { |
@@ -2038,13 +1566,13 @@ Messenger *new_messenger(Messenger_Options *options) | |||
2038 | return NULL; | 1566 | return NULL; |
2039 | } | 1567 | } |
2040 | 1568 | ||
2041 | new_connection_handler(m->net_crypto, &handle_new_connections, m); | ||
2042 | |||
2043 | m->onion = new_onion(m->dht); | 1569 | m->onion = new_onion(m->dht); |
2044 | m->onion_a = new_onion_announce(m->dht); | 1570 | m->onion_a = new_onion_announce(m->dht); |
2045 | m->onion_c = new_onion_client(m->net_crypto); | 1571 | m->onion_c = new_onion_client(m->net_crypto); |
1572 | m->fr_c = new_friend_connections(m->onion_c); | ||
2046 | 1573 | ||
2047 | if (!(m->onion && m->onion_a && m->onion_c)) { | 1574 | if (!(m->onion && m->onion_a && m->onion_c)) { |
1575 | kill_friend_connections(m->fr_c); | ||
2048 | kill_onion(m->onion); | 1576 | kill_onion(m->onion); |
2049 | kill_onion_announce(m->onion_a); | 1577 | kill_onion_announce(m->onion_a); |
2050 | kill_onion_client(m->onion_c); | 1578 | kill_onion_client(m->onion_c); |
@@ -2061,22 +1589,15 @@ Messenger *new_messenger(Messenger_Options *options) | |||
2061 | set_nospam(&(m->fr), random_int()); | 1589 | set_nospam(&(m->fr), random_int()); |
2062 | set_filter_function(&(m->fr), &friend_already_added, m); | 1590 | set_filter_function(&(m->fr), &friend_already_added, m); |
2063 | 1591 | ||
2064 | networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m); | ||
2065 | |||
2066 | return m; | 1592 | return m; |
2067 | } | 1593 | } |
2068 | 1594 | ||
2069 | /* Run this before closing shop. */ | 1595 | /* Run this before closing shop. */ |
2070 | void kill_messenger(Messenger *m) | 1596 | void kill_messenger(Messenger *m) |
2071 | { | 1597 | { |
2072 | /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger. | 1598 | uint32_t i; |
2073 | * This requires the other modules to expose cleanup functions. | ||
2074 | */ | ||
2075 | uint32_t i, numchats = m->numchats; | ||
2076 | |||
2077 | for (i = 0; i < numchats; ++i) | ||
2078 | del_groupchat(m, i); | ||
2079 | 1599 | ||
1600 | kill_friend_connections(m->fr_c); | ||
2080 | kill_onion(m->onion); | 1601 | kill_onion(m->onion); |
2081 | kill_onion_announce(m->onion_a); | 1602 | kill_onion_announce(m->onion_a); |
2082 | kill_onion_client(m->onion_c); | 1603 | kill_onion_client(m->onion_c); |
@@ -2124,8 +1645,6 @@ static int handle_status(void *object, int i, uint8_t status) | |||
2124 | m->friendlist[i].statusmessage_sent = 0; | 1645 | m->friendlist[i].statusmessage_sent = 0; |
2125 | m->friendlist[i].ping_lastrecv = temp_time; | 1646 | m->friendlist[i].ping_lastrecv = temp_time; |
2126 | } else { /* Went offline. */ | 1647 | } else { /* Went offline. */ |
2127 | m->friendlist[i].crypt_connection_id = -1; | ||
2128 | |||
2129 | if (m->friendlist[i].status == FRIEND_ONLINE) { | 1648 | if (m->friendlist[i].status == FRIEND_ONLINE) { |
2130 | set_friend_status(m, i, FRIEND_CONFIRMED); | 1649 | set_friend_status(m, i, FRIEND_CONFIRMED); |
2131 | } | 1650 | } |
@@ -2425,11 +1944,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2425 | return -1; | 1944 | return -1; |
2426 | 1945 | ||
2427 | switch (packet_id) { | 1946 | switch (packet_id) { |
2428 | case PACKET_ID_ALIVE: { | ||
2429 | m->friendlist[i].ping_lastrecv = temp_time; | ||
2430 | break; | ||
2431 | } | ||
2432 | |||
2433 | case PACKET_ID_NICKNAME: { | 1947 | case PACKET_ID_NICKNAME: { |
2434 | if (data_length > MAX_NAME_LENGTH || data_length == 0) | 1948 | if (data_length > MAX_NAME_LENGTH || data_length == 0) |
2435 | break; | 1949 | break; |
@@ -2599,33 +2113,15 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2599 | } | 2113 | } |
2600 | 2114 | ||
2601 | case PACKET_ID_INVITE_GROUPCHAT: { | 2115 | case PACKET_ID_INVITE_GROUPCHAT: { |
2602 | if (data_length != crypto_box_PUBLICKEYBYTES) | 2116 | if (data_length == 0) |
2603 | break; | 2117 | break; |
2604 | 2118 | ||
2605 | if (m->group_invite) | 2119 | if (m->group_invite) |
2606 | (*m->group_invite)(m, i, data, m->group_invite_userdata); | 2120 | (*m->group_invite)(m, i, data, data_length); |
2607 | 2121 | ||
2608 | break; | 2122 | break; |
2609 | } | 2123 | } |
2610 | 2124 | ||
2611 | case PACKET_ID_JOIN_GROUPCHAT: { | ||
2612 | if (data_length != crypto_box_PUBLICKEYBYTES * 2) | ||
2613 | break; | ||
2614 | |||
2615 | int groupnum = group_num(m, data); | ||
2616 | |||
2617 | if (groupnum == -1) | ||
2618 | break; | ||
2619 | |||
2620 | if (!group_invited(m, i, groupnum)) | ||
2621 | break; | ||
2622 | |||
2623 | group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); | ||
2624 | /* This is just there to speedup joining. */ | ||
2625 | chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); | ||
2626 | break; | ||
2627 | } | ||
2628 | |||
2629 | case PACKET_ID_FILE_SENDREQUEST: { | 2125 | case PACKET_ID_FILE_SENDREQUEST: { |
2630 | if (data_length < 1 + sizeof(uint64_t) + 1) | 2126 | if (data_length < 1 + sizeof(uint64_t) + 1) |
2631 | break; | 2127 | break; |
@@ -2720,27 +2216,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2720 | return 0; | 2216 | return 0; |
2721 | } | 2217 | } |
2722 | 2218 | ||
2723 | static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key) | ||
2724 | { | ||
2725 | if (friend_not_valid(m, friendnumber)) | ||
2726 | return -1; | ||
2727 | |||
2728 | if (m->friendlist[friendnumber].crypt_connection_id != -1) { | ||
2729 | return -1; | ||
2730 | } | ||
2731 | |||
2732 | int id = new_crypto_connection(m->net_crypto, real_public_key); | ||
2733 | |||
2734 | if (id == -1) | ||
2735 | return -1; | ||
2736 | |||
2737 | m->friendlist[friendnumber].crypt_connection_id = id; | ||
2738 | connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber); | ||
2739 | connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber); | ||
2740 | connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friendnumber); | ||
2741 | return 0; | ||
2742 | } | ||
2743 | |||
2744 | /* TODO: Make this function not suck. */ | 2219 | /* TODO: Make this function not suck. */ |
2745 | void do_friends(Messenger *m) | 2220 | void do_friends(Messenger *m) |
2746 | { | 2221 | { |
@@ -2767,32 +2242,6 @@ void do_friends(Messenger *m) | |||
2767 | */ | 2242 | */ |
2768 | check_friend_request_timed_out(m, i, temp_time); | 2243 | check_friend_request_timed_out(m, i, temp_time); |
2769 | } | 2244 | } |
2770 | |||
2771 | friend_new_connection(m, i, m->friendlist[i].client_id); | ||
2772 | } | ||
2773 | |||
2774 | if (m->friendlist[i].crypt_connection_id != -1) { | ||
2775 | uint8_t dht_public_key1[crypto_box_PUBLICKEYBYTES]; | ||
2776 | uint64_t timestamp1 = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key1); | ||
2777 | uint8_t dht_public_key2[crypto_box_PUBLICKEYBYTES]; | ||
2778 | uint64_t timestamp2 = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key2); | ||
2779 | |||
2780 | if (timestamp1 > timestamp2) { | ||
2781 | set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key1, timestamp1); | ||
2782 | } else if (timestamp1 < timestamp2) { | ||
2783 | onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key2, timestamp2); | ||
2784 | } | ||
2785 | |||
2786 | uint8_t direct_connected; | ||
2787 | unsigned int status = crypto_connection_status(m->net_crypto, m->friendlist[i].crypt_connection_id, &direct_connected); | ||
2788 | |||
2789 | if (direct_connected == 0 || status == CRYPTO_CONN_COOKIE_REQUESTING) { | ||
2790 | IP_Port friendip; | ||
2791 | |||
2792 | if (onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip) == 1) { | ||
2793 | set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, friendip); | ||
2794 | } | ||
2795 | } | ||
2796 | } | 2245 | } |
2797 | 2246 | ||
2798 | if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ | 2247 | if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ |
@@ -2821,17 +2270,6 @@ void do_friends(Messenger *m) | |||
2821 | m->friendlist[i].user_istyping_sent = 1; | 2270 | m->friendlist[i].user_istyping_sent = 1; |
2822 | } | 2271 | } |
2823 | 2272 | ||
2824 | if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { | ||
2825 | send_ping(m, i); | ||
2826 | } | ||
2827 | |||
2828 | if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { | ||
2829 | /* If we stopped receiving ping packets, kill it. */ | ||
2830 | crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); | ||
2831 | m->friendlist[i].crypt_connection_id = -1; | ||
2832 | set_friend_status(m, i, FRIEND_CONFIRMED); | ||
2833 | } | ||
2834 | |||
2835 | if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { | 2273 | if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { |
2836 | send_relays(m, i); | 2274 | send_relays(m, i); |
2837 | } | 2275 | } |
@@ -2901,8 +2339,8 @@ void do_messenger(Messenger *m) | |||
2901 | 2339 | ||
2902 | do_net_crypto(m->net_crypto); | 2340 | do_net_crypto(m->net_crypto); |
2903 | do_onion_client(m->onion_c); | 2341 | do_onion_client(m->onion_c); |
2342 | do_friend_connections(m->fr_c); | ||
2904 | do_friends(m); | 2343 | do_friends(m); |
2905 | do_allgroupchats(m); | ||
2906 | LANdiscovery(m); | 2344 | LANdiscovery(m); |
2907 | 2345 | ||
2908 | #ifdef LOGGING | 2346 | #ifdef LOGGING |
@@ -2913,16 +2351,6 @@ void do_messenger(Messenger *m) | |||
2913 | Assoc_status(m->dht->assoc); | 2351 | Assoc_status(m->dht->assoc); |
2914 | #endif | 2352 | #endif |
2915 | 2353 | ||
2916 | if (m->numchats > 0) { | ||
2917 | size_t c; | ||
2918 | |||
2919 | for (c = 0; c < m->numchats; c++) { | ||
2920 | if (m->chats[c]) | ||
2921 | Assoc_status(m->chats[c]->assoc); | ||
2922 | } | ||
2923 | } | ||
2924 | |||
2925 | |||
2926 | lastdump = unix_time(); | 2354 | lastdump = unix_time(); |
2927 | uint32_t client, last_pinged; | 2355 | uint32_t client, last_pinged; |
2928 | 2356 | ||
@@ -2992,8 +2420,8 @@ void do_messenger(Messenger *m) | |||
2992 | if (ping_lastrecv > 999) | 2420 | if (ping_lastrecv > 999) |
2993 | ping_lastrecv = 999; | 2421 | ping_lastrecv = 999; |
2994 | 2422 | ||
2995 | LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s", | 2423 | LOGGER_INFO("F[%2u:%2u] <%s> [%03u] %s", |
2996 | dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, | 2424 | dht2m[friend], friend, msgfptr->name, |
2997 | ping_lastrecv, ID2String(msgfptr->client_id)); | 2425 | ping_lastrecv, ID2String(msgfptr->client_id)); |
2998 | } else { | 2426 | } else { |
2999 | LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); | 2427 | LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); |
@@ -3429,51 +2857,3 @@ int get_friendlist(const Messenger *m, int32_t **out_list, uint32_t *out_list_le | |||
3429 | 2857 | ||
3430 | return 0; | 2858 | return 0; |
3431 | } | 2859 | } |
3432 | |||
3433 | /* Return the number of chats in the instance m. | ||
3434 | * You should use this to determine how much memory to allocate | ||
3435 | * for copy_chatlist. */ | ||
3436 | uint32_t count_chatlist(const Messenger *m) | ||
3437 | { | ||
3438 | uint32_t ret = 0; | ||
3439 | uint32_t i; | ||
3440 | |||
3441 | for (i = 0; i < m->numchats; i++) { | ||
3442 | if (m->chats[i]) { | ||
3443 | ret++; | ||
3444 | } | ||
3445 | } | ||
3446 | |||
3447 | return ret; | ||
3448 | } | ||
3449 | |||
3450 | /* Copy a list of valid chat IDs into the array out_list. | ||
3451 | * If out_list is NULL, returns 0. | ||
3452 | * Otherwise, returns the number of elements copied. | ||
3453 | * If the array was too small, the contents | ||
3454 | * of out_list will be truncated to list_size. */ | ||
3455 | uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size) | ||
3456 | { | ||
3457 | if (!out_list) | ||
3458 | return 0; | ||
3459 | |||
3460 | if (m->numchats == 0) { | ||
3461 | return 0; | ||
3462 | } | ||
3463 | |||
3464 | uint32_t i; | ||
3465 | uint32_t ret = 0; | ||
3466 | |||
3467 | for (i = 0; i < m->numchats; i++) { | ||
3468 | if (ret >= list_size) { | ||
3469 | break; /* Abandon ship */ | ||
3470 | } | ||
3471 | |||
3472 | if (m->chats[i]) { | ||
3473 | out_list[ret] = i; | ||
3474 | ret++; | ||
3475 | } | ||
3476 | } | ||
3477 | |||
3478 | return ret; | ||
3479 | } | ||
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index e6877002..4a5a5ae7 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -26,12 +26,9 @@ | |||
26 | #ifndef MESSENGER_H | 26 | #ifndef MESSENGER_H |
27 | #define MESSENGER_H | 27 | #define MESSENGER_H |
28 | 28 | ||
29 | #include "net_crypto.h" | ||
30 | #include "DHT.h" | ||
31 | #include "friend_requests.h" | 29 | #include "friend_requests.h" |
32 | #include "LAN_discovery.h" | 30 | #include "LAN_discovery.h" |
33 | #include "group_chats.h" | 31 | #include "friend_connection.h" |
34 | #include "onion_client.h" | ||
35 | 32 | ||
36 | #define MAX_NAME_LENGTH 128 | 33 | #define MAX_NAME_LENGTH 128 |
37 | /* TODO: this must depend on other variable. */ | 34 | /* TODO: this must depend on other variable. */ |
@@ -42,8 +39,7 @@ | |||
42 | 39 | ||
43 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) | 40 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) |
44 | 41 | ||
45 | /* NOTE: Packet ids below 16 must never be used. */ | 42 | /* NOTE: Packet ids below 17 must never be used. */ |
46 | #define PACKET_ID_ALIVE 16 | ||
47 | #define PACKET_ID_SHARE_RELAYS 17 | 43 | #define PACKET_ID_SHARE_RELAYS 17 |
48 | #define PACKET_ID_NICKNAME 48 | 44 | #define PACKET_ID_NICKNAME 48 |
49 | #define PACKET_ID_STATUSMESSAGE 49 | 45 | #define PACKET_ID_STATUSMESSAGE 49 |
@@ -61,12 +57,9 @@ | |||
61 | #define PACKET_ID_FILE_SENDREQUEST 80 | 57 | #define PACKET_ID_FILE_SENDREQUEST 80 |
62 | #define PACKET_ID_FILE_CONTROL 81 | 58 | #define PACKET_ID_FILE_CONTROL 81 |
63 | #define PACKET_ID_FILE_DATA 82 | 59 | #define PACKET_ID_FILE_DATA 82 |
64 | #define PACKET_ID_INVITE_GROUPCHAT 144 | 60 | #define PACKET_ID_INVITE_GROUPCHAT 96 |
65 | #define PACKET_ID_JOIN_GROUPCHAT 145 | 61 | #define PACKET_ID_MESSAGE_GROUPCHAT 97 |
66 | #define PACKET_ID_ACCEPT_GROUPCHAT 146 | ||
67 | 62 | ||
68 | /* Max number of groups we can invite someone at the same time to. */ | ||
69 | #define MAX_INVITED_GROUPS 64 | ||
70 | 63 | ||
71 | /* Max number of tcp relays sent to friends */ | 64 | /* Max number of tcp relays sent to friends */ |
72 | #define MAX_SHARED_RELAYS 16 | 65 | #define MAX_SHARED_RELAYS 16 |
@@ -108,15 +101,9 @@ enum { | |||
108 | /* Default start timeout in seconds between friend requests. */ | 101 | /* Default start timeout in seconds between friend requests. */ |
109 | #define FRIENDREQUEST_TIMEOUT 5; | 102 | #define FRIENDREQUEST_TIMEOUT 5; |
110 | 103 | ||
111 | /* Interval between the sending of ping packets. */ | ||
112 | #define FRIEND_PING_INTERVAL 6 | ||
113 | |||
114 | /* Interval between the sending of tcp relay information */ | 104 | /* Interval between the sending of tcp relay information */ |
115 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) | 105 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) |
116 | 106 | ||
117 | /* If no packets are received from friend in this time interval, kill the connection. */ | ||
118 | #define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) | ||
119 | |||
120 | /* Must be < MAX_CRYPTO_DATA_SIZE */ | 107 | /* Must be < MAX_CRYPTO_DATA_SIZE */ |
121 | #define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) | 108 | #define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) |
122 | 109 | ||
@@ -199,9 +186,9 @@ enum { | |||
199 | }; | 186 | }; |
200 | 187 | ||
201 | typedef struct { | 188 | typedef struct { |
202 | uint8_t client_id[CLIENT_ID_SIZE]; | 189 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; |
203 | uint32_t onion_friendnum; | 190 | int friendcon_id; |
204 | int crypt_connection_id; | 191 | |
205 | uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. | 192 | uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. |
206 | uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. | 193 | uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. |
207 | uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. | 194 | uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. |
@@ -222,13 +209,10 @@ typedef struct { | |||
222 | uint32_t message_id; // a semi-unique id used in read receipts. | 209 | uint32_t message_id; // a semi-unique id used in read receipts. |
223 | uint8_t receives_read_receipts; // shall we send read receipts to this person? | 210 | uint8_t receives_read_receipts; // shall we send read receipts to this person? |
224 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. | 211 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. |
225 | uint64_t ping_lastrecv; | 212 | uint64_t ping_lastrecv;//TODO remove |
226 | uint64_t ping_lastsent; | ||
227 | uint64_t share_relays_lastsent; | 213 | uint64_t share_relays_lastsent; |
228 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; | 214 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; |
229 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 215 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
230 | int invited_groups[MAX_INVITED_GROUPS]; | ||
231 | uint16_t invited_groups_num; | ||
232 | 216 | ||
233 | AVATAR_SENDDATA avatar_send_data; | 217 | AVATAR_SENDDATA avatar_send_data; |
234 | AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend. | 218 | AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend. |
@@ -255,6 +239,8 @@ typedef struct Messenger { | |||
255 | Onion_Announce *onion_a; | 239 | Onion_Announce *onion_a; |
256 | Onion_Client *onion_c; | 240 | Onion_Client *onion_c; |
257 | 241 | ||
242 | Friend_Connections *fr_c; | ||
243 | |||
258 | Friend_Requests fr; | 244 | Friend_Requests fr; |
259 | uint8_t name[MAX_NAME_LENGTH]; | 245 | uint8_t name[MAX_NAME_LENGTH]; |
260 | uint16_t name_length; | 246 | uint16_t name_length; |
@@ -274,9 +260,6 @@ typedef struct Messenger { | |||
274 | 260 | ||
275 | uint32_t numonline_friends; | 261 | uint32_t numonline_friends; |
276 | 262 | ||
277 | Group_Chat **chats; | ||
278 | uint32_t numchats; | ||
279 | |||
280 | uint64_t last_LANdiscovery; | 263 | uint64_t last_LANdiscovery; |
281 | 264 | ||
282 | #define NUM_SAVED_TCP_RELAYS 8 | 265 | #define NUM_SAVED_TCP_RELAYS 8 |
@@ -308,14 +291,9 @@ typedef struct Messenger { | |||
308 | void *avatar_data_recv_userdata; | 291 | void *avatar_data_recv_userdata; |
309 | void (*avatar_data_recv)(struct Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *); | 292 | void (*avatar_data_recv)(struct Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *); |
310 | 293 | ||
311 | void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, void *); | 294 | void *group_chat_object; /* Set by new_groupchats()*/ |
312 | void *group_invite_userdata; | 295 | void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, uint16_t); |
313 | void (*group_message)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); | 296 | void (*group_message)(struct Messenger *m, int32_t, const uint8_t *, uint16_t); |
314 | void *group_message_userdata; | ||
315 | void (*group_action)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); | ||
316 | void *group_action_userdata; | ||
317 | void (*group_namelistchange)(struct Messenger *m, int, int, uint8_t, void *); | ||
318 | void *group_namelistchange_userdata; | ||
319 | 297 | ||
320 | void (*file_sendrequest)(struct Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *); | 298 | void (*file_sendrequest)(struct Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *); |
321 | void *file_sendrequest_userdata; | 299 | void *file_sendrequest_userdata; |
@@ -518,6 +496,11 @@ uint8_t m_get_self_userstatus(const Messenger *m); | |||
518 | */ | 496 | */ |
519 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length); | 497 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length); |
520 | 498 | ||
499 | /* Unsets the user avatar. | ||
500 | |||
501 | returns 0 on success (currently always returns 0) */ | ||
502 | int m_unset_avatar(Messenger *m); | ||
503 | |||
521 | /* Get avatar data from the current user. | 504 | /* Get avatar data from the current user. |
522 | * Copies the current user avatar data to the destination buffer and sets the image format | 505 | * Copies the current user avatar data to the destination buffer and sets the image format |
523 | * accordingly. | 506 | * accordingly. |
@@ -747,97 +730,16 @@ void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, int32_t | |||
747 | 730 | ||
748 | /* Set the callback for group invites. | 731 | /* Set the callback for group invites. |
749 | * | 732 | * |
750 | * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 733 | * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length) |
751 | */ | ||
752 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), | ||
753 | void *userdata); | ||
754 | |||
755 | /* Set the callback for group messages. | ||
756 | * | ||
757 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
758 | */ | ||
759 | void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
760 | void *userdata); | ||
761 | |||
762 | /* Set the callback for group actions. | ||
763 | * | ||
764 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
765 | */ | ||
766 | void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
767 | void *userdata); | ||
768 | |||
769 | /* Set callback function for peer name list changes. | ||
770 | * | ||
771 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
772 | * Function(Tox *tox, int groupnumber, void *userdata) | ||
773 | */ | ||
774 | void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
775 | void *userdata); | ||
776 | |||
777 | /* Creates a new groupchat and puts it in the chats array. | ||
778 | * | ||
779 | * return group number on success. | ||
780 | * return -1 on failure. | ||
781 | */ | ||
782 | int add_groupchat(Messenger *m); | ||
783 | |||
784 | /* Delete a groupchat from the chats array. | ||
785 | * | ||
786 | * return 0 on success. | ||
787 | * return -1 if failure. | ||
788 | */ | ||
789 | int del_groupchat(Messenger *m, int groupnumber); | ||
790 | |||
791 | /* Copy the name of peernumber who is in groupnumber to name. | ||
792 | * name must be at least MAX_NICK_BYTES long. | ||
793 | * | ||
794 | * return length of name if success | ||
795 | * return -1 if failure | ||
796 | */ | ||
797 | int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name); | ||
798 | |||
799 | /* invite friendnumber to groupnumber | ||
800 | * return 0 on success | ||
801 | * return -1 on failure | ||
802 | */ | ||
803 | int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber); | ||
804 | |||
805 | /* Join a group (you need to have been invited first.) | ||
806 | * | ||
807 | * returns group number on success | ||
808 | * returns -1 on failure. | ||
809 | */ | ||
810 | int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key); | ||
811 | |||
812 | /* send a group message | ||
813 | * return 0 on success | ||
814 | * return -1 on failure | ||
815 | */ | ||
816 | int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length); | ||
817 | |||
818 | /* send a group action | ||
819 | * return 0 on success | ||
820 | * return -1 on failure | ||
821 | */ | ||
822 | int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length); | ||
823 | |||
824 | /* Return the number of peers in the group chat on success. | ||
825 | * return -1 on failure | ||
826 | */ | 734 | */ |
827 | int group_number_peers(const Messenger *m, int groupnumber); | 735 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t)); |
828 | 736 | ||
829 | /* List all the peers in the group chat. | 737 | /* Send a group invite packet. |
830 | * | 738 | * |
831 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | 739 | * return 1 on success |
832 | * | 740 | * return 0 on failure |
833 | * Copies the lengths of the names to lengths[length] | ||
834 | * | ||
835 | * returns the number of peers on success. | ||
836 | * | ||
837 | * return -1 on failure. | ||
838 | */ | 741 | */ |
839 | int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | 742 | int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); |
840 | uint16_t length); | ||
841 | 743 | ||
842 | /****************FILE SENDING*****************/ | 744 | /****************FILE SENDING*****************/ |
843 | 745 | ||
@@ -1013,16 +915,4 @@ uint32_t copy_friendlist(const Messenger *m, int32_t *out_list, uint32_t list_si | |||
1013 | */ | 915 | */ |
1014 | int get_friendlist(const Messenger *m, int **out_list, uint32_t *out_list_length); | 916 | int get_friendlist(const Messenger *m, int **out_list, uint32_t *out_list_length); |
1015 | 917 | ||
1016 | /* Return the number of chats in the instance m. | ||
1017 | * You should use this to determine how much memory to allocate | ||
1018 | * for copy_chatlist. */ | ||
1019 | uint32_t count_chatlist(const Messenger *m); | ||
1020 | |||
1021 | /* Copy a list of valid chat IDs into the array out_list. | ||
1022 | * If out_list is NULL, returns 0. | ||
1023 | * Otherwise, returns the number of elements copied. | ||
1024 | * If the array was too small, the contents | ||
1025 | * of out_list will be truncated to list_size. */ | ||
1026 | uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size); | ||
1027 | |||
1028 | #endif | 918 | #endif |
diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c new file mode 100644 index 00000000..09dea4c3 --- /dev/null +++ b/toxcore/friend_connection.c | |||
@@ -0,0 +1,565 @@ | |||
1 | /* friend_connection.c | ||
2 | * | ||
3 | * Connection to friends. | ||
4 | * | ||
5 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifdef HAVE_CONFIG_H | ||
25 | #include "config.h" | ||
26 | #endif | ||
27 | |||
28 | #include "friend_connection.h" | ||
29 | #include "util.h" | ||
30 | |||
31 | /* return 1 if the friendcon_id is not valid. | ||
32 | * return 0 if the friendcon_id is valid. | ||
33 | */ | ||
34 | static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id) | ||
35 | { | ||
36 | if ((unsigned int)friendcon_id >= fr_c->num_cons) | ||
37 | return 1; | ||
38 | |||
39 | if (fr_c->conns == NULL) | ||
40 | return 1; | ||
41 | |||
42 | if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE) | ||
43 | return 1; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | /* Set the size of the friend connections list to num. | ||
50 | * | ||
51 | * return -1 if realloc fails. | ||
52 | * return 0 if it succeeds. | ||
53 | */ | ||
54 | static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num) | ||
55 | { | ||
56 | if (num == 0) { | ||
57 | free(fr_c->conns); | ||
58 | fr_c->conns = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | Friend_Conn *newgroup_cons = realloc(fr_c->conns, num * sizeof(Friend_Conn)); | ||
63 | |||
64 | if (newgroup_cons == NULL) | ||
65 | return -1; | ||
66 | |||
67 | fr_c->conns = newgroup_cons; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* Create a new empty friend connection. | ||
72 | * | ||
73 | * return -1 on failure. | ||
74 | * return friendcon_id on success. | ||
75 | */ | ||
76 | static int create_friend_conn(Friend_Connections *fr_c) | ||
77 | { | ||
78 | uint32_t i; | ||
79 | |||
80 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
81 | if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) | ||
82 | return i; | ||
83 | } | ||
84 | |||
85 | int id = -1; | ||
86 | |||
87 | if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) { | ||
88 | id = fr_c->num_cons; | ||
89 | ++fr_c->num_cons; | ||
90 | memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn)); | ||
91 | } | ||
92 | |||
93 | return id; | ||
94 | } | ||
95 | |||
96 | /* Wipe a friend connection. | ||
97 | * | ||
98 | * return -1 on failure. | ||
99 | * return 0 on success. | ||
100 | */ | ||
101 | static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id) | ||
102 | { | ||
103 | if (friendconn_id_not_valid(fr_c, friendcon_id)) | ||
104 | return -1; | ||
105 | |||
106 | uint32_t i; | ||
107 | memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn)); | ||
108 | |||
109 | for (i = fr_c->num_cons; i != 0; --i) { | ||
110 | if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | if (fr_c->num_cons != i) { | ||
115 | fr_c->num_cons = i; | ||
116 | realloc_friendconns(fr_c, fr_c->num_cons); | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) | ||
123 | { | ||
124 | if (friendconn_id_not_valid(fr_c, friendcon_id)) | ||
125 | return 0; | ||
126 | |||
127 | return &fr_c->conns[friendcon_id]; | ||
128 | } | ||
129 | |||
130 | /* return friendcon_id corresponding to the real public key on success. | ||
131 | * return -1 on failure. | ||
132 | */ | ||
133 | int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk) | ||
134 | { | ||
135 | uint32_t i; | ||
136 | |||
137 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
138 | Friend_Conn *friend_con = get_conn(fr_c, i); | ||
139 | |||
140 | if (friend_con) { | ||
141 | if (memcmp(friend_con->real_public_key, real_pk, crypto_box_PUBLICKEYBYTES) == 0) | ||
142 | return i; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | /* callback for recv TCP relay nodes. */ | ||
150 | static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) | ||
151 | { | ||
152 | Friend_Connections *fr_c = object; | ||
153 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
154 | |||
155 | if (!friend_con) | ||
156 | return -1; | ||
157 | |||
158 | if (friend_con->crypt_connection_id != -1) { | ||
159 | return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key); | ||
160 | } else { | ||
161 | return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); | ||
166 | /* Callback for DHT ip_port changes. */ | ||
167 | static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port) | ||
168 | { | ||
169 | Friend_Connections *fr_c = object; | ||
170 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
171 | |||
172 | if (!friend_con) | ||
173 | return; | ||
174 | |||
175 | if (friend_con->crypt_connection_id == -1) { | ||
176 | friend_new_connection(fr_c, number); | ||
177 | } | ||
178 | |||
179 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port); | ||
180 | friend_con->dht_ip_port = ip_port; | ||
181 | friend_con->dht_ip_port_lastrecv = unix_time(); | ||
182 | } | ||
183 | |||
184 | /* Callback for dht public key changes. */ | ||
185 | static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key) | ||
186 | { | ||
187 | Friend_Connections *fr_c = object; | ||
188 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
189 | |||
190 | if (!friend_con) | ||
191 | return; | ||
192 | |||
193 | friend_con->dht_ping_lastrecv = unix_time(); | ||
194 | |||
195 | if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) | ||
196 | return; | ||
197 | |||
198 | if (friend_con->dht_lock) { | ||
199 | if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) { | ||
200 | printf("a. Could not delete dht peer. Please report this.\n"); | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | friend_con->dht_lock = 0; | ||
205 | } | ||
206 | |||
207 | DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, object, number, &friend_con->dht_lock); | ||
208 | |||
209 | if (friend_con->crypt_connection_id == -1) { | ||
210 | friend_new_connection(fr_c, number); | ||
211 | } | ||
212 | |||
213 | set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, dht_public_key); | ||
214 | onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); | ||
215 | |||
216 | memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES); | ||
217 | } | ||
218 | |||
219 | static int handle_status(void *object, int number, uint8_t status) | ||
220 | { | ||
221 | Friend_Connections *fr_c = object; | ||
222 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
223 | |||
224 | if (!friend_con) | ||
225 | return -1; | ||
226 | |||
227 | if (status) { /* Went online. */ | ||
228 | friend_con->status = FRIENDCONN_STATUS_CONNECTED; | ||
229 | friend_con->ping_lastrecv = unix_time(); | ||
230 | onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); | ||
231 | } else { /* Went offline. */ | ||
232 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; | ||
233 | friend_con->crypt_connection_id = -1; | ||
234 | friend_con->dht_ping_lastrecv = unix_time(); | ||
235 | } | ||
236 | |||
237 | unsigned int i; | ||
238 | |||
239 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
240 | if (friend_con->callbacks[i].status_callback) | ||
241 | friend_con->callbacks[i].status_callback(friend_con->callbacks[i].status_callback_object, | ||
242 | friend_con->callbacks[i].status_callback_id, status); | ||
243 | } | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int handle_packet(void *object, int number, uint8_t *data, uint16_t length) | ||
249 | { | ||
250 | if (length == 0) | ||
251 | return -1; | ||
252 | |||
253 | Friend_Connections *fr_c = object; | ||
254 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
255 | |||
256 | if (!friend_con) | ||
257 | return -1; | ||
258 | |||
259 | if (data[0] == PACKET_ID_ALIVE) { | ||
260 | friend_con->ping_lastrecv = unix_time(); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | unsigned int i; | ||
265 | |||
266 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
267 | if (friend_con->callbacks[i].data_callback) | ||
268 | friend_con->callbacks[i].data_callback(friend_con->callbacks[i].data_callback_object, | ||
269 | friend_con->callbacks[i].data_callback_id, data, length); | ||
270 | } | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length) | ||
276 | { | ||
277 | if (length == 0) | ||
278 | return -1; | ||
279 | |||
280 | Friend_Connections *fr_c = object; | ||
281 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
282 | |||
283 | if (!friend_con) | ||
284 | return -1; | ||
285 | |||
286 | unsigned int i; | ||
287 | |||
288 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
289 | if (friend_con->callbacks[i].lossy_data_callback) | ||
290 | friend_con->callbacks[i].lossy_data_callback(friend_con->callbacks[i].lossy_data_callback_object, | ||
291 | friend_con->callbacks[i].lossy_data_callback_id, data, length); | ||
292 | } | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int handle_new_connections(void *object, New_Connection *n_c) | ||
298 | { | ||
299 | Friend_Connections *fr_c = object; | ||
300 | int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); | ||
301 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
302 | |||
303 | if (friend_con) { | ||
304 | |||
305 | if (friend_con->crypt_connection_id != -1) | ||
306 | return -1; | ||
307 | |||
308 | int id = accept_crypto_connection(fr_c->net_crypto, n_c); | ||
309 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); | ||
310 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); | ||
311 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); | ||
312 | friend_con->crypt_connection_id = id; | ||
313 | |||
314 | if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) { | ||
315 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); | ||
316 | } else { | ||
317 | friend_con->dht_ip_port = n_c->source; | ||
318 | friend_con->dht_ip_port_lastrecv = unix_time(); | ||
319 | } | ||
320 | |||
321 | dht_pk_callback(fr_c, friendcon_id, n_c->dht_public_key); | ||
322 | |||
323 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | return -1; | ||
328 | } | ||
329 | |||
330 | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) | ||
331 | { | ||
332 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
333 | |||
334 | if (!friend_con) | ||
335 | return -1; | ||
336 | |||
337 | if (friend_con->crypt_connection_id != -1) { | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key); | ||
342 | |||
343 | if (id == -1) | ||
344 | return -1; | ||
345 | |||
346 | friend_con->crypt_connection_id = id; | ||
347 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); | ||
348 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); | ||
349 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); | ||
350 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int send_ping(const Friend_Connections *fr_c, int friendcon_id) | ||
356 | { | ||
357 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
358 | |||
359 | if (!friend_con) | ||
360 | return -1; | ||
361 | |||
362 | uint8_t ping = PACKET_ID_ALIVE; | ||
363 | int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0); | ||
364 | |||
365 | if (ret != -1) { | ||
366 | friend_con->ping_lastsent = unix_time(); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | return -1; | ||
371 | } | ||
372 | |||
373 | /* Set the callbacks for the friend connection. | ||
374 | * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. | ||
375 | * | ||
376 | * return 0 on success. | ||
377 | * return -1 on failure | ||
378 | */ | ||
379 | int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, | ||
380 | int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, | ||
381 | uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | ||
382 | int number) | ||
383 | { | ||
384 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
385 | |||
386 | if (!friend_con) | ||
387 | return -1; | ||
388 | |||
389 | if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) | ||
390 | return -1; | ||
391 | |||
392 | friend_con->callbacks[index].status_callback = status_callback; | ||
393 | friend_con->callbacks[index].data_callback = data_callback; | ||
394 | friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; | ||
395 | |||
396 | friend_con->callbacks[index].status_callback_object = | ||
397 | friend_con->callbacks[index].data_callback_object = | ||
398 | friend_con->callbacks[index].lossy_data_callback_object = object; | ||
399 | |||
400 | friend_con->callbacks[index].status_callback_id = | ||
401 | friend_con->callbacks[index].data_callback_id = | ||
402 | friend_con->callbacks[index].lossy_data_callback_id = number; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | /* return the crypt_connection_id for the connection. | ||
407 | * | ||
408 | * return crypt_connection_id on success. | ||
409 | * return -1 on failure. | ||
410 | */ | ||
411 | int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id) | ||
412 | { | ||
413 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
414 | |||
415 | if (!friend_con) | ||
416 | return -1; | ||
417 | |||
418 | return friend_con->crypt_connection_id; | ||
419 | } | ||
420 | |||
421 | /* Create a new friend connection. | ||
422 | * If one to that real public key already exists, increase lock count and return it. | ||
423 | * | ||
424 | * return -1 on failure. | ||
425 | * return connection id on success. | ||
426 | */ | ||
427 | int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) | ||
428 | { | ||
429 | int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); | ||
430 | |||
431 | if (friendcon_id != -1) { | ||
432 | ++fr_c->conns[friendcon_id].lock_count; | ||
433 | return friendcon_id; | ||
434 | } | ||
435 | |||
436 | friendcon_id = create_friend_conn(fr_c); | ||
437 | |||
438 | if (friendcon_id == -1) | ||
439 | return -1; | ||
440 | |||
441 | int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); | ||
442 | |||
443 | if (onion_friendnum == -1) | ||
444 | return -1; | ||
445 | |||
446 | Friend_Conn *friend_con = &fr_c->conns[friendcon_id]; | ||
447 | |||
448 | friend_con->crypt_connection_id = -1; | ||
449 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; | ||
450 | memcpy(friend_con->real_public_key, real_public_key, crypto_box_PUBLICKEYBYTES); | ||
451 | friend_con->onion_friendnum = onion_friendnum; | ||
452 | |||
453 | recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); | ||
454 | onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); | ||
455 | |||
456 | return friendcon_id; | ||
457 | } | ||
458 | |||
459 | /* Kill a friend connection. | ||
460 | * | ||
461 | * return -1 on failure. | ||
462 | * return 0 on success. | ||
463 | */ | ||
464 | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) | ||
465 | { | ||
466 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
467 | |||
468 | if (!friend_con) | ||
469 | return -1; | ||
470 | |||
471 | if (friend_con->lock_count) { | ||
472 | --friend_con->lock_count; | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); | ||
477 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); | ||
478 | |||
479 | if (friend_con->dht_lock) { | ||
480 | DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); | ||
481 | } | ||
482 | |||
483 | return wipe_friend_conn(fr_c, friendcon_id); | ||
484 | } | ||
485 | |||
486 | |||
487 | /* Create new friend_connections instance. */ | ||
488 | Friend_Connections *new_friend_connections(Onion_Client *onion_c) | ||
489 | { | ||
490 | if (!onion_c) | ||
491 | return NULL; | ||
492 | |||
493 | Friend_Connections *temp = calloc(1, sizeof(Friend_Connections)); | ||
494 | |||
495 | if (temp == NULL) | ||
496 | return NULL; | ||
497 | |||
498 | temp->dht = onion_c->dht; | ||
499 | temp->net_crypto = onion_c->c; | ||
500 | temp->onion_c = onion_c; | ||
501 | |||
502 | new_connection_handler(temp->net_crypto, &handle_new_connections, temp); | ||
503 | |||
504 | return temp; | ||
505 | } | ||
506 | |||
507 | /* main friend_connections loop. */ | ||
508 | void do_friend_connections(Friend_Connections *fr_c) | ||
509 | { | ||
510 | uint32_t i; | ||
511 | uint64_t temp_time = unix_time(); | ||
512 | |||
513 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
514 | Friend_Conn *friend_con = get_conn(fr_c, i); | ||
515 | |||
516 | if (friend_con) { | ||
517 | if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { | ||
518 | if (friend_con->dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { | ||
519 | if (friend_con->dht_lock) { | ||
520 | DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); | ||
521 | friend_con->dht_lock = 0; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { | ||
526 | friend_con->dht_ip_port.ip.family = 0; | ||
527 | } | ||
528 | |||
529 | if (friend_con->dht_lock) { | ||
530 | if (friend_new_connection(fr_c, i) == 0) { | ||
531 | set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_temp_pk); | ||
532 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { | ||
537 | if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { | ||
538 | send_ping(fr_c, i); | ||
539 | } | ||
540 | |||
541 | if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { | ||
542 | /* If we stopped receiving ping packets, kill it. */ | ||
543 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); | ||
544 | friend_con->crypt_connection_id = -1; | ||
545 | handle_status(fr_c, i, 0); /* Going offline. */ | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* Free everything related with friend_connections. */ | ||
553 | void kill_friend_connections(Friend_Connections *fr_c) | ||
554 | { | ||
555 | if (!fr_c) | ||
556 | return; | ||
557 | |||
558 | uint32_t i; | ||
559 | |||
560 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
561 | kill_friend_connection(fr_c, i); | ||
562 | } | ||
563 | |||
564 | free(fr_c); | ||
565 | } | ||
diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h new file mode 100644 index 00000000..62b82dc2 --- /dev/null +++ b/toxcore/friend_connection.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* friend_connection.h | ||
2 | * | ||
3 | * Connection to friends. | ||
4 | * | ||
5 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef FRIEND_CONNECTION_H | ||
26 | #define FRIEND_CONNECTION_H | ||
27 | |||
28 | #include "net_crypto.h" | ||
29 | #include "DHT.h" | ||
30 | #include "LAN_discovery.h" | ||
31 | #include "onion_client.h" | ||
32 | |||
33 | |||
34 | #define MAX_FRIEND_CONNECTION_CALLBACKS 2 | ||
35 | #define MESSENGER_CALLBACK_INDEX 0 | ||
36 | #define GROUPCHAT_CALLBACK_INDEX 1 | ||
37 | |||
38 | #define PACKET_ID_ALIVE 16 | ||
39 | |||
40 | /* Interval between the sending of ping packets. */ | ||
41 | #define FRIEND_PING_INTERVAL 6 | ||
42 | |||
43 | /* If no packets are received from friend in this time interval, kill the connection. */ | ||
44 | #define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) | ||
45 | |||
46 | /* Time before friend is removed from the DHT after last hearing about him. */ | ||
47 | #define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT | ||
48 | |||
49 | |||
50 | enum { | ||
51 | FRIENDCONN_STATUS_NONE, | ||
52 | FRIENDCONN_STATUS_CONNECTING, | ||
53 | FRIENDCONN_STATUS_CONNECTED | ||
54 | }; | ||
55 | |||
56 | typedef struct { | ||
57 | uint8_t status; | ||
58 | |||
59 | uint8_t real_public_key[crypto_box_PUBLICKEYBYTES]; | ||
60 | uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
61 | uint16_t dht_lock; | ||
62 | IP_Port dht_ip_port; | ||
63 | uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv; | ||
64 | |||
65 | int onion_friendnum; | ||
66 | int crypt_connection_id; | ||
67 | |||
68 | uint64_t ping_lastrecv, ping_lastsent; | ||
69 | |||
70 | struct { | ||
71 | int (*status_callback)(void *object, int id, uint8_t status); | ||
72 | void *status_callback_object; | ||
73 | int status_callback_id; | ||
74 | |||
75 | int (*data_callback)(void *object, int id, uint8_t *data, uint16_t length); | ||
76 | void *data_callback_object; | ||
77 | int data_callback_id; | ||
78 | |||
79 | int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length); | ||
80 | void *lossy_data_callback_object; | ||
81 | int lossy_data_callback_id; | ||
82 | } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; | ||
83 | |||
84 | uint16_t lock_count; | ||
85 | } Friend_Conn; | ||
86 | |||
87 | |||
88 | typedef struct { | ||
89 | Net_Crypto *net_crypto; | ||
90 | DHT *dht; | ||
91 | Onion_Client *onion_c; | ||
92 | |||
93 | Friend_Conn *conns; | ||
94 | uint32_t num_cons; | ||
95 | |||
96 | } Friend_Connections; | ||
97 | |||
98 | /* Set the callbacks for the friend connection. | ||
99 | * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. | ||
100 | * | ||
101 | * return 0 on success. | ||
102 | * return -1 on failure | ||
103 | */ | ||
104 | int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, | ||
105 | int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, | ||
106 | uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | ||
107 | int number); | ||
108 | |||
109 | /* return the crypt_connection_id for the connection. | ||
110 | * | ||
111 | * return crypt_connection_id on success. | ||
112 | * return -1 on failure. | ||
113 | */ | ||
114 | int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id); | ||
115 | |||
116 | /* Create a new friend connection. | ||
117 | * If one to that real public key already exists, increase lock count and return it. | ||
118 | * | ||
119 | * return -1 on failure. | ||
120 | * return connection id on success. | ||
121 | */ | ||
122 | int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key); | ||
123 | |||
124 | /* Kill a friend connection. | ||
125 | * | ||
126 | * return -1 on failure. | ||
127 | * return 0 on success. | ||
128 | */ | ||
129 | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); | ||
130 | |||
131 | /* Create new friend_connections instance. */ | ||
132 | Friend_Connections *new_friend_connections(Onion_Client *onion_c); | ||
133 | |||
134 | /* main friend_connections loop. */ | ||
135 | void do_friend_connections(Friend_Connections *fr_c); | ||
136 | |||
137 | /* Free everything related with friend_connections. */ | ||
138 | void kill_friend_connections(Friend_Connections *fr_c); | ||
139 | |||
140 | #endif | ||
diff --git a/toxcore/group.c b/toxcore/group.c new file mode 100644 index 00000000..d5244f65 --- /dev/null +++ b/toxcore/group.c | |||
@@ -0,0 +1,781 @@ | |||
1 | /* group.c | ||
2 | * | ||
3 | * Slightly better groupchats implementation. | ||
4 | * | ||
5 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifdef HAVE_CONFIG_H | ||
25 | #include "config.h" | ||
26 | #endif | ||
27 | |||
28 | #include "group.h" | ||
29 | #include "util.h" | ||
30 | |||
31 | /* return 1 if the groupnumber is not valid. | ||
32 | * return 0 if the groupnumber is valid. | ||
33 | */ | ||
34 | static uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber) | ||
35 | { | ||
36 | if ((unsigned int)groupnumber >= g_c->num_chats) | ||
37 | return 1; | ||
38 | |||
39 | if (g_c->chats == NULL) | ||
40 | return 1; | ||
41 | |||
42 | if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) | ||
43 | return 1; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | /* Set the size of the groupchat list to num. | ||
50 | * | ||
51 | * return -1 if realloc fails. | ||
52 | * return 0 if it succeeds. | ||
53 | */ | ||
54 | static int realloc_groupchats(Group_Chats *g_c, uint32_t num) | ||
55 | { | ||
56 | if (num == 0) { | ||
57 | free(g_c->chats); | ||
58 | g_c->chats = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | Group_c *newgroup_chats = realloc(g_c->chats, num * sizeof(Group_c)); | ||
63 | |||
64 | if (newgroup_chats == NULL) | ||
65 | return -1; | ||
66 | |||
67 | g_c->chats = newgroup_chats; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | |||
72 | /* Create a new empty groupchat connection. | ||
73 | * | ||
74 | * return -1 on failure. | ||
75 | * return groupnumber on success. | ||
76 | */ | ||
77 | static int create_group_chat(Group_Chats *g_c) | ||
78 | { | ||
79 | uint32_t i; | ||
80 | |||
81 | for (i = 0; i < g_c->num_chats; ++i) { | ||
82 | if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE) | ||
83 | return i; | ||
84 | } | ||
85 | |||
86 | int id = -1; | ||
87 | |||
88 | if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) { | ||
89 | id = g_c->num_chats; | ||
90 | ++g_c->num_chats; | ||
91 | memset(&(g_c->chats[id]), 0, sizeof(Group_c)); | ||
92 | } | ||
93 | |||
94 | return id; | ||
95 | } | ||
96 | |||
97 | |||
98 | /* Wipe a groupchat. | ||
99 | * | ||
100 | * return -1 on failure. | ||
101 | * return 0 on success. | ||
102 | */ | ||
103 | static int wipe_group_chat(Group_Chats *g_c, int groupnumber) | ||
104 | { | ||
105 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
106 | return -1; | ||
107 | |||
108 | uint32_t i; | ||
109 | memset(&(g_c->chats[groupnumber]), 0 , sizeof(Group_c)); | ||
110 | |||
111 | for (i = g_c->num_chats; i != 0; --i) { | ||
112 | if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (g_c->num_chats != i) { | ||
117 | g_c->num_chats = i; | ||
118 | realloc_groupchats(g_c, g_c->num_chats); | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber) | ||
125 | { | ||
126 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
127 | return 0; | ||
128 | |||
129 | return &g_c->chats[groupnumber]; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * check if peer with client_id is in peer array. | ||
134 | * | ||
135 | * return peer index if peer is in chat. | ||
136 | * return -1 if peer is not in chat. | ||
137 | * | ||
138 | * TODO: make this more efficient. | ||
139 | */ | ||
140 | |||
141 | static int peer_in_chat(const Group_c *chat, const uint8_t *client_id) | ||
142 | { | ||
143 | uint32_t i; | ||
144 | |||
145 | for (i = 0; i < chat->numpeers; ++i) | ||
146 | if (id_equal(chat->group[i].client_id, client_id)) | ||
147 | return i; | ||
148 | |||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * check if group with identifier is in group array. | ||
154 | * | ||
155 | * return group number if peer is in list. | ||
156 | * return -1 if group is not in list. | ||
157 | * | ||
158 | * TODO: make this more efficient and maybe use constant time comparisons? | ||
159 | */ | ||
160 | static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier) | ||
161 | { | ||
162 | uint32_t i; | ||
163 | |||
164 | for (i = 0; i < g_c->num_chats; ++i) | ||
165 | if (memcmp(g_c->chats[i].identifier, identifier, GROUP_IDENTIFIER_LENGTH) == 0) | ||
166 | return i; | ||
167 | |||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * check if peer with peer_number is in peer array. | ||
173 | * | ||
174 | * return peer number if peer is in chat. | ||
175 | * return -1 if peer is not in chat. | ||
176 | * | ||
177 | * TODO: make this more efficient. | ||
178 | */ | ||
179 | int get_peer_index(Group_c *g, uint16_t peer_number) | ||
180 | { | ||
181 | uint32_t i; | ||
182 | |||
183 | for (i = 0; i < g->numpeers; ++i) | ||
184 | if (g->group[i].peer_number == peer_number) | ||
185 | return i; | ||
186 | |||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Add a peer to the group chat. | ||
192 | * | ||
193 | * return peer_index if success or peer already in chat. | ||
194 | * return -1 if error. | ||
195 | */ | ||
196 | static int addpeer(Group_c *chat, const uint8_t *client_id, uint16_t peer_number) | ||
197 | { | ||
198 | //TODO | ||
199 | //int peer_index = peer_in_chat(chat, client_id); | ||
200 | |||
201 | //if (peer_index != -1) | ||
202 | // return peer_index; | ||
203 | |||
204 | Group_Peer *temp; | ||
205 | temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); | ||
206 | |||
207 | if (temp == NULL) | ||
208 | return -1; | ||
209 | |||
210 | memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); | ||
211 | chat->group = temp; | ||
212 | |||
213 | id_copy(chat->group[chat->numpeers].client_id, client_id); | ||
214 | chat->group[chat->numpeers].peer_number = peer_number; | ||
215 | |||
216 | chat->group[chat->numpeers].last_recv = unix_time(); | ||
217 | chat->group[chat->numpeers].last_recv_msgping = unix_time(); | ||
218 | ++chat->numpeers; | ||
219 | |||
220 | //if (chat->peer_namelistchange != NULL) | ||
221 | // (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata); | ||
222 | |||
223 | return (chat->numpeers - 1); | ||
224 | } | ||
225 | |||
226 | static int handle_packet(void *object, int number, uint8_t *data, uint16_t length); | ||
227 | |||
228 | /* Add friend to group chat. | ||
229 | * | ||
230 | * return 0 on success | ||
231 | * return -1 on failure. | ||
232 | */ | ||
233 | static int add_friend_to_groupchat(Group_Chats *g_c, int32_t friendnumber, int groupnumber, uint16_t other_groupnum) | ||
234 | { | ||
235 | if (!m_friend_exists(g_c->m, friendnumber)) | ||
236 | return -1; | ||
237 | |||
238 | Group_c *g = get_group_c(g_c, groupnumber); | ||
239 | |||
240 | if (!g) | ||
241 | return -1; | ||
242 | |||
243 | uint16_t i, ind = MAX_GROUP_CONNECTIONS; | ||
244 | |||
245 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
246 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { | ||
247 | ind = i; | ||
248 | continue; | ||
249 | } | ||
250 | |||
251 | if (g->close[i].type == GROUPCHAT_CLOSE_CONNECTION && g->close[i].number == (uint32_t)friendnumber) { | ||
252 | g->close[i].group_number = other_groupnum; /* update groupnum. */ | ||
253 | return 0; /* Already in list. */ | ||
254 | } | ||
255 | |||
256 | break; | ||
257 | } | ||
258 | |||
259 | if (ind == MAX_GROUP_CONNECTIONS) | ||
260 | return -1; | ||
261 | |||
262 | g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; | ||
263 | g->close[ind].number = friendnumber; | ||
264 | g->close[ind].group_number = other_groupnum; | ||
265 | int friendcon_id = g_c->m->friendlist[friendnumber].friendcon_id; | ||
266 | //TODO | ||
267 | friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, 0, &handle_packet, 0, g_c->m, | ||
268 | friendnumber); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* Creates a new groupchat and puts it in the chats array. | ||
274 | * | ||
275 | * return group number on success. | ||
276 | * return -1 on failure. | ||
277 | */ | ||
278 | int add_groupchat(Group_Chats *g_c) | ||
279 | { | ||
280 | int groupnumber = create_group_chat(g_c); | ||
281 | |||
282 | if (groupnumber == -1) | ||
283 | return -1; | ||
284 | |||
285 | Group_c *g = &g_c->chats[groupnumber]; | ||
286 | |||
287 | g->status = GROUPCHAT_STATUS_VALID; | ||
288 | new_symmetric_key(g->identifier); | ||
289 | g->peer_number = 0; /* Founder is peer 0. */ | ||
290 | return groupnumber; | ||
291 | } | ||
292 | |||
293 | /* Delete a groupchat from the chats array. | ||
294 | * | ||
295 | * return 0 on success. | ||
296 | * return -1 if failure. | ||
297 | */ | ||
298 | int del_groupchat(Group_Chats *g_c, int groupnumber) | ||
299 | { | ||
300 | Group_c *g = get_group_c(g_c, groupnumber); | ||
301 | |||
302 | if (!g) | ||
303 | return -1; | ||
304 | |||
305 | free(g->group); | ||
306 | return wipe_group_chat(g_c, groupnumber); | ||
307 | } | ||
308 | |||
309 | /* Send a group message packet. | ||
310 | * | ||
311 | * return 1 on success | ||
312 | * return 0 on failure | ||
313 | */ | ||
314 | int send_group_message_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) | ||
315 | { | ||
316 | if (length >= MAX_CRYPTO_DATA_SIZE) | ||
317 | return 0; | ||
318 | |||
319 | uint8_t packet[1 + length]; | ||
320 | packet[0] = PACKET_ID_MESSAGE_GROUPCHAT; | ||
321 | memcpy(packet + 1, data, length); | ||
322 | return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, | ||
323 | m->friendlist[friendnumber].friendcon_id), packet, sizeof(packet), 0) != -1; | ||
324 | } | ||
325 | |||
326 | #define INVITE_PACKET_SIZE (1 + sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) | ||
327 | #define INVITE_ID 0 | ||
328 | |||
329 | #define INVITE_RESPONSE_PACKET_SIZE (1 + sizeof(uint16_t) * 2 + GROUP_IDENTIFIER_LENGTH) | ||
330 | #define INVITE_RESPONSE_ID 1 | ||
331 | |||
332 | /* invite friendnumber to groupnumber | ||
333 | * return 0 on success | ||
334 | * return -1 on failure | ||
335 | */ | ||
336 | int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber) | ||
337 | { | ||
338 | Group_c *g = get_group_c(g_c, groupnumber); | ||
339 | |||
340 | if (!g) | ||
341 | return -1; | ||
342 | |||
343 | uint8_t invite[INVITE_PACKET_SIZE]; | ||
344 | invite[0] = INVITE_ID; | ||
345 | uint16_t groupchat_num = htons((uint16_t)groupnumber); | ||
346 | memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num)); | ||
347 | memcpy(invite + 1 + sizeof(groupchat_num), g->identifier, GROUP_IDENTIFIER_LENGTH); | ||
348 | |||
349 | if (send_group_invite_packet(g_c->m, friendnumber, invite, sizeof(invite))) { | ||
350 | return 0; | ||
351 | } else { | ||
352 | wipe_group_chat(g_c, groupnumber); | ||
353 | return -1; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | /* Join a group (you need to have been invited first.) | ||
358 | * | ||
359 | * returns group number on success | ||
360 | * returns -1 on failure. | ||
361 | */ | ||
362 | int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length) | ||
363 | { | ||
364 | if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) | ||
365 | return -1; | ||
366 | |||
367 | int groupnumber = create_group_chat(g_c); | ||
368 | |||
369 | if (groupnumber == -1) | ||
370 | return -1; | ||
371 | |||
372 | Group_c *g = &g_c->chats[groupnumber]; | ||
373 | |||
374 | uint16_t group_num = htons(groupnumber); | ||
375 | g->status = GROUPCHAT_STATUS_VALID; | ||
376 | uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; | ||
377 | response[0] = INVITE_RESPONSE_ID; | ||
378 | memcpy(response + 1, &group_num, sizeof(uint16_t)); | ||
379 | memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH); | ||
380 | |||
381 | if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { | ||
382 | uint16_t other_groupnum; | ||
383 | memcpy(&other_groupnum, data, sizeof(other_groupnum)); | ||
384 | other_groupnum = htons(other_groupnum); | ||
385 | memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); | ||
386 | add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum); | ||
387 | g->peer_number = rand(); /* TODO */ | ||
388 | return groupnumber; | ||
389 | } else { | ||
390 | return -1; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | /* Set the callback for group invites. | ||
395 | * | ||
396 | * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) | ||
397 | * | ||
398 | * data of length is what needs to be passed to join_groupchat(). | ||
399 | */ | ||
400 | void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, | ||
401 | void *), void *userdata) | ||
402 | { | ||
403 | g_c->invite_callback = function; | ||
404 | g_c->invite_callback_userdata = userdata; | ||
405 | } | ||
406 | |||
407 | /* Set the callback for group messages. | ||
408 | * | ||
409 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
410 | */ | ||
411 | void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
412 | void *), void *userdata) | ||
413 | { | ||
414 | g_c->message_callback = function; | ||
415 | g_c->message_callback_userdata = userdata; | ||
416 | } | ||
417 | |||
418 | static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) | ||
419 | { | ||
420 | Group_Chats *g_c = m->group_chat_object; | ||
421 | |||
422 | if (length <= 1) | ||
423 | return; | ||
424 | |||
425 | const uint8_t *invite_data = data + 1; | ||
426 | uint16_t invite_length = length - 1; | ||
427 | |||
428 | switch (data[0]) { | ||
429 | case INVITE_ID: { | ||
430 | if (length != INVITE_PACKET_SIZE) | ||
431 | return; | ||
432 | |||
433 | int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); | ||
434 | |||
435 | if (groupnumber == -1) { | ||
436 | if (g_c->invite_callback) | ||
437 | g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata); | ||
438 | |||
439 | return; | ||
440 | } else { | ||
441 | //TODO | ||
442 | uint16_t other_groupnum; | ||
443 | memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); | ||
444 | other_groupnum = ntohs(other_groupnum); | ||
445 | add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum); | ||
446 | } | ||
447 | |||
448 | break; | ||
449 | } | ||
450 | |||
451 | case INVITE_RESPONSE_ID: { | ||
452 | if (length != INVITE_RESPONSE_PACKET_SIZE) | ||
453 | return; | ||
454 | |||
455 | uint16_t other_groupnum, groupnum; | ||
456 | memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); | ||
457 | groupnum = ntohs(groupnum); | ||
458 | |||
459 | Group_c *g = get_group_c(g_c, groupnum); | ||
460 | |||
461 | if (!g) | ||
462 | return; | ||
463 | |||
464 | if (memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0) | ||
465 | return; | ||
466 | |||
467 | memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); | ||
468 | other_groupnum = ntohs(other_groupnum); | ||
469 | |||
470 | add_friend_to_groupchat(g_c, friendnumber, groupnum, other_groupnum); | ||
471 | |||
472 | break; | ||
473 | } | ||
474 | |||
475 | default: | ||
476 | return; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /* Find index of friend in the close list; | ||
481 | * | ||
482 | * returns index on success | ||
483 | * returns -1 on failure. | ||
484 | */ | ||
485 | static int friend_in_close(Group_c *g, int32_t friendnumber) | ||
486 | { | ||
487 | int i; | ||
488 | |||
489 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
490 | if (g->close[i].type != GROUPCHAT_CLOSE_CONNECTION) | ||
491 | continue; | ||
492 | |||
493 | if (g->close[i].number != (uint32_t)friendnumber) | ||
494 | continue; | ||
495 | |||
496 | return i; | ||
497 | } | ||
498 | |||
499 | return -1; | ||
500 | } | ||
501 | |||
502 | #define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) | ||
503 | |||
504 | /* Send message to all close except receiver (if receiver isn't -1) | ||
505 | * NOTE: this function appends the group chat number to the data passed to it. | ||
506 | * | ||
507 | * return number of messages sent. | ||
508 | */ | ||
509 | static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, | ||
510 | uint16_t length, int receiver) | ||
511 | { | ||
512 | |||
513 | Group_c *g = get_group_c(g_c, groupnumber); | ||
514 | |||
515 | if (!g) | ||
516 | return 0; | ||
517 | |||
518 | uint16_t i, sent = 0; | ||
519 | |||
520 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
521 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
522 | continue; | ||
523 | |||
524 | if ((int)i == receiver) | ||
525 | continue; | ||
526 | |||
527 | uint16_t other_groupnum = htons(g->close[i].group_number); | ||
528 | uint8_t packet[sizeof(uint16_t) + length]; | ||
529 | memcpy(packet, &other_groupnum, sizeof(uint16_t)); | ||
530 | memcpy(packet + sizeof(uint16_t), data, length); | ||
531 | |||
532 | if (send_group_message_packet(g_c->m, g->close[i].number, packet, sizeof(packet))) | ||
533 | ++sent; | ||
534 | } | ||
535 | |||
536 | return sent; | ||
537 | } | ||
538 | |||
539 | #define MAX_GROUP_MESSAGE_DATA_LEN (MAX_CRYPTO_DATA_SIZE - (1 + MIN_MESSAGE_PACKET_LEN)) | ||
540 | |||
541 | /* Send data of len with message_id to groupnumber. | ||
542 | * | ||
543 | * return number of peers it was sent to on success. | ||
544 | * return 0 on failure. | ||
545 | */ | ||
546 | static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, | ||
547 | uint16_t len) | ||
548 | { | ||
549 | if (len > MAX_GROUP_MESSAGE_DATA_LEN) | ||
550 | return 0; | ||
551 | |||
552 | Group_c *g = get_group_c(g_c, groupnumber); | ||
553 | |||
554 | if (!g) | ||
555 | return 0; | ||
556 | |||
557 | uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len]; | ||
558 | uint16_t peer_num = htons(g->peer_number); | ||
559 | memcpy(packet, &peer_num, sizeof(peer_num)); | ||
560 | |||
561 | ++g->message_number; | ||
562 | |||
563 | if (!g->message_number) | ||
564 | ++g->message_number; | ||
565 | |||
566 | uint32_t message_num = htonl(g->message_number); | ||
567 | memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num)); | ||
568 | |||
569 | packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id; | ||
570 | |||
571 | if (len) | ||
572 | memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len); | ||
573 | |||
574 | return send_message_all_close(g_c, groupnumber, packet, sizeof(packet), -1); | ||
575 | } | ||
576 | |||
577 | /* send a group message | ||
578 | * return 0 on success | ||
579 | * return -1 on failure | ||
580 | */ | ||
581 | int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length) | ||
582 | { | ||
583 | if (send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length)) { | ||
584 | return 0; | ||
585 | } else { | ||
586 | return -1; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, | ||
591 | int close_index) | ||
592 | { | ||
593 | if (length < MIN_MESSAGE_PACKET_LEN) | ||
594 | return; | ||
595 | |||
596 | Group_c *g = get_group_c(g_c, groupnumber); | ||
597 | |||
598 | if (!g) | ||
599 | return; | ||
600 | |||
601 | uint16_t peer_number; | ||
602 | memcpy(&peer_number, data + sizeof(uint16_t), sizeof(uint16_t)); | ||
603 | peer_number = ntohs(peer_number); | ||
604 | |||
605 | int index = get_peer_index(g, peer_number); | ||
606 | |||
607 | //TODO remove | ||
608 | if (index == -1) { | ||
609 | uint8_t empty_key[crypto_box_PUBLICKEYBYTES]; | ||
610 | index = addpeer(g, empty_key, peer_number); | ||
611 | } | ||
612 | |||
613 | if (index == -1) | ||
614 | return; | ||
615 | |||
616 | uint32_t message_number; | ||
617 | memcpy(&message_number, data + sizeof(uint16_t) * 2, sizeof(message_number)); | ||
618 | message_number = ntohl(message_number); | ||
619 | |||
620 | if (g->group[index].last_message_number == 0) { | ||
621 | g->group[index].last_message_number = message_number; | ||
622 | } else if (message_number - g->group[index].last_message_number > 64 || | ||
623 | message_number == g->group[index].last_message_number) { | ||
624 | return; | ||
625 | } | ||
626 | |||
627 | g->group[index].last_message_number = message_number; | ||
628 | |||
629 | uint8_t message_id = data[sizeof(uint16_t) * 2 + sizeof(message_number)]; | ||
630 | const uint8_t *msg_data = data + sizeof(uint16_t) * 2 + sizeof(message_number) + 1; | ||
631 | uint16_t msg_data_len = length - (sizeof(uint16_t) * 2 + sizeof(message_number) + 1); | ||
632 | |||
633 | switch (message_id) { | ||
634 | case PACKET_ID_MESSAGE: { | ||
635 | if (msg_data_len == 0) | ||
636 | return; | ||
637 | |||
638 | //TODO | ||
639 | if (g_c->message_callback) | ||
640 | g_c->message_callback(g_c->m, groupnumber, index, msg_data, msg_data_len, g_c->message_callback_userdata); | ||
641 | |||
642 | break; | ||
643 | } | ||
644 | |||
645 | default: | ||
646 | return; | ||
647 | } | ||
648 | |||
649 | send_message_all_close(g_c, groupnumber, data + sizeof(uint16_t), length - sizeof(uint16_t), close_index); | ||
650 | } | ||
651 | |||
652 | static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) | ||
653 | { | ||
654 | Group_Chats *g_c = m->group_chat_object; | ||
655 | |||
656 | if (length < MIN_MESSAGE_PACKET_LEN) | ||
657 | return; | ||
658 | |||
659 | uint16_t groupnumber; | ||
660 | memcpy(&groupnumber, data, sizeof(uint16_t)); | ||
661 | groupnumber = ntohs(groupnumber); | ||
662 | Group_c *g = get_group_c(g_c, groupnumber); | ||
663 | |||
664 | if (!g) | ||
665 | return; | ||
666 | |||
667 | int index = friend_in_close(g, friendnumber); | ||
668 | |||
669 | if (index == -1) | ||
670 | return; | ||
671 | |||
672 | handle_message_packet_group(g_c, groupnumber, data, length, index); | ||
673 | } | ||
674 | |||
675 | static int handle_packet(void *object, int number, uint8_t *data, uint16_t length) | ||
676 | { | ||
677 | if (length <= 1) | ||
678 | return -1; | ||
679 | |||
680 | switch (data[0]) { | ||
681 | case PACKET_ID_INVITE_GROUPCHAT: { | ||
682 | handle_friend_invite_packet(object, number, data + 1, length - 1); | ||
683 | break; | ||
684 | } | ||
685 | |||
686 | case PACKET_ID_MESSAGE_GROUPCHAT: { | ||
687 | handle_friend_message_packet(object, number, data + 1, length - 1); | ||
688 | break; | ||
689 | } | ||
690 | |||
691 | default: { | ||
692 | return 0; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | |||
700 | /* Create new groupchat instance. */ | ||
701 | Group_Chats *new_groupchats(Messenger *m) | ||
702 | { | ||
703 | if (!m) | ||
704 | return NULL; | ||
705 | |||
706 | Group_Chats *temp = calloc(1, sizeof(Group_Chats)); | ||
707 | |||
708 | if (temp == NULL) | ||
709 | return NULL; | ||
710 | |||
711 | temp->m = m; | ||
712 | m->group_chat_object = temp; | ||
713 | m_callback_group_invite(m, &handle_friend_invite_packet); | ||
714 | |||
715 | return temp; | ||
716 | } | ||
717 | |||
718 | /* main groupchats loop. */ | ||
719 | void do_groupchats(Group_Chats *g_c) | ||
720 | { | ||
721 | //TODO | ||
722 | } | ||
723 | |||
724 | /* Free everything related with group chats. */ | ||
725 | void kill_groupchats(Group_Chats *g_c) | ||
726 | { | ||
727 | //TODO | ||
728 | g_c->m->group_chat_object = 0; | ||
729 | free(g_c); | ||
730 | } | ||
731 | |||
732 | /* Return the number of chats in the instance m. | ||
733 | * You should use this to determine how much memory to allocate | ||
734 | * for copy_chatlist. */ | ||
735 | /* | ||
736 | uint32_t count_chatlist(const Messenger *m) | ||
737 | { | ||
738 | uint32_t ret = 0; | ||
739 | uint32_t i; | ||
740 | |||
741 | for (i = 0; i < m->numchats; i++) { | ||
742 | if (m->chats[i]) { | ||
743 | ret++; | ||
744 | } | ||
745 | } | ||
746 | |||
747 | return ret; | ||
748 | }*/ | ||
749 | |||
750 | /* Copy a list of valid chat IDs into the array out_list. | ||
751 | * If out_list is NULL, returns 0. | ||
752 | * Otherwise, returns the number of elements copied. | ||
753 | * If the array was too small, the contents | ||
754 | * of out_list will be truncated to list_size. */ | ||
755 | /* | ||
756 | uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size) | ||
757 | { | ||
758 | if (!out_list) | ||
759 | return 0; | ||
760 | |||
761 | if (m->numchats == 0) { | ||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | uint32_t i; | ||
766 | uint32_t ret = 0; | ||
767 | |||
768 | for (i = 0; i < m->numchats; i++) { | ||
769 | if (ret >= list_size) { | ||
770 | break; *//* Abandon ship *//* | ||
771 | } | ||
772 | |||
773 | if (m->chats[i]) { | ||
774 | out_list[ret] = i; | ||
775 | ret++; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return ret; | ||
780 | } | ||
781 | */ \ No newline at end of file | ||
diff --git a/toxcore/group.h b/toxcore/group.h new file mode 100644 index 00000000..a5b5723c --- /dev/null +++ b/toxcore/group.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* group.h | ||
2 | * | ||
3 | * Slightly better groupchats implementation. | ||
4 | * | ||
5 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef GROUP_H | ||
26 | #define GROUP_H | ||
27 | |||
28 | #include "Messenger.h" | ||
29 | |||
30 | enum { | ||
31 | GROUPCHAT_STATUS_NONE, | ||
32 | GROUPCHAT_STATUS_VALID | ||
33 | }; | ||
34 | |||
35 | typedef struct { | ||
36 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
37 | uint64_t pingid; | ||
38 | uint64_t last_pinged; | ||
39 | |||
40 | uint64_t last_recv; | ||
41 | uint64_t last_recv_msgping; | ||
42 | uint32_t last_message_number; | ||
43 | |||
44 | uint8_t nick[MAX_NAME_LENGTH]; | ||
45 | uint16_t nick_len; | ||
46 | |||
47 | uint8_t deleted; | ||
48 | uint64_t deleted_time; | ||
49 | |||
50 | uint16_t peer_number; | ||
51 | } Group_Peer; | ||
52 | |||
53 | #define DESIRED_CLOSE_CONNECTIONS 3 | ||
54 | #define MAX_GROUP_CONNECTIONS 16 | ||
55 | #define GROUP_IDENTIFIER_LENGTH crypto_box_KEYBYTES /* So we can use new_symmetric_key(...) to fill it */ | ||
56 | |||
57 | enum { | ||
58 | GROUPCHAT_CLOSE_NONE, | ||
59 | GROUPCHAT_CLOSE_CONNECTION | ||
60 | }; | ||
61 | |||
62 | typedef struct { | ||
63 | uint8_t status; | ||
64 | |||
65 | Group_Peer *group; | ||
66 | uint32_t numpeers; | ||
67 | |||
68 | struct { | ||
69 | uint8_t type; /* GROUPCHAT_CLOSE_* */ | ||
70 | uint32_t number; | ||
71 | uint16_t group_number; | ||
72 | } close[MAX_GROUP_CONNECTIONS]; | ||
73 | |||
74 | uint8_t identifier[GROUP_IDENTIFIER_LENGTH]; | ||
75 | |||
76 | uint32_t message_number; | ||
77 | uint16_t peer_number; | ||
78 | } Group_c; | ||
79 | |||
80 | typedef struct { | ||
81 | Messenger *m; | ||
82 | |||
83 | Group_c *chats; | ||
84 | uint32_t num_chats; | ||
85 | |||
86 | void (*invite_callback)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | ||
87 | void *invite_callback_userdata; | ||
88 | void (*message_callback)(Messenger *m, int, int, const uint8_t *, uint16_t, void *); | ||
89 | void *message_callback_userdata; | ||
90 | } Group_Chats; | ||
91 | |||
92 | /* Set the callback for group invites. | ||
93 | * | ||
94 | * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) | ||
95 | * | ||
96 | * data of length is what needs to be passed to join_groupchat(). | ||
97 | */ | ||
98 | void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, | ||
99 | void *), void *userdata); | ||
100 | |||
101 | /* Set the callback for group messages. | ||
102 | * | ||
103 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
104 | */ | ||
105 | void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
106 | void *), void *userdata); | ||
107 | |||
108 | /* Set the callback for group actions. | ||
109 | * | ||
110 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
111 | */ | ||
112 | void g_callback_group_action(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
113 | void *), void *userdata); | ||
114 | |||
115 | /* Set callback function for peer name list changes. | ||
116 | * | ||
117 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
118 | * Function(Group_Chats *g_c, int groupnumber, void *userdata) | ||
119 | */ | ||
120 | void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
121 | void *userdata); | ||
122 | |||
123 | /* Creates a new groupchat and puts it in the chats array. | ||
124 | * | ||
125 | * return group number on success. | ||
126 | * return -1 on failure. | ||
127 | */ | ||
128 | int add_groupchat(Group_Chats *g_c); | ||
129 | |||
130 | /* Delete a groupchat from the chats array. | ||
131 | * | ||
132 | * return 0 on success. | ||
133 | * return -1 if failure. | ||
134 | */ | ||
135 | int del_groupchat(Group_Chats *g_c, int groupnumber); | ||
136 | |||
137 | /* Copy the name of peernumber who is in groupnumber to name. | ||
138 | * name must be at least MAX_NAME_LENGTH long. | ||
139 | * | ||
140 | * return length of name if success | ||
141 | * return -1 if failure | ||
142 | */ | ||
143 | int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name); | ||
144 | |||
145 | /* invite friendnumber to groupnumber | ||
146 | * return 0 on success | ||
147 | * return -1 on failure | ||
148 | */ | ||
149 | int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber); | ||
150 | |||
151 | /* Join a group (you need to have been invited first.) | ||
152 | * | ||
153 | * returns group number on success | ||
154 | * returns -1 on failure. | ||
155 | */ | ||
156 | int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length); | ||
157 | |||
158 | /* send a group message | ||
159 | * return 0 on success | ||
160 | * return -1 on failure | ||
161 | */ | ||
162 | int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length); | ||
163 | |||
164 | /* send a group action | ||
165 | * return 0 on success | ||
166 | * return -1 on failure | ||
167 | */ | ||
168 | int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length); | ||
169 | |||
170 | /* Return the number of peers in the group chat on success. | ||
171 | * return -1 on failure | ||
172 | */ | ||
173 | int group_number_peers(const Group_Chats *g_c, int groupnumber); | ||
174 | |||
175 | /* List all the peers in the group chat. | ||
176 | * | ||
177 | * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. | ||
178 | * | ||
179 | * Copies the lengths of the names to lengths[length] | ||
180 | * | ||
181 | * returns the number of peers on success. | ||
182 | * | ||
183 | * return -1 on failure. | ||
184 | */ | ||
185 | int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], | ||
186 | uint16_t length); | ||
187 | |||
188 | /* Create new groupchat instance. */ | ||
189 | Group_Chats *new_groupchats(Messenger *m); | ||
190 | |||
191 | /* main groupchats loop. */ | ||
192 | void do_groupchats(Group_Chats *g_c); | ||
193 | |||
194 | /* Free everything related with group chats. */ | ||
195 | void kill_groupchats(Group_Chats *g_c); | ||
196 | |||
197 | #endif | ||
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c deleted file mode 100644 index 949ec53a..00000000 --- a/toxcore/group_chats.c +++ /dev/null | |||
@@ -1,837 +0,0 @@ | |||
1 | /* group_chats.c | ||
2 | * | ||
3 | * An implementation of massive text only group chats. | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
7 | * | ||
8 | * This file is part of Tox. | ||
9 | * | ||
10 | * Tox is free software: you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, either version 3 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * Tox is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifdef HAVE_CONFIG_H | ||
26 | #include "config.h" | ||
27 | #endif | ||
28 | |||
29 | #include "DHT.h" | ||
30 | #include "assoc.h" | ||
31 | #include "group_chats.h" | ||
32 | #include "LAN_discovery.h" | ||
33 | #include "util.h" | ||
34 | |||
35 | #define GROUPCHAT_MAXDATA_LENGTH (MAX_CRYPTO_REQUEST_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES)) | ||
36 | #define GROUPCHAT_MAXPLAINDATA_LENGTH (GROUPCHAT_MAXDATA_LENGTH - crypto_box_MACBYTES) | ||
37 | |||
38 | #define GROUP_MAX_SENDNODES (GROUP_CLOSE_CONNECTIONS * 2) | ||
39 | |||
40 | typedef struct { | ||
41 | uint64_t pingid; | ||
42 | //uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
43 | |||
44 | } getnodes_data; | ||
45 | |||
46 | typedef struct { | ||
47 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
48 | IP_Port ip_port; | ||
49 | |||
50 | } groupchat_nodes; | ||
51 | |||
52 | typedef struct { | ||
53 | uint64_t pingid; | ||
54 | groupchat_nodes nodes[GROUP_CLOSE_CONNECTIONS]; | ||
55 | //uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
56 | |||
57 | } sendnodes_data; | ||
58 | |||
59 | /* | ||
60 | * check if peer with client_id is in peer array. | ||
61 | * | ||
62 | * return peer number if peer is in chat. | ||
63 | * return -1 if peer is not in chat. | ||
64 | * | ||
65 | * TODO: make this more efficient. | ||
66 | */ | ||
67 | |||
68 | static int peer_in_chat(const Group_Chat *chat, const uint8_t *client_id) | ||
69 | { | ||
70 | uint32_t i; | ||
71 | |||
72 | for (i = 0; i < chat->numpeers; ++i) | ||
73 | if (id_equal(chat->group[i].client_id, client_id)) | ||
74 | return i; | ||
75 | |||
76 | return -1; | ||
77 | } | ||
78 | |||
79 | /* Compares client_id1 and client_id2 with client_id. | ||
80 | * | ||
81 | * return 0 if both are same distance. | ||
82 | * return 1 if client_id1 is closer. | ||
83 | * return 2 if client_id2 is closer. | ||
84 | */ | ||
85 | static int id_closest_groupchats(const uint8_t *id, const uint8_t *id1, const uint8_t *id2) | ||
86 | { | ||
87 | size_t i; | ||
88 | uint8_t distance1, distance2; | ||
89 | |||
90 | for (i = 0; i < CLIENT_ID_SIZE; ++i) { | ||
91 | |||
92 | distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]); | ||
93 | distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]); | ||
94 | |||
95 | if (distance1 < distance2) | ||
96 | return 1; | ||
97 | |||
98 | if (distance1 > distance2) | ||
99 | return 2; | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | #define BAD_GROUPNODE_TIMEOUT 30 | ||
106 | |||
107 | /* | ||
108 | * Check if peer is closer to us that the other peers in the list and if the peer is in the list. | ||
109 | * Return the number of peers it is closer to if it is not in the closelist. | ||
110 | * Return -1 if the peer is in the closelist. | ||
111 | */ | ||
112 | |||
113 | static int peer_okping(const Group_Chat *chat, const uint8_t *client_id) | ||
114 | { | ||
115 | uint32_t i, j = 0; | ||
116 | |||
117 | if (id_equal(chat->self_public_key, client_id)) | ||
118 | return -1; | ||
119 | |||
120 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { | ||
121 | if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { | ||
122 | ++j; | ||
123 | continue; | ||
124 | } | ||
125 | |||
126 | /* Equal */ | ||
127 | if (id_equal(chat->close[i].client_id, client_id)) | ||
128 | return -1; | ||
129 | |||
130 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) | ||
131 | ++j; | ||
132 | } | ||
133 | |||
134 | return j; | ||
135 | } | ||
136 | |||
137 | |||
138 | |||
139 | /* Attempt to add a peer to the close list. | ||
140 | * Update last_recv if it is in list. | ||
141 | * Attempt to add it to list if it is not. | ||
142 | * | ||
143 | * Return 0 if success. | ||
144 | * Return -1 if peer was not put in list/updated. | ||
145 | */ | ||
146 | static int add_closepeer(Group_Chat *chat, const uint8_t *client_id, IP_Port ip_port) | ||
147 | { | ||
148 | uint32_t i; | ||
149 | |||
150 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Check if node is already in list, if it is update its last_recv */ | ||
151 | if (id_equal(chat->close[i].client_id, client_id)) { | ||
152 | chat->close[i].last_recv = unix_time(); | ||
153 | return 0; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Try replacing bad nodes first */ | ||
158 | if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { | ||
159 | id_copy(chat->close[i].client_id, client_id); | ||
160 | chat->close[i].ip_port = ip_port; | ||
161 | chat->close[i].last_recv = unix_time(); | ||
162 | return 0; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ | ||
167 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { | ||
168 | id_copy(chat->close[i].client_id, client_id); | ||
169 | chat->close[i].ip_port = ip_port; | ||
170 | chat->close[i].last_recv = unix_time(); | ||
171 | return 0; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | static int send_groupchatpacket(const Group_Chat *chat, IP_Port ip_port, const uint8_t *public_key, const uint8_t *data, | ||
179 | uint32_t length, uint8_t request_id) | ||
180 | { | ||
181 | if (id_equal(chat->self_public_key, public_key)) | ||
182 | return -1; | ||
183 | |||
184 | uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; | ||
185 | int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); | ||
186 | packet[0] = NET_PACKET_GROUP_CHATS; | ||
187 | |||
188 | if (len == -1) | ||
189 | return -1; | ||
190 | |||
191 | if (sendpacket(chat->net, ip_port, packet, len) == len) | ||
192 | return 0; | ||
193 | |||
194 | return -1; | ||
195 | |||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Send data to all peers in close peer list. | ||
200 | * | ||
201 | * return the number of peers the packet was sent to. | ||
202 | */ | ||
203 | static uint8_t sendto_allpeers(const Group_Chat *chat, const uint8_t *data, uint16_t length, uint8_t request_id) | ||
204 | { | ||
205 | uint16_t sent = 0; | ||
206 | uint32_t i; | ||
207 | |||
208 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { | ||
209 | if (ip_isset(&chat->close[i].ip_port.ip) && | ||
210 | !is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { | ||
211 | if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, | ||
212 | data, length, request_id) == 0) | ||
213 | ++sent; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return sent; | ||
218 | } | ||
219 | |||
220 | |||
221 | /* | ||
222 | * Add a peer to the group chat. | ||
223 | * | ||
224 | * return peernum if success or peer already in chat. | ||
225 | * return -1 if error. | ||
226 | */ | ||
227 | static int addpeer(Group_Chat *chat, const uint8_t *client_id) | ||
228 | { | ||
229 | int peernum = peer_in_chat(chat, client_id); | ||
230 | |||
231 | if (peernum != -1) | ||
232 | return peernum; | ||
233 | |||
234 | Group_Peer *temp; | ||
235 | temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); | ||
236 | |||
237 | if (temp == NULL) | ||
238 | return -1; | ||
239 | |||
240 | memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); | ||
241 | chat->group = temp; | ||
242 | |||
243 | id_copy(chat->group[chat->numpeers].client_id, client_id); | ||
244 | chat->group[chat->numpeers].last_recv = unix_time(); | ||
245 | chat->group[chat->numpeers].last_recv_msgping = unix_time(); | ||
246 | ++chat->numpeers; | ||
247 | |||
248 | if (chat->peer_namelistchange != NULL) | ||
249 | (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata); | ||
250 | |||
251 | return (chat->numpeers - 1); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Set a peer from the group chat to deleted. | ||
256 | * | ||
257 | * return 0 if success | ||
258 | * return -1 if error. | ||
259 | */ | ||
260 | static int del_peer_set(Group_Chat *chat, int peernum) | ||
261 | { | ||
262 | if ((uint32_t)peernum >= chat->numpeers) | ||
263 | return -1; | ||
264 | |||
265 | chat->group[peernum].deleted = 1; | ||
266 | chat->group[peernum].deleted_time = unix_time(); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Delete a peer from the group chat. | ||
272 | * | ||
273 | * return 0 if success | ||
274 | * return -1 if error. | ||
275 | */ | ||
276 | static int delpeer(Group_Chat *chat, int peernum) | ||
277 | { | ||
278 | if ((uint32_t)peernum >= chat->numpeers) | ||
279 | return -1; | ||
280 | |||
281 | uint32_t i; | ||
282 | |||
283 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* If peer is in close list, time it out forcefully. */ | ||
284 | if (id_equal(chat->close[i].client_id, chat->group[peernum].client_id)) { | ||
285 | chat->close[i].last_recv = 0; | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | Group_Peer *temp; | ||
291 | --chat->numpeers; | ||
292 | |||
293 | if (chat->numpeers == 0) { | ||
294 | free(chat->group); | ||
295 | chat->group = NULL; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | if (chat->numpeers != (uint32_t)peernum) | ||
300 | memcpy(&chat->group[peernum], &chat->group[chat->numpeers], sizeof(Group_Peer)); | ||
301 | |||
302 | temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers)); | ||
303 | |||
304 | if (temp == NULL) | ||
305 | return -1; | ||
306 | |||
307 | chat->group = temp; | ||
308 | |||
309 | if (chat->peer_namelistchange != NULL) { | ||
310 | (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_DEL, chat->group_namelistchange_userdata); | ||
311 | } | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* Copy the name of peernum to name. | ||
317 | * name must be at least MAX_NICK_BYTES long. | ||
318 | * | ||
319 | * return length of name if success | ||
320 | * return -1 if failure | ||
321 | */ | ||
322 | int group_peername(const Group_Chat *chat, int peernum, uint8_t *name) | ||
323 | { | ||
324 | if ((uint32_t)peernum >= chat->numpeers) | ||
325 | return -1; | ||
326 | |||
327 | if (chat->group[peernum].nick_len == 0) { | ||
328 | /* memcpy(name, "NSA agent", 10); */ /* Srsly? */ /* Kindly remind the user that someone with no name might be a moronic NSA agent.*/ | ||
329 | name[0] = 0; | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len); | ||
334 | return chat->group[peernum].nick_len; | ||
335 | } | ||
336 | |||
337 | static void setnick(Group_Chat *chat, int peernum, const uint8_t *contents, uint16_t contents_len) | ||
338 | { | ||
339 | if (contents_len > MAX_NICK_BYTES || contents_len == 0) | ||
340 | return; | ||
341 | |||
342 | /* same name as already stored? */ | ||
343 | if (chat->group[peernum].nick_len == contents_len) | ||
344 | if (!memcmp(chat->group[peernum].nick, contents, contents_len)) | ||
345 | return; | ||
346 | |||
347 | memcpy(chat->group[peernum].nick, contents, contents_len); | ||
348 | chat->group[peernum].nick_len = contents_len; | ||
349 | |||
350 | if (chat->peer_namelistchange != NULL) | ||
351 | (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_NAME, chat->group_namelistchange_userdata); | ||
352 | } | ||
353 | |||
354 | /* min time between pings sent to one peer in seconds */ | ||
355 | /* TODO: move this to global section */ | ||
356 | #define GROUP_PING_TIMEOUT 5 | ||
357 | |||
358 | static int send_getnodes(const Group_Chat *chat, IP_Port ip_port, int peernum) | ||
359 | { | ||
360 | if ((uint32_t)peernum >= chat->numpeers) | ||
361 | return -1; | ||
362 | |||
363 | if (!is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT)) | ||
364 | return -1; | ||
365 | |||
366 | getnodes_data contents; | ||
367 | contents.pingid = random_64b(); | ||
368 | |||
369 | chat->group[peernum].last_pinged = unix_time(); | ||
370 | chat->group[peernum].pingid = contents.pingid; | ||
371 | chat->group[peernum].ping_via = ip_port; | ||
372 | |||
373 | if (chat->assoc) { | ||
374 | IPPTs ippts; | ||
375 | ippts.timestamp = unix_time(); | ||
376 | ippts.ip_port = ip_port; | ||
377 | |||
378 | Assoc_add_entry(chat->assoc, chat->group[peernum].client_id, &ippts, NULL, 1); | ||
379 | } | ||
380 | |||
381 | return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), | ||
382 | CRYPTO_PACKET_GROUP_CHAT_GET_NODES); | ||
383 | } | ||
384 | |||
385 | static int send_sendnodes(const Group_Chat *chat, IP_Port ip_port, int peernum, uint64_t pingid) | ||
386 | { | ||
387 | if ((uint32_t)peernum >= chat->numpeers) | ||
388 | return -1; | ||
389 | |||
390 | sendnodes_data contents; | ||
391 | contents.pingid = pingid; | ||
392 | uint32_t i, j = 0; | ||
393 | |||
394 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { | ||
395 | if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { | ||
396 | id_copy(contents.nodes[j].client_id, chat->close[i].client_id); | ||
397 | contents.nodes[j].ip_port = chat->close[i].ip_port; | ||
398 | to_net_family(&contents.nodes[j].ip_port.ip); | ||
399 | ++j; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, | ||
404 | sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, CRYPTO_PACKET_GROUP_CHAT_SEND_NODES); | ||
405 | } | ||
406 | |||
407 | static int handle_getnodes(const Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len) | ||
408 | { | ||
409 | if (len != sizeof(getnodes_data)) | ||
410 | return 1; | ||
411 | |||
412 | if ((uint32_t)peernum >= chat->numpeers) | ||
413 | return 1; | ||
414 | |||
415 | getnodes_data contents; | ||
416 | memcpy(&contents, data, sizeof(contents)); | ||
417 | send_sendnodes(chat, source, peernum, contents.pingid); | ||
418 | |||
419 | if (peer_okping(chat, chat->group[peernum].client_id) > 0) | ||
420 | send_getnodes(chat, source, peernum); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len) | ||
426 | { | ||
427 | if ((uint32_t)peernum >= chat->numpeers) | ||
428 | return 1; | ||
429 | |||
430 | if (len > sizeof(sendnodes_data) || len < sizeof(uint64_t)) | ||
431 | return 1; | ||
432 | |||
433 | if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0) | ||
434 | return 1; | ||
435 | |||
436 | if (is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT)) | ||
437 | return 1; | ||
438 | |||
439 | sendnodes_data contents; | ||
440 | memcpy(&contents, data, len); | ||
441 | |||
442 | if (contents.pingid != chat->group[peernum].pingid) | ||
443 | return 1; | ||
444 | |||
445 | uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes); | ||
446 | uint32_t i; | ||
447 | |||
448 | IPPTs ippts_send; | ||
449 | ippts_send.timestamp = unix_time(); | ||
450 | |||
451 | for (i = 0; i < numnodes; ++i) { | ||
452 | if (peer_okping(chat, contents.nodes[i].client_id) > 0) { | ||
453 | int peern = peer_in_chat(chat, contents.nodes[i].client_id); | ||
454 | |||
455 | if (peern == -1) { /*NOTE: This is just for testing and will be removed later.*/ | ||
456 | peern = addpeer(chat, contents.nodes[i].client_id); | ||
457 | } | ||
458 | |||
459 | if (peern == -1) | ||
460 | continue; | ||
461 | |||
462 | to_host_family(&contents.nodes[i].ip_port.ip); | ||
463 | send_getnodes(chat, contents.nodes[i].ip_port, peern); | ||
464 | |||
465 | if (chat->assoc) { | ||
466 | ippts_send.ip_port = contents.nodes[i].ip_port; | ||
467 | Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, NULL, 0); | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | add_closepeer(chat, chat->group[peernum].client_id, source); | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | #define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1) | ||
478 | static void send_names_new_peer(Group_Chat *chat); | ||
479 | |||
480 | static int handle_data(Group_Chat *chat, const uint8_t *data, uint32_t len) | ||
481 | { | ||
482 | if (len < GROUP_DATA_MIN_SIZE) | ||
483 | return 1; | ||
484 | |||
485 | //TODO: | ||
486 | int peernum = peer_in_chat(chat, data); | ||
487 | |||
488 | if (peernum == -1) { /*NOTE: This is just for testing and will be removed later.*/ | ||
489 | if (data[crypto_box_PUBLICKEYBYTES + sizeof(uint32_t)] != GROUP_CHAT_QUIT) | ||
490 | peernum = addpeer(chat, data); | ||
491 | } | ||
492 | |||
493 | if (peernum == -1) | ||
494 | return 1; | ||
495 | |||
496 | if (chat->group[peernum].deleted) | ||
497 | return 1; | ||
498 | |||
499 | /* Spam prevention (1 message per peer per second limit.) | ||
500 | |||
501 | if (chat->group[peernum].last_recv == temp_time) | ||
502 | return 1; | ||
503 | */ | ||
504 | chat->group[peernum].last_recv = unix_time(); | ||
505 | |||
506 | uint32_t message_num; | ||
507 | memcpy(&message_num, data + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); | ||
508 | message_num = ntohl(message_num); | ||
509 | |||
510 | if (chat->group[peernum].last_message_number == 0) { | ||
511 | chat->group[peernum].last_message_number = message_num; | ||
512 | } else if (message_num - chat->group[peernum].last_message_number > 64 || | ||
513 | message_num == chat->group[peernum].last_message_number) | ||
514 | return 1; | ||
515 | |||
516 | chat->group[peernum].last_message_number = message_num; | ||
517 | |||
518 | int handled = 1; | ||
519 | const uint8_t *contents = data + GROUP_DATA_MIN_SIZE; | ||
520 | uint16_t contents_len = len - GROUP_DATA_MIN_SIZE; | ||
521 | |||
522 | switch (data[crypto_box_PUBLICKEYBYTES + sizeof(message_num)]) { | ||
523 | case GROUP_CHAT_PING: /* If message is ping */ | ||
524 | if (contents_len != 0) | ||
525 | return 1; | ||
526 | |||
527 | chat->group[peernum].last_recv_msgping = unix_time(); | ||
528 | break; | ||
529 | |||
530 | case GROUP_CHAT_NEW_PEER: /* If message is new peer */ | ||
531 | if (contents_len != crypto_box_PUBLICKEYBYTES) | ||
532 | return 1; | ||
533 | |||
534 | addpeer(chat, contents); | ||
535 | send_names_new_peer(chat); | ||
536 | break; | ||
537 | |||
538 | case GROUP_CHAT_QUIT: /* If peer tells us he is quitting */ | ||
539 | if (contents_len != 0) | ||
540 | return 1; | ||
541 | |||
542 | del_peer_set(chat, peernum); | ||
543 | break; | ||
544 | |||
545 | case GROUP_CHAT_PEER_NICK: | ||
546 | if (contents_len > MAX_NICK_BYTES || contents_len == 0) | ||
547 | return 1; | ||
548 | |||
549 | setnick(chat, peernum, contents, contents_len); | ||
550 | break; | ||
551 | |||
552 | case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */ | ||
553 | if (chat->group_message != NULL) | ||
554 | (*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata); | ||
555 | |||
556 | break; | ||
557 | |||
558 | case GROUP_CHAT_ACTION: /* if message is a peer action */ | ||
559 | if (chat->group_action != NULL) | ||
560 | (*chat->group_action)(chat, peernum, contents, contents_len, chat->group_action_userdata); | ||
561 | |||
562 | break; | ||
563 | |||
564 | default: | ||
565 | handled = 0; | ||
566 | break; | ||
567 | |||
568 | } | ||
569 | |||
570 | if (handled == 1) { | ||
571 | sendto_allpeers(chat, data, len, CRYPTO_PACKET_GROUP_CHAT_BROADCAST); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | return 1; | ||
576 | } | ||
577 | |||
578 | static uint8_t send_data(Group_Chat *chat, const uint8_t *data, uint32_t len, uint8_t message_id) | ||
579 | { | ||
580 | if (len + GROUP_DATA_MIN_SIZE > MAX_CRYPTO_REQUEST_SIZE) /*NOTE: not the real maximum len.*/ | ||
581 | return 1; | ||
582 | |||
583 | uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; | ||
584 | ++chat->message_number; | ||
585 | |||
586 | if (chat->message_number == 0) | ||
587 | chat->message_number = 1; | ||
588 | |||
589 | uint32_t message_num = htonl(chat->message_number); | ||
590 | //TODO | ||
591 | id_copy(packet, chat->self_public_key); | ||
592 | memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num)); | ||
593 | |||
594 | if (len != 0) | ||
595 | memcpy(packet + GROUP_DATA_MIN_SIZE, data, len); | ||
596 | |||
597 | packet[crypto_box_PUBLICKEYBYTES + sizeof(message_num)] = message_id; | ||
598 | return sendto_allpeers(chat, packet, len + GROUP_DATA_MIN_SIZE, CRYPTO_PACKET_GROUP_CHAT_BROADCAST); | ||
599 | } | ||
600 | /* | ||
601 | * Handle get nodes group packet. | ||
602 | * | ||
603 | * return 0 if handled correctly. | ||
604 | * return 1 if error. | ||
605 | */ | ||
606 | |||
607 | int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length) | ||
608 | { | ||
609 | if (length > MAX_CRYPTO_REQUEST_SIZE) | ||
610 | return 1; | ||
611 | |||
612 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; | ||
613 | uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; | ||
614 | uint8_t number; | ||
615 | int len = handle_request(chat->self_public_key, chat->self_secret_key, public_key, data, &number, packet, length); | ||
616 | |||
617 | if (len <= 0) | ||
618 | return 1; | ||
619 | |||
620 | if (id_equal(chat->self_public_key, public_key)) | ||
621 | return 1; | ||
622 | |||
623 | int peernum = peer_in_chat(chat, public_key); | ||
624 | |||
625 | if (peernum == -1) | ||
626 | return 1; | ||
627 | |||
628 | switch (number) { | ||
629 | case CRYPTO_PACKET_GROUP_CHAT_GET_NODES: | ||
630 | return handle_getnodes(chat, source, peernum, data, len); | ||
631 | |||
632 | case CRYPTO_PACKET_GROUP_CHAT_SEND_NODES: | ||
633 | return handle_sendnodes(chat, source, peernum, data, len); | ||
634 | |||
635 | case CRYPTO_PACKET_GROUP_CHAT_BROADCAST: | ||
636 | return handle_data(chat, data, len); | ||
637 | |||
638 | default: | ||
639 | return 1; | ||
640 | } | ||
641 | |||
642 | return 1; | ||
643 | } | ||
644 | |||
645 | uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length) | ||
646 | { | ||
647 | return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values? | ||
648 | } | ||
649 | |||
650 | uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length) | ||
651 | { | ||
652 | return send_data(chat, action, length, GROUP_CHAT_ACTION); | ||
653 | } | ||
654 | |||
655 | /* | ||
656 | * Send id/nick combo to the group. | ||
657 | * | ||
658 | * returns the number of peers it has sent it to. | ||
659 | */ | ||
660 | static uint32_t group_send_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len) | ||
661 | { | ||
662 | if (nick_len > MAX_NICK_BYTES) | ||
663 | return 0; | ||
664 | |||
665 | return send_data(chat, nick, nick_len, GROUP_CHAT_PEER_NICK); | ||
666 | } | ||
667 | |||
668 | int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len) | ||
669 | { | ||
670 | if (nick_len > MAX_NICK_BYTES || nick_len == 0) | ||
671 | return -1; | ||
672 | |||
673 | memcpy(chat->nick, nick, nick_len); | ||
674 | chat->nick_len = nick_len; | ||
675 | group_send_nick(chat, chat->nick, chat->nick_len); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id) | ||
680 | { | ||
681 | addpeer(chat, client_id); | ||
682 | return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, GROUP_CHAT_NEW_PEER); //TODO: better return values? | ||
683 | } | ||
684 | |||
685 | void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
686 | void *userdata) | ||
687 | { | ||
688 | chat->group_message = function; | ||
689 | chat->group_message_userdata = userdata; | ||
690 | } | ||
691 | |||
692 | void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
693 | void *userdata) | ||
694 | { | ||
695 | chat->group_action = function; | ||
696 | chat->group_action_userdata = userdata; | ||
697 | } | ||
698 | |||
699 | void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), | ||
700 | void *userdata) | ||
701 | { | ||
702 | chat->peer_namelistchange = function; | ||
703 | chat->group_namelistchange_userdata = userdata; | ||
704 | } | ||
705 | |||
706 | uint32_t group_numpeers(const Group_Chat *chat) | ||
707 | { | ||
708 | return chat->numpeers; | ||
709 | } | ||
710 | |||
711 | uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | ||
712 | uint16_t length) | ||
713 | { | ||
714 | uint32_t i; | ||
715 | |||
716 | for (i = 0; i < chat->numpeers && i < length; ++i) { | ||
717 | lengths[i] = group_peername(chat, i, names[i]); | ||
718 | } | ||
719 | |||
720 | return i; | ||
721 | } | ||
722 | |||
723 | Group_Chat *new_groupchat(Networking_Core *net) | ||
724 | { | ||
725 | unix_time_update(); | ||
726 | |||
727 | if (net == 0) | ||
728 | return 0; | ||
729 | |||
730 | Group_Chat *chat = calloc(1, sizeof(Group_Chat)); | ||
731 | chat->net = net; | ||
732 | crypto_box_keypair(chat->self_public_key, chat->self_secret_key); | ||
733 | |||
734 | /* (2^4) * 5 = 80 entries seems to be a moderate size */ | ||
735 | chat->assoc = new_Assoc(4, 5, chat->self_public_key); | ||
736 | |||
737 | return chat; | ||
738 | } | ||
739 | |||
740 | #define NODE_PING_INTERVAL 10 | ||
741 | |||
742 | static void ping_close(Group_Chat *chat) | ||
743 | { | ||
744 | uint32_t i; | ||
745 | |||
746 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { | ||
747 | if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { | ||
748 | int peernum = peer_in_chat(chat, chat->close[i].client_id); | ||
749 | |||
750 | if (peernum == -1) | ||
751 | continue; | ||
752 | |||
753 | if (is_timeout(chat->group[peernum].last_pinged, NODE_PING_INTERVAL)) | ||
754 | send_getnodes(chat, chat->close[i].ip_port, peernum); | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | |||
759 | /* Interval in seconds to send ping messages */ | ||
760 | #define GROUP_PING_INTERVAL 30 | ||
761 | |||
762 | static void ping_group(Group_Chat *chat) | ||
763 | { | ||
764 | if (is_timeout(chat->last_sent_ping, GROUP_PING_INTERVAL)) { | ||
765 | if (send_data(chat, 0, 0, GROUP_CHAT_PING) != 0) /* Ping */ | ||
766 | chat->last_sent_ping = unix_time(); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | #define DEL_PEER_DELAY 3 | ||
771 | static void del_dead_peers(Group_Chat *chat) | ||
772 | { | ||
773 | uint32_t i; | ||
774 | |||
775 | for (i = 0; i < chat->numpeers; ++i) { | ||
776 | if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 4)) { | ||
777 | delpeer(chat, i); | ||
778 | } | ||
779 | |||
780 | if (chat->group == NULL || i >= chat->numpeers) | ||
781 | break; | ||
782 | |||
783 | if (chat->group[i].deleted) { | ||
784 | if (is_timeout(chat->group[i].deleted_time, DEL_PEER_DELAY)) | ||
785 | delpeer(chat, i); | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | |||
790 | #define NICK_SEND_INTERVAL 180 | ||
791 | static void send_names_new_peer(Group_Chat *chat) | ||
792 | { | ||
793 | group_send_nick(chat, chat->nick, chat->nick_len); | ||
794 | chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 15; | ||
795 | } | ||
796 | static void send_names(Group_Chat *chat) | ||
797 | { | ||
798 | /* send own nick from time to time, to let newly added peers be informed | ||
799 | * first time only: use a shorter timeframe, because we might not be in our own | ||
800 | * peer list yet */ | ||
801 | if (is_timeout(chat->last_sent_nick, 180)) | ||
802 | if (group_send_nick(chat, chat->nick, chat->nick_len) > 0) { | ||
803 | if (!chat->last_sent_nick) | ||
804 | chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 10; | ||
805 | else | ||
806 | chat->last_sent_nick = unix_time(); | ||
807 | } | ||
808 | } | ||
809 | |||
810 | void do_groupchat(Group_Chat *chat) | ||
811 | { | ||
812 | unix_time_update(); | ||
813 | ping_close(chat); | ||
814 | ping_group(chat); | ||
815 | /* TODO: Maybe run this less? */ | ||
816 | del_dead_peers(chat); | ||
817 | send_names(chat); | ||
818 | } | ||
819 | |||
820 | void kill_groupchat(Group_Chat *chat) | ||
821 | { | ||
822 | send_data(chat, 0, 0, GROUP_CHAT_QUIT); | ||
823 | kill_Assoc(chat->assoc); | ||
824 | free(chat->group); | ||
825 | free(chat); | ||
826 | } | ||
827 | |||
828 | void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id) | ||
829 | { | ||
830 | send_getnodes(chat, ip_port, addpeer(chat, client_id)); | ||
831 | } | ||
832 | |||
833 | void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id) | ||
834 | { | ||
835 | send_getnodes(chat, ip_port, addpeer(chat, client_id)); | ||
836 | add_closepeer(chat, client_id, ip_port); | ||
837 | } | ||
diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h deleted file mode 100644 index 1a7a2e04..00000000 --- a/toxcore/group_chats.h +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* group_chats.h | ||
2 | * | ||
3 | * An implementation of massive text only group chats. | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
7 | * | ||
8 | * This file is part of Tox. | ||
9 | * | ||
10 | * Tox is free software: you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, either version 3 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * Tox is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef GROUP_CHATS_H | ||
26 | #define GROUP_CHATS_H | ||
27 | |||
28 | #define MAX_NICK_BYTES 128 | ||
29 | |||
30 | typedef struct { | ||
31 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
32 | uint64_t pingid; | ||
33 | uint64_t last_pinged; | ||
34 | IP_Port ping_via; | ||
35 | |||
36 | uint64_t last_recv; | ||
37 | uint64_t last_recv_msgping; | ||
38 | uint32_t last_message_number; | ||
39 | |||
40 | uint8_t nick[MAX_NICK_BYTES]; | ||
41 | uint16_t nick_len; | ||
42 | |||
43 | uint8_t deleted; | ||
44 | uint64_t deleted_time; | ||
45 | } Group_Peer; | ||
46 | |||
47 | typedef struct { | ||
48 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
49 | IP_Port ip_port; | ||
50 | uint64_t last_recv; | ||
51 | } Group_Close; | ||
52 | |||
53 | #define GROUP_CLOSE_CONNECTIONS 6 | ||
54 | |||
55 | typedef struct Group_Chat { | ||
56 | Networking_Core *net; | ||
57 | uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; | ||
58 | uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; | ||
59 | |||
60 | Group_Peer *group; | ||
61 | Group_Close close[GROUP_CLOSE_CONNECTIONS]; | ||
62 | uint32_t numpeers; | ||
63 | |||
64 | uint32_t message_number; | ||
65 | void (*group_message)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); | ||
66 | void *group_message_userdata; | ||
67 | void (*group_action)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); | ||
68 | void *group_action_userdata; | ||
69 | void (*peer_namelistchange)(struct Group_Chat *m, int peer, uint8_t change, void *); | ||
70 | void *group_namelistchange_userdata; | ||
71 | |||
72 | uint64_t last_sent_ping; | ||
73 | |||
74 | uint8_t nick[MAX_NICK_BYTES]; | ||
75 | uint16_t nick_len; | ||
76 | uint64_t last_sent_nick; | ||
77 | |||
78 | struct Assoc *assoc; | ||
79 | } Group_Chat; | ||
80 | |||
81 | #define GROUP_CHAT_PING 0 | ||
82 | #define GROUP_CHAT_NEW_PEER 16 | ||
83 | #define GROUP_CHAT_QUIT 24 | ||
84 | #define GROUP_CHAT_PEER_NICK 48 | ||
85 | #define GROUP_CHAT_CHAT_MESSAGE 64 | ||
86 | #define GROUP_CHAT_ACTION 63 | ||
87 | |||
88 | /* Copy the name of peernum to name. | ||
89 | * name must be at least MAX_NICK_BYTES long. | ||
90 | * | ||
91 | * return length of name if success | ||
92 | * return -1 if failure | ||
93 | */ | ||
94 | int group_peername(const Group_Chat *chat, int peernum, uint8_t *name); | ||
95 | |||
96 | /* | ||
97 | * Set callback function for chat messages. | ||
98 | * | ||
99 | * format of function is: function(Group_Chat *chat, peer number, message, message length, userdata) | ||
100 | */ | ||
101 | void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
102 | void *userdata); | ||
103 | |||
104 | /* | ||
105 | * Set callback function for actions. | ||
106 | * | ||
107 | * format of function is: function(Group_Chat *chat, peer number, action, action length, userdata) | ||
108 | */ | ||
109 | void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
110 | void *userdata); | ||
111 | |||
112 | /* | ||
113 | * Set callback function for peer name list changes. | ||
114 | * | ||
115 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
116 | * | ||
117 | * format of function is: function(Group_Chat *chat, userdata) | ||
118 | */ | ||
119 | typedef enum { | ||
120 | CHAT_CHANGE_PEER_ADD, | ||
121 | CHAT_CHANGE_PEER_DEL, | ||
122 | CHAT_CHANGE_PEER_NAME, | ||
123 | } CHAT_CHANGE; | ||
124 | |||
125 | void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), | ||
126 | void *userdata); | ||
127 | |||
128 | /* | ||
129 | * Send a message to the group. | ||
130 | * | ||
131 | * returns the number of peers it has sent it to. | ||
132 | */ | ||
133 | uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length); | ||
134 | |||
135 | /* | ||
136 | * Send an action to the group. | ||
137 | * | ||
138 | * returns the number of peers it has sent it to. | ||
139 | */ | ||
140 | uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length); | ||
141 | |||
142 | /* | ||
143 | * Set our nick for this group. | ||
144 | * | ||
145 | * returns -1 on failure, 0 on success. | ||
146 | */ | ||
147 | int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len); | ||
148 | |||
149 | /* | ||
150 | * Tell everyone about a new peer (a person we are inviting for example.) | ||
151 | * | ||
152 | */ | ||
153 | uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id); | ||
154 | |||
155 | |||
156 | /* Create a new group chat. | ||
157 | * | ||
158 | * Returns a new group chat instance if success. | ||
159 | * | ||
160 | * Returns a NULL pointer if fail. | ||
161 | */ | ||
162 | Group_Chat *new_groupchat(Networking_Core *net); | ||
163 | |||
164 | |||
165 | /* Return the number of peers in the group chat. | ||
166 | */ | ||
167 | uint32_t group_numpeers(const Group_Chat *chat); | ||
168 | |||
169 | /* List all the peers in the group chat. | ||
170 | * | ||
171 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
172 | * | ||
173 | * returns the number of peers. | ||
174 | */ | ||
175 | uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | ||
176 | uint16_t length); | ||
177 | |||
178 | /* Kill a group chat | ||
179 | * | ||
180 | * Frees the memory and everything. | ||
181 | */ | ||
182 | void kill_groupchat(Group_Chat *chat); | ||
183 | |||
184 | /* | ||
185 | * This is the main loop. | ||
186 | */ | ||
187 | void do_groupchat(Group_Chat *chat); | ||
188 | |||
189 | /* if we receive a group chat packet we call this function so it can be handled. | ||
190 | return 0 if packet is handled correctly. | ||
191 | return 1 if it didn't handle the packet or if the packet was shit. */ | ||
192 | int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length); | ||
193 | |||
194 | |||
195 | void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); | ||
196 | void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); | ||
197 | |||
198 | |||
199 | #endif | ||
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 48bf5164..63012ce6 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c | |||
@@ -1238,7 +1238,11 @@ static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, cons | |||
1238 | 1238 | ||
1239 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1239 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1240 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1240 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1241 | set_connection_dht_public_key(c, crypt_connection_id, dht_public_key, current_time_monotonic()); | 1241 | set_connection_dht_public_key(c, crypt_connection_id, dht_public_key); |
1242 | |||
1243 | if (conn->dht_pk_callback) | ||
1244 | conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key); | ||
1245 | |||
1242 | } else { | 1246 | } else { |
1243 | return -1; | 1247 | return -1; |
1244 | } | 1248 | } |
@@ -1473,7 +1477,11 @@ static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const | |||
1473 | if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { | 1477 | if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { |
1474 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1478 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1475 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1479 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1476 | set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key, current_time_monotonic()); | 1480 | set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key); |
1481 | |||
1482 | if (conn->dht_pk_callback) | ||
1483 | conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, n_c.dht_public_key); | ||
1484 | |||
1477 | ret = 0; | 1485 | ret = 0; |
1478 | } | 1486 | } |
1479 | } | 1487 | } |
@@ -1522,7 +1530,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) | |||
1522 | 1530 | ||
1523 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1531 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1524 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1532 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1525 | set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key, current_time_monotonic()); | 1533 | set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key); |
1526 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; | 1534 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; |
1527 | conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; | 1535 | conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; |
1528 | crypto_connection_add_source(c, crypt_connection_id, n_c->source); | 1536 | crypto_connection_add_source(c, crypt_connection_id, n_c->source); |
@@ -1618,9 +1626,9 @@ static int connect_peer_tcp(Net_Crypto *c, int crypt_connection_id) | |||
1618 | /* Copy friends DHT public key into dht_key. | 1626 | /* Copy friends DHT public key into dht_key. |
1619 | * | 1627 | * |
1620 | * return 0 on failure (no key copied). | 1628 | * return 0 on failure (no key copied). |
1621 | * return timestamp on success (key copied). | 1629 | * return 1 on success (key copied). |
1622 | */ | 1630 | */ |
1623 | uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) | 1631 | unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) |
1624 | { | 1632 | { |
1625 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | 1633 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); |
1626 | 1634 | ||
@@ -1631,28 +1639,22 @@ uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, ui | |||
1631 | return 0; | 1639 | return 0; |
1632 | 1640 | ||
1633 | memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES); | 1641 | memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES); |
1634 | return conn->dht_public_key_timestamp; | 1642 | return 1; |
1635 | } | 1643 | } |
1636 | 1644 | ||
1637 | 1645 | ||
1638 | /* Set the DHT public key of the crypto connection. | 1646 | /* Set the DHT public key of the crypto connection. |
1639 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | ||
1640 | * the other peer. | ||
1641 | * | 1647 | * |
1642 | * return -1 on failure. | 1648 | * return -1 on failure. |
1643 | * return 0 on success. | 1649 | * return 0 on success. |
1644 | */ | 1650 | */ |
1645 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, | 1651 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key) |
1646 | uint64_t timestamp) | ||
1647 | { | 1652 | { |
1648 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | 1653 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); |
1649 | 1654 | ||
1650 | if (conn == 0) | 1655 | if (conn == 0) |
1651 | return -1; | 1656 | return -1; |
1652 | 1657 | ||
1653 | if (timestamp <= conn->dht_public_key_timestamp) | ||
1654 | return -1; | ||
1655 | |||
1656 | if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) | 1658 | if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) |
1657 | return -1; | 1659 | return -1; |
1658 | 1660 | ||
@@ -1662,7 +1664,6 @@ int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const | |||
1662 | 1664 | ||
1663 | memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES); | 1665 | memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES); |
1664 | conn->dht_public_key_set = 1; | 1666 | conn->dht_public_key_set = 1; |
1665 | conn->dht_public_key_timestamp = timestamp; | ||
1666 | 1667 | ||
1667 | if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { | 1668 | if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { |
1668 | conn->cookie_request_number = random_64b(); | 1669 | conn->cookie_request_number = random_64b(); |
@@ -1692,6 +1693,9 @@ int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port) | |||
1692 | if (conn == 0) | 1693 | if (conn == 0) |
1693 | return -1; | 1694 | return -1; |
1694 | 1695 | ||
1696 | if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) | ||
1697 | return -1; | ||
1698 | |||
1695 | if (!ipport_equal(&ip_port, &conn->ip_port)) { | 1699 | if (!ipport_equal(&ip_port, &conn->ip_port)) { |
1696 | if (bs_list_add(&c->ip_port_list, &ip_port, crypt_connection_id)) { | 1700 | if (bs_list_add(&c->ip_port_list, &ip_port, crypt_connection_id)) { |
1697 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); | 1701 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); |
@@ -2243,6 +2247,29 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, | |||
2243 | return 0; | 2247 | return 0; |
2244 | } | 2248 | } |
2245 | 2249 | ||
2250 | |||
2251 | /* Set the function for this friend that will be callbacked with object and number | ||
2252 | * when that friend gives us his DHT temporary public key. | ||
2253 | * | ||
2254 | * object and number will be passed as argument to this function. | ||
2255 | * | ||
2256 | * return -1 on failure. | ||
2257 | * return 0 on success. | ||
2258 | */ | ||
2259 | int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, | ||
2260 | const uint8_t *dht_public_key), void *object, uint32_t number) | ||
2261 | { | ||
2262 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | ||
2263 | |||
2264 | if (conn == 0) | ||
2265 | return -1; | ||
2266 | |||
2267 | conn->dht_pk_callback = function; | ||
2268 | conn->dht_pk_callback_object = object; | ||
2269 | conn->dht_pk_callback_number = number; | ||
2270 | return 0; | ||
2271 | } | ||
2272 | |||
2246 | /* Get the crypto connection id from the ip_port. | 2273 | /* Get the crypto connection id from the ip_port. |
2247 | * | 2274 | * |
2248 | * return -1 on failure. | 2275 | * return -1 on failure. |
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 5e5df499..3245b6a2 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h | |||
@@ -111,7 +111,6 @@ typedef struct { | |||
111 | uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ | 111 | uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ |
112 | uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */ | 112 | uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */ |
113 | uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */ | 113 | uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */ |
114 | uint64_t dht_public_key_timestamp; /* Timestamp of the last time we confirmed the key was correct. */ | ||
115 | 114 | ||
116 | uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ | 115 | uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ |
117 | uint16_t temp_packet_length; | 116 | uint16_t temp_packet_length; |
@@ -161,6 +160,10 @@ typedef struct { | |||
161 | uint8_t maximum_speed_reached; | 160 | uint8_t maximum_speed_reached; |
162 | 161 | ||
163 | pthread_mutex_t mutex; | 162 | pthread_mutex_t mutex; |
163 | |||
164 | void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key); | ||
165 | void *dht_pk_callback_object; | ||
166 | uint32_t dht_pk_callback_number; | ||
164 | } Crypto_Connection; | 167 | } Crypto_Connection; |
165 | 168 | ||
166 | typedef struct { | 169 | typedef struct { |
@@ -236,19 +239,16 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key); | |||
236 | /* Copy friends DHT public key into dht_key. | 239 | /* Copy friends DHT public key into dht_key. |
237 | * | 240 | * |
238 | * return 0 on failure (no key copied). | 241 | * return 0 on failure (no key copied). |
239 | * return timestamp on success (key copied). | 242 | * return 1 on success (key copied). |
240 | */ | 243 | */ |
241 | uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); | 244 | unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); |
242 | 245 | ||
243 | /* Set the DHT public key of the crypto connection. | 246 | /* Set the DHT public key of the crypto connection. |
244 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | ||
245 | * the other peer. | ||
246 | * | 247 | * |
247 | * return -1 on failure. | 248 | * return -1 on failure. |
248 | * return 0 on success. | 249 | * return 0 on success. |
249 | */ | 250 | */ |
250 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, | 251 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key); |
251 | uint64_t timestamp); | ||
252 | 252 | ||
253 | /* Set the direct ip of the crypto connection. | 253 | /* Set the direct ip of the crypto connection. |
254 | * | 254 | * |
@@ -294,6 +294,17 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, | |||
294 | int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | 294 | int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, |
295 | int id); | 295 | int id); |
296 | 296 | ||
297 | /* Set the function for this friend that will be callbacked with object and number | ||
298 | * when that friend gives us his DHT temporary public key. | ||
299 | * | ||
300 | * object and number will be passed as argument to this function. | ||
301 | * | ||
302 | * return -1 on failure. | ||
303 | * return 0 on success. | ||
304 | */ | ||
305 | int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, | ||
306 | const uint8_t *dht_public_key), void *object, uint32_t number); | ||
307 | |||
297 | /* returns the number of packet slots left in the sendbuffer. | 308 | /* returns the number of packet slots left in the sendbuffer. |
298 | * return 0 if failure. | 309 | * return 0 if failure. |
299 | */ | 310 | */ |
diff --git a/toxcore/network.h b/toxcore/network.h index b250604e..2c090aef 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -105,7 +105,6 @@ typedef int sock_t; | |||
105 | #define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ | 105 | #define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ |
106 | #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ | 106 | #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ |
107 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ | 107 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ |
108 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ | ||
109 | 108 | ||
110 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ | 109 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ |
111 | #define NET_PACKET_ONION_SEND_INITIAL 128 | 110 | #define NET_PACKET_ONION_SEND_INITIAL 128 |
@@ -135,8 +134,7 @@ typedef int sock_t; | |||
135 | #define TCP_INET6 (AF_INET6 + 3) | 134 | #define TCP_INET6 (AF_INET6 + 3) |
136 | #define TCP_FAMILY (AF_INET6 + 4) | 135 | #define TCP_FAMILY (AF_INET6 + 4) |
137 | 136 | ||
138 | typedef union __attribute__ ((__packed__)) | 137 | typedef union { |
139 | { | ||
140 | uint8_t uint8[4]; | 138 | uint8_t uint8[4]; |
141 | uint16_t uint16[2]; | 139 | uint16_t uint16[2]; |
142 | uint32_t uint32; | 140 | uint32_t uint32; |
@@ -144,8 +142,7 @@ typedef union __attribute__ ((__packed__)) | |||
144 | } | 142 | } |
145 | IP4; | 143 | IP4; |
146 | 144 | ||
147 | typedef union __attribute__ ((__packed__)) | 145 | typedef union { |
148 | { | ||
149 | uint8_t uint8[16]; | 146 | uint8_t uint8[16]; |
150 | uint16_t uint16[8]; | 147 | uint16_t uint16[8]; |
151 | uint32_t uint32[4]; | 148 | uint32_t uint32[4]; |
@@ -154,8 +151,7 @@ typedef union __attribute__ ((__packed__)) | |||
154 | } | 151 | } |
155 | IP6; | 152 | IP6; |
156 | 153 | ||
157 | typedef struct __attribute__ ((__packed__)) | 154 | typedef struct { |
158 | { | ||
159 | uint8_t family; | 155 | uint8_t family; |
160 | union { | 156 | union { |
161 | IP4 ip4; | 157 | IP4 ip4; |
@@ -164,8 +160,7 @@ typedef struct __attribute__ ((__packed__)) | |||
164 | } | 160 | } |
165 | IP; | 161 | IP; |
166 | 162 | ||
167 | typedef struct __attribute__ ((__packed__)) __attribute__((gcc_struct)) | 163 | typedef struct { |
168 | { | ||
169 | IP ip; | 164 | IP ip; |
170 | uint16_t port; | 165 | uint16_t port; |
171 | } | 166 | } |
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 3b130602..8ba1fdc5 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c | |||
@@ -638,7 +638,12 @@ static int handle_fakeid_announce(void *object, const uint8_t *source_pubkey, co | |||
638 | return 1; | 638 | return 1; |
639 | 639 | ||
640 | onion_c->friends_list[friend_num].last_noreplay = no_replay; | 640 | onion_c->friends_list[friend_num].last_noreplay = no_replay; |
641 | onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t), current_time_monotonic()); | 641 | |
642 | if (onion_c->friends_list[friend_num].dht_pk_callback) | ||
643 | onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object, | ||
644 | onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t)); | ||
645 | |||
646 | onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t)); | ||
642 | onion_c->friends_list[friend_num].last_seen = unix_time(); | 647 | onion_c->friends_list[friend_num].last_seen = unix_time(); |
643 | 648 | ||
644 | uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH; | 649 | uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH; |
@@ -957,8 +962,8 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num) | |||
957 | if ((uint32_t)friend_num >= onion_c->num_friends) | 962 | if ((uint32_t)friend_num >= onion_c->num_friends) |
958 | return -1; | 963 | return -1; |
959 | 964 | ||
960 | if (onion_c->friends_list[friend_num].is_fake_clientid) | 965 | //if (onion_c->friends_list[friend_num].is_fake_clientid) |
961 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 966 | // DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, 0); |
962 | 967 | ||
963 | memset(&(onion_c->friends_list[friend_num]), 0, sizeof(Onion_Friend)); | 968 | memset(&(onion_c->friends_list[friend_num]), 0, sizeof(Onion_Friend)); |
964 | uint32_t i; | 969 | uint32_t i; |
@@ -996,22 +1001,37 @@ int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_rela | |||
996 | return 0; | 1001 | return 0; |
997 | } | 1002 | } |
998 | 1003 | ||
999 | /* Set a friends DHT public key. | 1004 | /* Set the function for this friend that will be callbacked with object and number |
1000 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | 1005 | * when that friend gives us his DHT temporary public key. |
1001 | * the other peer. | 1006 | * |
1007 | * object and number will be passed as argument to this function. | ||
1002 | * | 1008 | * |
1003 | * return -1 on failure. | 1009 | * return -1 on failure. |
1004 | * return 0 on success. | 1010 | * return 0 on success. |
1005 | */ | 1011 | */ |
1006 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp) | 1012 | int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, |
1013 | const uint8_t *dht_public_key), void *object, uint32_t number) | ||
1007 | { | 1014 | { |
1008 | if ((uint32_t)friend_num >= onion_c->num_friends) | 1015 | if ((uint32_t)friend_num >= onion_c->num_friends) |
1009 | return -1; | 1016 | return -1; |
1010 | 1017 | ||
1011 | if (onion_c->friends_list[friend_num].status == 0) | 1018 | onion_c->friends_list[friend_num].dht_pk_callback = function; |
1019 | onion_c->friends_list[friend_num].dht_pk_callback_object = object; | ||
1020 | onion_c->friends_list[friend_num].dht_pk_callback_number = number; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | /* Set a friends DHT public key. | ||
1025 | * | ||
1026 | * return -1 on failure. | ||
1027 | * return 0 on success. | ||
1028 | */ | ||
1029 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key) | ||
1030 | { | ||
1031 | if ((uint32_t)friend_num >= onion_c->num_friends) | ||
1012 | return -1; | 1032 | return -1; |
1013 | 1033 | ||
1014 | if (onion_c->friends_list[friend_num].fake_client_id_timestamp >= timestamp) | 1034 | if (onion_c->friends_list[friend_num].status == 0) |
1015 | return -1; | 1035 | return -1; |
1016 | 1036 | ||
1017 | if (onion_c->friends_list[friend_num].is_fake_clientid) { | 1037 | if (onion_c->friends_list[friend_num].is_fake_clientid) { |
@@ -1019,16 +1039,11 @@ int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uin | |||
1019 | return -1; | 1039 | return -1; |
1020 | } | 1040 | } |
1021 | 1041 | ||
1022 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 1042 | onion_c->friends_list[friend_num].is_fake_clientid = 0; |
1023 | } | ||
1024 | |||
1025 | if (DHT_addfriend(onion_c->dht, dht_key) == 1) { | ||
1026 | return -1; | ||
1027 | } | 1043 | } |
1028 | 1044 | ||
1029 | onion_c->friends_list[friend_num].last_seen = unix_time(); | 1045 | onion_c->friends_list[friend_num].last_seen = unix_time(); |
1030 | onion_c->friends_list[friend_num].is_fake_clientid = 1; | 1046 | onion_c->friends_list[friend_num].is_fake_clientid = 1; |
1031 | onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp; | ||
1032 | memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES); | 1047 | memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES); |
1033 | 1048 | ||
1034 | return 0; | 1049 | return 0; |
@@ -1037,9 +1052,9 @@ int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uin | |||
1037 | /* Copy friends DHT public key into dht_key. | 1052 | /* Copy friends DHT public key into dht_key. |
1038 | * | 1053 | * |
1039 | * return 0 on failure (no key copied). | 1054 | * return 0 on failure (no key copied). |
1040 | * return timestamp on success (key copied). | 1055 | * return 1 on success (key copied). |
1041 | */ | 1056 | */ |
1042 | uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) | 1057 | unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) |
1043 | { | 1058 | { |
1044 | if ((uint32_t)friend_num >= onion_c->num_friends) | 1059 | if ((uint32_t)friend_num >= onion_c->num_friends) |
1045 | return 0; | 1060 | return 0; |
@@ -1051,7 +1066,7 @@ uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, | |||
1051 | return 0; | 1066 | return 0; |
1052 | 1067 | ||
1053 | memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES); | 1068 | memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES); |
1054 | return onion_c->friends_list[friend_num].fake_client_id_timestamp; | 1069 | return 1; |
1055 | } | 1070 | } |
1056 | 1071 | ||
1057 | /* Get the ip of friend friendnum and put it in ip_port | 1072 | /* Get the ip of friend friendnum and put it in ip_port |
@@ -1189,23 +1204,6 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
1189 | } | 1204 | } |
1190 | } | 1205 | } |
1191 | 1206 | ||
1192 | /* Timeout before which a peer is considered dead and removed from the DHT search. */ | ||
1193 | #define DEAD_ONION_TIMEOUT (10 * 60) | ||
1194 | |||
1195 | static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) | ||
1196 | { | ||
1197 | if (friendnum >= onion_c->num_friends) | ||
1198 | return; | ||
1199 | |||
1200 | if (onion_c->friends_list[friendnum].status == 0) | ||
1201 | return; | ||
1202 | |||
1203 | if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online | ||
1204 | && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { | ||
1205 | onion_c->friends_list[friendnum].is_fake_clientid = 0; | ||
1206 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); | ||
1207 | } | ||
1208 | } | ||
1209 | 1207 | ||
1210 | /* Function to call when onion data packet with contents beginning with byte is received. */ | 1208 | /* Function to call when onion data packet with contents beginning with byte is received. */ |
1211 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) | 1209 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) |
@@ -1278,7 +1276,6 @@ void do_onion_client(Onion_Client *onion_c) | |||
1278 | if (onion_isconnected(onion_c)) { | 1276 | if (onion_isconnected(onion_c)) { |
1279 | for (i = 0; i < onion_c->num_friends; ++i) { | 1277 | for (i = 0; i < onion_c->num_friends; ++i) { |
1280 | do_friend(onion_c, i); | 1278 | do_friend(onion_c, i); |
1281 | cleanup_friend(onion_c, i); | ||
1282 | } | 1279 | } |
1283 | } | 1280 | } |
1284 | 1281 | ||
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index cf0975d3..483038e8 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #define ONION_FAKEID_INTERVAL 30 | 36 | #define ONION_FAKEID_INTERVAL 30 |
37 | #define DHT_FAKEID_INTERVAL 20 | 37 | #define DHT_FAKEID_INTERVAL 20 |
38 | 38 | ||
39 | #define NUMBER_ONION_PATHS 3 | 39 | #define NUMBER_ONION_PATHS 6 |
40 | 40 | ||
41 | /* The timeout the first time the path is added and | 41 | /* The timeout the first time the path is added and |
42 | then for all the next consecutive times */ | 42 | then for all the next consecutive times */ |
@@ -79,7 +79,6 @@ typedef struct { | |||
79 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ | 79 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ |
80 | 80 | ||
81 | uint8_t is_fake_clientid; /* 0 if we don't know the fake client id of the other 1 if we do. */ | 81 | uint8_t is_fake_clientid; /* 0 if we don't know the fake client id of the other 1 if we do. */ |
82 | uint64_t fake_client_id_timestamp; | ||
83 | uint8_t fake_client_id[crypto_box_PUBLICKEYBYTES]; | 82 | uint8_t fake_client_id[crypto_box_PUBLICKEYBYTES]; |
84 | uint8_t real_client_id[crypto_box_PUBLICKEYBYTES]; | 83 | uint8_t real_client_id[crypto_box_PUBLICKEYBYTES]; |
85 | 84 | ||
@@ -103,6 +102,10 @@ typedef struct { | |||
103 | void *tcp_relay_node_callback_object; | 102 | void *tcp_relay_node_callback_object; |
104 | uint32_t tcp_relay_node_callback_number; | 103 | uint32_t tcp_relay_node_callback_number; |
105 | 104 | ||
105 | void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key); | ||
106 | void *dht_pk_callback_object; | ||
107 | uint32_t dht_pk_callback_number; | ||
108 | |||
106 | uint32_t run_count; | 109 | uint32_t run_count; |
107 | } Onion_Friend; | 110 | } Onion_Friend; |
108 | 111 | ||
@@ -205,6 +208,18 @@ int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_p | |||
205 | int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, | 208 | int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, |
206 | uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); | 209 | uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); |
207 | 210 | ||
211 | |||
212 | /* Set the function for this friend that will be callbacked with object and number | ||
213 | * when that friend gives us his DHT temporary public key. | ||
214 | * | ||
215 | * object and number will be passed as argument to this function. | ||
216 | * | ||
217 | * return -1 on failure. | ||
218 | * return 0 on success. | ||
219 | */ | ||
220 | int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, | ||
221 | const uint8_t *dht_public_key), void *object, uint32_t number); | ||
222 | |||
208 | /* Set a friends DHT public key. | 223 | /* Set a friends DHT public key. |
209 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | 224 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to |
210 | * the other peer. | 225 | * the other peer. |
@@ -212,14 +227,14 @@ int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_rela | |||
212 | * return -1 on failure. | 227 | * return -1 on failure. |
213 | * return 0 on success. | 228 | * return 0 on success. |
214 | */ | 229 | */ |
215 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp); | 230 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key); |
216 | 231 | ||
217 | /* Copy friends DHT public key into dht_key. | 232 | /* Copy friends DHT public key into dht_key. |
218 | * | 233 | * |
219 | * return 0 on failure (no key copied). | 234 | * return 0 on failure (no key copied). |
220 | * return timestamp on success (key copied). | 235 | * return 1 on success (key copied). |
221 | */ | 236 | */ |
222 | uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); | 237 | unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); |
223 | 238 | ||
224 | #define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) | 239 | #define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) |
225 | #define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) | 240 | #define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) |
diff --git a/toxcore/tox.c b/toxcore/tox.c index e8ec593b..19e1c0a4 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #include "Messenger.h" | 28 | #include "Messenger.h" |
29 | #include "group.h" | ||
29 | #include "logger.h" | 30 | #include "logger.h" |
30 | 31 | ||
31 | #define __TOX_DEFINED__ | 32 | #define __TOX_DEFINED__ |
@@ -544,13 +545,15 @@ int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t | |||
544 | 545 | ||
545 | /* Set the callback for group invites. | 546 | /* Set the callback for group invites. |
546 | * | 547 | * |
547 | * Function(Tox *tox, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 548 | * Function(Tox *tox, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) |
549 | * | ||
550 | * data of length is what needs to be passed to join_groupchat(). | ||
548 | */ | 551 | */ |
549 | void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, void *), | 552 | void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *), |
550 | void *userdata) | 553 | void *userdata) |
551 | { | 554 | { |
552 | Messenger *m = tox; | 555 | Messenger *m = tox; |
553 | m_callback_group_invite(m, function, userdata); | 556 | g_callback_group_invite(m->group_chat_object, function, userdata); |
554 | } | 557 | } |
555 | 558 | ||
556 | /* Set the callback for group messages. | 559 | /* Set the callback for group messages. |
@@ -561,7 +564,7 @@ void tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int, | |||
561 | void *userdata) | 564 | void *userdata) |
562 | { | 565 | { |
563 | Messenger *m = tox; | 566 | Messenger *m = tox; |
564 | m_callback_group_message(m, function, userdata); | 567 | g_callback_group_message(m->group_chat_object, function, userdata); |
565 | } | 568 | } |
566 | 569 | ||
567 | /* Set the callback for group actions. | 570 | /* Set the callback for group actions. |
@@ -572,7 +575,7 @@ void tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, i | |||
572 | void *userdata) | 575 | void *userdata) |
573 | { | 576 | { |
574 | Messenger *m = tox; | 577 | Messenger *m = tox; |
575 | m_callback_group_action(m, function, userdata); | 578 | //m_callback_group_action(m, function, userdata); |
576 | } | 579 | } |
577 | 580 | ||
578 | /* Set callback function for peer name list changes. | 581 | /* Set callback function for peer name list changes. |
@@ -583,7 +586,7 @@ void tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, i | |||
583 | void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata) | 586 | void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata) |
584 | { | 587 | { |
585 | Messenger *m = tox; | 588 | Messenger *m = tox; |
586 | m_callback_group_namelistchange(m, function, userdata); | 589 | //m_callback_group_namelistchange(m, function, userdata); |
587 | } | 590 | } |
588 | 591 | ||
589 | /* Creates a new groupchat and puts it in the chats array. | 592 | /* Creates a new groupchat and puts it in the chats array. |
@@ -594,8 +597,9 @@ void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int | |||
594 | int tox_add_groupchat(Tox *tox) | 597 | int tox_add_groupchat(Tox *tox) |
595 | { | 598 | { |
596 | Messenger *m = tox; | 599 | Messenger *m = tox; |
597 | return add_groupchat(m); | 600 | return add_groupchat(m->group_chat_object); |
598 | } | 601 | } |
602 | |||
599 | /* Delete a groupchat from the chats array. | 603 | /* Delete a groupchat from the chats array. |
600 | * | 604 | * |
601 | * return 0 on success. | 605 | * return 0 on success. |
@@ -604,7 +608,7 @@ int tox_add_groupchat(Tox *tox) | |||
604 | int tox_del_groupchat(Tox *tox, int groupnumber) | 608 | int tox_del_groupchat(Tox *tox, int groupnumber) |
605 | { | 609 | { |
606 | Messenger *m = tox; | 610 | Messenger *m = tox; |
607 | return del_groupchat(m, groupnumber); | 611 | return del_groupchat(m->group_chat_object, groupnumber); |
608 | } | 612 | } |
609 | 613 | ||
610 | /* Copy the name of peernumber who is in groupnumber to name. | 614 | /* Copy the name of peernumber who is in groupnumber to name. |
@@ -616,8 +620,10 @@ int tox_del_groupchat(Tox *tox, int groupnumber) | |||
616 | int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name) | 620 | int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name) |
617 | { | 621 | { |
618 | const Messenger *m = tox; | 622 | const Messenger *m = tox; |
619 | return m_group_peername(m, groupnumber, peernumber, name); | 623 | //return m_group_peername(m, groupnumber, peernumber, name); |
624 | return -1; | ||
620 | } | 625 | } |
626 | |||
621 | /* invite friendnumber to groupnumber | 627 | /* invite friendnumber to groupnumber |
622 | * return 0 on success | 628 | * return 0 on success |
623 | * return -1 on failure | 629 | * return -1 on failure |
@@ -625,37 +631,40 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t | |||
625 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber) | 631 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber) |
626 | { | 632 | { |
627 | Messenger *m = tox; | 633 | Messenger *m = tox; |
628 | return invite_friend(m, friendnumber, groupnumber); | 634 | return invite_friend(m->group_chat_object, friendnumber, groupnumber); |
629 | } | 635 | } |
630 | /* Join a group (you need to have been invited first.) | 636 | |
637 | /* Join a group (you need to have been invited first.) using data of length obtained | ||
638 | * in the group invite callback. | ||
631 | * | 639 | * |
632 | * returns group number on success | 640 | * returns group number on success |
633 | * returns -1 on failure. | 641 | * returns -1 on failure. |
634 | */ | 642 | */ |
635 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key) | 643 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length) |
636 | { | 644 | { |
637 | Messenger *m = tox; | 645 | Messenger *m = tox; |
638 | return join_groupchat(m, friendnumber, friend_group_public_key); | 646 | return join_groupchat(m->group_chat_object, friendnumber, data, length); |
639 | } | 647 | } |
640 | 648 | ||
641 | /* send a group message | 649 | /* send a group message |
642 | * return 0 on success | 650 | * return 0 on success |
643 | * return -1 on failure | 651 | * return -1 on failure |
644 | */ | 652 | */ |
645 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length) | 653 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length) |
646 | { | 654 | { |
647 | Messenger *m = tox; | 655 | Messenger *m = tox; |
648 | return group_message_send(m, groupnumber, message, length); | 656 | return group_message_send(m->group_chat_object, groupnumber, message, length); |
649 | } | 657 | } |
650 | 658 | ||
651 | /* send a group action | 659 | /* send a group action |
652 | * return 0 on success | 660 | * return 0 on success |
653 | * return -1 on failure | 661 | * return -1 on failure |
654 | */ | 662 | */ |
655 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length) | 663 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length) |
656 | { | 664 | { |
657 | Messenger *m = tox; | 665 | Messenger *m = tox; |
658 | return group_action_send(m, groupnumber, action, length); | 666 | //return group_action_send(m, groupnumber, action, length); |
667 | return -1; | ||
659 | } | 668 | } |
660 | 669 | ||
661 | /* Return the number of peers in the group chat on success. | 670 | /* Return the number of peers in the group chat on success. |
@@ -664,7 +673,8 @@ int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint | |||
664 | int tox_group_number_peers(const Tox *tox, int groupnumber) | 673 | int tox_group_number_peers(const Tox *tox, int groupnumber) |
665 | { | 674 | { |
666 | const Messenger *m = tox; | 675 | const Messenger *m = tox; |
667 | return group_number_peers(m, groupnumber); | 676 | //return group_number_peers(m, groupnumber); |
677 | return -1; | ||
668 | } | 678 | } |
669 | 679 | ||
670 | /* List all the peers in the group chat. | 680 | /* List all the peers in the group chat. |
@@ -681,7 +691,8 @@ int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX | |||
681 | uint16_t length) | 691 | uint16_t length) |
682 | { | 692 | { |
683 | const Messenger *m = tox; | 693 | const Messenger *m = tox; |
684 | return group_names(m, groupnumber, names, lengths, length); | 694 | //return group_names(m, groupnumber, names, lengths, length); |
695 | return -1; | ||
685 | } | 696 | } |
686 | 697 | ||
687 | /* Return the number of chats in the instance m. | 698 | /* Return the number of chats in the instance m. |
@@ -690,7 +701,8 @@ int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX | |||
690 | uint32_t tox_count_chatlist(const Tox *tox) | 701 | uint32_t tox_count_chatlist(const Tox *tox) |
691 | { | 702 | { |
692 | const Messenger *m = tox; | 703 | const Messenger *m = tox; |
693 | return count_chatlist(m); | 704 | //return count_chatlist(m); |
705 | return 0; | ||
694 | } | 706 | } |
695 | 707 | ||
696 | /* Copy a list of valid chat IDs into the array out_list. | 708 | /* Copy a list of valid chat IDs into the array out_list. |
@@ -701,7 +713,8 @@ uint32_t tox_count_chatlist(const Tox *tox) | |||
701 | uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size) | 713 | uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size) |
702 | { | 714 | { |
703 | const Messenger *m = tox; | 715 | const Messenger *m = tox; |
704 | return copy_chatlist(m, out_list, list_size); | 716 | //return copy_chatlist(m, out_list, list_size); |
717 | return 0; | ||
705 | } | 718 | } |
706 | 719 | ||
707 | 720 | ||
@@ -820,6 +833,12 @@ int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t lengt | |||
820 | return m_set_avatar(m, format, data, length); | 833 | return m_set_avatar(m, format, data, length); |
821 | } | 834 | } |
822 | 835 | ||
836 | int tox_unset_avatar(Tox *tox) | ||
837 | { | ||
838 | Messenger *m = tox; | ||
839 | return m_unset_avatar(m); | ||
840 | } | ||
841 | |||
823 | int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash) | 842 | int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash) |
824 | { | 843 | { |
825 | const Messenger *m = tox; | 844 | const Messenger *m = tox; |
@@ -947,7 +966,14 @@ Tox *tox_new(Tox_Options *options) | |||
947 | } | 966 | } |
948 | } | 967 | } |
949 | 968 | ||
950 | return new_messenger(&m_options); | 969 | Messenger *m = new_messenger(&m_options); |
970 | |||
971 | if (!new_groupchats(m)) { | ||
972 | kill_messenger(m); | ||
973 | return NULL; | ||
974 | } | ||
975 | |||
976 | return m; | ||
951 | } | 977 | } |
952 | 978 | ||
953 | /* Run this before closing shop. | 979 | /* Run this before closing shop. |
@@ -956,6 +982,7 @@ Tox *tox_new(Tox_Options *options) | |||
956 | void tox_kill(Tox *tox) | 982 | void tox_kill(Tox *tox) |
957 | { | 983 | { |
958 | Messenger *m = tox; | 984 | Messenger *m = tox; |
985 | kill_groupchats(m->group_chat_object); | ||
959 | kill_messenger(m); | 986 | kill_messenger(m); |
960 | } | 987 | } |
961 | 988 | ||
diff --git a/toxcore/tox.h b/toxcore/tox.h index 61cfdf70..ccb5a83e 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -419,9 +419,12 @@ int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t | |||
419 | 419 | ||
420 | /* Set the callback for group invites. | 420 | /* Set the callback for group invites. |
421 | * | 421 | * |
422 | * Function(Tox *tox, int friendnumber, uint8_t *group_public_key, void *userdata) | 422 | * Function(Tox *tox, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) |
423 | * | ||
424 | * data of length is what needs to be passed to join_groupchat(). | ||
423 | */ | 425 | */ |
424 | void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, void *), void *userdata); | 426 | void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), |
427 | void *userdata); | ||
425 | 428 | ||
426 | /* Set the callback for group messages. | 429 | /* Set the callback for group messages. |
427 | * | 430 | * |
@@ -479,24 +482,25 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t | |||
479 | */ | 482 | */ |
480 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber); | 483 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber); |
481 | 484 | ||
482 | /* Join a group (you need to have been invited first.) | 485 | /* Join a group (you need to have been invited first.) using data of length obtained |
486 | * in the group invite callback. | ||
483 | * | 487 | * |
484 | * returns group number on success | 488 | * returns group number on success |
485 | * returns -1 on failure. | 489 | * returns -1 on failure. |
486 | */ | 490 | */ |
487 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key); | 491 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length); |
488 | 492 | ||
489 | /* send a group message | 493 | /* send a group message |
490 | * return 0 on success | 494 | * return 0 on success |
491 | * return -1 on failure | 495 | * return -1 on failure |
492 | */ | 496 | */ |
493 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length); | 497 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length); |
494 | 498 | ||
495 | /* send a group action | 499 | /* send a group action |
496 | * return 0 on success | 500 | * return 0 on success |
497 | * return -1 on failure | 501 | * return -1 on failure |
498 | */ | 502 | */ |
499 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length); | 503 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length); |
500 | 504 | ||
501 | /* Return the number of peers in the group chat on success. | 505 | /* Return the number of peers in the group chat on success. |
502 | * return -1 on failure | 506 | * return -1 on failure |
@@ -539,8 +543,8 @@ uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size); | |||
539 | * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata) | 543 | * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata) |
540 | * | 544 | * |
541 | * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT) and 'hash' is the hash of | 545 | * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT) and 'hash' is the hash of |
542 | * the avatar data for caching purposes and it is exactly TOX_AVATAR_HASH_LENGTH long. If the | 546 | * the avatar data for caching purposes and it is exactly TOX_HASH_LENGTH long. If the image |
543 | * image format is NONE, the hash is zeroed. | 547 | * format is NONE, the hash is zeroed. |
544 | * | 548 | * |
545 | */ | 549 | */ |
546 | void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *), | 550 | void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *), |
@@ -556,12 +560,12 @@ void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint | |||
556 | * | 560 | * |
557 | * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT); 'hash' is the | 561 | * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT); 'hash' is the |
558 | * locally-calculated cryptographic hash of the avatar data and it is exactly | 562 | * locally-calculated cryptographic hash of the avatar data and it is exactly |
559 | * TOX_AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length | 563 | * TOX_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length |
560 | * of such data. | 564 | * of such data. |
561 | * | 565 | * |
562 | * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is | 566 | * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is |
563 | * always validated locally with the function tox_avatar_hash and ensured to match the image | 567 | * always validated locally with the function tox_hash and ensured to match the image data, |
564 | * data, so this value can be safely used to compare with cached avatars. | 568 | * so this value can be safely used to compare with cached avatars. |
565 | * | 569 | * |
566 | * WARNING: users MUST treat all avatar image data received from another peer as untrusted and | 570 | * WARNING: users MUST treat all avatar image data received from another peer as untrusted and |
567 | * potentially malicious. The library only ensures that the data which arrived is the same the | 571 | * potentially malicious. The library only ensures that the data which arrived is the same the |
@@ -586,6 +590,10 @@ void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint | |||
586 | */ | 590 | */ |
587 | int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length); | 591 | int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length); |
588 | 592 | ||
593 | /* Unsets the user avatar. | ||
594 | |||
595 | returns 0 on success (currently always returns 0) */ | ||
596 | int tox_unset_avatar(Tox *tox); | ||
589 | 597 | ||
590 | /* Get avatar data from the current user. | 598 | /* Get avatar data from the current user. |
591 | * Copies the current user avatar data to the destination buffer and sets the image format | 599 | * Copies the current user avatar data to the destination buffer and sets the image format |
@@ -601,7 +609,7 @@ int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t lengt | |||
601 | * buf - destination buffer to the image data. Must have at least 'maxlen' bytes; | 609 | * buf - destination buffer to the image data. Must have at least 'maxlen' bytes; |
602 | * length - destination pointer to the image data length; | 610 | * length - destination pointer to the image data length; |
603 | * maxlen - length of the destination buffer 'buf'; | 611 | * maxlen - length of the destination buffer 'buf'; |
604 | * hash - destination pointer to the avatar hash (it must be exactly TOX_AVATAR_HASH_LENGTH bytes long). | 612 | * hash - destination pointer to the avatar hash (it must be exactly TOX_HASH_LENGTH bytes long). |
605 | * | 613 | * |
606 | * returns 0 on success; | 614 | * returns 0 on success; |
607 | * returns -1 on failure. | 615 | * returns -1 on failure. |