Group chats are starting to work.

This commit is contained in:
irungentoo 2014-09-26 13:25:52 -04:00
parent d5d84818fe
commit 8b35d194c0
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
5 changed files with 349 additions and 50 deletions

View File

@ -1001,11 +1001,11 @@ void print_help(char *prog_name)
puts(" -f keyfile [Optional] Specify a keyfile to read from and write to.");
}
void print_invite(Tox *m, int friendnumber, const uint8_t *group_public_key, void *userdata)
void print_invite(Tox *m, int friendnumber, const uint8_t *data, uint16_t length, void *userdata)
{
char msg[256];
sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber,
tox_join_groupchat(m, friendnumber, group_public_key));
tox_join_groupchat(m, friendnumber, data, length));
new_lines(msg);
}

View File

@ -220,7 +220,7 @@ static int wipe_group_chat(Group_Chats *g_c, int groupnumber)
return 0;
}
static Group_c *get_group_c(Group_Chats *g_c, int groupnumber)
static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber)
{
if (groupnumber_not_valid(g_c, groupnumber))
return 0;
@ -231,7 +231,7 @@ static Group_c *get_group_c(Group_Chats *g_c, int groupnumber)
/*
* check if peer with client_id is in peer array.
*
* return peer number if peer is in chat.
* return peer index if peer is in chat.
* return -1 if peer is not in chat.
*
* TODO: make this more efficient.
@ -267,18 +267,38 @@ static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier)
return -1;
}
/*
* check if peer with peer_number is in peer array.
*
* return peer number if peer is in chat.
* return -1 if peer is not in chat.
*
* TODO: make this more efficient.
*/
int get_peer_index(Group_c *g, uint16_t peer_number)
{
uint32_t i;
for (i = 0; i < g->numpeers; ++i)
if (g->group[i].peer_number == peer_number)
return i;
return -1;
}
/*
* Add a peer to the group chat.
*
* return peernum if success or peer already in chat.
* return peer_index if success or peer already in chat.
* return -1 if error.
*/
static int addpeer(Group_c *chat, const uint8_t *client_id)
static int addpeer(Group_c *chat, const uint8_t *client_id, uint16_t peer_number)
{
int peernum = peer_in_chat(chat, client_id);
//TODO
//int peer_index = peer_in_chat(chat, client_id);
if (peernum != -1)
return peernum;
//if (peer_index != -1)
// return peer_index;
Group_Peer *temp;
temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1));
@ -290,6 +310,8 @@ static int addpeer(Group_c *chat, const uint8_t *client_id)
chat->group = temp;
id_copy(chat->group[chat->numpeers].client_id, client_id);
chat->group[chat->numpeers].peer_number = peer_number;
chat->group[chat->numpeers].last_recv = unix_time();
chat->group[chat->numpeers].last_recv_msgping = unix_time();
++chat->numpeers;
@ -300,6 +322,39 @@ static int addpeer(Group_c *chat, const uint8_t *client_id)
return (chat->numpeers - 1);
}
/* Add friend to group chat.
*
* return 0 on success
* return -1 on failure.
*/
static int add_friend_to_groupchat(Group_Chats *g_c, int32_t friendnumber, int groupnumber, uint16_t other_groupnum)
{
if (!m_friend_exists(g_c->m, friendnumber))
return -1;
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
return -1;
uint16_t i;
for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
if (g->close[i].type != GROUPCHAT_CLOSE_NONE)
continue;
break;
}
if (i == MAX_GROUP_CONNECTIONS)
return -1;
g->close[i].type = GROUPCHAT_CLOSE_FRIEND;
g->close[i].number = friendnumber;
g->close[i].group_number = other_groupnum;
return 0;
}
/* Creates a new groupchat and puts it in the chats array.
*
@ -310,13 +365,14 @@ int add_groupchat(Group_Chats *g_c)
{
int groupnumber = create_group_chat(g_c);
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
if (groupnumber == -1)
return -1;
Group_c *g = &g_c->chats[groupnumber];
g->status = GROUPCHAT_STATUS_VALID;
new_symmetric_key(g->identifier);
g->peer_number = 0; /* Founder is peer 0. */
return groupnumber;
}
@ -356,18 +412,18 @@ int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber)
* returns group number on success
* returns -1 on failure.
*/
int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length)
int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length)
{
if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)
return -1;
int groupnumber = create_group_chat(g_c);
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
if (groupnumber == -1)
return -1;
Group_c *g = &g_c->chats[groupnumber];
uint16_t group_num = htons(groupnumber);
g->status = GROUPCHAT_STATUS_VALID;
uint8_t response[INVITE_RESPONSE_PACKET_SIZE];
@ -379,7 +435,9 @@ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16
uint16_t other_groupnum;
memcpy(&other_groupnum, data, sizeof(other_groupnum));
other_groupnum = htons(other_groupnum);
//TODO add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH);
add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
g->peer_number = rand(); /* TODO */
return groupnumber;
} else {
return -1;
@ -428,10 +486,16 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t));
if (groupnumber == -1) {
g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata);
if (g_c->invite_callback)
g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata);
return;
} else {
//TODO
uint16_t other_groupnum;
memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
other_groupnum = ntohs(other_groupnum);
add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
}
break;
@ -441,13 +505,22 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
if (length != INVITE_RESPONSE_PACKET_SIZE)
return;
int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t));
uint16_t other_groupnum, groupnum;
memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t));
groupnum = ntohs(groupnum);
if (groupnumber == -1) {
Group_c *g = get_group_c(g_c, groupnum);
if (!g)
return;
} else {
//TODO add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
}
if (memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0)
return;
memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
other_groupnum = ntohs(other_groupnum);
add_friend_to_groupchat(g_c, friendnumber, groupnum, other_groupnum);
break;
}
@ -457,9 +530,197 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
}
}
static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
/* Find index of friend in the close list;
*
* returns index on success
* returns -1 on failure.
*/
static int friend_in_close(Group_c *g, int32_t friendnumber)
{
int i;
for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
if (g->close[i].type != GROUPCHAT_CLOSE_FRIEND)
continue;
if (g->close[i].number != (uint32_t)friendnumber)
continue;
break;
}
if (i == MAX_GROUP_CONNECTIONS)
return -1;
return i;
}
#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1)
/* Send message to all close except receiver (if receiver isn't -1)
* NOTE: this function appends the group chat number to the data passed to it.
*
* return number of messages sent.
*/
static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data,
uint16_t length, int receiver)
{
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
return 0;
uint16_t i, sent = 0;
for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
continue;
if ((int)i == receiver)
continue;
uint16_t other_groupnum = htons(g->close[i].group_number);
uint8_t packet[sizeof(uint16_t) + length];
memcpy(packet, &other_groupnum, sizeof(uint16_t));
memcpy(packet + sizeof(uint16_t), data, length);
if (send_group_message_packet(g_c->m, g->close[i].number, packet, sizeof(packet)))
++sent;
}
return sent;
}
/* Send data of len with message_id to groupnumber.
*
* return number of peers it was sent to on success.
* return 0 on failure.
*/
static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data,
uint16_t len)
{
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
return 0;
uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len];
uint16_t peer_num = htons(g->peer_number);
memcpy(packet, &peer_num, sizeof(peer_num));
++g->message_number;
if (!g->message_number)
++g->message_number;
uint32_t message_num = htonl(g->message_number);
memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num));
packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id;
if (len)
memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len);
return send_message_all_close(g_c, groupnumber, packet, sizeof(packet), -1);
}
/* send a group message
* return 0 on success
* return -1 on failure
*/
int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length)
{
if (send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length)) {
return 0;
} else {
return -1;
}
}
static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,
int close_index)
{
if (length < MIN_MESSAGE_PACKET_LEN)
return;
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
return;
uint16_t peer_number;
memcpy(&peer_number, data + sizeof(uint16_t), sizeof(uint16_t));
peer_number = ntohs(peer_number);
int index = get_peer_index(g, peer_number);
//TODO remove
if (index == -1) {
uint8_t empty_key[crypto_box_PUBLICKEYBYTES];
index = addpeer(g, empty_key, peer_number);
}
if (index == -1)
return;
uint32_t message_number;
memcpy(&message_number, data + sizeof(uint16_t) * 2, sizeof(message_number));
message_number = ntohl(message_number);
if (g->group[index].last_message_number == 0) {
g->group[index].last_message_number = message_number;
} else if (message_number - g->group[index].last_message_number > 64 ||
message_number == g->group[index].last_message_number) {
return;
}
g->group[index].last_message_number = message_number;
uint8_t message_id = data[sizeof(uint16_t) * 2 + sizeof(message_number)];
const uint8_t *msg_data = data + sizeof(uint16_t) * 2 + sizeof(message_number) + 1;
uint16_t msg_data_len = length - (sizeof(uint16_t) * 2 + sizeof(message_number) + 1);
switch (message_id) {
case PACKET_ID_MESSAGE: {
if (msg_data_len == 0)
return;
//TODO
if (g_c->message_callback)
g_c->message_callback(g_c->m, groupnumber, index, msg_data, msg_data_len, g_c->message_callback_userdata);
break;
}
default:
return;
}
send_message_all_close(g_c, groupnumber, data + sizeof(uint16_t), length - sizeof(uint16_t), close_index);
}
static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
{
Group_Chats *g_c = m->group_chat_object;
if (length < MIN_MESSAGE_PACKET_LEN)
return;
uint16_t groupnumber;
memcpy(&groupnumber, data, sizeof(uint16_t));
groupnumber = ntohs(groupnumber);
Group_c *g = get_group_c(g_c, groupnumber);
if (!g)
return;
int index = friend_in_close(g, friendnumber);
if (index == -1)
return;
handle_message_packet_group(g_c, groupnumber, data, length, index);
}
/* Create new groupchat instance. */
@ -476,6 +737,7 @@ Group_Chats *new_groupchats(Messenger *m)
temp->m = m;
m->group_chat_object = temp;
m_callback_group_invite(m, &handle_friend_invite_packet);
m_callback_group_message(m, &handle_friend_message_packet);
return temp;
}

