summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-01-16 21:13:32 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-01-16 21:13:32 +0300
commit2ad44a4cd4f811d6c7da5c8e9e31acf6e0152c79 (patch)
tree0585db93be035ea25d807b788ccfc4c7217c7587
parent8fc53a06b7a8163d61c06fbde88ffea904222bdd (diff)
fixes #1767 (Update toxcore to 0.2.9)
-rw-r--r--protocols/Tox/libtox/src/toxcore/DHT.c22
-rw-r--r--protocols/Tox/libtox/src/toxcore/LAN_discovery.c4
-rw-r--r--protocols/Tox/libtox/src/toxcore/LAN_discovery.h2
-rw-r--r--protocols/Tox/libtox/src/toxcore/Messenger.c156
-rw-r--r--protocols/Tox/libtox/src/toxcore/Messenger.h34
-rw-r--r--protocols/Tox/libtox/src/toxcore/crypto_core.c52
-rw-r--r--protocols/Tox/libtox/src/toxcore/friend_connection.c16
-rw-r--r--protocols/Tox/libtox/src/toxcore/friend_connection.h5
-rw-r--r--protocols/Tox/libtox/src/toxcore/group.c598
-rw-r--r--protocols/Tox/libtox/src/toxcore/group.h56
-rw-r--r--protocols/Tox/libtox/src/toxcore/logger.c3
-rw-r--r--protocols/Tox/libtox/src/toxcore/logger.h14
-rw-r--r--protocols/Tox/libtox/src/toxcore/mono_time.h17
-rw-r--r--protocols/Tox/libtox/src/toxcore/net_crypto.c8
-rw-r--r--protocols/Tox/libtox/src/toxcore/network.c25
-rw-r--r--protocols/Tox/libtox/src/toxcore/onion_client.c46
-rw-r--r--protocols/Tox/libtox/src/toxcore/state.c54
-rw-r--r--protocols/Tox/libtox/src/toxcore/state.h29
-rw-r--r--protocols/Tox/libtox/src/toxcore/tox.api.h94
-rw-r--r--protocols/Tox/libtox/src/toxcore/tox.c275
-rw-r--r--protocols/Tox/libtox/src/toxcore/tox.h38
-rw-r--r--protocols/Tox/libtox/src/toxcore/tox_api.c8
-rw-r--r--protocols/Tox/libtox/src/toxcore/util.c34
-rw-r--r--protocols/Tox/libtox/src/toxcore/util.h15
-rw-r--r--protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h5
-rw-r--r--protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c16
-rw-r--r--protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h5
27 files changed, 1251 insertions, 380 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/DHT.c b/protocols/Tox/libtox/src/toxcore/DHT.c
index 1eebb0c736..6b2715ee55 100644
--- a/protocols/Tox/libtox/src/toxcore/DHT.c
+++ b/protocols/Tox/libtox/src/toxcore/DHT.c
@@ -2741,10 +2741,12 @@ DHT *new_dht(const Logger *log, Mono_Time *mono_time, Networking_Core *net, bool
dht->dht_harden_ping_array = ping_array_new(DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {
- uint8_t random_key_bytes[CRYPTO_PUBLIC_KEY_SIZE];
- random_bytes(random_key_bytes, sizeof(random_key_bytes));
+ uint8_t random_public_key_bytes[CRYPTO_PUBLIC_KEY_SIZE];
+ uint8_t random_secret_key_bytes[CRYPTO_SECRET_KEY_SIZE];
- if (dht_addfriend(dht, random_key_bytes, nullptr, nullptr, 0, nullptr) != 0) {
+ crypto_new_keypair(random_public_key_bytes, random_secret_key_bytes);
+
+ if (dht_addfriend(dht, random_public_key_bytes, nullptr, nullptr, 0, nullptr) != 0) {
kill_dht(dht);
return nullptr;
}
@@ -2803,6 +2805,11 @@ uint32_t dht_size(const DHT *dht)
uint32_t numv4 = 0;
uint32_t numv6 = 0;
+ for (uint32_t i = 0; i < dht->loaded_num_nodes; ++i) {
+ numv4 += net_family_is_ipv4(dht->loaded_nodes_list[i].ip_port.ip.family);
+ numv6 += net_family_is_ipv6(dht->loaded_nodes_list[i].ip_port.ip.family);
+ }
+
for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
numv4 += (dht->close_clientlist[i].assoc4.timestamp != 0);
numv6 += (dht->close_clientlist[i].assoc6.timestamp != 0);
@@ -2826,7 +2833,7 @@ uint32_t dht_size(const DHT *dht)
/* Save the DHT in data where data is an array of size dht_size(). */
void dht_save(const DHT *dht, uint8_t *data)
{
- host_to_lendian32(data, DHT_STATE_COOKIE_GLOBAL);
+ host_to_lendian_bytes32(data, DHT_STATE_COOKIE_GLOBAL);
data += sizeof(uint32_t);
uint8_t *const old_data = data;
@@ -2838,6 +2845,11 @@ void dht_save(const DHT *dht, uint8_t *data)
uint32_t num = 0;
+ if (dht->loaded_num_nodes > 0) {
+ memcpy(clients, dht->loaded_nodes_list, sizeof(Node_format) * dht->loaded_num_nodes);
+ num += dht->loaded_num_nodes;
+ }
+
for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
if (dht->close_clientlist[i].assoc4.timestamp != 0) {
memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
@@ -2950,7 +2962,7 @@ int dht_load(DHT *dht, const uint8_t *data, uint32_t length)
if (length > cookie_len) {
uint32_t data32;
- lendian_to_host32(&data32, data);
+ lendian_bytes_to_host32(&data32, data);
if (data32 == DHT_STATE_COOKIE_GLOBAL) {
return state_load(dht->log, dht_load_state_callback, dht, data + cookie_len,
diff --git a/protocols/Tox/libtox/src/toxcore/LAN_discovery.c b/protocols/Tox/libtox/src/toxcore/LAN_discovery.c
index aeeea5661a..1137fc3d2f 100644
--- a/protocols/Tox/libtox/src/toxcore/LAN_discovery.c
+++ b/protocols/Tox/libtox/src/toxcore/LAN_discovery.c
@@ -119,7 +119,7 @@ static void fetch_broadcast_info(uint16_t port)
}
}
-#elif defined(__linux__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <netinet/in.h>
#include <sys/ioctl.h>
@@ -131,7 +131,7 @@ static void fetch_broadcast_info(uint16_t port)
#include <linux/netdevice.h>
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <net/if.h>
#endif
diff --git a/protocols/Tox/libtox/src/toxcore/LAN_discovery.h b/protocols/Tox/libtox/src/toxcore/LAN_discovery.h
index 8c48316d9e..1364a28078 100644
--- a/protocols/Tox/libtox/src/toxcore/LAN_discovery.h
+++ b/protocols/Tox/libtox/src/toxcore/LAN_discovery.h
@@ -70,4 +70,4 @@ bool ip_is_local(IP ip);
*/
bool ip_is_lan(IP ip);
-#endif
+#endif // C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
diff --git a/protocols/Tox/libtox/src/toxcore/Messenger.c b/protocols/Tox/libtox/src/toxcore/Messenger.c
index 594fc79a07..ae2d1d3bb0 100644
--- a/protocols/Tox/libtox/src/toxcore/Messenger.c
+++ b/protocols/Tox/libtox/src/toxcore/Messenger.c
@@ -2593,12 +2593,12 @@ void do_messenger(Messenger *m, void *userdata)
if (!m->has_added_relays) {
m->has_added_relays = true;
- int i;
-
- for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) {
+ for (uint16_t i = 0; i < m->num_loaded_relays; ++i) {
add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key);
}
+ m->num_loaded_relays = 0;
+
if (m->tcp_server) {
/* Add self tcp server. */
IP_Port local_ip_port;
@@ -2739,10 +2739,6 @@ void do_messenger(Messenger *m, void *userdata)
/* new messenger format for load/save, more robust and forward compatible */
-#define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f
-
-#define MESSENGER_STATE_COOKIE_TYPE 0x01ce
-
#define SAVED_FRIEND_REQUEST_SIZE 1024
#define NUM_SAVED_PATH_NODES 8
@@ -2881,7 +2877,7 @@ static uint32_t m_state_plugins_size(const Messenger *m)
* returns true on success
* returns false on failure
*/
-bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_size_cb size_callback,
+bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb size_callback,
m_state_load_cb load_callback,
m_state_save_cb save_callback)
{
@@ -2904,7 +2900,7 @@ bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_si
return true;
}
-static uint32_t m_plugin_size(const Messenger *m, Messenger_State_Type type)
+static uint32_t m_plugin_size(const Messenger *m, State_Type type)
{
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin plugin = m->options.state_plugins[i];
@@ -2922,30 +2918,18 @@ static uint32_t m_plugin_size(const Messenger *m, Messenger_State_Type type)
/* return size of the messenger data (for saving) */
uint32_t messenger_size(const Messenger *m)
{
- const uint32_t size32 = sizeof(uint32_t);
- const uint32_t sizesubhead = size32 * 2;
- return size32 * 2 // global cookie
- + m_state_plugins_size(m)
- + sizesubhead;
+ return m_state_plugins_size(m);
}
-/* Save the messenger in data of size Messenger_size(). */
-void messenger_save(const Messenger *m, uint8_t *data)
+/* Save the messenger in data of size messenger_size(). */
+uint8_t *messenger_save(const Messenger *m, uint8_t *data)
{
- memset(data, 0, messenger_size(m));
-
- const uint32_t size32 = sizeof(uint32_t);
-
- // write cookie
- memset(data, 0, size32);
- data += size32;
- host_to_lendian32(data, MESSENGER_STATE_COOKIE_GLOBAL);
- data += size32;
-
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin plugin = m->options.state_plugins[i];
data = plugin.save(m, data);
}
+
+ return data;
}
// nospam state plugin
@@ -2956,12 +2940,12 @@ static uint32_t nospam_keys_size(const Messenger *m)
static State_Load_Status load_nospam_keys(Messenger *m, const uint8_t *data, uint32_t length)
{
- if (length != m_plugin_size(m, MESSENGER_STATE_TYPE_NOSPAMKEYS)) {
+ if (length != m_plugin_size(m, STATE_TYPE_NOSPAMKEYS)) {
return STATE_LOAD_STATUS_ERROR;
}
uint32_t nospam;
- lendian_to_host32(&nospam, data);
+ lendian_bytes_to_host32(&nospam, data);
set_nospam(m->fr, nospam);
load_secret_key(m->net_crypto, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE);
@@ -2974,11 +2958,11 @@ static State_Load_Status load_nospam_keys(Messenger *m, const uint8_t *data, uin
static uint8_t *save_nospam_keys(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_NOSPAMKEYS);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_NOSPAMKEYS);
assert(sizeof(get_nospam(m->fr)) == sizeof(uint32_t));
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_NOSPAMKEYS);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NOSPAMKEYS);
uint32_t nospam = get_nospam(m->fr);
- host_to_lendian32(data, nospam);
+ host_to_lendian_bytes32(data, nospam);
save_keys(m->net_crypto, data + sizeof(uint32_t));
data += len;
return data;
@@ -2992,8 +2976,8 @@ static uint32_t m_dht_size(const Messenger *m)
static uint8_t *save_dht(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_DHT);
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_DHT);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_DHT);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_DHT);
dht_save(m->dht, data);
data += len;
return data;
@@ -3013,8 +2997,8 @@ static uint32_t saved_friendslist_size(const Messenger *m)
static uint8_t *friends_list_save(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_FRIENDS);
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_FRIENDS);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_FRIENDS);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_FRIENDS);
uint32_t num = 0;
uint8_t *cur_data = data;
@@ -3035,6 +3019,7 @@ static uint8_t *friends_list_save(const Messenger *m, uint8_t *data)
temp.info_size = net_htons(m->friendlist[i].info_size);
temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam;
} else {
+ temp.status = 3;
memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length);
temp.name_length = net_htons(m->friendlist[i].name_length);
memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length);
@@ -3118,8 +3103,8 @@ static uint32_t name_size(const Messenger *m)
static uint8_t *save_name(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_NAME);
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_NAME);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_NAME);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NAME);
memcpy(data, m->name, len);
data += len;
return data;
@@ -3142,8 +3127,8 @@ static uint32_t status_message_size(const Messenger *m)
static uint8_t *save_status_message(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_STATUSMESSAGE);
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_STATUSMESSAGE);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUSMESSAGE);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUSMESSAGE);
memcpy(data, m->statusmessage, len);
data += len;
return data;
@@ -3166,8 +3151,8 @@ static uint32_t status_size(const Messenger *m)
static uint8_t *save_status(const Messenger *m, uint8_t *data)
{
- const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_STATUS);
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_STATUS);
+ const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUS);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUS);
*data = m->userstatus;
data += len;
return data;
@@ -3192,13 +3177,19 @@ static uint8_t *save_tcp_relays(const Messenger *m, uint8_t *data)
{
Node_format relays[NUM_SAVED_TCP_RELAYS];
uint8_t *temp_data = data;
- data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_TCP_RELAY);
- unsigned int num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);
+ data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, 0, STATE_TYPE_TCP_RELAY);
+ uint32_t num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);
+
+ if (m->num_loaded_relays > 0) {
+ memcpy(relays, m->loaded_relays, sizeof(Node_format) * m->num_loaded_relays);
+ num = min_u32(num + m->num_loaded_relays, NUM_SAVED_TCP_RELAYS);
+ }
+
int l = pack_nodes(data, NUM_SAVED_TCP_RELAYS * packed_node_size(net_family_tcp_ipv6), relays, num);
if (l > 0) {
const uint32_t len = l;
- data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_TCP_RELAY);
+ data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_TCP_RELAY);
data += len;
}
@@ -3208,7 +3199,7 @@ static uint8_t *save_tcp_relays(const Messenger *m, uint8_t *data)
static State_Load_Status load_tcp_relays(Messenger *m, const uint8_t *data, uint32_t length)
{
if (length != 0) {
- unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, nullptr, data, length, 1);
+ m->num_loaded_relays = unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, nullptr, data, length, 1);
m->has_added_relays = false;
}
@@ -3225,14 +3216,14 @@ static uint8_t *save_path_nodes(const Messenger *m, uint8_t *data)
{
Node_format nodes[NUM_SAVED_PATH_NODES];
uint8_t *temp_data = data;
- data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_PATH_NODE);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_PATH_NODE);
memset(nodes, 0, sizeof(nodes));
const unsigned int num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);
const int l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6), nodes, num);
if (l > 0) {
const uint32_t len = l;
- data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_PATH_NODE);
+ data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_PATH_NODE);
data += len;
}
@@ -3254,77 +3245,32 @@ static State_Load_Status load_path_nodes(Messenger *m, const uint8_t *data, uint
return STATE_LOAD_STATUS_CONTINUE;
}
-// end state plugin
-static uint32_t end_size(const Messenger *m)
-{
- return 0;
-}
-
-static uint8_t *save_end(const Messenger *m, uint8_t *data)
-{
- return state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_END);
-}
-
-static State_Load_Status load_end(Messenger *m, const uint8_t *data, uint32_t length)
-{
- if (length != 0) {
- return STATE_LOAD_STATUS_ERROR;
- }
-
- return STATE_LOAD_STATUS_END;
-}
-
static void m_register_default_plugins(Messenger *m)
{
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_NAME, name_size, load_name, save_name);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
+ m_register_state_plugin(m, STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
+ m_register_state_plugin(m, STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
+ m_register_state_plugin(m, STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
+ m_register_state_plugin(m, STATE_TYPE_NAME, name_size, load_name, save_name);
+ m_register_state_plugin(m, STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
save_status_message);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_STATUS, status_size, load_status, save_status);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
- m_register_state_plugin(m, MESSENGER_STATE_TYPE_END, end_size, load_end, save_end);
+ m_register_state_plugin(m, STATE_TYPE_STATUS, status_size, load_status, save_status);
+ m_register_state_plugin(m, STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
+ m_register_state_plugin(m, STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
}
-static State_Load_Status messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
+bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
+ State_Load_Status *status)
{
- Messenger *m = (Messenger *)outer;
-
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin *const plugin = &m->options.state_plugins[i];
if (plugin->type == type) {
- return plugin->load(m, data, length);
+ *status = plugin->load(m, data, length);
+ return true;
}
}
- LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)\n",
- length, type);
-
- return STATE_LOAD_STATUS_CONTINUE;
-}
-
-/* Load the messenger from data of size length. */
-int messenger_load(Messenger *m, const uint8_t *data, uint32_t length)
-{
- uint32_t data32[2];
- uint32_t cookie_len = sizeof(data32);
-
- if (length < cookie_len) {
- return -1;
- }
-
- memcpy(data32, data, sizeof(uint32_t));
- lendian_to_host32(data32 + 1, data + sizeof(uint32_t));
-
- if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) {
- return state_load(m->log, messenger_load_state_callback, m, data + cookie_len,
- length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);
- }
-
- return -1;
+ return false;
}
/* Return the number of friends in the instance m.
diff --git a/protocols/Tox/libtox/src/toxcore/Messenger.h b/protocols/Tox/libtox/src/toxcore/Messenger.h
index ab9d72568e..a3376e237a 100644
--- a/protocols/Tox/libtox/src/toxcore/Messenger.h
+++ b/protocols/Tox/libtox/src/toxcore/Messenger.h
@@ -62,20 +62,8 @@ typedef uint8_t *m_state_save_cb(const Messenger *m, uint8_t *data);
// Returns if there were any erros during loading
typedef State_Load_Status m_state_load_cb(Messenger *m, const uint8_t *data, uint32_t length);
-typedef enum Messenger_State_Type {
- MESSENGER_STATE_TYPE_NOSPAMKEYS = 1,
- MESSENGER_STATE_TYPE_DHT = 2,
- MESSENGER_STATE_TYPE_FRIENDS = 3,
- MESSENGER_STATE_TYPE_NAME = 4,
- MESSENGER_STATE_TYPE_STATUSMESSAGE = 5,
- MESSENGER_STATE_TYPE_STATUS = 6,
- MESSENGER_STATE_TYPE_TCP_RELAY = 10,
- MESSENGER_STATE_TYPE_PATH_NODE = 11,
- MESSENGER_STATE_TYPE_END = 255,
-} Messenger_State_Type;
-
typedef struct Messenger_State_Plugin {
- Messenger_State_Type type;
+ State_Type type;
m_state_size_cb *size;
m_state_save_cb *save;
m_state_load_cb *load;
@@ -293,6 +281,8 @@ struct Messenger {
time_t lastdump;
bool has_added_relays; // If the first connection has occurred in do_messenger
+
+ uint16_t num_loaded_relays;
Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config
m_friend_message_cb *friend_message;
@@ -795,17 +785,25 @@ uint32_t messenger_run_interval(const Messenger *m);
* returns true on success
* returns false on error
*/
-bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_size_cb size_callback,
+bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb size_callback,
m_state_load_cb load_callback, m_state_save_cb save_callback);
/* return size of the messenger data (for saving). */
uint32_t messenger_size(const Messenger *m);
-/* Save the messenger in data (must be allocated memory of size Messenger_size()) */
-void messenger_save(const Messenger *m, uint8_t *data);
+/* Save the messenger in data (must be allocated memory of size at least Messenger_size()) */
+uint8_t *messenger_save(const Messenger *m, uint8_t *data);
-/* Load the messenger from data of size length. */
-int messenger_load(Messenger *m, const uint8_t *data, uint32_t length);
+/* Load a state section.
+ *
+ * @param data Data to load.
+ * @param length Length of data.
+ * @param type Type of section (STATE_TYPE_*).
+ * @param status Result of loading section is stored here if the section is handled.
+ * @return true iff section handled.
+ */
+bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
+ State_Load_Status *status);
/* Return the number of friends in the instance m.
* You should use this to determine how much memory to allocate
diff --git a/protocols/Tox/libtox/src/toxcore/crypto_core.c b/protocols/Tox/libtox/src/toxcore/crypto_core.c
index 1fd6286681..0e53100acd 100644
--- a/protocols/Tox/libtox/src/toxcore/crypto_core.c
+++ b/protocols/Tox/libtox/src/toxcore/crypto_core.c
@@ -30,6 +30,7 @@
#include "ccompat.h"
#include "crypto_core.h"
+#include <stdlib.h>
#include <string.h>
#ifndef VANILLA_NACL
@@ -82,6 +83,20 @@
#error "CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for public_key_cmp to work,"
#endif
+static uint8_t *crypto_malloc(size_t bytes)
+{
+ return (uint8_t *)malloc(bytes);
+}
+
+static void crypto_free(uint8_t *ptr, size_t bytes)
+{
+ if (ptr != nullptr) {
+ crypto_memzero(ptr, bytes);
+ }
+
+ free(ptr);
+}
+
int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2)
{
return crypto_verify_32(pk1, pk2);
@@ -142,8 +157,17 @@ int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
return -1;
}
- VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES);
- VLA(uint8_t, temp_encrypted, length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES);
+ const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
+ const size_t size_temp_encrypted = length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES;
+
+ uint8_t *temp_plain = crypto_malloc(size_temp_plain);
+ uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
+
+ if (temp_plain == nullptr || temp_encrypted == nullptr) {
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
+ return -1;
+ }
memset(temp_plain, 0, crypto_box_ZEROBYTES);
// Pad the message with 32 0 bytes.
@@ -151,11 +175,17 @@ int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce,
secret_key) != 0) {
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
return -1;
}
// Unpad the encrypted message.
memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);
+
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
+
return length + crypto_box_MACBYTES;
}
@@ -166,8 +196,17 @@ int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
return -1;
}
- VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES);
- VLA(uint8_t, temp_encrypted, length + crypto_box_BOXZEROBYTES);
+ const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
+ const size_t size_temp_encrypted = length + crypto_box_BOXZEROBYTES;
+
+ uint8_t *temp_plain = crypto_malloc(size_temp_plain);
+ uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
+
+ if (temp_plain == nullptr || temp_encrypted == nullptr) {
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
+ return -1;
+ }
memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES);
// Pad the message with 16 0 bytes.
@@ -175,10 +214,15 @@ int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce,
secret_key) != 0) {
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
return -1;
}
memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);
+
+ crypto_free(temp_plain, size_temp_plain);
+ crypto_free(temp_encrypted, size_temp_encrypted);
return length - crypto_box_MACBYTES;
}
diff --git a/protocols/Tox/libtox/src/toxcore/friend_connection.c b/protocols/Tox/libtox/src/toxcore/friend_connection.c
index 9c805b45ed..69533def1e 100644
--- a/protocols/Tox/libtox/src/toxcore/friend_connection.c
+++ b/protocols/Tox/libtox/src/toxcore/friend_connection.c
@@ -85,6 +85,9 @@ struct Friend_Connections {
fr_request_cb *fr_request_callback;
void *fr_request_object;
+ global_status_cb *global_status_callback;
+ void *global_status_callback_object;
+
uint64_t last_lan_discovery;
uint16_t next_lan_port;
@@ -401,9 +404,11 @@ static int handle_status(void *object, int number, uint8_t status, void *userdat
}
if (status_changed) {
- unsigned int i;
+ if (fr_c->global_status_callback) {
+ fr_c->global_status_callback(fr_c->global_status_callback_object, number, status, userdata);
+ }
- for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
+ for (unsigned i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
if (friend_con->callbacks[i].status_callback) {
friend_con->callbacks[i].status_callback(
friend_con->callbacks[i].callback_object,
@@ -716,6 +721,13 @@ int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsi
return 0;
}
+/* Set global status callback for friend connections. */
+void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object)
+{
+ fr_c->global_status_callback = global_status_callback;
+ fr_c->global_status_callback_object = object;
+}
+
/* return the crypt_connection_id for the connection.
*
* return crypt_connection_id on success.
diff --git a/protocols/Tox/libtox/src/toxcore/friend_connection.h b/protocols/Tox/libtox/src/toxcore/friend_connection.h
index 149a4fa7ec..166c731b84 100644
--- a/protocols/Tox/libtox/src/toxcore/friend_connection.h
+++ b/protocols/Tox/libtox/src/toxcore/friend_connection.h
@@ -101,10 +101,15 @@ void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *
*/
int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key);
+typedef int global_status_cb(void *object, int id, uint8_t status, void *userdata);
+
typedef int fc_status_cb(void *object, int id, uint8_t status, void *userdata);
typedef int fc_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
typedef int fc_lossy_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
+/* Set global status callback for friend connections. */
+void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object);
+
/* Set the callbacks for the friend connection.
* index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.
*
diff --git a/protocols/Tox/libtox/src/toxcore/group.c b/protocols/Tox/libtox/src/toxcore/group.c
index 5feb483b74..101c11963d 100644
--- a/protocols/Tox/libtox/src/toxcore/group.c
+++ b/protocols/Tox/libtox/src/toxcore/group.c
@@ -27,10 +27,12 @@
#include "group.h"
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "mono_time.h"
+#include "state.h"
#include "util.h"
/**
@@ -40,6 +42,7 @@ typedef enum Group_Message_Id {
GROUP_MESSAGE_PING_ID = 0,
GROUP_MESSAGE_NEW_PEER_ID = 16,
GROUP_MESSAGE_KILL_PEER_ID = 17,
+ GROUP_MESSAGE_FREEZE_PEER_ID = 18,
GROUP_MESSAGE_NAME_ID = 48,
GROUP_MESSAGE_TITLE_ID = 49,
} Group_Message_Id;
@@ -199,6 +202,17 @@ static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk)
return -1;
}
+static int frozen_in_chat(const Group_c *chat, const uint8_t *real_pk)
+{
+ for (uint32_t i = 0; i < chat->numfrozen; ++i) {
+ if (id_equal(chat->frozen[i].real_pk, real_pk)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
/*
* check if group with the given type and id is in group array.
*
@@ -237,7 +251,7 @@ int32_t conference_by_id(const Group_Chats *g_c, const uint8_t *id)
*
* TODO(irungentoo): make this more efficient.
*/
-static int get_peer_index(Group_c *g, uint16_t peer_number)
+static int get_peer_index(const Group_c *g, uint16_t peer_number)
{
for (uint32_t i = 0; i < g->numpeers; ++i) {
if (g->group[i].peer_number == peer_number) {
@@ -350,7 +364,7 @@ static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t
return 0;
}
-static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk)
+static unsigned int pk_in_closest_peers(const Group_c *g, uint8_t *real_pk)
{
unsigned int i;
@@ -373,7 +387,7 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t gr
static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t i, uint8_t reason);
static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type,
- uint8_t *id);
+ const uint8_t *id);
static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
{
@@ -443,7 +457,7 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
return 0;
}
-static int get_frozen_index(Group_c *g, uint16_t peer_number)
+static int get_frozen_index(const Group_c *g, uint16_t peer_number)
{
for (uint32_t i = 0; i < g->numfrozen; ++i) {
if (g->frozen[i].peer_number == peer_number) {
@@ -454,6 +468,34 @@ static int get_frozen_index(Group_c *g, uint16_t peer_number)
return -1;
}
+static bool delete_frozen(Group_c *g, uint32_t frozen_index)
+{
+ if (frozen_index >= g->numfrozen) {
+ return false;
+ }
+
+ --g->numfrozen;
+
+ if (g->numfrozen == 0) {
+ free(g->frozen);
+ g->frozen = nullptr;
+ } else {
+ if (g->numfrozen != frozen_index) {
+ g->frozen[frozen_index] = g->frozen[g->numfrozen];
+ }
+
+ Group_Peer *const frozen_temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen));
+
+ if (frozen_temp == nullptr) {
+ return false;
+ }
+
+ g->frozen = frozen_temp;
+ }
+
+ return true;
+}
+
/* Update last_active timestamp on peer, and thaw the peer if it is frozen.
*
* return peer index if peer is in the conference.
@@ -497,23 +539,8 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
++g->numpeers;
- --g->numfrozen;
-
- if (g->numfrozen == 0) {
- free(g->frozen);
- g->frozen = nullptr;
- } else {
- if (g->numfrozen != (uint32_t)frozen_index) {
- g->frozen[frozen_index] = g->frozen[g->numfrozen];
- }
-
- Group_Peer *frozen_temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen));
-
- if (frozen_temp == nullptr) {
- return -1;
- }
-
- g->frozen = frozen_temp;
+ if (!delete_frozen(g, frozen_index)) {
+ return -1;
}
if (g_c->peer_list_changed_callback) {
@@ -529,6 +556,29 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
return g->numpeers - 1;
}
+static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata, bool keep_connection);
+
+static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, void *userdata)
+{
+ Group_c *g = get_group_c(g_c, groupnumber);
+
+ if (!g) {
+ return;
+ }
+
+ const int prev_peer_index = peer_in_chat(g, real_pk);
+
+ if (prev_peer_index >= 0) {
+ delpeer(g_c, groupnumber, prev_peer_index, userdata, false);
+ }
+
+ const int prev_frozen_index = frozen_in_chat(g, real_pk);
+
+ if (prev_frozen_index >= 0) {
+ delete_frozen(g, prev_frozen_index);
+ }
+}
+
/* Add a peer to the group chat, or update an existing peer.
*
* fresh indicates whether we should consider this information on the peer to
@@ -581,6 +631,8 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
}
}
+ delete_any_peer_with_pk(g_c, groupnumber, real_pk, userdata);
+
Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
if (temp == nullptr) {
@@ -880,13 +932,23 @@ static void rejoin_frozen_friend(Group_Chats *g_c, int friendcon_id)
}
}
+static int g_handle_any_status(void *object, int friendcon_id, uint8_t status, void *userdata)
+{
+ Group_Chats *g_c = (Group_Chats *)object;
+
+ if (status) {
+ rejoin_frozen_friend(g_c, friendcon_id);
+ }
+
+ return 0;
+}
+
static int g_handle_status(void *object, int friendcon_id, uint8_t status, void *userdata)
{
Group_Chats *g_c = (Group_Chats *)object;
if (status) { /* Went online */
set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE, userdata);
- rejoin_frozen_friend(g_c, friendcon_id);
} else { /* Went offline */
set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION, userdata);
// TODO(irungentoo): remove timedout connections?
@@ -978,7 +1040,10 @@ static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t
if (reason == GROUPCHAT_CLOSE_REASON_INTRODUCER) {
--g->num_introducer_connections;
- send_peer_introduced(g_c, g->close[i].number, g->close[i].group_number);
+
+ if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) {
+ send_peer_introduced(g_c, g->close[i].number, g->close[i].group_number);
+ }
}
if (g->close[i].reasons == 0) {
@@ -1021,13 +1086,15 @@ int add_groupchat(Group_Chats *g_c, uint8_t type)
return groupnumber;
}
-static int group_kill_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num);
-/* Delete a groupchat from the chats array.
+static bool group_leave(const Group_Chats *g_c, uint32_t groupnumber, bool permanent);
+
+/* Delete a groupchat from the chats array, informing the group first as
+ * appropriate.
*
* return 0 on success.
* return -1 if groupnumber is invalid.
*/
-int del_groupchat(Group_Chats *g_c, uint32_t groupnumber)
+int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently)
{
Group_c *g = get_group_c(g_c, groupnumber);
@@ -1035,7 +1102,7 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber)
return -1;
}
- group_kill_peer_send(g_c, groupnumber, g->peer_number);
+ group_leave(g_c, groupnumber, leave_permanently);
for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
@@ -1062,82 +1129,115 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber)
return wipe_group_chat(g_c, groupnumber);
}
-/* Copy the public key of peernumber who is in groupnumber to pk.
- * pk must be CRYPTO_PUBLIC_KEY_SIZE long.
+/* Copy the public key of (frozen, if frozen is true) peernumber who is in
+ * groupnumber to pk. pk must be CRYPTO_PUBLIC_KEY_SIZE long.
*
* return 0 on success
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk)
+int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
}
- if ((uint32_t)peernumber >= g->numpeers) {
+ const Group_Peer *list = frozen ? g->frozen : g->group;
+ const uint32_t num = frozen ? g->numfrozen : g->numpeers;
+
+ if ((uint32_t)peernumber >= num) {
return -2;
}
- memcpy(pk, g->group[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
+ memcpy(pk, list[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
return 0;
}
/*
- * Return the size of peernumber's name.
+ * Return the size of (frozen, if frozen is true) peernumber's name.
*
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernumber)
+int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, bool frozen)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
}
- if ((uint32_t)peernumber >= g->numpeers) {
+ const Group_Peer *list = frozen ? g->frozen : g->group;
+ const uint32_t num = frozen ? g->numfrozen : g->numpeers;
+
+ if ((uint32_t)peernumber >= num) {
return -2;
}
- if (g->group[peernumber].nick_len == 0) {
+ if (list[peernumber].nick_len == 0) {
return 0;
}
- return g->group[peernumber].nick_len;
+ return list[peernumber].nick_len;
}
-/* Copy the name of peernumber who is in groupnumber to name.
- * name must be at least MAX_NAME_LENGTH long.
+/* Copy the name of (frozen, if frozen is true) peernumber who is in
+ * groupnumber to name. name must be at least MAX_NAME_LENGTH long.
*
* return length of name if success
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name)
+int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
}
- if ((uint32_t)peernumber >= g->numpeers) {
+ const Group_Peer *list = frozen ? g->frozen : g->group;
+ const uint32_t num = frozen ? g->numfrozen : g->numpeers;
+
+ if ((uint32_t)peernumber >= num) {
return -2;
}
- if (g->group[peernumber].nick_len == 0) {
+ if (list[peernumber].nick_len == 0) {
return 0;
}
- memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len);
- return g->group[peernumber].nick_len;
+ memcpy(name, list[peernumber].nick, list[peernumber].nick_len);
+ return list[peernumber].nick_len;
+}
+
+/* Copy last active timestamp of frozennumber who is in groupnumber to
+ * last_active.
+ *
+ * return 0 on success.
+ * return -1 if groupnumber is invalid.
+ * return -2 if frozennumber is invalid.
+ */
+int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
+ uint64_t *last_active)
+{
+ const Group_c *g = get_group_c(g_c, groupnumber);
+
+ if (!g) {
+ return -1;
+ }
+
+ if ((uint32_t)peernumber >= g->numfrozen) {
+ return -2;
+ }
+
+ *last_active = g->frozen[peernumber].last_active;
+ return 0;
}
-/* List all the peers in the group chat.
+/* List all the (frozen, if frozen is true) peers in the group chat.
*
* Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.
*
@@ -1148,35 +1248,38 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
* return -1 on failure.
*/
int group_names(const Group_Chats *g_c, uint32_t groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[],
- uint16_t length)
+ uint16_t length, bool frozen)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
}
+ const uint32_t num = frozen ? g->numfrozen : g->numpeers;
+
unsigned int i;
- for (i = 0; i < g->numpeers && i < length; ++i) {
- lengths[i] = group_peername(g_c, groupnumber, i, names[i]);
+ for (i = 0; i < num && i < length; ++i) {
+ lengths[i] = group_peername(g_c, groupnumber, i, names[i], frozen);
}
return i;
}
-/* Return the number of peers in the group chat on success.
+/* Return the number of (frozen, if frozen is true) peers in the group chat on
+ * success.
* return -1 if groupnumber is invalid.
*/
-int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber)
+int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
}
- return g->numpeers;
+ return frozen ? g->numfrozen : g->numpeers;
}
/* return 1 if the peernumber corresponds to ours.
@@ -1187,7 +1290,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber)
*/
int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int peernumber)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -1553,10 +1656,9 @@ static int group_new_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uin
}
/* send a kill_peer message
- * return 0 on success
- * return -1 on failure
+ * return true on success
*/
-static int group_kill_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num)
+static bool group_kill_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num)
{
uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH];
@@ -1564,10 +1666,27 @@ static int group_kill_peer_send(const Group_Chats *g_c, uint32_t groupnumber, ui
memcpy(packet, &peer_num, sizeof(uint16_t));
if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_KILL_PEER_ID, packet, sizeof(packet)) > 0) {
- return 0;
+ return true;
}
- return -1;
+ return false;
+}
+
+/* send a freeze_peer message
+ * return true on success
+ */
+static bool group_freeze_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num)
+{
+ uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH];
+
+ peer_num = net_htons(peer_num);
+ memcpy(packet, &peer_num, sizeof(uint16_t));
+
+ if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_FREEZE_PEER_ID, packet, sizeof(packet)) > 0) {
+ return true;
+ }
+
+ return false;
}
/* send a name message
@@ -1587,6 +1706,25 @@ static int group_name_send(const Group_Chats *g_c, uint32_t groupnumber, const u
return -1;
}
+/* send message to announce leaving group
+ * return true on success
+ */
+static bool group_leave(const Group_Chats *g_c, uint32_t groupnumber, bool permanent)
+{
+ const Group_c *g = get_group_c(g_c, groupnumber);
+
+ if (!g) {
+ return false;
+ }
+
+ if (permanent) {
+ return group_kill_peer_send(g_c, groupnumber, g->peer_number);
+ } else {
+ return group_freeze_peer_send(g_c, groupnumber, g->peer_number);
+ }
+}
+
+
/* set the group's title, limited to MAX_NAME_LENGTH
* return 0 on success
* return -1 if groupnumber is invalid.
@@ -1630,7 +1768,7 @@ int group_title_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t
*/
int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -1652,7 +1790,7 @@ int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber)
*/
int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -1675,11 +1813,11 @@ static bool get_peer_number(const Group_c *g, const uint8_t *real_pk, uint16_t *
return true;
}
- for (uint32_t i = 0; i < g->numfrozen; ++i) {
- if (id_equal(g->frozen[i].real_pk, real_pk)) {
- *peer_number = g->frozen[i].peer_number;
- return true;
- }
+ const int frozen_index = frozen_in_chat(g, real_pk);
+
+ if (frozen_index >= 0) {
+ *peer_number = g->frozen[frozen_index].peer_number;
+ return true;
}
return false;
@@ -1790,7 +1928,7 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
* returns index on success
* returns -1 on failure.
*/
-static int friend_in_close(Group_c *g, int friendcon_id)
+static int friend_in_close(const Group_c *g, int friendcon_id)
{
unsigned int i;
@@ -1811,7 +1949,7 @@ static int friend_in_close(Group_c *g, int friendcon_id)
/* return number of connected close connections.
*/
-static unsigned int count_close_connected(Group_c *g)
+static unsigned int count_close_connected(const Group_c *g)
{
unsigned int i, count = 0;
@@ -1825,7 +1963,7 @@ static unsigned int count_close_connected(Group_c *g)
}
static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type,
- uint8_t *id)
+ const uint8_t *id)
{
uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE];
group_num = net_htons(group_num);
@@ -1906,7 +2044,7 @@ static int handle_packet_rejoin(Group_Chats *g_c, int friendcon_id, const uint8_
const int32_t groupnum = get_group_num(g_c, *data, data + 1);
- Group_c *g = get_group_c(g_c, groupnum);
+ const Group_c *g = get_group_c(g_c, groupnum);
if (!g) {
return -1;
@@ -1960,7 +2098,7 @@ static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t
*/
static unsigned int send_peers(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint16_t group_num)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return 0;
@@ -2083,7 +2221,7 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
switch (data[0]) {
case PEER_INTRODUCED_ID: {
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return;
@@ -2095,12 +2233,16 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
break;
case PEER_QUERY_ID: {
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return;
}
+ if (g->close[close_index].type != GROUPCHAT_CLOSE_ONLINE) {
+ return;
+ }
+
send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number);
}
@@ -2113,7 +2255,7 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
break;
case PEER_TITLE_ID: {
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
break;
@@ -2136,7 +2278,7 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
static unsigned int send_message_all_close(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data,
uint16_t length, int receiver)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return 0;
@@ -2171,7 +2313,7 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
uint16_t length,
int receiver)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return 0;
@@ -2257,7 +2399,7 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
* return -1 if groupnumber is invalid.
* return -2 if message is too long.
* return -3 if we are not connected to the group.
- * reutrn -4 if message failed to send.
+ * return -4 if message failed to send.
*/
static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint8_t message_id, const uint8_t *data,
uint16_t len)
@@ -2272,7 +2414,7 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
return -2;
}
- if (g->status != GROUPCHAT_STATUS_CONNECTED) {
+ if (g->status != GROUPCHAT_STATUS_CONNECTED || count_close_connected(g) == 0) {
return -3;
}
@@ -2418,7 +2560,7 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
return;
}
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return;
@@ -2428,9 +2570,28 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
memcpy(&peer_number, data, sizeof(uint16_t));
peer_number = net_ntohs(peer_number);
- const int index = note_peer_active(g_c, groupnumber, peer_number, userdata);
+ uint32_t message_number;
+ memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number));
+ message_number = net_ntohl(message_number);
+
+ const uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)];
+ const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1;
+ const uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1);
+
+ const bool ignore_frozen = message_id == GROUP_MESSAGE_FREEZE_PEER_ID;
+
+ const int index = ignore_frozen ? get_peer_index(g, peer_number)
+ : note_peer_active(g_c, groupnumber, peer_number, userdata);
if (index == -1) {
+ if (ignore_frozen) {
+ return;
+ }
+
+ if (g->close[close_index].type != GROUPCHAT_CLOSE_ONLINE) {
+ return;
+ }
+
/* If we don't know the peer this packet came from, then we query the
* list of peers from the relaying peer.
* (They would not have relayed it if they didn't know the peer.) */
@@ -2457,14 +2618,6 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
}
}
- uint32_t message_number;
- memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number));
- message_number = net_ntohl(message_number);
-
- const uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)];
- const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1;
- const uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1);
-
if (!check_message_info(message_number, message_id, &g->group[index])) {
return;
}
@@ -2486,7 +2639,8 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
}
break;
- case GROUP_MESSAGE_KILL_PEER_ID: {
+ case GROUP_MESSAGE_KILL_PEER_ID:
+ case GROUP_MESSAGE_FREEZE_PEER_ID: {
if (msg_data_len != GROUP_MESSAGE_KILL_PEER_LENGTH) {
return;
}
@@ -2496,7 +2650,11 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
kill_peer_number = net_ntohs(kill_peer_number);
if (peer_number == kill_peer_number) {
- delpeer(g_c, groupnumber, index, userdata, false);
+ if (message_id == GROUP_MESSAGE_KILL_PEER_ID) {
+ delpeer(g_c, groupnumber, index, userdata, false);
+ } else {
+ freeze_peer(g_c, groupnumber, index, userdata);
+ }
} else {
return;
// TODO(irungentoo):
@@ -2582,7 +2740,7 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
uint16_t groupnumber;
memcpy(&groupnumber, data + 1, sizeof(uint16_t));
groupnumber = net_ntohs(groupnumber);
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -2622,7 +2780,7 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
*
* TODO(irungentoo): test this
*/
-static unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16_t message_number)
+static unsigned int lossy_packet_not_received(const Group_c *g, int peer_index, uint16_t message_number)
{
if (peer_index == -1) {
// TODO(sudden6): invalid return value
@@ -2693,7 +2851,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
peer_number = net_ntohs(peer_number);
message_number = net_ntohs(message_number);
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -2762,7 +2920,7 @@ int group_set_object(const Group_Chats *g_c, uint32_t groupnumber, void *object)
*/
int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, void *object)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return -1;
@@ -2783,7 +2941,7 @@ int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peer
*/
void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return nullptr;
@@ -2799,7 +2957,7 @@ void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber)
*/
void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber)
{
- Group_c *g = get_group_c(g_c, groupnumber);
+ const Group_c *g = get_group_c(g_c, groupnumber);
if (!g) {
return nullptr;
@@ -2875,6 +3033,244 @@ void send_name_all_groups(Group_Chats *g_c)
}
}
+#define SAVED_PEER_SIZE_CONSTANT (2 * CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint16_t) + sizeof(uint64_t) + 1)
+
+static uint32_t saved_peer_size(const Group_Peer *peer)
+{
+ return SAVED_PEER_SIZE_CONSTANT + peer->nick_len;
+}
+
+static uint8_t *save_peer(const Group_Peer *peer, uint8_t *data)
+{
+ memcpy(data, peer->real_pk, CRYPTO_PUBLIC_KEY_SIZE);
+ data += CRYPTO_PUBLIC_KEY_SIZE;
+
+ memcpy(data, peer->temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
+ data += CRYPTO_PUBLIC_KEY_SIZE;
+
+ host_to_lendian_bytes16(data, peer->peer_number);
+ data += sizeof(uint16_t);
+
+ host_to_lendian_bytes64(data, peer->last_active);
+ data += sizeof(uint64_t);
+
+ *data = peer->nick_len;
+ ++data;
+
+ memcpy(data, peer->nick, peer->nick_len);
+ data += peer->nick_len;
+
+ return data;
+}
+
+#define SAVED_CONF_SIZE_CONSTANT (1 + GROUP_ID_LENGTH + sizeof(uint32_t) \
+ + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + 1)
+
+static uint32_t saved_conf_size(const Group_c *g)
+{
+ uint32_t len = SAVED_CONF_SIZE_CONSTANT + g->title_len;
+
+ for (uint32_t j = 0; j < g->numpeers + g->numfrozen; ++j) {
+ const Group_Peer *peer = (j < g->numpeers) ? &g->group[j] : &g->frozen[j - g->numpeers];
+
+ if (id_equal(peer->real_pk, g->real_pk)) {
+ continue;
+ }
+
+ len += saved_peer_size(peer);
+ }
+
+ return len;
+}
+
+static uint8_t *save_conf(const Group_c *g, uint8_t *data)
+{
+ *data = g->type;
+ ++data;
+
+ memcpy(data, g->id, GROUP_ID_LENGTH);
+ data += GROUP_ID_LENGTH;
+
+ host_to_lendian_bytes32(data, g->message_number);
+ data += sizeof(uint32_t);
+
+ host_to_lendian_bytes16(data, g->lossy_message_number);
+ data += sizeof(uint16_t);
+
+ host_to_lendian_bytes16(data, g->peer_number);
+ data += sizeof(uint16_t);
+
+ uint8_t *const numsaved_location = data;
+ data += sizeof(uint32_t);
+
+ *data = g->title_len;
+ ++data;
+
+ memcpy(data, g->title, g->title_len);
+ data += g->title_len;
+
+ uint32_t numsaved = 0;
+
+ for (uint32_t j = 0; j < g->numpeers + g->numfrozen; ++j) {
+ const Group_Peer *peer = (j < g->numpeers) ? &g->group[j] : &g->frozen[j - g->numpeers];
+
+ if (id_equal(peer->real_pk, g->real_pk)) {
+ continue;
+ }
+
+ data = save_peer(peer, data);
+ ++numsaved;
+ }
+
+ host_to_lendian_bytes32(numsaved_location, numsaved);
+
+ return data;
+}
+
+static uint32_t conferences_section_size(const Group_Chats *g_c)
+{
+ uint32_t len = 0;
+
+ for (uint16_t i = 0; i < g_c->num_chats; ++i) {
+ const Group_c *g = get_group_c(g_c, i);
+
+ if (!g || g->status != GROUPCHAT_STATUS_CONNECTED) {
+ continue;
+ }
+
+ len += saved_conf_size(g);
+ }
+
+ return len;
+}
+
+uint32_t conferences_size(const Group_Chats *g_c)
+{
+ return 2 * sizeof(uint32_t) + conferences_section_size(g_c);
+}
+
+uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data)
+{
+ const uint32_t len = conferences_section_size(g_c);
+ data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_CONFERENCES);
+
+ for (uint16_t i = 0; i < g_c->num_chats; ++i) {
+ const Group_c *g = get_group_c(g_c, i);
+
+ if (!g || g->status != GROUPCHAT_STATUS_CONNECTED) {
+ continue;
+ }
+
+ data = save_conf(g, data);
+ }
+
+ return data;
+}
+
+static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, uint32_t length)
+{
+ const uint8_t *init_data = data;
+
+ while (length >= (uint32_t)(data - init_data) + SAVED_CONF_SIZE_CONSTANT) {
+ const int groupnumber = create_group_chat(g_c);
+
+ if (groupnumber == -1) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ Group_c *g = &g_c->chats[groupnumber];
+
+ g->type = *data;
+ ++data;
+
+ memcpy(g->id, data, GROUP_ID_LENGTH);
+ data += GROUP_ID_LENGTH;
+
+ lendian_bytes_to_host32(&g->message_number, data);
+ data += sizeof(uint32_t);
+
+ lendian_bytes_to_host16(&g->lossy_message_number, data);
+ data += sizeof(uint16_t);
+
+ lendian_bytes_to_host16(&g->peer_number, data);
+ data += sizeof(uint16_t);
+
+ lendian_bytes_to_host32(&g->numfrozen, data);
+ data += sizeof(uint32_t);
+
+ g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen);
+
+ if (g->frozen == nullptr) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ g->title_len = *data;
+ ++data;
+
+ if (length < (uint32_t)(data - init_data) + g->title_len) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ memcpy(g->title, data, g->title_len);
+ data += g->title_len;
+
+ for (uint32_t j = 0; j < g->numfrozen; ++j) {
+ if (length < (uint32_t)(data - init_data) + SAVED_PEER_SIZE_CONSTANT) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ Group_Peer *peer = &g->frozen[j];
+ memset(peer, 0, sizeof(Group_Peer));
+
+ id_copy(peer->real_pk, data);
+ data += CRYPTO_PUBLIC_KEY_SIZE;
+ id_copy(peer->temp_pk, data);
+ data += CRYPTO_PUBLIC_KEY_SIZE;
+
+ lendian_bytes_to_host16(&peer->peer_number, data);
+ data += sizeof(uint16_t);
+
+ lendian_bytes_to_host64(&peer->last_active, data);
+ data += sizeof(uint64_t);
+
+ peer->nick_len = *data;
+ ++data;
+
+ if (length < (uint32_t)(data - init_data) + peer->nick_len) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ memcpy(peer->nick, data, peer->nick_len);
+ data += peer->nick_len;
+ }
+
+ g->status = GROUPCHAT_STATUS_CONNECTED;
+ memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
+ const int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), g->peer_number,
+ nullptr, true, false);
+
+ if (peer_index == -1) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length, nullptr, false);
+ }
+
+ return STATE_LOAD_STATUS_CONTINUE;
+}
+
+bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
+ State_Load_Status *status)
+{
+ if (type != STATE_TYPE_CONFERENCES) {
+ return false;
+ }
+
+ *status = load_conferences(g_c, data, length);
+ return true;
+}
+
+
/* Create new groupchat instance. */
Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m)
{
@@ -2894,6 +3290,8 @@ Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m)
m->conferences_object = temp;
m_callback_conference_invite(m, &handle_friend_invite_packet);
+ set_global_status_callback(m->fr_c, &g_handle_any_status, temp);
+
return temp;
}
@@ -2926,7 +3324,7 @@ void do_groupchats(Group_Chats *g_c, void *userdata)
void kill_groupchats(Group_Chats *g_c)
{
for (uint16_t i = 0; i < g_c->num_chats; ++i) {
- del_groupchat(g_c, i);
+ del_groupchat(g_c, i, false);
}
m_callback_conference_invite(g_c->m, nullptr);
diff --git a/protocols/Tox/libtox/src/toxcore/group.h b/protocols/Tox/libtox/src/toxcore/group.h
index 7acd46371e..83015273b3 100644
--- a/protocols/Tox/libtox/src/toxcore/group.h
+++ b/protocols/Tox/libtox/src/toxcore/group.h
@@ -238,38 +238,51 @@ void g_callback_peer_list_changed(Group_Chats *g_c, peer_list_changed_cb *functi
*/
int add_groupchat(Group_Chats *g_c, uint8_t type);
-/* Delete a groupchat from the chats array.
+/* Delete a groupchat from the chats array, informing the group first as
+ * appropriate.
*
* return 0 on success.
* return -1 if groupnumber is invalid.
*/
-int del_groupchat(Group_Chats *g_c, uint32_t groupnumber);
+int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently);
-/* Copy the public key of peernumber who is in groupnumber to pk.
+/* Copy the public key of (frozen, if frozen is true) peernumber who is in
+ * groupnumber to pk.
* pk must be CRYPTO_PUBLIC_KEY_SIZE long.
*
* return 0 on success
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk);
+int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen);
/*
- * Return the size of peernumber's name.
+ * Return the size of (frozen, if frozen is true) peernumber's name.
*
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t peernumber);
+int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t peernumber, bool frozen);
-/* Copy the name of peernumber who is in groupnumber to name.
+/* Copy the name of (frozen, if frozen is true) peernumber who is in
+ * groupnumber to name.
* name must be at least MAX_NAME_LENGTH long.
*
* return length of name if success
* return -1 if groupnumber is invalid.
* return -2 if peernumber is invalid.
*/
-int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name);
+int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen);
+
+/* Copy last active timestamp of frozen peernumber who is in groupnumber to
+ * last_active.
+ *
+ * return 0 on success.
+ * return -1 if groupnumber is invalid.
+ * return -2 if peernumber is invalid.
+ */
+int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
+ uint64_t *last_active);
/* invite friendnumber to groupnumber
*
@@ -330,10 +343,11 @@ int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber);
*/
int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title);
-/* Return the number of peers in the group chat on success.
+/* Return the number of (frozen, if frozen is true) peers in the group chat on
+ * success.
* return -1 if groupnumber is invalid.
*/
-int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber);
+int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen);
/* return 1 if the peernumber corresponds to ours.
* return 0 if the peernumber is not ours.
@@ -343,7 +357,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber);
*/
int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int peernumber);
-/* List all the peers in the group chat.
+/* List all the (frozen, if frozen is true) peers in the group chat.
*
* Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.
*
@@ -354,7 +368,7 @@ int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int p
* return -1 on failure.
*/
int group_names(const Group_Chats *g_c, uint32_t groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[],
- uint16_t length);
+ uint16_t length, bool frozen);
/* Set handlers for custom lossy packets. */
void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, lossy_packet_cb *function);
@@ -448,6 +462,24 @@ int callback_groupchat_peer_delete(Group_Chats *g_c, uint32_t groupnumber, peer_
*/
int callback_groupchat_delete(Group_Chats *g_c, uint32_t groupnumber, group_on_delete_cb *function);
+/* Return size of the conferences data (for saving). */
+uint32_t conferences_size(const Group_Chats *g_c);
+
+/* Save the conferences in data (must be allocated memory of size at least conferences_size()) */
+uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data);
+
+/**
+ * Load a state section.
+ *
+ * @param data Data to load
+ * @param length Length of data
+ * @param type Type of section (STATE_TYPE_*)
+ * @param status Result of loading section is stored here if the section is handled.
+ * @return true iff section handled.
+ */
+bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
+ State_Load_Status *status);
+
/* Create new groupchat instance. */
Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m);
diff --git a/protocols/Tox/libtox/src/toxcore/logger.c b/protocols/Tox/libtox/src/toxcore/logger.c
index 51c30edec4..808332198c 100644
--- a/protocols/Tox/libtox/src/toxcore/logger.c
+++ b/protocols/Tox/libtox/src/toxcore/logger.c
@@ -104,7 +104,8 @@ void logger_write(const Logger *log, Logger_Level level, const char *file, int l
#ifdef USE_STDERR_LOGGER
log = &logger_stderr;
#else
- assert(!"NULL logger not permitted");
+ fprintf(stderr, "NULL logger not permitted.\n");
+ abort();
#endif
}
diff --git a/protocols/Tox/libtox/src/toxcore/logger.h b/protocols/Tox/libtox/src/toxcore/logger.h
index 2cae7a0efd..3abed896c2 100644
--- a/protocols/Tox/libtox/src/toxcore/logger.h
+++ b/protocols/Tox/libtox/src/toxcore/logger.h
@@ -91,4 +91,18 @@ void logger_write(
#define LOGGER_WARNING(log, ...) LOGGER_WRITE(log, LOGGER_LEVEL_WARNING, __VA_ARGS__)
#define LOGGER_ERROR(log, ...) LOGGER_WRITE(log, LOGGER_LEVEL_ERROR , __VA_ARGS__)
+#define LOGGER_FATAL(log, ...) \
+ do { \
+ LOGGER_ERROR(log, __VA_ARGS__); \
+ abort(); \
+ } while(0)
+
+#define LOGGER_ASSERT(log, cond, ...) \
+ do { \
+ if (!(cond)) { \
+ LOGGER_ERROR(log, "Assertion failed"); \
+ LOGGER_FATAL(log, __VA_ARGS__); \
+ } \
+ } while(0)
+
#endif // C_TOXCORE_TOXCORE_LOGGER_H
diff --git a/protocols/Tox/libtox/src/toxcore/mono_time.h b/protocols/Tox/libtox/src/toxcore/mono_time.h
index 503548f222..aa244baeb0 100644
--- a/protocols/Tox/libtox/src/toxcore/mono_time.h
+++ b/protocols/Tox/libtox/src/toxcore/mono_time.h
@@ -45,11 +45,26 @@ typedef struct Mono_Time Mono_Time;
Mono_Time *mono_time_new(void);
void mono_time_free(Mono_Time *mono_time);
+/**
+ * Update mono_time; subsequent calls to mono_time_get or mono_time_is_timeout
+ * will use the time at the call to mono_time_update.
+ */
void mono_time_update(Mono_Time *mono_time);
+
+/**
+ * Return unix time since epoch in seconds.
+ */
uint64_t mono_time_get(const Mono_Time *mono_time);
+
+/**
+ * Return true iff timestamp is at least timeout seconds in the past.
+ */
bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout);
-/* return current monotonic time in milliseconds (ms). */
+/**
+ * Return current monotonic time in milliseconds (ms). The starting point is
+ * unspecified.
+ */
uint64_t current_time_monotonic(Mono_Time *mono_time);
typedef uint64_t mono_time_current_time_cb(Mono_Time *mono_time, void *user_data);
diff --git a/protocols/Tox/libtox/src/toxcore/net_crypto.c b/protocols/Tox/libtox/src/toxcore/net_crypto.c
index 736b9c4a25..3ace3beaea 100644
--- a/protocols/Tox/libtox/src/toxcore/net_crypto.c
+++ b/protocols/Tox/libtox/src/toxcore/net_crypto.c
@@ -2529,16 +2529,18 @@ static void send_crypto_packets(Net_Crypto *c)
unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE;
conn->last_sendqueue_size[pos] = num_packets_array(&conn->send_array);
- ++conn->last_sendqueue_counter;
long signed int sum = 0;
- sum = (long signed int)conn->last_sendqueue_size[(pos) % CONGESTION_QUEUE_ARRAY_SIZE] -
- (long signed int)conn->last_sendqueue_size[(pos - (CONGESTION_QUEUE_ARRAY_SIZE - 1)) % CONGESTION_QUEUE_ARRAY_SIZE];
+ sum = (long signed int)conn->last_sendqueue_size[pos] -
+ (long signed int)conn->last_sendqueue_size[(pos + 1) % CONGESTION_QUEUE_ARRAY_SIZE];
unsigned int n_p_pos = conn->last_sendqueue_counter % CONGESTION_LAST_SENT_ARRAY_SIZE;
conn->last_num_packets_sent[n_p_pos] = packets_sent;
conn->last_num_packets_resent[n_p_pos] = packets_resent;
+ conn->last_sendqueue_counter = (conn->last_sendqueue_counter + 1) %
+ (CONGESTION_QUEUE_ARRAY_SIZE * CONGESTION_LAST_SENT_ARRAY_SIZE);
+
bool direct_connected = 0;
crypto_connection_status(c, i, &direct_connected, nullptr);
diff --git a/protocols/Tox/libtox/src/toxcore/network.c b/protocols/Tox/libtox/src/toxcore/network.c
index 917556ac44..5e5160d893 100644
--- a/protocols/Tox/libtox/src/toxcore/network.c
+++ b/protocols/Tox/libtox/src/toxcore/network.c
@@ -405,16 +405,23 @@ bool set_socket_dualstack(Socket sock)
static uint32_t data_0(uint16_t buflen, const uint8_t *buffer)
{
- // TODO(iphydf): Do this differently. Right now this is most likely a
- // misaligned memory access in reality, and definitely undefined behaviour
- // in terms of C standard.
- const uint8_t *const start = buffer + 1;
- return buflen > 4 ? net_ntohl(*(const uint32_t *)start) : 0;
+ uint32_t data = 0;
+
+ if (buflen > 4) {
+ net_unpack_u32(buffer + 1, &data);
+ }
+
+ return data;
}
static uint32_t data_1(uint16_t buflen, const uint8_t *buffer)
{
- const uint8_t *const start = buffer + 5;
- return buflen > 7 ? net_ntohl(*(const uint32_t *)start) : 0;
+ uint32_t data = 0;
+
+ if (buflen > 7) {
+ net_unpack_u32(buffer + 5, &data);
+ }
+
+ return data;
}
static void loglogdata(const Logger *log, const char *message, const uint8_t *buffer,
@@ -426,13 +433,13 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
int error = net_error();
const char *strerror = net_new_strerror(error);
LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x",
- buffer[0], message, (buflen < 999 ? buflen : 999), 'E',
+ buffer[0], message, min_u16(buflen, 999), 'E',
ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), error,
strerror, data_0(buflen, buffer), data_1(buflen, buffer));
net_kill_strerror(strerror);
} else if ((res > 0) && ((size_t)res <= buflen)) {
LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x",
- buffer[0], message, (res < 999 ? res : 999), ((size_t)res < buflen ? '<' : '='),
+ buffer[0], message, min_u16(res, 999), ((size_t)res < buflen ? '<' : '='),
ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), 0, "OK",
data_0(buflen, buffer), data_1(buflen, buffer));
} else { /* empty or overwrite */
diff --git a/protocols/Tox/libtox/src/toxcore/onion_client.c b/protocols/Tox/libtox/src/toxcore/onion_client.c
index 1c3b34dabf..d11a91e81d 100644
--- a/protocols/Tox/libtox/src/toxcore/onion_client.c
+++ b/protocols/Tox/libtox/src/toxcore/onion_client.c
@@ -232,27 +232,35 @@ static int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uin
*/
uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num)
{
- unsigned int i;
-
if (!max_num) {
return 0;
}
- unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;
+ const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES);
+ uint16_t i = 0;
- if (num_nodes == 0) {
- return 0;
+ while (i < max_num && i < num_nodes) {
+ nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes];
+ ++i;
}
- if (num_nodes < max_num) {
- max_num = num_nodes;
- }
+ for (uint16_t j = 0; i < max_num && j < MAX_PATH_NODES && j < onion_c->path_nodes_index_bs; ++j) {
+ bool already_saved = false;
- for (i = 0; i < max_num; ++i) {
- nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes];
+ for (uint16_t k = 0; k < num_nodes; ++k) {
+ if (public_key_cmp(nodes[k].public_key, onion_c->path_nodes_bs[j].public_key) == 0) {
+ already_saved = true;
+ break;
+ }
+ }
+
+ if (!already_saved) {
+ nodes[i] = onion_c->path_nodes_bs[j];
+ ++i;
+ }
}
- return max_num;
+ return i;
}
/* Put up to max_num random nodes in nodes.
@@ -267,7 +275,7 @@ static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format
return 0;
}
- const uint32_t num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;
+ const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES);
// if (dht_non_lan_connected(onion_c->dht)) {
if (dht_isconnected(onion_c->dht)) {
@@ -293,8 +301,7 @@ static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format
nodes[i] = onion_c->path_nodes[random_u32() % num_nodes];
}
} else {
- unsigned int num_nodes_bs = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs :
- MAX_PATH_NODES;
+ const uint16_t num_nodes_bs = min_u16(onion_c->path_nodes_index_bs, MAX_PATH_NODES);
if (num_nodes_bs == 0) {
return 0;
@@ -1611,9 +1618,8 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum)
}
if (count != MAX_ONION_CLIENTS) {
- unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;
-
- unsigned int n = num_nodes;
+ const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES);
+ uint16_t n = num_nodes;
if (num_nodes > (MAX_ONION_CLIENTS / 2)) {
n = (MAX_ONION_CLIENTS / 2);
@@ -1732,14 +1738,14 @@ static void do_announce(Onion_Client *onion_c)
}
if (count != MAX_ONION_CLIENTS_ANNOUNCE) {
- unsigned int num_nodes;
+ uint16_t num_nodes;
Node_format *path_nodes;
if (random_u08() % 2 == 0 || onion_c->path_nodes_index == 0) {
- num_nodes = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : MAX_PATH_NODES;
+ num_nodes = min_u16(onion_c->path_nodes_index_bs, MAX_PATH_NODES);
path_nodes = onion_c->path_nodes_bs;
} else {
- num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;
+ num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES);
path_nodes = onion_c->path_nodes;
}
diff --git a/protocols/Tox/libtox/src/toxcore/state.c b/protocols/Tox/libtox/src/toxcore/state.c
index 29b4af88a3..bca7a1512d 100644
--- a/protocols/Tox/libtox/src/toxcore/state.c
+++ b/protocols/Tox/libtox/src/toxcore/state.c
@@ -16,10 +16,10 @@ int state_load(const Logger *log, state_load_cb *state_load_callback, void *oute
while (length >= size_head) {
uint32_t length_sub;
- lendian_to_host32(&length_sub, data);
+ lendian_bytes_to_host32(&length_sub, data);
uint32_t cookie_type;
- lendian_to_host32(&cookie_type, data + sizeof(uint32_t));
+ lendian_bytes_to_host32(&cookie_type, data + sizeof(uint32_t));
data += size_head;
length -= size_head;
@@ -63,9 +63,9 @@ int state_load(const Logger *log, state_load_cb *state_load_callback, void *oute
uint8_t *state_write_section_header(uint8_t *data, uint16_t cookie_type, uint32_t len, uint32_t section_type)
{
- host_to_lendian32(data, len);
+ host_to_lendian_bytes32(data, len);
data += sizeof(uint32_t);
- host_to_lendian32(data, (host_tolendian16(cookie_type) << 16) | host_tolendian16(section_type));
+ host_to_lendian_bytes32(data, (host_to_lendian16(cookie_type) << 16) | host_to_lendian16(section_type));
data += sizeof(uint32_t);
return data;
}
@@ -79,12 +79,34 @@ uint16_t lendian_to_host16(uint16_t lendian)
#endif
}
-uint16_t host_tolendian16(uint16_t host)
+uint16_t host_to_lendian16(uint16_t host)
{
return lendian_to_host16(host);
}
-void host_to_lendian32(uint8_t *dest, uint32_t num)
+void host_to_lendian_bytes64(uint8_t *dest, uint64_t num)
+{
+#ifdef WORDS_BIGENDIAN
+ num = ((num << 8) & 0xFF00FF00FF00FF00) | ((num >> 8) & 0xFF00FF00FF00FF);
+ num = ((num << 16) & 0xFFFF0000FFFF0000) | ((num >> 16) & 0xFFFF0000FFFF);
+ num = (num << 32) | (num >> 32);
+#endif
+ memcpy(dest, &num, sizeof(uint64_t));
+}
+
+void lendian_bytes_to_host64(uint64_t *dest, const uint8_t *lendian)
+{
+ uint64_t d;
+ memcpy(&d, lendian, sizeof(uint64_t));
+#ifdef WORDS_BIGENDIAN
+ d = ((d << 8) & 0xFF00FF00FF00FF00) | ((d >> 8) & 0xFF00FF00FF00FF);
+ d = ((d << 16) & 0xFFFF0000FFFF0000) | ((d >> 16) & 0xFFFF0000FFFF);
+ d = (d << 32) | (d >> 32);
+#endif
+ *dest = d;
+}
+
+void host_to_lendian_bytes32(uint8_t *dest, uint32_t num)
{
#ifdef WORDS_BIGENDIAN
num = ((num << 8) & 0xFF00FF00) | ((num >> 8) & 0xFF00FF);
@@ -93,7 +115,7 @@ void host_to_lendian32(uint8_t *dest, uint32_t num)
memcpy(dest, &num, sizeof(uint32_t));
}
-void lendian_to_host32(uint32_t *dest, const uint8_t *lendian)
+void lendian_bytes_to_host32(uint32_t *dest, const uint8_t *lendian)
{
uint32_t d;
memcpy(&d, lendian, sizeof(uint32_t));
@@ -103,3 +125,21 @@ void lendian_to_host32(uint32_t *dest, const uint8_t *lendian)
#endif
*dest = d;
}
+
+void host_to_lendian_bytes16(uint8_t *dest, uint16_t num)
+{
+#ifdef WORDS_BIGENDIAN
+ num = (num << 8) | (num >> 8);
+#endif
+ memcpy(dest, &num, sizeof(uint16_t));
+}
+
+void lendian_bytes_to_host16(uint16_t *dest, const uint8_t *lendian)
+{
+ uint16_t d;
+ memcpy(&d, lendian, sizeof(uint16_t));
+#ifdef WORDS_BIGENDIAN
+ d = (d << 8) | (d >> 8);
+#endif
+ *dest = d;
+}
diff --git a/protocols/Tox/libtox/src/toxcore/state.h b/protocols/Tox/libtox/src/toxcore/state.h
index 2d1f62c36d..829036d8dd 100644
--- a/protocols/Tox/libtox/src/toxcore/state.h
+++ b/protocols/Tox/libtox/src/toxcore/state.h
@@ -18,6 +18,23 @@
extern "C" {
#endif
+#define STATE_COOKIE_GLOBAL 0x15ed1b1f
+
+#define STATE_COOKIE_TYPE 0x01ce
+
+typedef enum State_Type {
+ STATE_TYPE_NOSPAMKEYS = 1,
+ STATE_TYPE_DHT = 2,
+ STATE_TYPE_FRIENDS = 3,
+ STATE_TYPE_NAME = 4,
+ STATE_TYPE_STATUSMESSAGE = 5,
+ STATE_TYPE_STATUS = 6,
+ STATE_TYPE_TCP_RELAY = 10,
+ STATE_TYPE_PATH_NODE = 11,
+ STATE_TYPE_CONFERENCES = 20,
+ STATE_TYPE_END = 255,
+} State_Type;
+
// Returned by the state_load_cb to instruct the loader on what to do next.
typedef enum State_Load_Status {
// Continue loading state data sections.
@@ -39,10 +56,16 @@ uint8_t *state_write_section_header(uint8_t *data, uint16_t cookie_type, uint32_
// Utilities for state data serialisation.
uint16_t lendian_to_host16(uint16_t lendian);
-uint16_t host_tolendian16(uint16_t host);
+uint16_t host_to_lendian16(uint16_t host);
+
+void host_to_lendian_bytes64(uint8_t *dest, uint64_t num);
+void lendian_bytes_to_host64(uint64_t *dest, const uint8_t *lendian);
+
+void host_to_lendian_bytes32(uint8_t *dest, uint32_t num);
+void lendian_bytes_to_host32(uint32_t *dest, const uint8_t *lendian);
-void host_to_lendian32(uint8_t *dest, uint32_t num);
-void lendian_to_host32(uint32_t *dest, const uint8_t *lendian);
+void host_to_lendian_bytes16(uint8_t *dest, uint16_t num);
+void lendian_bytes_to_host16(uint16_t *dest, const uint8_t *lendian);
#ifdef __cplusplus
} // extern "C"
diff --git a/protocols/Tox/libtox/src/toxcore/tox.api.h b/protocols/Tox/libtox/src/toxcore/tox.api.h
index 5378847358..237254de73 100644
--- a/protocols/Tox/libtox/src/toxcore/tox.api.h
+++ b/protocols/Tox/libtox/src/toxcore/tox.api.h
@@ -182,7 +182,7 @@ const VERSION_MINOR = 2;
* The patch or revision number. Incremented when bugfixes are applied without
* changing any functionality or API or ABI.
*/
-const VERSION_PATCH = 8;
+const VERSION_PATCH = 9;
/**
* A macro to check at preprocessing time whether the client code is compatible
@@ -2257,32 +2257,32 @@ namespace conference {
CONFERENCE_NOT_FOUND,
}
-
- namespace peer {
-
+ /**
+ * Error codes for peer info queries.
+ */
+ error for peer_query {
/**
- * Error codes for peer info queries.
+ * The conference number passed did not designate a valid conference.
*/
- error for query {
- /**
- * The conference number passed did not designate a valid conference.
- */
- CONFERENCE_NOT_FOUND,
- /**
- * The peer number passed did not designate a valid peer.
- */
- PEER_NOT_FOUND,
- /**
- * The client is not connected to the conference.
- */
- NO_CONNECTION,
- }
+ CONFERENCE_NOT_FOUND,
+ /**
+ * The peer number passed did not designate a valid peer.
+ */
+ PEER_NOT_FOUND,
+ /**
+ * The client is not connected to the conference.
+ */
+ NO_CONNECTION,
+ }
+
+
+ namespace peer {
/**
* Return the number of peers in the conference. Return value is unspecified on failure.
*/
const uint32_t count(uint32_t conference_number)
- with error for query;
+ with error for peer_query;
uint8_t[size] name {
@@ -2290,7 +2290,7 @@ namespace conference {
* Return the length of the peer's name. Return value is unspecified on failure.
*/
size(uint32_t conference_number, uint32_t peer_number)
- with error for query;
+ with error for peer_query;
/**
* Copy the name of peer_number who is in conference_number to name.
@@ -2299,7 +2299,7 @@ namespace conference {
* @return true on success.
*/
get(uint32_t conference_number, uint32_t peer_number)
- with error for query;
+ with error for peer_query;
}
/**
@@ -2310,17 +2310,63 @@ namespace conference {
*/
uint8_t[PUBLIC_KEY_SIZE] public_key {
get(uint32_t conference_number, uint32_t peer_number)
- with error for query;
+ with error for peer_query;
}
/**
* Return true if passed peer_number corresponds to our own.
*/
const bool number_is_ours(uint32_t conference_number, uint32_t peer_number)
- with error for query;
+ with error for peer_query;
}
+ namespace offline_peer {
+
+ /**
+ * Return the number of offline peers in the conference. Return value is unspecified on failure.
+ */
+ const uint32_t count(uint32_t conference_number)
+ with error for peer_query;
+
+ uint8_t[size] name {
+
+ /**
+ * Return the length of the offline peer's name. Return value is unspecified on failure.
+ */
+ size(uint32_t conference_number, uint32_t offline_peer_number)
+ with error for peer_query;
+
+ /**
+ * Copy the name of offline_peer_number who is in conference_number to name.
+ * name must be at least $MAX_NAME_LENGTH long.
+ *
+ * @return true on success.
+ */
+ get(uint32_t conference_number, uint32_t offline_peer_number)
+ with error for peer_query;
+ }
+
+ /**
+ * Copy the public key of offline_peer_number who is in conference_number to public_key.
+ * public_key must be $PUBLIC_KEY_SIZE long.
+ *
+ * @return true on success.
+ */
+ uint8_t[PUBLIC_KEY_SIZE] public_key {
+ get(uint32_t conference_number, uint32_t offline_peer_number)
+ with error for peer_query;
+ }
+
+ /**
+ * Return a unix-time timestamp of the last time offline_peer_number was seen to be active.
+ */
+ uint64_t last_active {
+ get(uint32_t conference_number, uint32_t offline_peer_number)
+ with error for peer_query;
+ }
+
+ }
/**
* Invites a friend to a conference.
diff --git a/protocols/Tox/libtox/src/toxcore/tox.c b/protocols/Tox/libtox/src/toxcore/tox.c
index 5258e9b6e3..d59094afa3 100644
--- a/protocols/Tox/libtox/src/toxcore/tox.c
+++ b/protocols/Tox/libtox/src/toxcore/tox.c
@@ -328,6 +328,51 @@ bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)
return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch);
}
+static State_Load_Status state_load_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
+{
+ const Tox *tox = (const Tox *)outer;
+ State_Load_Status status = STATE_LOAD_STATUS_CONTINUE;
+
+ if (messenger_load_state_section(tox->m, data, length, type, &status)
+ || conferences_load_state_section(tox->m->conferences_object, data, length, type, &status)) {
+ return status;
+ }
+
+ if (type == STATE_TYPE_END) {
+ if (length != 0) {
+ return STATE_LOAD_STATUS_ERROR;
+ }
+
+ return STATE_LOAD_STATUS_END;
+ }
+
+ LOGGER_ERROR(tox->m->log, "Load state: contains unrecognized part (len %u, type %u)\n",
+ length, type);
+
+ return STATE_LOAD_STATUS_CONTINUE;
+}
+
+/* Load tox from data of size length. */
+static int tox_load(Tox *tox, const uint8_t *data, uint32_t length)
+{
+ uint32_t data32[2];
+ const uint32_t cookie_len = sizeof(data32);
+
+ if (length < cookie_len) {
+ return -1;
+ }
+
+ memcpy(data32, data, sizeof(uint32_t));
+ lendian_bytes_to_host32(data32 + 1, data + sizeof(uint32_t));
+
+ if (data32[0] != 0 || data32[1] != STATE_COOKIE_GLOBAL) {
+ return -1;
+ }
+
+ return state_load(tox->m->log, state_load_callback, tox, data + cookie_len,
+ length - cookie_len, STATE_COOKIE_TYPE);
+}
+
Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
{
@@ -488,7 +533,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
}
if (load_savedata_tox
- && messenger_load(m, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
+ && tox_load(tox, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
} else if (load_savedata_sk) {
load_secret_key(m->net_crypto, tox_options_get_savedata_data(opts));
@@ -530,25 +575,52 @@ void tox_kill(Tox *tox)
}
Messenger *m = tox->m;
- assert(m->msi_packet == nullptr && "Attempted to kill tox while toxav is still alive");
+ LOGGER_ASSERT(m->log, m->msi_packet == nullptr, "Attempted to kill tox while toxav is still alive");
kill_groupchats(m->conferences_object);
kill_messenger(m);
mono_time_free(tox->mono_time);
free(tox);
}
+static uint32_t end_size(void)
+{
+ return 2 * sizeof(uint32_t);
+}
+
+static void end_save(uint8_t *data)
+{
+ state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_END);
+}
+
size_t tox_get_savedata_size(const Tox *tox)
{
const Messenger *m = tox->m;
- return messenger_size(m);
+ return 2 * sizeof(uint32_t)
+ + messenger_size(m)
+ + conferences_size(m->conferences_object)
+ + end_size();
}
void tox_get_savedata(const Tox *tox, uint8_t *savedata)
{
- if (savedata) {
- const Messenger *m = tox->m;
- messenger_save(m, savedata);
+ if (savedata == nullptr) {
+ return;
}
+
+ memset(savedata, 0, tox_get_savedata_size(tox));
+
+ const uint32_t size32 = sizeof(uint32_t);
+
+ // write cookie
+ memset(savedata, 0, size32);
+ savedata += size32;
+ host_to_lendian_bytes32(savedata, STATE_COOKIE_GLOBAL);
+ savedata += size32;
+
+ const Messenger *m = tox->m;
+ savedata = messenger_save(m, savedata);
+ savedata = conferences_save(m->conferences_object, savedata);
+ end_save(savedata);
}
bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, Tox_Err_Bootstrap *error)
@@ -565,7 +637,7 @@ bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *pub
IP_Port *root;
- int32_t count = net_getipport(host, &root, TOX_SOCK_DGRAM);
+ const int32_t count = net_getipport(host, &root, TOX_SOCK_DGRAM);
if (count == -1) {
net_freeipport(root);
@@ -641,7 +713,7 @@ Tox_Connection tox_self_get_connection_status(const Tox *tox)
{
const Messenger *m = tox->m;
- unsigned int ret = onion_connection_status(m->onion_c);
+ const unsigned int ret = onion_connection_status(m->onion_c);
if (ret == 2) {
return TOX_CONNECTION_UDP;
@@ -793,7 +865,7 @@ Tox_User_Status tox_self_get_status(const Tox *tox)
return (Tox_User_Status)status;
}
-static void set_friend_error(int32_t ret, Tox_Err_Friend_Add *error)
+static void set_friend_error(const Logger *log, int32_t ret, Tox_Err_Friend_Add *error)
{
switch (ret) {
case FAERR_TOOLONG:
@@ -826,7 +898,7 @@ static void set_friend_error(int32_t ret, Tox_Err_Friend_Add *error)
default:
/* can't happen */
- assert(!"impossible: unknown friend-add error");
+ LOGGER_FATAL(log, "impossible: unknown friend-add error");
break;
}
}
@@ -840,14 +912,14 @@ uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message
}
Messenger *m = tox->m;
- int32_t ret = m_addfriend(m, address, message, length);
+ const int32_t ret = m_addfriend(m, address, message, length);
if (ret >= 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
return ret;
}
- set_friend_error(ret, error);
+ set_friend_error(m->log, ret, error);
return UINT32_MAX;
}
@@ -859,21 +931,21 @@ uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, Tox_Err_F
}
Messenger *m = tox->m;
- int32_t ret = m_addfriend_norequest(m, public_key);
+ const int32_t ret = m_addfriend_norequest(m, public_key);
if (ret >= 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
return ret;
}
- set_friend_error(ret, error);
+ set_friend_error(m->log, ret, error);
return UINT32_MAX;
}
bool tox_friend_delete(Tox *tox, uint32_t friend_number, Tox_Err_Friend_Delete *error)
{
Messenger *m = tox->m;
- int ret = m_delfriend(m, friend_number);
+ const int ret = m_delfriend(m, friend_number);
// TODO(irungentoo): handle if realloc fails?
if (ret == -1) {
@@ -893,7 +965,7 @@ uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, Tox
}
const Messenger *m = tox->m;
- int32_t ret = getfriend_id(m, public_key);
+ const int32_t ret = getfriend_id(m, public_key);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND);
@@ -931,7 +1003,7 @@ bool tox_friend_exists(const Tox *tox, uint32_t friend_number)
uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Get_Last_Online *error)
{
const Messenger *m = tox->m;
- uint64_t timestamp = m_get_last_online(m, friend_number);
+ const uint64_t timestamp = m_get_last_online(m, friend_number);
if (timestamp == UINT64_MAX) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND);
@@ -960,7 +1032,7 @@ void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list)
size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
{
const Messenger *m = tox->m;
- int ret = m_get_name_size(m, friend_number);
+ const int ret = m_get_name_size(m, friend_number);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -979,7 +1051,7 @@ bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name,
}
const Messenger *m = tox->m;
- int ret = getname(m, friend_number, name);
+ const int ret = getname(m, friend_number, name);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -998,7 +1070,7 @@ void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback)
size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
{
const Messenger *m = tox->m;
- int ret = m_get_statusmessage_size(m, friend_number);
+ const int ret = m_get_statusmessage_size(m, friend_number);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -1026,7 +1098,7 @@ bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8
}
const int ret = m_copy_statusmessage(m, friend_number, status_message, size);
- assert(ret == size && "concurrency problem: friend status message changed");
+ LOGGER_ASSERT(m->log, ret == size, "concurrency problem: friend status message changed");
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
return ret == size;
@@ -1041,7 +1113,7 @@ Tox_User_Status tox_friend_get_status(const Tox *tox, uint32_t friend_number, To
{
const Messenger *m = tox->m;
- int ret = m_get_userstatus(m, friend_number);
+ const int ret = m_get_userstatus(m, friend_number);
if (ret == USERSTATUS_INVALID) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -1061,7 +1133,7 @@ Tox_Connection tox_friend_get_connection_status(const Tox *tox, uint32_t friend_
{
const Messenger *m = tox->m;
- int ret = m_get_friend_connectionstatus(m, friend_number);
+ const int ret = m_get_friend_connectionstatus(m, friend_number);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -1080,7 +1152,7 @@ void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_statu
bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
{
const Messenger *m = tox->m;
- int ret = m_get_istyping(m, friend_number);
+ const int ret = m_get_istyping(m, friend_number);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
@@ -1109,7 +1181,7 @@ bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, Tox_Err_
return 1;
}
-static void set_message_error(int ret, Tox_Err_Friend_Send_Message *error)
+static void set_message_error(const Logger *log, int ret, Tox_Err_Friend_Send_Message *error)
{
switch (ret) {
case 0:
@@ -1133,9 +1205,12 @@ static void set_message_error(int ret, Tox_Err_Friend_Send_Message *error)
break;
case -5:
+ LOGGER_FATAL(log, "impossible: Messenger and Tox disagree on message types");
+ break;
+
default:
/* can't happen */
- assert(!"impossible: unknown send-message error");
+ LOGGER_FATAL(log, "impossible: unknown send-message error: %d", ret);
break;
}
}
@@ -1155,7 +1230,7 @@ uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, Tox_Message_T
Messenger *m = tox->m;
uint32_t message_id = 0;
- set_message_error(m_send_message_generic(m, friend_number, type, message, length, &message_id), error);
+ set_message_error(m->log, m_send_message_generic(m, friend_number, type, message, length, &message_id), error);
return message_id;
}
@@ -1188,7 +1263,7 @@ bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, To
Tox_Err_File_Control *error)
{
Messenger *m = tox->m;
- int ret = file_control(m, friend_number, file_number, control);
+ const int ret = file_control(m, friend_number, file_number, control);
if (ret == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);
@@ -1237,7 +1312,7 @@ bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint6
Tox_Err_File_Seek *error)
{
Messenger *m = tox->m;
- int ret = file_seek(m, friend_number, file_number, position);
+ const int ret = file_seek(m, friend_number, file_number, position);
if (ret == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK);
@@ -1289,7 +1364,7 @@ bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_
}
const Messenger *m = tox->m;
- int ret = file_get_id(m, friend_number, file_number, file_id);
+ const int ret = file_get_id(m, friend_number, file_number, file_id);
if (ret == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK);
@@ -1322,7 +1397,7 @@ uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t
}
Messenger *m = tox->m;
- long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length);
+ const long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length);
if (file_num >= 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
@@ -1355,7 +1430,7 @@ bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number,
size_t length, Tox_Err_File_Send_Chunk *error)
{
Messenger *m = tox->m;
- int ret = file_data(m, friend_number, file_number, position, data, length);
+ const int ret = file_data(m, friend_number, file_number, position, data, length);
if (ret == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);
@@ -1444,7 +1519,7 @@ void tox_callback_conference_peer_list_changed(Tox *tox, tox_conference_peer_lis
uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error)
{
Messenger *m = tox->m;
- int ret = add_groupchat(m->conferences_object, GROUPCHAT_TYPE_TEXT);
+ const int ret = add_groupchat(m->conferences_object, GROUPCHAT_TYPE_TEXT);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT);
@@ -1458,7 +1533,7 @@ uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error)
bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error)
{
Messenger *m = tox->m;
- int ret = del_groupchat(m->conferences_object, conference_number);
+ const int ret = del_groupchat(m->conferences_object, conference_number, true);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND);
@@ -1472,7 +1547,7 @@ bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Confere
uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Peer_Query *error)
{
const Messenger *m = tox->m;
- int ret = group_number_peers(m->conferences_object, conference_number);
+ const int ret = group_number_peers(m->conferences_object, conference_number, false);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
@@ -1487,7 +1562,7 @@ size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_num
Tox_Err_Conference_Peer_Query *error)
{
const Messenger *m = tox->m;
- int ret = group_peername_size(m->conferences_object, conference_number, peer_number);
+ const int ret = group_peername_size(m->conferences_object, conference_number, peer_number, false);
switch (ret) {
case -1:
@@ -1507,7 +1582,7 @@ bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, ui
Tox_Err_Conference_Peer_Query *error)
{
const Messenger *m = tox->m;
- int ret = group_peername(m->conferences_object, conference_number, peer_number, name);
+ const int ret = group_peername(m->conferences_object, conference_number, peer_number, name, false);
switch (ret) {
case -1:
@@ -1527,7 +1602,7 @@ bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_numb
uint8_t *public_key, Tox_Err_Conference_Peer_Query *error)
{
const Messenger *m = tox->m;
- int ret = group_peer_pubkey(m->conferences_object, conference_number, peer_number, public_key);
+ const int ret = group_peer_pubkey(m->conferences_object, conference_number, peer_number, public_key, false);
switch (ret) {
case -1:
@@ -1547,7 +1622,7 @@ bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_numb
Tox_Err_Conference_Peer_Query *error)
{
const Messenger *m = tox->m;
- int ret = group_peernumber_is_ours(m->conferences_object, conference_number, peer_number);
+ const int ret = group_peernumber_is_ours(m->conferences_object, conference_number, peer_number);
switch (ret) {
case -1:
@@ -1567,11 +1642,111 @@ bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_numb
return ret;
}
+uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number,
+ Tox_Err_Conference_Peer_Query *error)
+{
+ const Messenger *m = tox->m;
+ const int ret = group_number_peers(m->conferences_object, conference_number, true);
+
+ if (ret == -1) {
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
+ return UINT32_MAX;
+ }
+
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
+ return ret;
+}
+
+size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number,
+ Tox_Err_Conference_Peer_Query *error)
+{
+ const Messenger *m = tox->m;
+ const int ret = group_peername_size(m->conferences_object, conference_number, offline_peer_number, true);
+
+ switch (ret) {
+ case -1:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
+ return -1;
+
+ case -2:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
+ return -1;
+ }
+
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
+ return ret;
+}
+
+bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number,
+ uint8_t *name,
+ Tox_Err_Conference_Peer_Query *error)
+{
+ const Messenger *m = tox->m;
+ const int ret = group_peername(m->conferences_object, conference_number, offline_peer_number, name, true);
+
+ switch (ret) {
+ case -1:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
+ return false;
+
+ case -2:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
+ return false;
+ }
+
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
+ return true;
+}
+
+bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number,
+ uint8_t *public_key, Tox_Err_Conference_Peer_Query *error)
+{
+ const Messenger *m = tox->m;
+ const int ret = group_peer_pubkey(m->conferences_object, conference_number, offline_peer_number, public_key, true);
+
+ switch (ret) {
+ case -1:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
+ return false;
+
+ case -2:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
+ return false;
+ }
+
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
+ return true;
+}
+
+uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number,
+ Tox_Err_Conference_Peer_Query *error)
+{
+ const Messenger *m = tox->m;
+ uint64_t last_active = UINT64_MAX;
+ const int ret = group_frozen_last_active(m->conferences_object, conference_number, offline_peer_number, &last_active);
+
+ switch (ret) {
+ case -1:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
+ return UINT64_MAX;
+
+ case -2:
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
+ return UINT64_MAX;
+ }
+
+ SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
+ return last_active;
+}
+
bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number,
Tox_Err_Conference_Invite *error)
{
Messenger *m = tox->m;
- int ret = invite_friend(m->conferences_object, friend_number, conference_number);
+ const int ret = invite_friend(m->conferences_object, friend_number, conference_number);
switch (ret) {
case -1:
@@ -1595,7 +1770,7 @@ uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *co
Tox_Err_Conference_Join *error)
{
Messenger *m = tox->m;
- int ret = join_groupchat(m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length);
+ const int ret = join_groupchat(m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length);
switch (ret) {
case -1:
@@ -1664,7 +1839,7 @@ bool tox_conference_send_message(Tox *tox, uint32_t conference_number, Tox_Messa
size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Title *error)
{
const Messenger *m = tox->m;
- int ret = group_title_get_size(m->conferences_object, conference_number);
+ const int ret = group_title_get_size(m->conferences_object, conference_number);
switch (ret) {
case -1:
@@ -1684,7 +1859,7 @@ bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_
Tox_Err_Conference_Title *error)
{
const Messenger *m = tox->m;
- int ret = group_title_get(m->conferences_object, conference_number, title);
+ const int ret = group_title_get(m->conferences_object, conference_number, title);
switch (ret) {
case -1:
@@ -1704,7 +1879,7 @@ bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_
Tox_Err_Conference_Title *error)
{
Messenger *m = tox->m;
- int ret = group_title_send(m->conferences_object, conference_number, title, length);
+ const int ret = group_title_send(m->conferences_object, conference_number, title, length);
switch (ret) {
case -1:
@@ -1733,7 +1908,7 @@ size_t tox_conference_get_chatlist_size(const Tox *tox)
void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist)
{
const Messenger *m = tox->m;
- size_t list_size = tox_conference_get_chatlist_size(tox);
+ const size_t list_size = tox_conference_get_chatlist_size(tox);
copy_chatlist(m->conferences_object, chatlist, list_size);
}
@@ -1741,7 +1916,7 @@ Tox_Conference_Type tox_conference_get_type(const Tox *tox, uint32_t conference_
Tox_Err_Conference_Get_Type *error)
{
const Messenger *m = tox->m;
- int ret = group_get_type(m->conferences_object, conference_number);
+ const int ret = group_get_type(m->conferences_object, conference_number);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND);
@@ -1770,7 +1945,7 @@ uint32_t tox_conference_by_id(const Tox *tox, const uint8_t *id, Tox_Err_Confere
return UINT32_MAX;
}
- int32_t ret = conference_by_id(tox->m->conferences_object, id);
+ const int32_t ret = conference_by_id(tox->m->conferences_object, id);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND);
@@ -1855,7 +2030,7 @@ bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_
return 0;
}
- int ret = m_send_custom_lossy_packet(m, friend_number, data, length);
+ const int ret = m_send_custom_lossy_packet(m, friend_number, data, length);
set_custom_packet_error(ret, error);
@@ -1886,7 +2061,7 @@ bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uin
return 0;
}
- int ret = send_custom_lossless_packet(m, friend_number, data, length);
+ const int ret = send_custom_lossless_packet(m, friend_number, data, length);
set_custom_packet_error(ret, error);
@@ -1913,7 +2088,7 @@ void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id)
uint16_t tox_self_get_udp_port(const Tox *tox, Tox_Err_Get_Port *error)
{
const Messenger *m = tox->m;
- uint16_t port = net_htons(net_port(m->net));
+ const uint16_t port = net_htons(net_port(m->net));
if (port) {
SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
diff --git a/protocols/Tox/libtox/src/toxcore/tox.h b/protocols/Tox/libtox/src/toxcore/tox.h
index ee8a01cc7d..ba67d5ad30 100644
--- a/protocols/Tox/libtox/src/toxcore/tox.h
+++ b/protocols/Tox/libtox/src/toxcore/tox.h
@@ -183,7 +183,7 @@ uint32_t tox_version_minor(void);
* The patch or revision number. Incremented when bugfixes are applied without
* changing any functionality or API or ABI.
*/
-#define TOX_VERSION_PATCH 8
+#define TOX_VERSION_PATCH 9
uint32_t tox_version_patch(void);
@@ -2631,6 +2631,42 @@ bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_numb
bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
TOX_ERR_CONFERENCE_PEER_QUERY *error);
+/**
+ * Return the number of offline peers in the conference. Return value is unspecified on failure.
+ */
+uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number,
+ TOX_ERR_CONFERENCE_PEER_QUERY *error);
+
+/**
+ * Return the length of the offline peer's name. Return value is unspecified on failure.
+ */
+size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error);
+
+/**
+ * Copy the name of offline_peer_number who is in conference_number to name.
+ * name must be at least TOX_MAX_NAME_LENGTH long.
+ *
+ * @return true on success.
+ */
+bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number,
+ uint8_t *name, TOX_ERR_CONFERENCE_PEER_QUERY *error);
+
+/**
+ * Copy the public key of offline_peer_number who is in conference_number to public_key.
+ * public_key must be TOX_PUBLIC_KEY_SIZE long.
+ *
+ * @return true on success.
+ */
+bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number, uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error);
+
+/**
+ * Return a unix-time timestamp of the last time offline_peer_number was seen to be active.
+ */
+uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
+ uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error);
+
typedef enum TOX_ERR_CONFERENCE_INVITE {
/**
diff --git a/protocols/Tox/libtox/src/toxcore/tox_api.c b/protocols/Tox/libtox/src/toxcore/tox_api.c
index 871239686a..025c745623 100644
--- a/protocols/Tox/libtox/src/toxcore/tox_api.c
+++ b/protocols/Tox/libtox/src/toxcore/tox_api.c
@@ -19,6 +19,8 @@ CONST_FUNCTION(version_minor, VERSION_MINOR)
CONST_FUNCTION(version_patch, VERSION_PATCH)
CONST_FUNCTION(public_key_size, PUBLIC_KEY_SIZE)
CONST_FUNCTION(secret_key_size, SECRET_KEY_SIZE)
+CONST_FUNCTION(conference_uid_size, CONFERENCE_UID_SIZE)
+CONST_FUNCTION(conference_id_size, CONFERENCE_ID_SIZE)
CONST_FUNCTION(nospam_size, NOSPAM_SIZE)
CONST_FUNCTION(address_size, ADDRESS_SIZE)
CONST_FUNCTION(max_name_length, MAX_NAME_LENGTH)
@@ -44,14 +46,14 @@ void tox_options_set_##ns##name(struct Tox_Options *options, type name) \
ACCESSORS(bool,, ipv6_enabled)
ACCESSORS(bool,, udp_enabled)
-ACCESSORS(TOX_PROXY_TYPE, proxy_, type)
+ACCESSORS(Tox_Proxy_Type, proxy_, type)
ACCESSORS(const char *, proxy_, host)
ACCESSORS(uint16_t, proxy_, port)
ACCESSORS(uint16_t,, start_port)
ACCESSORS(uint16_t,, end_port)
ACCESSORS(uint16_t,, tcp_port)
ACCESSORS(bool,, hole_punching_enabled)
-ACCESSORS(TOX_SAVEDATA_TYPE, savedata_, type)
+ACCESSORS(Tox_Savedata_Type, savedata_, type)
ACCESSORS(size_t, savedata_, length)
ACCESSORS(tox_log_cb *, log_, callback)
ACCESSORS(void *, log_, user_data)
@@ -81,7 +83,7 @@ void tox_options_default(struct Tox_Options *options)
}
}
-struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error)
+struct Tox_Options *tox_options_new(Tox_Err_Options_New *error)
{
struct Tox_Options *options = (struct Tox_Options *)malloc(sizeof(struct Tox_Options));
diff --git a/protocols/Tox/libtox/src/toxcore/util.c b/protocols/Tox/libtox/src/toxcore/util.c
index adc0dc09dc..73e16c4585 100644
--- a/protocols/Tox/libtox/src/toxcore/util.c
+++ b/protocols/Tox/libtox/src/toxcore/util.c
@@ -95,21 +95,53 @@ int create_recursive_mutex(pthread_mutex_t *mutex)
return 0;
}
+int16_t max_s16(int16_t a, int16_t b)
+{
+ return a > b ? a : b;
+}
int32_t max_s32(int32_t a, int32_t b)
{
return a > b ? a : b;
}
+int64_t max_s64(int64_t a, int64_t b)
+{
+ return a > b ? a : b;
+}
+int16_t min_s16(int16_t a, int16_t b)
+{
+ return a < b ? a : b;
+}
int32_t min_s32(int32_t a, int32_t b)
{
return a < b ? a : b;
}
+int64_t min_s64(int64_t a, int64_t b)
+{
+ return a < b ? a : b;
+}
+
+uint16_t max_u16(uint16_t a, uint16_t b)
+{
+ return a > b ? a : b;
+}
+uint32_t max_u32(uint32_t a, uint32_t b)
+{
+ return a > b ? a : b;
+}
+uint64_t max_u64(uint64_t a, uint64_t b)
+{
+ return a > b ? a : b;
+}
+uint16_t min_u16(uint16_t a, uint16_t b)
+{
+ return a < b ? a : b;
+}
uint32_t min_u32(uint32_t a, uint32_t b)
{
return a < b ? a : b;
}
-
uint64_t min_u64(uint64_t a, uint64_t b)
{
return a < b ? a : b;
diff --git a/protocols/Tox/libtox/src/toxcore/util.h b/protocols/Tox/libtox/src/toxcore/util.h
index 8558672473..79f5deb528 100644
--- a/protocols/Tox/libtox/src/toxcore/util.h
+++ b/protocols/Tox/libtox/src/toxcore/util.h
@@ -46,8 +46,23 @@ void net_to_host(uint8_t *num, uint16_t numbytes);
/* Returns -1 if failed or 0 if success */
int create_recursive_mutex(pthread_mutex_t *mutex);
+// Safe min/max functions with specific types. This forces the conversion to the
+// desired type before the comparison expression, giving the choice of
+// conversion to the caller. Use these instead of inline comparisons or MIN/MAX
+// macros (effectively inline comparisons).
+int16_t max_s16(int16_t a, int16_t b);
int32_t max_s32(int32_t a, int32_t b);
+int64_t max_s64(int64_t a, int64_t b);
+
+int16_t min_s16(int16_t a, int16_t b);
int32_t min_s32(int32_t a, int32_t b);
+int64_t min_s64(int64_t a, int64_t b);
+
+uint16_t max_u16(uint16_t a, uint16_t b);
+uint32_t max_u32(uint32_t a, uint32_t b);
+uint64_t max_u64(uint64_t a, uint64_t b);
+
+uint16_t min_u16(uint16_t a, uint16_t b);
uint32_t min_u32(uint32_t a, uint32_t b);
uint64_t min_u64(uint64_t a, uint64_t b);
diff --git a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h
index 28d7a650a4..c6a395f3eb 100644
--- a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h
+++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h
@@ -313,5 +313,10 @@ static bool is_data_encrypted(const uint8_t *data);
}
#endif
+typedef TOX_ERR_KEY_DERIVATION Tox_Err_Key_Derivation;
+typedef TOX_ERR_ENCRYPTION Tox_Err_Encryption;
+typedef TOX_ERR_DECRYPTION Tox_Err_Decryption;
+typedef TOX_ERR_GET_SALT Tox_Err_Get_Salt;
+
#endif // C_TOXCORE_TOXENCRYPTSAVE_TOXENCRYPTSAVE_H
%}
diff --git a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c
index 6221b0b6b9..a3e70b2f1e 100644
--- a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c
+++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c
@@ -91,7 +91,7 @@ void tox_pass_key_free(Tox_Pass_Key *pass_key)
* success does not say anything about the validity of the data, only that data of
* the appropriate size was copied
*/
-bool tox_get_salt(const uint8_t *data, uint8_t *salt, TOX_ERR_GET_SALT *error)
+bool tox_get_salt(const uint8_t *data, uint8_t *salt, Tox_Err_Get_Salt *error)
{
if (!data || !salt) {
SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_NULL);
@@ -121,7 +121,7 @@ bool tox_get_salt(const uint8_t *data, uint8_t *salt, TOX_ERR_GET_SALT *error)
* returns true on success
*/
Tox_Pass_Key *tox_pass_key_derive(const uint8_t *passphrase, size_t pplength,
- TOX_ERR_KEY_DERIVATION *error)
+ Tox_Err_Key_Derivation *error)
{
uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];
random_bytes(salt, sizeof salt);
@@ -132,7 +132,7 @@ Tox_Pass_Key *tox_pass_key_derive(const uint8_t *passphrase, size_t pplength,
* The salt must be TOX_PASS_SALT_LENGTH bytes in length.
*/
Tox_Pass_Key *tox_pass_key_derive_with_salt(const uint8_t *passphrase, size_t pplength,
- const uint8_t *salt, TOX_ERR_KEY_DERIVATION *error)
+ const uint8_t *salt, Tox_Err_Key_Derivation *error)
{
if (!salt || (!passphrase && pplength != 0)) {
SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL);
@@ -181,7 +181,7 @@ Tox_Pass_Key *tox_pass_key_derive_with_salt(const uint8_t *passphrase, size_t pp
* returns true on success
*/
bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t data_len, uint8_t *out,
- TOX_ERR_ENCRYPTION *error)
+ Tox_Err_Encryption *error)
{
if (data_len == 0 || !data || !key || !out) {
SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL);
@@ -227,9 +227,9 @@ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t d
* returns true on success
*/
bool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out,
- TOX_ERR_ENCRYPTION *error)
+ Tox_Err_Encryption *error)
{
- TOX_ERR_KEY_DERIVATION _error;
+ Tox_Err_Key_Derivation _error;
Tox_Pass_Key *key = tox_pass_key_derive(passphrase, pplength, &_error);
if (!key) {
@@ -255,7 +255,7 @@ bool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passp
* returns true on success
*/
bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t length, uint8_t *out,
- TOX_ERR_DECRYPTION *error)
+ Tox_Err_Decryption *error)
{
if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);
@@ -301,7 +301,7 @@ bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t l
* returns true on success
*/
bool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out,
- TOX_ERR_DECRYPTION *error)
+ Tox_Err_Decryption *error)
{
if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);
diff --git a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h
index 400483cba8..0d608b1ced 100644
--- a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h
+++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h
@@ -375,4 +375,9 @@ bool tox_is_data_encrypted(const uint8_t *data);
}
#endif
+typedef TOX_ERR_KEY_DERIVATION Tox_Err_Key_Derivation;
+typedef TOX_ERR_ENCRYPTION Tox_Err_Encryption;
+typedef TOX_ERR_DECRYPTION Tox_Err_Decryption;
+typedef TOX_ERR_GET_SALT Tox_Err_Get_Salt;
+
#endif // C_TOXCORE_TOXENCRYPTSAVE_TOXENCRYPTSAVE_H