diff --git a/CMakeLists.txt b/CMakeLists.txt index ffaa9cb4540..da0fb6467bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,7 @@ set(toxcore_PKGCONFIG_REQUIRES) # LAYER 1: Crypto core # -------------------- set(toxcore_SOURCES ${toxcore_SOURCES} + toxcore/ccompat.c toxcore/ccompat.h toxcore/crypto_core.c toxcore/crypto_core.h) @@ -240,10 +241,22 @@ set(toxcore_SOURCES ${toxcore_SOURCES} set(toxcore_SOURCES ${toxcore_SOURCES} toxcore/tox_api.c toxcore/tox.c - toxcore/tox_private.h - toxcore/tox.h) + toxcore/tox.h + toxcore/tox_events.c + toxcore/tox_events.h + toxcore/tox_private.h) set(toxcore_API_HEADERS ${toxcore_API_HEADERS} ${toxcore_SOURCE_DIR}/toxcore/tox.h^tox) +# LAYER 9: New async events API +# ------------------- +set(toxcore_SOURCES ${toxcore_SOURCES} + toxcore/events/friend_message.c + toxcore/events/internal.c + toxcore/events/internal.h + toxcore/tox_events.c + toxcore/tox_events.h) +set(toxcore_API_HEADERS ${toxcore_API_HEADERS} ${toxcore_SOURCE_DIR}/toxcore/tox_events.h^tox) + ################################################################################ # # :: Audio/Video Library @@ -441,6 +454,7 @@ auto_test(save_load) auto_test(send_message) auto_test(set_name) auto_test(set_status_message) +auto_test(tox_events) auto_test(tox_many) auto_test(tox_many_tcp) auto_test(tox_one) diff --git a/auto_tests/BUILD.bazel b/auto_tests/BUILD.bazel index 5838cb77e1f..64b8b61ab60 100644 --- a/auto_tests/BUILD.bazel +++ b/auto_tests/BUILD.bazel @@ -61,6 +61,7 @@ flaky_tests = { "//c-toxcore/toxcore:onion", "//c-toxcore/toxcore:onion_announce", "//c-toxcore/toxcore:onion_client", + "//c-toxcore/toxcore:tox_events", "//c-toxcore/toxencryptsave", "@libsodium", "@libvpx", diff --git a/auto_tests/tox_events_test.c b/auto_tests/tox_events_test.c new file mode 100644 index 00000000000..53be20e3e40 --- /dev/null +++ b/auto_tests/tox_events_test.c @@ -0,0 +1,105 @@ +/* Auto Tests: Many clients. + */ + +#include +#include +#include +#include + +#include "../testing/misc_tools.h" +#include "../toxcore/tox.h" +#include "../toxcore/tox_events.h" +#include "check_compat.h" + +static bool await_message(Tox **toxes) +{ + for (uint32_t i = 0; i < 100; ++i) { + // Ignore events on tox 1. + tox_events_free(tox_events_iterate(toxes[0])); + // Check if tox 2 got the message from tox 1. + Tox_Events *events = tox_events_iterate(toxes[1]); + + if (events != nullptr) { + ck_assert(tox_events_get_friend_messages_size(events) == 1); + const Tox_Event_Friend_Message *msg_event = tox_events_get_friend_message(events, 0); + ck_assert(tox_event_friend_message_get_message_length(msg_event) == sizeof("hello")); + const uint8_t *msg = tox_event_friend_message_get_message(msg_event); + ck_assert_msg(memcmp(msg, "hello", sizeof("hello")) == 0, + "message was not expected 'hello' but '%s'", (const char *)msg); + tox_events_free(events); + return true; + } + + c_sleep(tox_iteration_interval(toxes[0])); + } + + return false; +} + +static void test_tox_events(void) +{ + uint8_t message[sizeof("hello")]; + memcpy(message, "hello", sizeof(message)); + + Tox *toxes[2]; + uint32_t index[2]; + + for (uint32_t i = 0; i < 2; ++i) { + index[i] = i + 1; + toxes[i] = tox_new_log(nullptr, nullptr, &index[i]); + tox_events_init(toxes[i]); + ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i); + } + + uint8_t pk[TOX_PUBLIC_KEY_SIZE]; + tox_self_get_dht_id(toxes[0], pk); + tox_bootstrap(toxes[1], "localhost", tox_self_get_udp_port(toxes[0], nullptr), pk, nullptr); + + tox_self_get_public_key(toxes[0], pk); + tox_friend_add_norequest(toxes[1], pk, nullptr); + + tox_self_get_public_key(toxes[1], pk); + tox_friend_add_norequest(toxes[0], pk, nullptr); + + printf("bootstrapping and connecting 2 toxes\n"); + + while (tox_self_get_connection_status(toxes[0]) == TOX_CONNECTION_NONE || + tox_self_get_connection_status(toxes[1]) == TOX_CONNECTION_NONE) { + // Ignore connection events for now. + tox_events_free(tox_events_iterate(toxes[0])); + tox_events_free(tox_events_iterate(toxes[1])); + + c_sleep(tox_iteration_interval(toxes[0])); + } + + printf("toxes online, waiting for friend connection\n"); + + while (tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_NONE || + tox_friend_get_connection_status(toxes[1], 0, nullptr) == TOX_CONNECTION_NONE) { + // Ignore connection events for now. + tox_events_free(tox_events_iterate(toxes[0])); + tox_events_free(tox_events_iterate(toxes[1])); + + c_sleep(tox_iteration_interval(toxes[0])); + } + + printf("friends are connected via %s, now sending message\n", + tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_TCP ? "TCP" : "UDP"); + + Tox_Err_Friend_Send_Message err; + tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof(message), &err); + ck_assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK); + + ck_assert(await_message(toxes)); + + for (uint32_t i = 0; i < 2; ++i) { + tox_kill(toxes[i]); + } +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + test_tox_events(); + return 0; +} diff --git a/other/docker/autotools/run b/other/docker/autotools/run new file mode 100755 index 00000000000..c4b2c11f102 --- /dev/null +++ b/other/docker/autotools/run @@ -0,0 +1,3 @@ +#!/bin/sh + +docker build -t toxchat/toxcore-autotools -f other/docker/autotools/Dockerfile . diff --git a/other/docker/circleci/Dockerfile b/other/docker/circleci/Dockerfile index a4070a8d6d0..ef90683b92a 100644 --- a/other/docker/circleci/Dockerfile +++ b/other/docker/circleci/Dockerfile @@ -10,6 +10,7 @@ RUN apt-get update && \ libopus-dev \ libsodium-dev \ libvpx-dev \ + llvm-dev \ ninja-build \ pkg-config \ && apt-get clean \ diff --git a/other/docker/circleci/run b/other/docker/circleci/run new file mode 100755 index 00000000000..2cb57ee4589 --- /dev/null +++ b/other/docker/circleci/run @@ -0,0 +1,6 @@ +#!/bin/sh + +SANITIZER="${1:-asan}" + +docker build -t toxchat/toxcore-circleci other/docker/circleci +docker run --rm -it -v "$PWD:/c-toxcore" toxchat/toxcore-circleci "$SANITIZER" diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 07a8ce24e00..4824ce49b44 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -10,6 +10,7 @@ exports_files( cc_library( name = "ccompat", + srcs = ["ccompat.c"], hdrs = ["ccompat.h"], visibility = ["//c-toxcore:__subpackages__"], ) @@ -459,6 +460,20 @@ cc_library( ], ) +cc_library( + name = "tox_events", + srcs = ["tox_events.c"] + glob([ + "events/*.c", + "events/*.h", + ]), + hdrs = ["tox_events.h"], + visibility = ["//c-toxcore:__subpackages__"], + deps = [ + ":ccompat", + ":toxcore", + ], +) + sh_library( name = "cimple_files", srcs = glob([ diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 4aedb5228b1..1484d05d39e 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -6,6 +6,9 @@ libtoxcore_la_include_HEADERS = \ libtoxcore_la_includedir = $(includedir)/tox libtoxcore_la_SOURCES = ../toxcore/ccompat.h \ + ../toxcore/events/internal.h \ + ../toxcore/events/internal.c \ + ../toxcore/events/friend_message.c \ ../toxcore/DHT.h \ ../toxcore/DHT.c \ ../toxcore/mono_time.h \ @@ -31,8 +34,10 @@ libtoxcore_la_SOURCES = ../toxcore/ccompat.h \ ../toxcore/state.h \ ../toxcore/state.c \ ../toxcore/tox.h \ - ../toxcore/tox_private.h \ ../toxcore/tox.c \ + ../toxcore/tox_events.h \ + ../toxcore/tox_events.c \ + ../toxcore/tox_private.h \ ../toxcore/tox_api.c \ ../toxcore/util.h \ ../toxcore/util.c \ diff --git a/toxcore/ccompat.c b/toxcore/ccompat.c new file mode 100644 index 00000000000..2564b12d8ec --- /dev/null +++ b/toxcore/ccompat.c @@ -0,0 +1,15 @@ +#include "ccompat.h" + +#include +#include + +void *salloc(uint32_t size, const void *default_value) +{ + void *ptr = malloc(size); + + if (ptr != nullptr) { + memcpy(ptr, default_value, size); + } + + return ptr; +} diff --git a/toxcore/ccompat.h b/toxcore/ccompat.h index f03dbad11fc..6889364c6ca 100644 --- a/toxcore/ccompat.h +++ b/toxcore/ccompat.h @@ -10,6 +10,7 @@ #include #include +#include bool unused_for_tokstyle(void); @@ -59,8 +60,12 @@ bool unused_for_tokstyle(void); #ifndef static_assert #define static_assert(cond, msg) extern const int unused_for_static_assert #endif +#define new(T) (T *)salloc(sizeof(T), &(T){0}) +#define delete(obj) free(obj) #endif +void *salloc(uint32_t size, const void *default_value); + #ifdef __GNUC__ #define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a))) #else diff --git a/toxcore/events/friend_message.c b/toxcore/events/friend_message.c new file mode 100644 index 00000000000..08bca175b8c --- /dev/null +++ b/toxcore/events/friend_message.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. + */ + +#include "internal.h" + +#include +#include + +#include "../ccompat.h" +#include "../tox.h" +#include "../tox_events.h" + + +/***************************************************** + * + * :: struct and accessors + * + *****************************************************/ + + +struct Tox_Event_Friend_Message { + uint32_t friend_number; + Tox_Message_Type type; + uint8_t *message; + uint16_t message_length; +}; + +static void tox_event_friend_message_construct(Tox_Event_Friend_Message *friend_message) +{ + *friend_message = (Tox_Event_Friend_Message) { + 0 + }; +} +static void tox_event_friend_message_destruct(Tox_Event_Friend_Message *friend_message) +{ + free(friend_message->message); +} + +static void tox_event_friend_message_set_friend_number(Tox_Event_Friend_Message *friend_message, + uint32_t friend_number) +{ + assert(friend_message != nullptr); + friend_message->friend_number = friend_number; +} +uint32_t tox_event_friend_message_get_friend_number(const Tox_Event_Friend_Message *friend_message) +{ + assert(friend_message != nullptr); + return friend_message->friend_number; +} + +static void tox_event_friend_message_set_type(Tox_Event_Friend_Message *friend_message, Tox_Message_Type type) +{ + assert(friend_message != nullptr); + friend_message->type = type; +} +Tox_Message_Type tox_event_friend_message_get_type(const Tox_Event_Friend_Message *friend_message) +{ + assert(friend_message != nullptr); + return friend_message->type; +} + +static bool tox_event_friend_message_set_message(Tox_Event_Friend_Message *friend_message, const uint8_t *message, + uint16_t message_length) +{ + assert(friend_message != nullptr); + + if (friend_message->message != nullptr) { + free(friend_message->message); + friend_message->message = nullptr; + friend_message->message_length = 0; + } + + friend_message->message = (uint8_t *)malloc(message_length); + + if (friend_message->message == nullptr) { + return false; + } + + memcpy(friend_message->message, message, message_length); + friend_message->message_length = message_length; + return true; +} +uint16_t tox_event_friend_message_get_message_length(const Tox_Event_Friend_Message *friend_message) +{ + assert(friend_message != nullptr); + return friend_message->message_length; +} +uint8_t *tox_event_friend_message_get_message(const Tox_Event_Friend_Message *friend_message) +{ + assert(friend_message != nullptr); + return friend_message->message; +} + + +/***************************************************** + * + * :: add/clear/get + * + *****************************************************/ + + +static Tox_Event_Friend_Message *tox_events_add_friend_message(Tox_Events *events) +{ + if (events->friend_messages_size == UINT32_MAX) { + return nullptr; + } + + if (events->friend_messages_size == events->friend_messages_capacity) { + const uint32_t new_friend_messages_capacity = events->friend_messages_capacity * 2 + 1; + Tox_Event_Friend_Message *new_friend_messages = (Tox_Event_Friend_Message *)realloc( + events->friend_messages, new_friend_messages_capacity * sizeof(Tox_Event_Friend_Message)); + + if (new_friend_messages == nullptr) { + return nullptr; + } + + events->friend_messages = new_friend_messages; + events->friend_messages_capacity = new_friend_messages_capacity; + } + + Tox_Event_Friend_Message *const friend_message = &events->friend_messages[events->friend_messages_size]; + tox_event_friend_message_construct(friend_message); + ++events->friend_messages_size; + return friend_message; +} + +void tox_events_clear_friend_messages(Tox_Events *events) +{ + if (events == nullptr) { + return; + } + + for (uint32_t i = 0; i < events->friend_messages_size; ++i) { + tox_event_friend_message_destruct(&events->friend_messages[i]); + } + + free(events->friend_messages); + events->friend_messages = nullptr; + events->friend_messages_size = 0; + events->friend_messages_capacity = 0; +} + +uint32_t tox_events_get_friend_messages_size(const Tox_Events *events) +{ + return events->friend_messages_size; +} + +const Tox_Event_Friend_Message *tox_events_get_friend_message(const Tox_Events *events, uint32_t index) +{ + assert(index < events->friend_messages_size); + assert(events->friend_messages != nullptr); + return &events->friend_messages[index]; +} + + +/***************************************************** + * + * :: event handler + * + *****************************************************/ + + +void tox_events_handle_friend_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message, + size_t length, void *user_data) +{ + Tox_Events *events = tox_events_alloc(user_data); + + if (events == nullptr) { + return; + } + + Tox_Event_Friend_Message *friend_message = tox_events_add_friend_message(events); + + if (friend_message == nullptr) { + return; + } + + tox_event_friend_message_set_friend_number(friend_message, friend_number); + tox_event_friend_message_set_type(friend_message, type); + tox_event_friend_message_set_message(friend_message, message, length); +} diff --git a/toxcore/events/internal.c b/toxcore/events/internal.c new file mode 100644 index 00000000000..d3123a42f48 --- /dev/null +++ b/toxcore/events/internal.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. + */ + +#include "internal.h" + +#include +#include + +#include "../ccompat.h" + +Tox_Events *tox_events_alloc(void *user_data) +{ + Tox_Events **events_ptr = (Tox_Events **)user_data; + assert(events_ptr != nullptr); + + if (*events_ptr == nullptr) { + *events_ptr = new (Tox_Events); + } + + return *events_ptr; +} diff --git a/toxcore/events/internal.h b/toxcore/events/internal.h new file mode 100644 index 00000000000..2f7aad16a85 --- /dev/null +++ b/toxcore/events/internal.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. + */ + +#ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H +#define C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H + +#include "../tox_events.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Tox_Events { + Tox_Event_Friend_Message *friend_messages; + uint32_t friend_messages_size; + uint32_t friend_messages_capacity; +}; + +tox_friend_message_cb tox_events_handle_friend_message; +void tox_events_clear_friend_messages(Tox_Events *events); + +Tox_Events *tox_events_alloc(void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif // C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index e51099b7a49..083f891a655 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -669,14 +669,14 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t return -1; } - int direct_send_attempt = 0; + bool direct_send_attempt = false; pthread_mutex_lock(conn->mutex); IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id); // TODO(irungentoo): on bad networks, direct connections might not last indefinitely. if (!net_family_is_unspec(ip_port.ip.family)) { - bool direct_connected = 0; + bool direct_connected = false; // FIXME(sudden6): handle return value crypto_connection_status(c, crypt_connection_id, &direct_connected, nullptr); @@ -688,6 +688,7 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t } pthread_mutex_unlock(conn->mutex); + LOGGER_WARNING(c->log, "sending packet of length %d failed", length); return -1; } @@ -697,7 +698,7 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) < current_time && length < 96) || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { if ((uint32_t)sendpacket(dht_get_net(c->dht), ip_port, data, length) == length) { - direct_send_attempt = 1; + direct_send_attempt = true; conn->direct_send_attempt_time = mono_time_get(c->mono_time); } } @@ -705,7 +706,7 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t pthread_mutex_unlock(conn->mutex); pthread_mutex_lock(&c->tcp_mutex); - int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); + const int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); pthread_mutex_unlock(&c->tcp_mutex); pthread_mutex_lock(conn->mutex); @@ -716,11 +717,11 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t pthread_mutex_unlock(conn->mutex); - if (ret == 0 || direct_send_attempt) { + if (direct_send_attempt) { return 0; } - return -1; + return ret; } /*** START: Array Related functions */ @@ -1052,22 +1053,26 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_ const uint16_t max_length = MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE); if (length == 0 || length > max_length) { + LOGGER_WARNING(c->log, "zero-length or too large data packet: %d (max: %d)", length, max_length); return -1; } Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); if (conn == nullptr) { + LOGGER_WARNING(c->log, "connection id %d not found", crypt_connection_id); return -1; } pthread_mutex_lock(conn->mutex); - VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + const uint16_t packet_size = 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE; + VLA(uint8_t, packet, packet_size); packet[0] = NET_PACKET_CRYPTO_DATA; memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); const int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); - if (len + 1 + sizeof(uint16_t) != SIZEOF_VLA(packet)) { + if (len + 1 + sizeof(uint16_t) != packet_size) { + LOGGER_WARNING(c->log, "encryption failed: %d", len); pthread_mutex_unlock(conn->mutex); return -1; } @@ -1087,6 +1092,7 @@ static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint3 const uint8_t *data, uint16_t length) { if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + LOGGER_WARNING(c->log, "zero-length or too large data packet: %d (max: %d)", length, MAX_CRYPTO_PACKET_SIZE); return -1; } @@ -1161,7 +1167,7 @@ static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, cons dt.length = length; memcpy(dt.data, data, length); pthread_mutex_lock(conn->mutex); - int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); + const int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); pthread_mutex_unlock(conn->mutex); if (packet_num == -1) { @@ -1180,7 +1186,7 @@ static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, cons } } else { conn->maximum_speed_reached = 1; - LOGGER_DEBUG(c->log, "send_data_packet failed"); + LOGGER_DEBUG(c->log, "send_data_packet failed (packet_num = %ld)", (long)packet_num); } return packet_num; diff --git a/toxcore/tox.h b/toxcore/tox.h index 72f36f7dba6..323a2b6704d 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -1050,6 +1050,7 @@ uint32_t tox_iteration_interval(const Tox *tox); void tox_iterate(Tox *tox, void *user_data); + /******************************************************************************* * * :: Internal client information (Tox address/id) diff --git a/toxcore/tox_events.c b/toxcore/tox_events.c new file mode 100644 index 00000000000..d781598c408 --- /dev/null +++ b/toxcore/tox_events.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. + */ + +#include "tox_events.h" + +#include +#include + +#include "ccompat.h" +#include "events/internal.h" +#include "tox.h" + + +/***************************************************** + * + * :: Set up event handlers. + * + *****************************************************/ + + +void tox_events_init(Tox *tox) +{ + tox_callback_friend_message(tox, tox_events_handle_friend_message); +} + +Tox_Events *tox_events_iterate(Tox *tox) +{ + Tox_Events *events = nullptr; + tox_iterate(tox, &events); + return events; +} + +void tox_events_free(Tox_Events *events) +{ + if (events == nullptr) { + return; + } + + tox_events_clear_friend_messages(events); + delete (events); +} diff --git a/toxcore/tox_events.h b/toxcore/tox_events.h new file mode 100644 index 00000000000..b6d92e7954f --- /dev/null +++ b/toxcore/tox_events.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. + */ + +#ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_H +#define C_TOXCORE_TOXCORE_TOX_EVENTS_H + +#include "tox.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Tox_Event_Friend_Message Tox_Event_Friend_Message; + +uint32_t tox_event_friend_message_get_friend_number(const Tox_Event_Friend_Message *friend_message); +Tox_Message_Type tox_event_friend_message_get_type(const Tox_Event_Friend_Message *friend_message); +uint16_t tox_event_friend_message_get_message_length(const Tox_Event_Friend_Message *friend_message); +uint8_t *tox_event_friend_message_get_message(const Tox_Event_Friend_Message *friend_message); + +/** + * TODO(iphydf): Document. + */ +typedef struct Tox_Events Tox_Events; + +uint32_t tox_events_get_friend_messages_size(const Tox_Events *events); +const Tox_Event_Friend_Message *tox_events_get_friend_message(const Tox_Events *events, uint32_t index); + +/** + * TODO(iphydf): Document. + */ +void tox_events_init(Tox *tox); + +/** + * TODO(iphydf): Document. + */ +Tox_Events *tox_events_iterate(Tox *tox); + +/** + * TODO(iphydf): Document. + */ +void tox_events_free(Tox_Events *events); + +#ifdef __cplusplus +} +#endif + +#endif // C_TOXCORE_TOXCORE_TOX_EVENTS_H