From 91d7f4857f3c555f0cc3f13a07a68b40ea6d6a5b Mon Sep 17 00:00:00 2001 From: irungentoo Date: Thu, 12 Sep 2013 19:26:30 -0400 Subject: [PATCH] Very basic group chats, tested and working with nTox. Please wait until the tox.h API is updated before integrating it into your clients. nTox: /g creates a new group chat /i friendnum groupnum invite friendnum to groupnum /z groupnum message send message to groupnum NOTE: group chats currenly might not handle packet loss well if there are less than 6 participants. --- testing/nTox.c | 45 ++++++++++++++-- testing/nTox.h | 2 +- toxcore/Messenger.c | 121 ++++++++++++++++++++++++++++++++++++++++-- toxcore/Messenger.h | 56 ++++++++++++++++++- toxcore/group_chats.h | 1 + 5 files changed, 217 insertions(+), 8 deletions(-) diff --git a/testing/nTox.c b/testing/nTox.c index 438468bd..d6e25ac0 100644 --- a/testing/nTox.c +++ b/testing/nTox.c @@ -348,13 +348,34 @@ void line_eval(Tox *m, char *line) do_refresh(); } else if (inpt_command == 'h') { //help new_lines(help); - } else if (inpt_command == 'i') { //info + } else if (inpt_command == 'x') { //info char idstring[200]; get_id(m, idstring); new_lines(idstring); - } + } else if (inpt_command == 'g') { //create new group chat + char msg[256]; + sprintf(msg, "[g] Created new group chat with number: %u", add_groupchat(m)); + new_lines(msg); + } else if (inpt_command == 'i') { //invite friendnum to groupnum + char *posi[1]; + int friendnumber = strtoul(line + prompt_offset, posi, 0); + int groupnumber = strtoul(*posi + 1, NULL, 0); + char msg[256]; + sprintf(msg, "[g] Invited friend number %u to group number %u, returned: %u (0 means success)", friendnumber, + groupnumber, invite_friend(m, friendnumber, groupnumber)); + new_lines(msg); + } else if (inpt_command == 'z') { //send message to groupnum + char *posi[1]; + int groupnumber = strtoul(line + prompt_offset, posi, 0); - else if (inpt_command == 'q') { //exit + if (**posi != 0) { + char msg[256 + 1024]; + sprintf(msg, "[g] sent message: %s to group num: %u returned: %u (0 means success)", *posi + 1, groupnumber, + group_message_send(m, groupnumber, (uint8_t *)*posi + 1, strlen(*posi + 1) + 1)); + new_lines(msg); + } + + } else if (inpt_command == 'q') { //exit endwin(); exit(EXIT_SUCCESS); } else { @@ -535,6 +556,22 @@ void print_help(void) puts("\t-f\t-\tSpecify a keyfile to read (or write to) from."); } +void print_invite(Messenger *m, int friendnumber, uint8_t *group_public_key, void *userdata) +{ + char msg[256]; + sprintf(msg, "[i] recieved group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, + join_groupchat(m, friendnumber, group_public_key)); + new_lines(msg); +} + +void print_groupmessage(Messenger *m, int groupnumber, uint8_t *message, uint16_t length, void *userdata) +{ + char msg[256 + length]; + sprintf(msg, "[g] %u: %s", groupnumber, message); + new_lines(msg); +} + + int main(int argc, char *argv[]) { int on = 0; @@ -579,6 +616,8 @@ int main(int argc, char *argv[]) tox_callback_friendmessage(m, print_message, NULL); tox_callback_namechange(m, print_nickchange, NULL); tox_callback_statusmessage(m, print_statuschange, NULL); + m_callback_group_invite(m, print_invite, NULL); + m_callback_group_message(m, print_groupmessage, NULL); initscr(); noecho(); diff --git a/testing/nTox.h b/testing/nTox.h index a72ce0c2..8a41965b 100644 --- a/testing/nTox.h +++ b/testing/nTox.h @@ -31,7 +31,7 @@ #include #include "../toxcore/tox.h" - +#include "../toxcore/Messenger.h" //TODO: remove this #define STRING_LENGTH 256 #define HISTORY 50 #define PUB_KEY_BYTES 32 diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 177b8eb0..99279d5e 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -673,6 +673,40 @@ static int group_num(Messenger *m, uint8_t *group_public_key) return -1; } +/* Set the callback for group invites. + * + * Function(Messenger *m, int friendnumber, uint8_t *group_public_key, void *userdata) + */ +void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, void *), void *userdata) +{ + m->group_invite = function; + m->group_invite_userdata = userdata; +} + +/* Set the callback for group messages. + * + * Function(Messenger *m, int groupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), + void *userdata) +{ + m->group_message = function; + m->group_message_userdata = userdata; +} +static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *message, uint16_t length, void *userdata) +{ + Messenger *m = userdata; + uint32_t i; + + for (i = 0; i < m->numchats; ++i) { //TODO: remove this + if (m->chats[i] == chat) + break; + } + + if (m->group_message) + (*m->group_message)(m, i, message, length, m->group_invite_userdata); +} + /* Creates a new groupchat and puts it in the chats array. * * return group number on success. @@ -689,6 +723,7 @@ int add_groupchat(Messenger *m) if (newchat == NULL) return -1; + callback_groupmessage(newchat, &group_message_function, m); m->chats[i] = newchat; return i; } @@ -705,6 +740,8 @@ int add_groupchat(Messenger *m) if (temp[m->numchats] == NULL) return -1; + m->chats = temp; + callback_groupmessage(temp[m->numchats], &group_message_function, m); ++m->numchats; return (m->numchats - 1); } @@ -714,7 +751,7 @@ int add_groupchat(Messenger *m) * return 0 on success. * return -1 if failure. */ -static int del_groupchat(Messenger *m, int groupnumber) +int del_groupchat(Messenger *m, int groupnumber) { if ((unsigned int)groupnumber >= m->numchats) return -1; @@ -748,9 +785,42 @@ static int del_groupchat(Messenger *m, int groupnumber) return 0; } +/* return 1 if that friend was invited to the group + * return 0 if the friend was not or error. + */ +static uint8_t group_invited(Messenger *m, int friendnumber, int groupnumber) +{ + //TODO: this function; + return 1; +} + +/* invite friendnumber to groupnumber + * return 0 on success + * return -1 on failure + */ +int invite_friend(Messenger *m, int friendnumber, int groupnumber) +{ + if (friend_not_valid(m, friendnumber) || (unsigned int)groupnumber >= m->numchats) + return -1; + + if (m->chats == NULL) + return -1; + + if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL) + return -1; + + //TODO: store invited friends. + if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key, + crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + return 0; +} + + /* Join a group (you need to have been invited first.) * - * returns 0 on success + * returns group number on success * returns -1 on failure. */ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_key) @@ -770,12 +840,34 @@ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_ 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 groupnum; } return -1; } +/* send a group message + * return 0 on success + * return -1 on failure + */ + +int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length) +{ + if ((unsigned int)groupnumber >= m->numchats) + return -1; + + if (m->chats == NULL) + return -1; + + if (m->chats[groupnumber] == NULL) + return -1; + + if (group_sendmessage(m->chats[groupnumber], message, length) > 0) + return 0; + + return -1; +} + static int handle_group(void *object, IP_Port source, uint8_t *packet, uint32_t length) { Messenger *m = object; @@ -1064,6 +1156,29 @@ void doFriends(Messenger *m) break; } + + case PACKET_ID_INVITE_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES) + break; + + if (m->group_invite) + (*m->group_invite)(m, i, data, m->group_invite_userdata); + } + + case PACKET_ID_JOIN_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES * 2) + break; + + int groupnum = group_num(m, data); + + if (groupnum == -1) + break; + + if (!group_invited(m, i, groupnum)) + break; + + group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); + } } } else { if (is_cryptoconnected(m->net_crypto, diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 7649a779..0656c736 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -157,7 +157,10 @@ typedef struct Messenger { void *friend_statuschange_userdata; void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); void *friend_connectionstatuschange_userdata; - + void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); + void *group_invite_userdata; + void (*group_message)(struct Messenger *m, int, uint8_t *, uint16_t, void *); + void *group_message_userdata; } Messenger; @@ -369,6 +372,57 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, u */ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); +/**********GROUP CHATS************/ + +/* Set the callback for group invites. + * + * Function(Messenger *m, int friendnumber, uint8_t *group_public_key, void *userdata) + */ +void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, void *), void *userdata); + +/* Set the callback for group messages. + * + * Function(Messenger *m, int groupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), + void *userdata); + +/* 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); + +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if failure. + */ +int del_groupchat(Messenger *m, int groupnumber); + +/* invite friendnumber to groupnumber + * return 0 on success + * return -1 on failure + */ +int invite_friend(Messenger *m, int friendnumber, int groupnumber); + +/* Join a group (you need to have been invited first.) + * + * returns group number on success + * returns -1 on failure. + */ +int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_key); + +/* send a group message + * return 0 on success + * return -1 on failure + */ + +int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); + +/*********************************/ + /* Run this at startup. * return allocated instance of Messenger on success. * return 0 if there are problems. diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h index 535b46db..78a5488c 100644 --- a/toxcore/group_chats.h +++ b/toxcore/group_chats.h @@ -77,6 +77,7 @@ void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, /* * Send a message to the group. * + * returns the number of peers it has sent it to. */ uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length);