Merge branch 'group-chat'

This commit is contained in:
irungentoo 2013-09-17 20:06:33 -04:00
commit 7c5b98397a
12 changed files with 270 additions and 173 deletions

View File

@ -239,12 +239,14 @@ START_TEST(test_dht_state_saveloadsave)
memset(buffer, 0xCD, extra);
memset(buffer + extra + size, 0xCD, extra);
DHT_save(m->dht, buffer + extra);
for(i = 0; i < extra; i++) {
for (i = 0; i < extra; i++) {
ck_assert_msg(buffer[i] == 0xCD, "Buffer underwritten from DHT_save() @%u", i);
ck_assert_msg(buffer[extra + size + i] == 0xCD, "Buffer overwritten from DHT_save() @%u", i);
}
int res = DHT_load_new(m->dht, buffer + extra, size);
if (res == -1)
ck_assert_msg(res == 0, "Failed to load back stored buffer: res == -1");
else {
@ -279,12 +281,14 @@ START_TEST(test_messenger_state_saveloadsave)
memset(buffer, 0xCD, extra);
memset(buffer + extra + size, 0xCD, extra);
Messenger_save(m, buffer + extra);
for(i = 0; i < extra; i++) {
for (i = 0; i < extra; i++) {
ck_assert_msg(buffer[i] == 0xCD, "Buffer underwritten from Messenger_save() @%u", i);
ck_assert_msg(buffer[extra + size + i] == 0xCD, "Buffer overwritten from Messenger_save() @%u", i);
}
int res = Messenger_load(m, buffer + extra, size);
if (res == -1)
ck_assert_msg(res == 0, "Failed to load back stored buffer: res == -1");
else {

View File

@ -1,154 +1,154 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <check.h>
#include <stdlib.h>
#include <time.h>
#include "../toxcore/network.h"
START_TEST(test_addr_resolv_localhost)
{
#ifdef __CYGWIN__
/* force initialization of network stack
* normally this should happen automatically
* cygwin doesn't do it for every network related function though
* e.g. not for getaddrinfo... */
socket(0, 0, 0);
errno = 0;
#endif
const char localhost[] = "localhost";
IP ip;
ip_init(&ip, 0);
int res = addr_resolve(localhost, &ip, NULL);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET, "Expected family AF_INET, got %u.", ip.family);
ck_assert_msg(ip.ip4.uint32 == htonl(0x7F000001), "Expected 127.0.0.1, got %s.", inet_ntoa(ip.ip4.in_addr));
}
ip_init(&ip, 1);
res = addr_resolve(localhost, &ip, NULL);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET6, "Expected family AF_INET6, got %u.", ip.family);
ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), "Expected ::1, got %s.", ip_ntoa(&ip));
}
ip_init(&ip, 1);
ip.family = AF_UNSPEC;
IP extra;
ip_reset(&extra);
res = addr_resolve(localhost, &ip, &extra);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET6, "Expected family AF_INET6, got %u.", ip.family);
ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), "Expected ::1, got %s.", ip_ntoa(&ip));
ck_assert_msg(extra.family == AF_INET, "Expected family AF_INET, got %u.", extra.family);
ck_assert_msg(extra.ip4.uint32 == htonl(0x7F000001), "Expected 127.0.0.1, got %s.", inet_ntoa(extra.ip4.in_addr));
}
}
END_TEST
START_TEST(test_ip_equal)
{
int res;
IP ip1, ip2;
ip_reset(&ip1);
ip_reset(&ip2);
res = ip_equal(NULL, NULL);
ck_assert_msg(res == 0, "ip_equal(NULL, NULL): expected result 0, got %u.", res);
res = ip_equal(&ip1, NULL);
ck_assert_msg(res == 0, "ip_equal(PTR, NULL): expected result 0, got %u.", res);
res = ip_equal(NULL, &ip1);
ck_assert_msg(res == 0, "ip_equal(NULL, PTR): expected result 0, got %u.", res);
ip1.family = AF_INET;
ip1.ip4.uint32 = htonl(0x7F000001);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_UNSPEC, 0} ): expected result 0, got %u.", res);
ip2.family = AF_INET;
ip2.ip4.uint32 = htonl(0x7F000001);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.1} ): expected result != 0, got 0.");
ip2.ip4.uint32 = htonl(0x7F000002);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.2} ): expected result 0, got %u.", res);
ip2.family = AF_INET6;
ip2.ip6.uint32[0] = 0;
ip2.ip6.uint32[1] = 0;
ip2.ip6.uint32[2] = htonl(0xFFFF);
ip2.ip6.uint32[3] = htonl(0x7F000001);
ck_assert_msg(IN6_IS_ADDR_V4MAPPED(&ip2.ip6) != 0, "IN6_IS_ADDR_V4MAPPED(::ffff:127.0.0.1): expected != 0, got 0.");
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::ffff:127.0.0.1} ): expected result != 0, got 0.");
memcpy(&ip2.ip6, &in6addr_loopback, sizeof(IP6));
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::1} ): expected result 0, got %u.", res);
memcpy(&ip1, &ip2, sizeof(IP));
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET6, ::1}, {AF_INET6, ::1} ): expected result != 0, got 0.");
ip2.ip6.uint8[15]++;
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET6, ::1}, {AF_INET6, ::2} ): expected result 0, got %res.", res);
}
END_TEST
#define DEFTESTCASE(NAME) \
TCase *NAME = tcase_create(#NAME); \
tcase_add_test(NAME, test_##NAME); \
suite_add_tcase(s, NAME);
Suite *network_suite(void)
{
Suite *s = suite_create("Network");
DEFTESTCASE(addr_resolv_localhost);
DEFTESTCASE(ip_equal);
return s;
}
int main(int argc, char *argv[])
{
srand((unsigned int) time(NULL));
Suite *network = network_suite();
SRunner *test_runner = srunner_create(network);
int number_failed = 0;
srunner_run_all(test_runner, CK_NORMAL);
number_failed = srunner_ntests_failed(test_runner);
srunner_free(test_runner);
return number_failed;
}
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <check.h>
#include <stdlib.h>
#include <time.h>
#include "../toxcore/network.h"
START_TEST(test_addr_resolv_localhost)
{
#ifdef __CYGWIN__
/* force initialization of network stack
* normally this should happen automatically
* cygwin doesn't do it for every network related function though
* e.g. not for getaddrinfo... */
socket(0, 0, 0);
errno = 0;
#endif
const char localhost[] = "localhost";
IP ip;
ip_init(&ip, 0);
int res = addr_resolve(localhost, &ip, NULL);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET, "Expected family AF_INET, got %u.", ip.family);
ck_assert_msg(ip.ip4.uint32 == htonl(0x7F000001), "Expected 127.0.0.1, got %s.", inet_ntoa(ip.ip4.in_addr));
}
ip_init(&ip, 1);
res = addr_resolve(localhost, &ip, NULL);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET6, "Expected family AF_INET6, got %u.", ip.family);
ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), "Expected ::1, got %s.", ip_ntoa(&ip));
}
ip_init(&ip, 1);
ip.family = AF_UNSPEC;
IP extra;
ip_reset(&extra);
res = addr_resolve(localhost, &ip, &extra);
ck_assert_msg(res > 0, "Resolver failed: %u, %s (%x, %x)", errno, strerror(errno));
if (res > 0) {
ck_assert_msg(ip.family == AF_INET6, "Expected family AF_INET6, got %u.", ip.family);
ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), "Expected ::1, got %s.", ip_ntoa(&ip));
ck_assert_msg(extra.family == AF_INET, "Expected family AF_INET, got %u.", extra.family);
ck_assert_msg(extra.ip4.uint32 == htonl(0x7F000001), "Expected 127.0.0.1, got %s.", inet_ntoa(extra.ip4.in_addr));
}
}
END_TEST
START_TEST(test_ip_equal)
{
int res;
IP ip1, ip2;
ip_reset(&ip1);
ip_reset(&ip2);
res = ip_equal(NULL, NULL);
ck_assert_msg(res == 0, "ip_equal(NULL, NULL): expected result 0, got %u.", res);
res = ip_equal(&ip1, NULL);
ck_assert_msg(res == 0, "ip_equal(PTR, NULL): expected result 0, got %u.", res);
res = ip_equal(NULL, &ip1);
ck_assert_msg(res == 0, "ip_equal(NULL, PTR): expected result 0, got %u.", res);
ip1.family = AF_INET;
ip1.ip4.uint32 = htonl(0x7F000001);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_UNSPEC, 0} ): expected result 0, got %u.", res);
ip2.family = AF_INET;
ip2.ip4.uint32 = htonl(0x7F000001);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.1} ): expected result != 0, got 0.");
ip2.ip4.uint32 = htonl(0x7F000002);
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.2} ): expected result 0, got %u.", res);
ip2.family = AF_INET6;
ip2.ip6.uint32[0] = 0;
ip2.ip6.uint32[1] = 0;
ip2.ip6.uint32[2] = htonl(0xFFFF);
ip2.ip6.uint32[3] = htonl(0x7F000001);
ck_assert_msg(IN6_IS_ADDR_V4MAPPED(&ip2.ip6) != 0, "IN6_IS_ADDR_V4MAPPED(::ffff:127.0.0.1): expected != 0, got 0.");
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::ffff:127.0.0.1} ): expected result != 0, got 0.");
memcpy(&ip2.ip6, &in6addr_loopback, sizeof(IP6));
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::1} ): expected result 0, got %u.", res);
memcpy(&ip1, &ip2, sizeof(IP));
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res != 0, "ip_equal( {AF_INET6, ::1}, {AF_INET6, ::1} ): expected result != 0, got 0.");
ip2.ip6.uint8[15]++;
res = ip_equal(&ip1, &ip2);
ck_assert_msg(res == 0, "ip_equal( {AF_INET6, ::1}, {AF_INET6, ::2} ): expected result 0, got %res.", res);
}
END_TEST
#define DEFTESTCASE(NAME) \
TCase *NAME = tcase_create(#NAME); \
tcase_add_test(NAME, test_##NAME); \
suite_add_tcase(s, NAME);
Suite *network_suite(void)
{
Suite *s = suite_create("Network");
DEFTESTCASE(addr_resolv_localhost);
DEFTESTCASE(ip_equal);
return s;
}
int main(int argc, char *argv[])
{
srand((unsigned int) time(NULL));
Suite *network = network_suite();
SRunner *test_runner = srunner_create(network);
int number_failed = 0;
srunner_run_all(test_runner, CK_NORMAL);
number_failed = srunner_ntests_failed(test_runner);
srunner_free(test_runner);
return number_failed;
}

View File

@ -137,6 +137,7 @@ void get_id(Tox *m, char *data)
tox_getaddress(m, address);
uint32_t i = 0;
for (; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
sprintf(data + 2 * i + offset, "%02X ", address[i]);
}
@ -257,9 +258,9 @@ void line_eval(Tox *m, char *line)
if (num >= 0) {
sprintf(numstring, "[i] Added friend as %d.", num);
save_data(m);
}
else
} else
sprintf(numstring, "[i] Unknown error %i.", num);
break;
}
@ -508,12 +509,14 @@ static int load_data(Tox *m)
{
FILE *data_file = fopen(data_file_name, "r");
size_t size = 0;
if (data_file) {
fseek(data_file, 0, SEEK_END);
size = ftell(data_file);
rewind(data_file);
uint8_t data[size];
if (fread(data, sizeof(uint8_t), size, data_file) != size) {
fputs("[!] could not read data file!\n", stderr);
fclose(data_file);
@ -537,6 +540,7 @@ static int load_data(Tox *m)
static int save_data(Tox *m)
{
FILE *data_file = fopen(data_file_name, "w");
if (!data_file) {
perror("[!] load_key");
return 0;
@ -563,6 +567,7 @@ static int save_data(Tox *m)
static int load_data_or_init(Tox *m, char *path)
{
data_file_name = path;
if (load_data(m))
return 1;
@ -588,10 +593,12 @@ void print_invite(Tox *m, int friendnumber, uint8_t *group_public_key, void *use
new_lines(msg);
}
void print_groupmessage(Tox *m, int groupnumber, uint8_t *message, uint16_t length, void *userdata)
void print_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata)
{
char msg[256 + length];
sprintf(msg, "[g] %u: %s", groupnumber, message);
uint8_t name[TOX_MAX_NAME_LENGTH];
tox_group_peername(m, groupnumber, peernumber, name);
sprintf(msg, "[g] %u: <%s>: %s", groupnumber, name, message);
new_lines(msg);
}
@ -669,6 +676,7 @@ int main(int argc, char *argv[])
new_lines("[i] change username with /n");
uint8_t name[TOX_MAX_NAME_LENGTH];
uint16_t namelen = tox_getselfname(m, name, sizeof(name));
if (namelen > 0) {
char whoami[128 + TOX_MAX_NAME_LENGTH];
snprintf(whoami, sizeof(whoami), "[i] your current username is: %s", name);

View File

@ -1579,6 +1579,7 @@ void DHT_save(DHT *dht, uint8_t *data)
len = num * sizeof(Client_data);
type = DHT_STATE_TYPE_CLIENTS;
data = z_state_save_subheader(data, len, type);
if (num) {
Client_data *clients = (Client_data *)data;
@ -1586,6 +1587,7 @@ void DHT_save(DHT *dht, uint8_t *data)
if (dht->close_clientlist[i].timestamp != 0)
memcpy(&clients[num++], &dht->close_clientlist[i], sizeof(Client_data));
}
data += len;
}

View File

@ -686,9 +686,9 @@ void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int, u
/* Set the callback for group messages.
*
* Function(Messenger *m, int groupnumber, uint8_t * message, uint16_t length, void *userdata)
* Function(Tox *tox, int groupnumber, int friendgroupnumber, 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 m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t *, uint16_t, void *),
void *userdata)
{
m->group_message = function;
@ -705,7 +705,7 @@ static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *m
}
if (m->group_message)
(*m->group_message)(m, i, message, length, m->group_invite_userdata);
(*m->group_message)(m, i, peer_number, message, length, m->group_invite_userdata);
}
/* Creates a new groupchat and puts it in the chats array.
@ -788,6 +788,25 @@ int del_groupchat(Messenger *m, int groupnumber)
return 0;
}
/* Copy the name of peernumber who is in groupnumber to name.
* name must be at least MAX_NICK_BYTES long.
*
* return length of name if success
* return -1 if failure
*/
int m_group_peername(Messenger *m, int groupnumber, int peernumber, uint8_t *name)
{
if ((unsigned int)groupnumber >= m->numchats)
return -1;
if (m->chats == NULL)
return -1;
if (m->chats[groupnumber] == NULL)
return -1;
return group_peername(m->chats[groupnumber], peernumber, name);
}
/* return 1 if that friend was invited to the group
* return 0 if the friend was not or error.
*/
@ -1593,6 +1612,7 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le
break;
#ifdef DEBUG
default:
fprintf(stderr, "Load state: contains unrecognized part (len %u, type %u)\n",
length, type);

View File

@ -159,7 +159,7 @@ typedef struct Messenger {
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)(struct Messenger *m, int, int, uint8_t *, uint16_t, void *);
void *group_message_userdata;
} Messenger;
@ -382,9 +382,9 @@ void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int, u
/* Set the callback for group messages.
*
* Function(Messenger *m, int groupnumber, uint8_t * message, uint16_t length, void *userdata)
* Function(Tox *tox, int groupnumber, int friendgroupnumber, 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 m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t *, uint16_t, void *),
void *userdata);
/* Creates a new groupchat and puts it in the chats array.
@ -401,6 +401,14 @@ int add_groupchat(Messenger *m);
*/
int del_groupchat(Messenger *m, int groupnumber);
/* Copy the name of peernumber who is in groupnumber to name.
* name must be at least MAX_NICK_BYTES long.
*
* return length of name if success
* return -1 if failure
*/
int m_group_peername(Messenger *m, int groupnumber, int peernumber, uint8_t *name);
/* invite friendnumber to groupnumber
* return 0 on success
* return -1 on failure

View File

@ -278,6 +278,28 @@ static int delpeer(Group_Chat *chat, uint8_t *client_id)
return -1;
}
/* Copy the name of peernum to name.
* name must be at least MAX_NICK_BYTES long.
*
* return length of name if success
* return -1 if failure
*/
int group_peername(Group_Chat *chat, int peernum, uint8_t *name)
{
if ((uint32_t)peernum >= chat->numpeers)
return -1;
if (chat->group[peernum].nick_len == 0) {
memcpy(name, "NSA Agent", 10); /* Kindly remind the user that someone with no name might be a NSA agent.*/
return 10;
}
memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len);
return chat->group[peernum].nick_len;
}
/* min time between pings sent to one peer in seconds */
#define PING_TIMEOUT 5
static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum)

View File

@ -31,6 +31,8 @@
extern "C" {
#endif
#define MAX_NICK_BYTES 128
typedef struct {
uint8_t client_id[crypto_box_PUBLICKEYBYTES];
uint64_t pingid;
@ -39,6 +41,9 @@ typedef struct {
uint64_t last_recv;
uint64_t last_recv_msgping;
uint32_t last_message_number;
uint8_t nick[MAX_NICK_BYTES];
uint16_t nick_len;
} Group_Peer;
typedef struct {
@ -65,6 +70,14 @@ typedef struct Group_Chat {
} Group_Chat;
/* Copy the name of peernum to name.
* name must be at least MAX_NICK_BYTES long.
*
* return length of name if success
* return -1 if failure
*/
int group_peername(Group_Chat *chat, int peernum, uint8_t *name);
/*
* Set callback function for chat messages.
*

View File

@ -456,7 +456,7 @@ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
}
if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1
|| c->crypto_connections == NULL)
|| c->crypto_connections == NULL)
return -1;
memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));
@ -580,7 +580,7 @@ int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key,
* }
*/
if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1
|| c->crypto_connections == NULL)
|| c->crypto_connections == NULL)
return -1;
memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));

View File

@ -379,9 +379,9 @@ void tox_callback_group_invite(void *tox, void (*function)(Messenger *tox, int,
}
/* Set the callback for group messages.
*
* Function(Tox *tox, int groupnumber, uint8_t * message, uint16_t length, void *userdata)
* Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)
*/
void tox_callback_group_message(void *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *),
void tox_callback_group_message(void *tox, void (*function)(Messenger *tox, int, int, uint8_t *, uint16_t, void *),
void *userdata)
{
Messenger *m = tox;
@ -407,6 +407,18 @@ int tox_del_groupchat(void *tox, int groupnumber)
Messenger *m = tox;
return del_groupchat(m, groupnumber);
}
/* Copy the name of peernumber who is in groupnumber to name.
* name must be at least MAX_NICK_BYTES long.
*
* return length of name if success
* return -1 if failure
*/
int tox_group_peername(void *tox, int groupnumber, int peernumber, uint8_t *name)
{
Messenger *m = tox;
return m_group_peername(m, groupnumber, peernumber, name);
}
/* invite friendnumber to groupnumber
* return 0 on success
* return -1 on failure

View File

@ -357,9 +357,9 @@ void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int, uint8_t
/* Set the callback for group messages.
*
* Function(Tox *tox, int groupnumber, uint8_t * message, uint16_t length, void *userdata)
* Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)
*/
void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *),
void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t *, uint16_t, void *),
void *userdata);
/* Creates a new groupchat and puts it in the chats array.
@ -376,6 +376,14 @@ int tox_add_groupchat(Tox *tox);
*/
int tox_del_groupchat(Tox *tox, int groupnumber);
/* Copy the name of peernumber who is in groupnumber to name.
* name must be at least TOX_MAX_NAME_LENGTH long.
*
* return length of name if success
* return -1 if failure
*/
int tox_group_peername(Tox *tox, int groupnumber, int peernumber, uint8_t *name);
/* invite friendnumber to groupnumber
* return 0 on success
* return -1 on failure

View File

@ -18,7 +18,7 @@ void id_cpy(uint8_t *dest, uint8_t *src);
typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len, uint16_t type);
int load_state(load_state_callback_func load_state_callback, void *outer,
uint8_t *data, uint32_t length, uint16_t cookie_inner);
uint8_t *data, uint32_t length, uint16_t cookie_inner);
#undef LOGGING
/* #define LOGGING */