View File

@ -41,7 +41,6 @@ typedef struct {
uint8_t client_id[crypto_box_PUBLICKEYBYTES];
uint64_t pingid;
uint64_t last_pinged;
IP_Port ping_via;
uint64_t last_recv;
uint64_t last_recv_msgping;
@ -52,12 +51,20 @@ typedef struct {
uint8_t deleted;
uint64_t deleted_time;
uint16_t peer_number;
} Group_Peer;
#define MAX_GROUP_CONNECTIONS 4
#define DESIRED_CLOSE_CONNECTIONS 3
#define MAX_GROUP_CONNECTIONS 16
#define GROUP_IDENTIFIER_LENGTH crypto_box_KEYBYTES /* So we can use new_symmetric_key(...) to fill it */
enum {
GROUPCHAT_CLOSE_NONE,
GROUPCHAT_CLOSE_FRIEND,
GROUPCHAT_CLOSE_GROUPCON
};
typedef struct {
uint8_t status;
@ -65,11 +72,15 @@ typedef struct {
uint32_t numpeers;
struct {
uint8_t type;
uint8_t type; /* GROUPCHAT_CLOSE_* */
uint32_t number;
uint16_t group_number;
} close[MAX_GROUP_CONNECTIONS];
uint8_t identifier[GROUP_IDENTIFIER_LENGTH];
uint32_t message_number;
uint16_t peer_number;
} Group_c;
typedef struct {
@ -155,19 +166,19 @@ int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber);
* returns group number on success
* returns -1 on failure.
*/
int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length);
int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length);
/* send a group message
* return 0 on success
* return -1 on failure
*/
int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint32_t length);
int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length);
/* send a group action
* return 0 on success
* return -1 on failure
*/
int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint32_t length);
int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length);
/* Return the number of peers in the group chat on success.
* return -1 on failure

View File

@ -26,6 +26,7 @@
#endif
#include "Messenger.h"
#include "group.h"
#include "logger.h"
#define __TOX_DEFINED__
@ -544,13 +545,15 @@ int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t
/* Set the callback for group invites.
*
* Function(Tox *tox, int32_t friendnumber, uint8_t *group_public_key, void *userdata)
* Function(Tox *tox, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata)
*
* data of length is what needs to be passed to join_groupchat().
*/
void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, void *),
void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *),
void *userdata)
{
Messenger *m = tox;
//m_callback_group_invite(m, function, userdata);
g_callback_group_invite(m->group_chat_object, function, userdata);
}
/* Set the callback for group messages.
@ -561,7 +564,7 @@ void tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int,
void *userdata)
{
Messenger *m = tox;
//m_callback_group_message(m, function, userdata);
g_callback_group_message(m->group_chat_object, function, userdata);
}
/* Set the callback for group actions.
@ -594,8 +597,9 @@ void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int
int tox_add_groupchat(Tox *tox)
{
Messenger *m = tox;
//return add_groupchat(m);
return add_groupchat(m->group_chat_object);
}
/* Delete a groupchat from the chats array.
*
* return 0 on success.
@ -605,6 +609,7 @@ int tox_del_groupchat(Tox *tox, int groupnumber)
{
Messenger *m = tox;
//return del_groupchat(m, groupnumber);
return -1;
}
/* Copy the name of peernumber who is in groupnumber to name.
@ -617,7 +622,9 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t
{
const Messenger *m = tox;
//return m_group_peername(m, groupnumber, peernumber, name);
return -1;
}
/* invite friendnumber to groupnumber
* return 0 on success
* return -1 on failure
@ -625,37 +632,40 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t
int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber)
{
Messenger *m = tox;
//return invite_friend(m, friendnumber, groupnumber);
return invite_friend(m->group_chat_object, friendnumber, groupnumber);
}
/* Join a group (you need to have been invited first.)
/* Join a group (you need to have been invited first.) using data of length obtained
* in the group invite callback.
*
* returns group number on success
* returns -1 on failure.
*/
int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key)
int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length)
{
Messenger *m = tox;
//return join_groupchat(m, friendnumber, friend_group_public_key);
return join_groupchat(m->group_chat_object, friendnumber, data, length);
}
/* send a group message
* return 0 on success
* return -1 on failure
*/
int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length)
int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length)
{
Messenger *m = tox;
//return group_message_send(m, groupnumber, message, length);
return group_message_send(m->group_chat_object, groupnumber, message, length);
}
/* send a group action
* return 0 on success
* return -1 on failure
*/
int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length)
int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length)
{
Messenger *m = tox;
//return group_action_send(m, groupnumber, action, length);
return -1;
}
/* Return the number of peers in the group chat on success.
@ -665,6 +675,7 @@ int tox_group_number_peers(const Tox *tox, int groupnumber)
{
const Messenger *m = tox;
//return group_number_peers(m, groupnumber);
return -1;
}
/* List all the peers in the group chat.
@ -682,6 +693,7 @@ int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX
{
const Messenger *m = tox;
//return group_names(m, groupnumber, names, lengths, length);
return -1;
}
/* Return the number of chats in the instance m.
@ -691,6 +703,7 @@ uint32_t tox_count_chatlist(const Tox *tox)
{
const Messenger *m = tox;
//return count_chatlist(m);
return 0;
}
/* Copy a list of valid chat IDs into the array out_list.
@ -702,6 +715,7 @@ uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size)
{
const Messenger *m = tox;
//return copy_chatlist(m, out_list, list_size);
return 0;
}
@ -947,7 +961,14 @@ Tox *tox_new(Tox_Options *options)
}
}
return new_messenger(&m_options);
Messenger *m = new_messenger(&m_options);
if (!new_groupchats(m)) {
kill_messenger(m);
return NULL;
}
return m;
}
/* Run this before closing shop.
@ -956,6 +977,7 @@ Tox *tox_new(Tox_Options *options)
void tox_kill(Tox *tox)
{
Messenger *m = tox;
kill_groupchats(m->group_chat_object);
kill_messenger(m);
}

View File

@ -419,9 +419,12 @@ int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t
/* Set the callback for group invites.
*
* Function(Tox *tox, int friendnumber, uint8_t *group_public_key, void *userdata)
* Function(Tox *tox, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata)
*
* data of length is what needs to be passed to join_groupchat().
*/
void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, void *), void *userdata);
void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *),
void *userdata);
/* Set the callback for group messages.
*
@ -479,24 +482,25 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t
*/
int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber);
/* Join a group (you need to have been invited first.)
/* Join a group (you need to have been invited first.) using data of length obtained
* in the group invite callback.
*
* returns group number on success
* returns -1 on failure.
*/
int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key);
int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length);
/* send a group message
* return 0 on success
* return -1 on failure
*/
int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length);
int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length);
/* send a group action
* return 0 on success
* return -1 on failure
*/
int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length);
int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length);
/* Return the number of peers in the group chat on success.
* return -1 on failure