diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index ae13e9d6..656b384b 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -637,6 +637,181 @@ int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); } +/**********GROUP CHATS************/ + +/* returns valid ip port of connected friend on success + * returns zeroed out IP_Port on failure + */ +static IP_Port get_friend_ipport(Messenger *m, int friendnumber) +{ + IP_Port zero; + memset(&zero, 0, sizeof(zero)); + + if (friend_not_valid(m, friendnumber)) + return zero; + + int crypt_id = m->friendlist[friendnumber].crypt_connection_id; + + if (is_cryptoconnected(m->net_crypto, crypt_id) != 3) + return zero; + + return connection_ip(m->net_crypto->lossless_udp, m->net_crypto->crypto_connections[crypt_id].number); +} + +/* returns the group number of the chat with public key group_public_key. + * returns -1 on failure. + */ +static int group_num(Messenger *m, uint8_t *group_public_key) +{ + uint32_t i; + + for (i = 0; i < m->numchats; ++i) { + if (memcmp(m->chats[i]->self_public_key, group_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + +/* Creates a new groupchat and puts it in the chats array. + * + * return group number on success. + * return -1 on failure. + */ +int add_groupchat(Messenger *m) +{ + uint32_t i; + + for (i = 0; i < m->numchats; ++i) { + if (m->chats[i] == NULL) { + Group_Chat *newchat = new_groupchat(m->net); + + if (newchat == NULL) + return -1; + + m->chats[i] = newchat; + return i; + } + } + + Group_Chat **temp; + temp = realloc(m->chats, sizeof(Group_Chat *) * (m->numchats + 1)); + + if (temp == NULL) + return -1; + + temp[m->numchats] = new_groupchat(m->net); + + if (temp[m->numchats] == NULL) + return -1; + + ++m->numchats; + return (m->numchats - 1); +} + +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if failure. + */ +static int del_groupchat(Messenger *m, int groupnumber) +{ + if ((unsigned int)groupnumber >= m->numchats) + return -1; + + if (m->chats == NULL) + return -1; + + if (m->chats[groupnumber] == NULL) + return -1; + + kill_groupchat(m->chats[groupnumber]); + m->chats[groupnumber] = NULL; + + uint32_t i; + + for (i = m->numchats; i != 0; --i) { + if (m->chats[i - 1] != NULL) + break; + } + + if (i == 0) { + free(m->chats); + m->chats = NULL; + } else { + Group_Chat **temp = realloc(m->chats, sizeof(Group_Chat *) * i); + + if (temp != NULL) + m->chats = temp; + } + + return 0; +} + +/* Join a group (you need to have been invited first.) + * + * returns 0 on success + * returns -1 on failure. + */ +int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_key) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + uint8_t data[crypto_box_PUBLICKEYBYTES * 2]; + int groupnum = add_groupchat(m); + + if (groupnum == -1) + return -1; + + memcpy(data, friend_group_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(data + crypto_box_PUBLICKEYBYTES, m->chats[groupnum]->self_public_key, crypto_box_PUBLICKEYBYTES); + + if (write_cryptpacket_id(m, friendnumber, PACKET_ID_JOIN_GROUPCHAT, data, sizeof(data))) { + chat_bootstrap_nonlazy(m->chats[groupnum], get_friend_ipport(m, friendnumber), + friend_group_public_key); //TODO: check if ip returned is zero? + return 0; + } + + return -1; +} + +static int handle_group(void *object, IP_Port source, uint8_t *packet, uint32_t length) +{ + Messenger *m = object; + + if (length < crypto_box_PUBLICKEYBYTES + 1) { + return 1; + } + + uint32_t i; + + for (i = 0; i < m->numchats; ++i) { + if (m->chats[i] == NULL) + continue; + + if (memcmp(packet + 1, m->chats[i]->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return handle_groupchatpacket(m->chats[i], source, packet, length); + } + + return 1; +} + +static void do_allgroupchats(Messenger *m) +{ + uint32_t i; + + for (i = 0; i < m->numchats; ++i) { + if (m->chats[i] != NULL) + do_groupchat(m->chats[i]); + } +} + +/*********************************/ + +/* Interval in seconds between LAN discovery packet sending. */ +#define LAN_DISCOVERY_INTERVAL 60 + /* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ static void LANdiscovery(Messenger *m) { @@ -686,6 +861,7 @@ Messenger *initMessenger(uint8_t ipv6enabled) friendreq_init(&(m->fr), m->net_crypto); LANdiscovery_init(m->dht); set_nospam(&(m->fr), random_int()); + networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m); return m; } @@ -939,6 +1115,7 @@ void doMessenger(Messenger *m) do_net_crypto(m->net_crypto); doInbound(m); doFriends(m); + do_allgroupchats(m); LANdiscovery(m); } diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index dfb3f7c6..b7032bbd 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -44,7 +44,9 @@ #define PACKET_ID_RECEIPT 65 #define PACKET_ID_MESSAGE 64 #define PACKET_ID_ACTION 63 - +#define PACKET_ID_INVITE_GROUPCHAT 144 +#define PACKET_ID_JOIN_GROUPCHAT 145 +#define PACKET_ID_ACCEPT_GROUPCHAT 146 /* Status definitions. */ enum { @@ -134,7 +136,7 @@ typedef struct Messenger { Friend *friendlist; uint32_t numfriends; - Group_Chat *chats; + Group_Chat **chats; uint32_t numchats; uint64_t last_LANdiscovery; diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 4ee487d9..f37c6a9c 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c @@ -184,7 +184,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ uint8_t packet[MAX_DATA_SIZE]; int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); - packet[0] = 48; + packet[0] = NET_PACKET_GROUP_CHATS; if (len == -1) return -1; @@ -581,3 +581,10 @@ void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id) { send_getnodes(chat, ip_port, addpeer(chat, client_id)); } + +void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id) +{ + send_getnodes(chat, ip_port, addpeer(chat, client_id)); + add_closepeer(chat, client_id, ip_port); +} + diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h index 7af13d8d..535b46db 100644 --- a/toxcore/group_chats.h +++ b/toxcore/group_chats.h @@ -115,7 +115,7 @@ int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, ui void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id); - +void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id); #ifdef __cplusplus } #endif diff --git a/toxcore/network.h b/toxcore/network.h index 6cdf300d..12a48868 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -78,6 +78,7 @@ typedef int sock_t; #define NET_PACKET_DATA 18 /* Data packet ID. */ #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ +#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ #define TOX_PORTRANGE_FROM 33445 #define TOX_PORTRANGE_TO 33455