/* tox.c * * The Tox public API. * * Copyright (C) 2013 Tox project All Rights Reserved. * * This file is part of Tox. * * Tox is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Tox is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Tox. If not, see . * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define TOX_DEFINED typedef struct Messenger Tox; #include "tox.h" #include "Messenger.h" #include "group.h" #include "logger.h" #include "../toxencryptsave/defines.h" #define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} #if TOX_HASH_LENGTH != crypto_hash_sha256_BYTES #error TOX_HASH_LENGTH is assumed to be equal to crypto_hash_sha256_BYTES #endif #if FILE_ID_LENGTH != crypto_box_KEYBYTES #error FILE_ID_LENGTH is assumed to be equal to crypto_box_KEYBYTES #endif #if TOX_FILE_ID_LENGTH != crypto_box_KEYBYTES #error TOX_FILE_ID_LENGTH is assumed to be equal to crypto_box_KEYBYTES #endif #if TOX_FILE_ID_LENGTH != TOX_HASH_LENGTH #error TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH #endif #if TOX_PUBLIC_KEY_SIZE != crypto_box_PUBLICKEYBYTES #error TOX_PUBLIC_KEY_SIZE is assumed to be equal to crypto_box_PUBLICKEYBYTES #endif #if TOX_SECRET_KEY_SIZE != crypto_box_SECRETKEYBYTES #error TOX_SECRET_KEY_SIZE is assumed to be equal to crypto_box_SECRETKEYBYTES #endif #if TOX_MAX_NAME_LENGTH != MAX_NAME_LENGTH #error TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH #endif #if TOX_MAX_STATUS_MESSAGE_LENGTH != MAX_STATUSMESSAGE_LENGTH #error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH #endif uint32_t tox_version_major(void) { return TOX_VERSION_MAJOR; } uint32_t tox_version_minor(void) { return TOX_VERSION_MINOR; } uint32_t tox_version_patch(void) { return TOX_VERSION_PATCH; } bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) { return (TOX_VERSION_MAJOR == major && /* Force the major version */ (TOX_VERSION_MINOR > minor || /* Current minor version must be newer than requested -- or -- */ (TOX_VERSION_MINOR == minor && TOX_VERSION_PATCH >= patch) /* the patch must be the same or newer */ ) ); } #define CONST_FUNCTION(lowercase, uppercase) \ uint32_t tox_##lowercase(void) \ { \ return TOX_##uppercase; \ } CONST_FUNCTION(public_key_size, PUBLIC_KEY_SIZE) CONST_FUNCTION(secret_key_size, SECRET_KEY_SIZE) CONST_FUNCTION(address_size, ADDRESS_SIZE) CONST_FUNCTION(max_name_length, MAX_NAME_LENGTH) CONST_FUNCTION(max_status_message_length, MAX_STATUS_MESSAGE_LENGTH) CONST_FUNCTION(max_friend_request_length, MAX_FRIEND_REQUEST_LENGTH) CONST_FUNCTION(max_message_length, MAX_MESSAGE_LENGTH) CONST_FUNCTION(max_custom_packet_size, MAX_CUSTOM_PACKET_SIZE) CONST_FUNCTION(hash_length, HASH_LENGTH) CONST_FUNCTION(file_id_length, FILE_ID_LENGTH) CONST_FUNCTION(max_filename_length, MAX_FILENAME_LENGTH) #define ACCESSORS(type, ns, name) \ type tox_options_get_##ns##name(const struct Tox_Options *options) \ { \ return options->ns##name; \ } \ void tox_options_set_##ns##name(struct Tox_Options *options, type name) \ { \ options->ns##name = name; \ } ACCESSORS(bool, , ipv6_enabled) ACCESSORS(bool, , udp_enabled) 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(TOX_SAVEDATA_TYPE, savedata_, type) ACCESSORS(size_t, savedata_, length) const uint8_t *tox_options_get_savedata_data(const struct Tox_Options *options) { return options->savedata_data; } void tox_options_set_savedata_data(struct Tox_Options *options, const uint8_t *data, size_t length) { options->savedata_data = data; options->savedata_length = length; } void tox_options_default(struct Tox_Options *options) { if (options) { memset(options, 0, sizeof(struct Tox_Options)); options->ipv6_enabled = 1; options->udp_enabled = 1; options->proxy_type = TOX_PROXY_TYPE_NONE; } } struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error) { struct Tox_Options *options = (struct Tox_Options *)calloc(sizeof(struct Tox_Options), 1); if (options) { tox_options_default(options); SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK); return options; } SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC); return NULL; } void tox_options_free(struct Tox_Options *options) { free(options); } Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error) { Messenger_Options m_options = {0}; bool load_savedata_sk = 0, load_savedata_tox = 0; if (options == NULL) { m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; } else { if (options->savedata_type != TOX_SAVEDATA_TYPE_NONE) { if (options->savedata_data == NULL || options->savedata_length == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); return NULL; } } if (options->savedata_type == TOX_SAVEDATA_TYPE_SECRET_KEY) { if (options->savedata_length != TOX_SECRET_KEY_SIZE) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); return NULL; } load_savedata_sk = 1; } else if (options->savedata_type == TOX_SAVEDATA_TYPE_TOX_SAVE) { if (options->savedata_length < TOX_ENC_SAVE_MAGIC_LENGTH) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); return NULL; } if (sodium_memcmp(options->savedata_data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED); return NULL; } load_savedata_tox = 1; } m_options.ipv6enabled = options->ipv6_enabled; m_options.udp_disabled = !options->udp_enabled; m_options.port_range[0] = options->start_port; m_options.port_range[1] = options->end_port; m_options.tcp_server_port = options->tcp_port; switch (options->proxy_type) { case TOX_PROXY_TYPE_HTTP: m_options.proxy_info.proxy_type = TCP_PROXY_HTTP; break; case TOX_PROXY_TYPE_SOCKS5: m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5; break; case TOX_PROXY_TYPE_NONE: m_options.proxy_info.proxy_type = TCP_PROXY_NONE; break; default: SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE); return NULL; } if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) { if (options->proxy_port == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT); return NULL; } ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); if (m_options.ipv6enabled) { m_options.proxy_info.ip_port.ip.family = AF_UNSPEC; } if (!addr_resolve_or_parse_ip(options->proxy_host, &m_options.proxy_info.ip_port.ip, NULL)) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain. return NULL; } m_options.proxy_info.ip_port.port = htons(options->proxy_port); } } Logger *log = logger_new(); if (log == NULL) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); return NULL; } unsigned int m_error; Messenger *m = new_messenger(log, &m_options, &m_error); if (!new_groupchats(m)) { kill_messenger(m); logger_kill(log); if (m_error == MESSENGER_ERROR_PORT) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); } else if (m_error == MESSENGER_ERROR_TCP_SERVER) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); } else { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); } return NULL; } if (load_savedata_tox && messenger_load(m, options->savedata_data, options->savedata_length) == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); } else if (load_savedata_sk) { load_secret_key(m->net_crypto, options->savedata_data); SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); } else { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); } return m; } void tox_kill(Tox *tox) { if (tox == NULL) { return; } Messenger *m = tox; Logger *log = m->log; kill_groupchats((Group_Chats *)m->conferences_object); kill_messenger(m); logger_kill(log); } void tox_callback_log(Tox *tox, tox_log_cb *callback, void *user_data) { Messenger *m = tox; m_callback_log(m, (logger_cb *)callback, tox, user_data); } size_t tox_get_savedata_size(const Tox *tox) { const Messenger *m = tox; return messenger_size(m); } void tox_get_savedata(const Tox *tox, uint8_t *savedata) { if (savedata) { const Messenger *m = tox; messenger_save(m, savedata); } } bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error) { if (!address || !public_key) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); return 0; } if (port == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); return 0; } struct addrinfo *root, *info; if (getaddrinfo(address, NULL, NULL, &root) != 0) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); return 0; } info = root; unsigned int count = 0; do { IP_Port ip_port; ip_port.port = htons(port); ip_port.ip.family = info->ai_family; if (info->ai_socktype && info->ai_socktype != SOCK_DGRAM) { continue; } if (info->ai_family == AF_INET) { ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr; } else if (info->ai_family == AF_INET6) { ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr; } else { continue; } Messenger *m = tox; onion_add_bs_path_node(m->onion_c, ip_port, public_key); DHT_bootstrap(m->dht, ip_port, public_key); ++count; } while ((info = info->ai_next)); freeaddrinfo(root); if (count) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); return 1; } SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); return 0; } bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error) { if (!address || !public_key) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); return 0; } if (port == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); return 0; } struct addrinfo *root, *info; if (getaddrinfo(address, NULL, NULL, &root) != 0) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); return 0; } info = root; unsigned int count = 0; do { IP_Port ip_port; ip_port.port = htons(port); ip_port.ip.family = info->ai_family; if (info->ai_socktype && info->ai_socktype != SOCK_STREAM) { continue; } if (info->ai_family == AF_INET) { ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr; } else if (info->ai_family == AF_INET6) { ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr; } else { continue; } Messenger *m = tox; add_tcp_relay(m->net_crypto, ip_port, public_key); ++count; } while ((info = info->ai_next)); freeaddrinfo(root); if (count) { SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); return 1; } SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); return 0; } TOX_CONNECTION tox_self_get_connection_status(const Tox *tox) { const Messenger *m = tox; unsigned int ret = onion_connection_status(m->onion_c); if (ret == 2) { return TOX_CONNECTION_UDP; } if (ret == 1) { return TOX_CONNECTION_TCP; } return TOX_CONNECTION_NONE; } void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback) { Messenger *m = tox; m_callback_core_connection(m, (void (*)(Messenger *, unsigned int, void *))callback); } uint32_t tox_iteration_interval(const Tox *tox) { const Messenger *m = tox; return messenger_run_interval(m); } void tox_iterate(Tox *tox, void *user_data) { Messenger *m = tox; do_messenger(m, user_data); do_groupchats((Group_Chats *)m->conferences_object, user_data); } void tox_self_get_address(const Tox *tox, uint8_t *address) { if (address) { const Messenger *m = tox; getaddress(m, address); } } void tox_self_set_nospam(Tox *tox, uint32_t nospam) { Messenger *m = tox; set_nospam(&(m->fr), nospam); } uint32_t tox_self_get_nospam(const Tox *tox) { const Messenger *m = tox; return get_nospam(&(m->fr)); } void tox_self_get_public_key(const Tox *tox, uint8_t *public_key) { const Messenger *m = tox; if (public_key) { memcpy(public_key, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); } } void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key) { const Messenger *m = tox; if (secret_key) { memcpy(secret_key, m->net_crypto->self_secret_key, crypto_box_SECRETKEYBYTES); } } bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error) { if (!name && length != 0) { SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); return 0; } Messenger *m = tox; if (setname(m, name, length) == 0) { // TODO(irungentoo): function to set different per group names? send_name_all_groups((Group_Chats *)m->conferences_object); SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); return 1; } SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); return 0; } size_t tox_self_get_name_size(const Tox *tox) { const Messenger *m = tox; return m_get_self_name_size(m); } void tox_self_get_name(const Tox *tox, uint8_t *name) { if (name) { const Messenger *m = tox; getself_name(m, name); } } bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, TOX_ERR_SET_INFO *error) { if (!status_message && length != 0) { SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); return 0; } Messenger *m = tox; if (m_set_statusmessage(m, status_message, length) == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); return 1; } SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); return 0; } size_t tox_self_get_status_message_size(const Tox *tox) { const Messenger *m = tox; return m_get_self_statusmessage_size(m); } void tox_self_get_status_message(const Tox *tox, uint8_t *status_message) { if (status_message) { const Messenger *m = tox; m_copy_self_statusmessage(m, status_message); } } void tox_self_set_status(Tox *tox, TOX_USER_STATUS status) { Messenger *m = tox; m_set_userstatus(m, status); } TOX_USER_STATUS tox_self_get_status(const Tox *tox) { const Messenger *m = tox; return (TOX_USER_STATUS)m_get_self_userstatus(m); } static void set_friend_error(int32_t ret, TOX_ERR_FRIEND_ADD *error) { switch (ret) { case FAERR_TOOLONG: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG); break; case FAERR_NOMESSAGE: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE); break; case FAERR_OWNKEY: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY); break; case FAERR_ALREADYSENT: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT); break; case FAERR_BADCHECKSUM: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM); break; case FAERR_SETNEWNOSPAM: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM); break; case FAERR_NOMEM: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC); break; } } uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, TOX_ERR_FRIEND_ADD *error) { if (!address || !message) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); return UINT32_MAX; } Messenger *m = tox; 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); return UINT32_MAX; } uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error) { if (!public_key) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); return UINT32_MAX; } Messenger *m = tox; 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); return UINT32_MAX; } bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error) { Messenger *m = tox; int ret = m_delfriend(m, friend_number); // TODO(irungentoo): handle if realloc fails? if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK); return 1; } uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error) { if (!public_key) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL); return UINT32_MAX; } const Messenger *m = tox; int32_t ret = getfriend_id(m, public_key); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND); return UINT32_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK); return ret; } bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, TOX_ERR_FRIEND_GET_PUBLIC_KEY *error) { if (!public_key) { return 0; } const Messenger *m = tox; if (get_real_pk(m, friend_number, public_key) == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK); return 1; } bool tox_friend_exists(const Tox *tox, uint32_t friend_number) { const Messenger *m = tox; return m_friend_exists(m, 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; 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) return UINT64_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK); return timestamp; } size_t tox_self_get_friend_list_size(const Tox *tox) { const Messenger *m = tox; return count_friendlist(m); } void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list) { if (friend_list) { const Messenger *m = tox; // TODO(irungentoo): size parameter? copy_friendlist(m, friend_list, tox_self_get_friend_list_size(tox)); } } size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) { const Messenger *m = tox; int ret = m_get_name_size(m, friend_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return SIZE_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return ret; } bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error) { if (!name) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); return 0; } const Messenger *m = tox; int ret = getname(m, friend_number, name); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return 1; } void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback) { Messenger *m = tox; m_callback_namechange(m, 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; int ret = m_get_statusmessage_size(m, friend_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return SIZE_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return ret; } bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message, TOX_ERR_FRIEND_QUERY *error) { if (!status_message) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); return 0; } const Messenger *m = tox; // TODO(irungentoo): size parameter? int ret = m_copy_statusmessage(m, friend_number, status_message, m_get_statusmessage_size(m, friend_number)); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return 1; } void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback) { Messenger *m = tox; m_callback_statusmessage(m, callback); } TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) { const Messenger *m = tox; int ret = m_get_userstatus(m, friend_number); if (ret == USERSTATUS_INVALID) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return (TOX_USER_STATUS)(TOX_USER_STATUS_BUSY + 1); } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return (TOX_USER_STATUS)ret; } void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback) { Messenger *m = tox; m_callback_userstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); } TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) { const Messenger *m = tox; int ret = m_get_friend_connectionstatus(m, friend_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return TOX_CONNECTION_NONE; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return (TOX_CONNECTION)ret; } void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback) { Messenger *m = tox; m_callback_connectionstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); } bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) { const Messenger *m = tox; int ret = m_get_istyping(m, friend_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); return !!ret; } void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback) { Messenger *m = tox; m_callback_typingchange(m, callback); } bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, TOX_ERR_SET_TYPING *error) { Messenger *m = tox; if (m_set_usertyping(m, friend_number, typing) == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK); return 1; } static void set_message_error(int ret, TOX_ERR_FRIEND_SEND_MESSAGE *error) { switch (ret) { case 0: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK); break; case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND); break; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG); break; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED); break; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ); break; case -5: /* can't happen */ break; } } uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error) { if (!message) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL); return 0; } if (!length) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY); return 0; } Messenger *m = tox; uint32_t message_id = 0; set_message_error(m_send_message_generic(m, friend_number, type, message, length, &message_id), error); return message_id; } void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback) { Messenger *m = tox; m_callback_read_receipt(m, callback); } void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback) { Messenger *m = tox; m_callback_friendrequest(m, callback); } void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback) { Messenger *m = tox; m_callback_friendmessage(m, (void (*)(Messenger *, uint32_t, unsigned int, const uint8_t *, size_t, void *))callback); } bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length) { if (!hash || (length && !data)) { return 0; } crypto_hash_sha256(hash, data, length); return 1; } bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, TOX_ERR_FILE_CONTROL *error) { Messenger *m = tox; int ret = file_control(m, friend_number, file_number, control); if (ret == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK); return 1; } switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND); return 0; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED); return 0; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND); return 0; case -4: /* can't happen */ return 0; case -5: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED); return 0; case -6: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED); return 0; case -7: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED); return 0; case -8: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ); return 0; } /* can't happen */ return 0; } bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, TOX_ERR_FILE_SEEK *error) { Messenger *m = tox; int ret = file_seek(m, friend_number, file_number, position); if (ret == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK); return 1; } switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND); return 0; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED); return 0; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND); return 0; case -4: // fall-through case -5: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED); return 0; case -6: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION); return 0; case -8: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ); return 0; } /* can't happen */ return 0; } void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback) { Messenger *m = tox; callback_file_control(m, (void (*)(Messenger *, uint32_t, uint32_t, unsigned int, void *))callback); } bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id, TOX_ERR_FILE_GET *error) { if (!file_id) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL); return 0; } const Messenger *m = tox; int ret = file_get_id(m, friend_number, file_number, file_id); if (ret == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK); return 1; } if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND); } else { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND); } return 0; } uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id, const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error) { if (filename_length && !filename) { SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL); return UINT32_MAX; } uint8_t f_id[FILE_ID_LENGTH]; if (!file_id) { /* Tox keys are 32 bytes like FILE_ID_LENGTH. */ new_symmetric_key(f_id); file_id = f_id; } Messenger *m = tox; 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); return file_num; } switch (file_num) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND); return UINT32_MAX; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG); return UINT32_MAX; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY); return UINT32_MAX; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED); return UINT32_MAX; } /* can't happen */ return UINT32_MAX; } bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, size_t length, TOX_ERR_FILE_SEND_CHUNK *error) { Messenger *m = tox; 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); return 1; } switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND); return 0; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED); return 0; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND); return 0; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING); return 0; case -5: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH); return 0; case -6: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ); return 0; case -7: SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION); return 0; } /* can't happen */ return 0; } void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback) { Messenger *m = tox; callback_file_reqchunk(m, callback); } void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback) { Messenger *m = tox; callback_file_sendrequest(m, callback); } void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback) { Messenger *m = tox; callback_file_data(m, callback); } void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback) { Messenger *m = tox; g_callback_group_invite((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, int, const uint8_t *, size_t, void *))callback); } void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback) { Messenger *m = tox; g_callback_group_message((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, uint32_t, int, const uint8_t *, size_t, void *))callback); } void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback) { Messenger *m = tox; g_callback_group_title((Group_Chats *)m->conferences_object, callback); } void tox_callback_conference_namelist_change(Tox *tox, tox_conference_namelist_change_cb *callback) { Messenger *m = tox; g_callback_group_namelistchange((Group_Chats *)m->conferences_object, (void (*)(struct Messenger *, int, int, uint8_t, void *))callback); } uint32_t tox_conference_new(Tox *tox, TOX_ERR_CONFERENCE_NEW *error) { Messenger *m = tox; int ret = add_groupchat((Group_Chats *)m->conferences_object, GROUPCHAT_TYPE_TEXT); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT); return UINT32_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_OK); return ret; } bool tox_conference_delete(Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_DELETE *error) { Messenger *m = tox; int ret = del_groupchat((Group_Chats *)m->conferences_object, conference_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_OK); return true; } uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error) { const Messenger *m = tox; int ret = group_number_peers((Group_Chats *)m->conferences_object, conference_number); 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_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error) { const Messenger *m = tox; int ret = group_peername_size((Group_Chats *)m->conferences_object, conference_number, peer_number); 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_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name, TOX_ERR_CONFERENCE_PEER_QUERY *error) { const Messenger *m = tox; int ret = group_peername((Group_Chats *)m->conferences_object, conference_number, peer_number, name); 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_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error) { const Messenger *m = tox; int ret = group_peer_pubkey((Group_Chats *)m->conferences_object, conference_number, peer_number, public_key); 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_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error) { const Messenger *m = tox; int ret = group_peernumber_is_ours((Group_Chats *)m->conferences_object, conference_number, peer_number); 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; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); return ret; } bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, TOX_ERR_CONFERENCE_INVITE *error) { Messenger *m = tox; int ret = invite_friend((Group_Chats *)m->conferences_object, friend_number, conference_number); switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND); return false; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK); return true; } uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length, TOX_ERR_CONFERENCE_JOIN *error) { Messenger *m = tox; int ret = join_groupchat((Group_Chats *)m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length); switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH); return UINT32_MAX; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE); return UINT32_MAX; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND); return UINT32_MAX; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_DUPLICATE); return UINT32_MAX; case -5: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INIT_FAIL); return UINT32_MAX; case -6: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FAIL_SEND); return UINT32_MAX; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_OK); return ret; } bool tox_conference_send_message(Tox *tox, uint32_t conference_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, TOX_ERR_CONFERENCE_SEND_MESSAGE *error) { Messenger *m = tox; int ret = 0; if (type == TOX_MESSAGE_TYPE_NORMAL) { ret = group_message_send((Group_Chats *)m->conferences_object, conference_number, message, length); } else { ret = group_action_send((Group_Chats *)m->conferences_object, conference_number, message, length); } switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND); return false; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG); return false; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION); return false; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_OK); return true; } size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_TITLE *error) { const Messenger *m = tox; int ret = group_title_get_size((Group_Chats *)m->conferences_object, conference_number); switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); return -1; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); return -1; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); return ret; } bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title, TOX_ERR_CONFERENCE_TITLE *error) { const Messenger *m = tox; int ret = group_title_get((Group_Chats *)m->conferences_object, conference_number, title); switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); return false; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); return true; } bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length, TOX_ERR_CONFERENCE_TITLE *error) { Messenger *m = tox; int ret = group_title_send((Group_Chats *)m->conferences_object, conference_number, title, length); switch (ret) { case -1: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); return false; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); return false; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_FAIL_SEND); return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); return true; } size_t tox_conference_get_chatlist_size(const Tox *tox) { const Messenger *m = tox; return count_chatlist((Group_Chats *)m->conferences_object); } void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist) { const Messenger *m = tox; size_t list_size = tox_conference_get_chatlist_size(tox); copy_chatlist((Group_Chats *)m->conferences_object, chatlist, list_size); } TOX_CONFERENCE_TYPE tox_conference_get_type(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_GET_TYPE *error) { const Messenger *m = tox; int ret = group_get_type((Group_Chats *)m->conferences_object, conference_number); if (ret == -1) { SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND); return (TOX_CONFERENCE_TYPE)ret; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_OK); return (TOX_CONFERENCE_TYPE)ret; } static void set_custom_packet_error(int ret, TOX_ERR_FRIEND_CUSTOM_PACKET *error) { switch (ret) { case 0: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK); break; case -1: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND); break; case -2: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG); break; case -3: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); break; case -4: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED); break; case -5: SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ); break; } } bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, TOX_ERR_FRIEND_CUSTOM_PACKET *error) { if (!data) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); return 0; } Messenger *m = tox; if (length == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); return 0; } if (data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); return 0; } int ret = send_custom_lossy_packet(m, friend_number, data, length); set_custom_packet_error(ret, error); if (ret == 0) { return 1; } return 0; } void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback) { Messenger *m = tox; custom_lossy_packet_registerhandler(m, callback); } bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, TOX_ERR_FRIEND_CUSTOM_PACKET *error) { if (!data) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); return 0; } Messenger *m = tox; if (length == 0) { SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); return 0; } int ret = send_custom_lossless_packet(m, friend_number, data, length); set_custom_packet_error(ret, error); if (ret == 0) { return 1; } return 0; } void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback) { Messenger *m = tox; custom_lossless_packet_registerhandler(m, callback); } void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id) { if (dht_id) { const Messenger *m = tox; memcpy(dht_id , m->dht->self_public_key, crypto_box_PUBLICKEYBYTES); } } uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error) { const Messenger *m = tox; uint16_t port = htons(m->net->port); if (port) { SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); } else { SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); } return port; } uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error) { const Messenger *m = tox; if (m->tcp_server) { SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); return m->options.tcp_server_port; } SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); return 0; }