summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/Tox/Tox_12.vcxproj3
-rw-r--r--protocols/Tox/Tox_12.vcxproj.filters3
-rw-r--r--protocols/Tox/bin/x64/libtox.dllbin3961462 -> 3986031 bytes
-rw-r--r--protocols/Tox/bin/x64/libtox.pdbbin633856 -> 642048 bytes
-rw-r--r--protocols/Tox/bin/x86/libtox.dllbin3303030 -> 3324527 bytes
-rw-r--r--protocols/Tox/bin/x86/libtox.pdbbin625664 -> 625664 bytes
-rw-r--r--protocols/Tox/include/tox.h2344
-rw-r--r--protocols/Tox/include/tox_old.h173
-rw-r--r--protocols/Tox/include/toxav.h5
-rw-r--r--protocols/Tox/include/toxencryptsave.h200
-rw-r--r--protocols/Tox/res/resource.rc64
-rw-r--r--protocols/Tox/src/api_avatars.cpp5
-rw-r--r--protocols/Tox/src/api_connection.cpp22
-rw-r--r--protocols/Tox/src/api_encryption.cpp82
-rw-r--r--protocols/Tox/src/api_main.cpp134
-rw-r--r--protocols/Tox/src/api_transfer.cpp40
-rw-r--r--protocols/Tox/src/common.h2
-rw-r--r--protocols/Tox/src/resource.h40
-rw-r--r--protocols/Tox/src/tox_accounts.cpp13
-rw-r--r--protocols/Tox/src/tox_address.h10
-rw-r--r--protocols/Tox/src/tox_avatars.cpp173
-rw-r--r--protocols/Tox/src/tox_chatrooms.cpp5
-rw-r--r--protocols/Tox/src/tox_contacts.cpp188
-rw-r--r--protocols/Tox/src/tox_core.cpp152
-rw-r--r--protocols/Tox/src/tox_dialogs.h21
-rw-r--r--protocols/Tox/src/tox_events.cpp12
-rw-r--r--protocols/Tox/src/tox_menus.cpp7
-rw-r--r--protocols/Tox/src/tox_menus.h12
-rw-r--r--protocols/Tox/src/tox_messages.cpp104
-rw-r--r--protocols/Tox/src/tox_network.cpp37
-rw-r--r--protocols/Tox/src/tox_options.cpp983
-rw-r--r--protocols/Tox/src/tox_options.h108
-rw-r--r--protocols/Tox/src/tox_profile.cpp194
-rw-r--r--protocols/Tox/src/tox_proto.cpp72
-rw-r--r--protocols/Tox/src/tox_proto.h57
-rw-r--r--protocols/Tox/src/tox_search.cpp4
-rw-r--r--protocols/Tox/src/tox_services.cpp9
-rw-r--r--protocols/Tox/src/tox_transfer.cpp301
-rw-r--r--protocols/Tox/src/tox_transfer.h12
-rw-r--r--protocols/Tox/src/tox_utils.cpp26
-rw-r--r--protocols/Tox/src/version.h4
41 files changed, 3378 insertions, 2243 deletions
diff --git a/protocols/Tox/Tox_12.vcxproj b/protocols/Tox/Tox_12.vcxproj
index 9afe2be779..efcff313df 100644
--- a/protocols/Tox/Tox_12.vcxproj
+++ b/protocols/Tox/Tox_12.vcxproj
@@ -97,7 +97,7 @@
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
- <AdditionalDependencies>dnsapi.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>dnsapi.lib;comctl32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -208,6 +208,7 @@ copy docs\tox.ini "$(SolutionDir)$(Configuration)64\Plugins" /y</Command>
<ClInclude Include="src\resource.h" />
<ClInclude Include="src\tox_address.h" />
<ClInclude Include="src\tox_chatrooms.h" />
+ <ClInclude Include="src\tox_dialogs.h" />
<ClInclude Include="src\tox_icons.h" />
<ClInclude Include="src\tox_menus.h" />
<ClInclude Include="src\tox_options.h" />
diff --git a/protocols/Tox/Tox_12.vcxproj.filters b/protocols/Tox/Tox_12.vcxproj.filters
index d04033b672..8303981019 100644
--- a/protocols/Tox/Tox_12.vcxproj.filters
+++ b/protocols/Tox/Tox_12.vcxproj.filters
@@ -60,6 +60,9 @@
<ClInclude Include="src\tox_menus.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="src\tox_dialogs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\tox_proto.cpp">
diff --git a/protocols/Tox/bin/x64/libtox.dll b/protocols/Tox/bin/x64/libtox.dll
index 34adfce713..e7b1933c0d 100644
--- a/protocols/Tox/bin/x64/libtox.dll
+++ b/protocols/Tox/bin/x64/libtox.dll
Binary files differ
diff --git a/protocols/Tox/bin/x64/libtox.pdb b/protocols/Tox/bin/x64/libtox.pdb
index 4f7941a801..9ac4c3709b 100644
--- a/protocols/Tox/bin/x64/libtox.pdb
+++ b/protocols/Tox/bin/x64/libtox.pdb
Binary files differ
diff --git a/protocols/Tox/bin/x86/libtox.dll b/protocols/Tox/bin/x86/libtox.dll
index 4d670482c4..d2c12e7ea4 100644
--- a/protocols/Tox/bin/x86/libtox.dll
+++ b/protocols/Tox/bin/x86/libtox.dll
Binary files differ
diff --git a/protocols/Tox/bin/x86/libtox.pdb b/protocols/Tox/bin/x86/libtox.pdb
index aabb2b8199..f556956e33 100644
--- a/protocols/Tox/bin/x86/libtox.pdb
+++ b/protocols/Tox/bin/x86/libtox.pdb
Binary files differ
diff --git a/protocols/Tox/include/tox.h b/protocols/Tox/include/tox.h
index ee678cc1f5..034b1d786f 100644
--- a/protocols/Tox/include/tox.h
+++ b/protocols/Tox/include/tox.h
@@ -24,928 +24,1996 @@
#ifndef TOX_H
#define TOX_H
+#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
-
#ifdef __cplusplus
extern "C" {
#endif
-#define TOX_MAX_NAME_LENGTH 128
+/** \page core Public core API for Tox clients.
+ *
+ * Every function that can fail takes a function-specific error code pointer
+ * that can be used to diagnose problems with the Tox state or the function
+ * arguments. The error code pointer can be NULL, which does not influence the
+ * function's behaviour, but can be done if the reason for failure is irrelevant
+ * to the client.
+ *
+ * The exception to this rule are simple allocation functions whose only failure
+ * mode is allocation failure. They return NULL in that case, and do not set an
+ * error code.
+ *
+ * Every error code type has an OK value to which functions will set their error
+ * code value on success. Clients can keep their error code uninitialised before
+ * passing it to a function. The library guarantees that after returning, the
+ * value pointed to by the error code pointer has been initialised.
+ *
+ * Functions with pointer parameters often have a NULL error code, meaning they
+ * could not perform any operation, because one of the required parameters was
+ * NULL. Some functions operate correctly or are defined as effectless on NULL.
+ *
+ * Some functions additionally return a value outside their
+ * return type domain, or a bool containing true on success and false on
+ * failure.
+ *
+ * All functions that take a Tox instance pointer will cause undefined behaviour
+ * when passed a NULL Tox pointer.
+ *
+ * All integer values are expected in host byte order.
+ *
+ * Functions with parameters with enum types cause unspecified behaviour if the
+ * enumeration value is outside the valid range of the type. If possible, the
+ * function will try to use a sane default, but there will be no error code,
+ * and one possible action for the function to take is to have no effect.
+ */
-/* Maximum length of single messages after which they should be split. */
-#define TOX_MAX_MESSAGE_LENGTH 1368
-#define TOX_MAX_STATUSMESSAGE_LENGTH 1007
-#define TOX_MAX_FRIENDREQUEST_LENGTH 1016
+/** \subsection events Events and callbacks
+ *
+ * Events are handled by callbacks. One callback can be registered per event.
+ * All events have a callback function type named `tox_${event}_cb` and a
+ * function to register it named `tox_callback_${event}`. Passing a NULL
+ * callback will result in no callback being registered for that event. Only
+ * one callback per event can be registered, so if a client needs multiple
+ * event listeners, it needs to implement the dispatch functionality itself.
+ */
-#define TOX_PUBLIC_KEY_SIZE 32
-/* TODO: remove */
-#define TOX_CLIENT_ID_SIZE TOX_PUBLIC_KEY_SIZE
+/** \subsection threading Threading implications
+ *
+ * It is possible to run multiple concurrent threads with a Tox instance for
+ * each thread. It is also possible to run all Tox instances in the same thread.
+ * A common way to run Tox (multiple or single instance) is to have one thread
+ * running a simple tox_iteration loop, sleeping for tox_iteration_interval
+ * milliseconds on each iteration.
+ *
+ * If you want to access a single Tox instance from multiple threads, access
+ * to the instance must be synchronised. While multiple threads can concurrently
+ * access multiple different Tox instances, no more than one API function can
+ * operate on a single instance at any given time.
+ *
+ * Functions that write to variable length byte arrays will always have a size
+ * function associated with them. The result of this size function is only valid
+ * until another mutating function (one that takes a pointer to non-const Tox)
+ * is called. Thus, clients must ensure that no other thread calls a mutating
+ * function between the call to the size function and the call to the retrieval
+ * function.
+ *
+ * E.g. to get the current nickname, one would write
+ *
+ * \code
+ * size_t length = tox_self_get_name_size(tox);
+ * uint8_t *name = malloc(length);
+ * if (!name) abort();
+ * tox_self_get_name(tox, name);
+ * \endcode
+ *
+ * If any other thread calls tox_self_set_name while this thread is allocating
+ * memory, the length will have become invalid, and the call to
+ * tox_self_get_name may cause undefined behaviour.
+ */
-#define TOX_AVATAR_MAX_DATA_LENGTH 16384
-#define TOX_HASH_LENGTH /*crypto_hash_sha256_BYTES*/ 32
+#ifndef TOX_DEFINED
+#define TOX_DEFINED
+/**
+ * The Tox instance type. All the state associated with a connection is held
+ * within the instance. Multiple instances can exist and operate concurrently.
+ * The maximum number of Tox instances that can exist on a single network
+ * device is limited. Note that this is not just a per-process limit, since the
+ * limiting factor is the number of usable ports on a device.
+ */
+typedef struct Tox Tox;
+#endif
-#define TOX_FRIEND_ADDRESS_SIZE (TOX_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
-#define TOX_ENABLE_IPV6_DEFAULT 1
+/*******************************************************************************
+ *
+ * :: API version
+ *
+ ******************************************************************************/
-#define TOX_ENC_SAVE_MAGIC_NUMBER "toxEsave"
-#define TOX_ENC_SAVE_MAGIC_LENGTH 8
-/* Errors for m_addfriend
- * FAERR - Friend Add Error
+/**
+ * The major version number. Incremented when the API or ABI changes in an
+ * incompatible way.
*/
-enum {
- TOX_FAERR_TOOLONG = -1,
- TOX_FAERR_NOMESSAGE = -2,
- TOX_FAERR_OWNKEY = -3,
- TOX_FAERR_ALREADYSENT = -4,
- TOX_FAERR_UNKNOWN = -5,
- TOX_FAERR_BADCHECKSUM = -6,
- TOX_FAERR_SETNEWNOSPAM = -7,
- TOX_FAERR_NOMEM = -8
-};
+#define TOX_VERSION_MAJOR 0u
+/**
+ * The minor version number. Incremented when functionality is added without
+ * breaking the API or ABI. Set to 0 when the major version number is
+ * incremented.
+ */
+#define TOX_VERSION_MINOR 0u
+/**
+ * The patch or revision number. Incremented when bugfixes are applied without
+ * changing any functionality or API or ABI.
+ */
+#define TOX_VERSION_PATCH 0u
-/* USERSTATUS -
- * Represents userstatuses someone can have.
+/**
+ * A macro to check at preprocessing time whether the client code is compatible
+ * with the installed version of Tox.
*/
-typedef enum {
- TOX_USERSTATUS_NONE,
- TOX_USERSTATUS_AWAY,
- TOX_USERSTATUS_BUSY,
- TOX_USERSTATUS_INVALID
-}
-TOX_USERSTATUS;
+#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH) \
+ (TOX_VERSION_MAJOR == MAJOR && \
+ (TOX_VERSION_MINOR > MINOR || \
+ (TOX_VERSION_MINOR == MINOR && \
+ TOX_VERSION_PATCH >= PATCH)))
+
+/**
+ * A macro to make compilation fail if the client code is not compatible with
+ * the installed version of Tox.
+ */
+#define TOX_VERSION_REQUIRE(MAJOR, MINOR, PATCH) \
+ typedef char tox_required_version[TOX_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]
-/* AVATAR_FORMAT -
- * Data formats for user avatar images
+/**
+ * Return the major version number of the library. Can be used to display the
+ * Tox library version or to check whether the client is compatible with the
+ * dynamically linked version of Tox.
*/
-typedef enum {
- TOX_AVATAR_FORMAT_NONE = 0,
- TOX_AVATAR_FORMAT_PNG
-}
-TOX_AVATAR_FORMAT;
+uint32_t tox_version_major(void);
+
+/**
+ * Return the minor version number of the library.
+ */
+uint32_t tox_version_minor(void);
+
+/**
+ * Return the patch number of the library.
+ */
+uint32_t tox_version_patch(void);
+
+/**
+ * Return whether the compiled library version is compatible with the passed
+ * version numbers.
+ */
+bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);
+
+/**
+ * A convenience macro to call tox_version_is_compatible with the currently
+ * compiling API version.
+ */
+#define TOX_VERSION_IS_ABI_COMPATIBLE() \
+ tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH)
-#ifndef __TOX_DEFINED__
-#define __TOX_DEFINED__
-typedef struct Tox Tox;
-#endif
-/* NOTE: Strings in Tox are all UTF-8, (This means that there is no terminating NULL character.)
+/*******************************************************************************
*
- * The exact buffer you send will be received at the other end without modification.
+ * :: Numeric constants
*
- * Do not treat Tox strings as C strings.
+ ******************************************************************************/
+
+
+/**
+ * The size of a Tox Public Key in bytes.
*/
+#define TOX_PUBLIC_KEY_SIZE 32
-/* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others.
- * format: [public_key (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]
+/**
+ * The size of a Tox Secret Key in bytes.
*/
-void tox_get_address(const Tox *tox, uint8_t *address);
+#define TOX_SECRET_KEY_SIZE 32
-/* Add a friend.
- * Set the data that will be sent along with friend request.
- * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be TOX_FRIEND_ADDRESS_SIZE bytes. TODO: add checksum.
- * data is the data and length is the length (maximum length of data is TOX_MAX_FRIENDREQUEST_LENGTH).
+/**
+ * The size of a Tox address in bytes. Tox addresses are in the format
+ * [Public Key (TOX_PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)].
*
- * return the friend number if success.
- * return TOX_FAERR_TOOLONG if message length is too long.
- * return TOX_FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
- * return TOX_FAERR_OWNKEY if user's own key.
- * return TOX_FAERR_ALREADYSENT if friend request already sent or already a friend.
- * return TOX_FAERR_UNKNOWN for unknown error.
- * return TOX_FAERR_BADCHECKSUM if bad checksum in address.
- * return TOX_FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
- * (the nospam for that friend was set to the new one).
- * return TOX_FAERR_NOMEM if increasing the friend list size fails.
+ * The checksum is computed over the Public Key and the nospam value. The first
+ * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an
+ * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.
*/
-int32_t tox_add_friend(Tox *tox, const uint8_t *address, const uint8_t *data, uint16_t length);
+#define TOX_ADDRESS_SIZE (TOX_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
+/**
+ * Maximum length of a nickname in bytes.
+ */
+#define TOX_MAX_NAME_LENGTH 128
-/* Add a friend without sending a friendrequest.
- * return the friend number if success.
- * return -1 if failure.
+/**
+ * Maximum length of a status message in bytes.
*/
-int32_t tox_add_friend_norequest(Tox *tox, const uint8_t *public_key);
+#define TOX_MAX_STATUS_MESSAGE_LENGTH 1007
-/* return the friend number associated to that client id.
- return -1 if no such friend */
-int32_t tox_get_friend_number(const Tox *tox, const uint8_t *public_key);
+/**
+ * Maximum length of a friend request message in bytes.
+ */
+#define TOX_MAX_FRIEND_REQUEST_LENGTH 1016
-/* Copies the public key associated to that friend id into public_key buffer.
- * Make sure that public_key is of size TOX_PUBLIC_KEY_SIZE.
- * return 0 if success.
- * return -1 if failure.
+/**
+ * Maximum length of a single message after which it should be split.
*/
-int tox_get_client_id(const Tox *tox, int32_t friendnumber, uint8_t *public_key);
+#define TOX_MAX_MESSAGE_LENGTH 1372
-/* Remove a friend.
- *
- * return 0 if success.
- * return -1 if failure.
+/**
+ * Maximum size of custom packets. TODO: should be LENGTH?
*/
-int tox_del_friend(Tox *tox, int32_t friendnumber);
+#define TOX_MAX_CUSTOM_PACKET_SIZE 1373
-/* Checks friend's connecting status.
- *
- * return 1 if friend is connected to us (Online).
- * return 0 if friend is not connected to us (Offline).
- * return -1 on failure.
+/**
+ * The number of bytes in a hash generated by tox_hash.
*/
-int tox_get_friend_connection_status(const Tox *tox, int32_t friendnumber);
+#define TOX_HASH_LENGTH /*crypto_hash_sha256_BYTES*/ 32
-/* Checks if there exists a friend with given friendnumber.
+/**
+ * The number of bytes in a file id.
+ */
+#define TOX_FILE_ID_LENGTH 32
+
+/**
+ * Maximum file name length for file tran.
+ */
+#define TOX_MAX_FILENAME_LENGTH 255
+
+/*******************************************************************************
*
- * return 1 if friend exists.
- * return 0 if friend doesn't exist.
+ * :: Global enumerations
+ *
+ ******************************************************************************/
+
+
+/**
+ * Represents the possible statuses a client can have.
*/
-int tox_friend_exists(const Tox *tox, int32_t friendnumber);
+typedef enum TOX_USER_STATUS {
+ /**
+ * User is online and available.
+ */
+ TOX_USER_STATUS_NONE,
+ /**
+ * User is away. Clients can set this e.g. after a user defined
+ * inactivity time.
+ */
+ TOX_USER_STATUS_AWAY,
+ /**
+ * User is busy. Signals to other clients that this client does not
+ * currently wish to communicate.
+ */
+ TOX_USER_STATUS_BUSY
+} TOX_USER_STATUS;
-/* Send a text chat message to an online friend.
+/**
+ * Represents message types for friend messages and group chat
+ * messages.
+ */
+typedef enum TOX_MESSAGE_TYPE {
+ /**
+ * Normal text message. Similar to PRIVMSG on IRC.
+ */
+ TOX_MESSAGE_TYPE_NORMAL,
+ /**
+ * A message describing an user action. This is similar to /me (CTCP ACTION)
+ * on IRC.
+ */
+ TOX_MESSAGE_TYPE_ACTION
+} TOX_MESSAGE_TYPE;
+
+/*******************************************************************************
*
- * return the message id if packet was successfully put into the send queue.
- * return 0 if it was not.
+ * :: Startup options
*
- * maximum length of messages is TOX_MAX_MESSAGE_LENGTH, your client must split larger messages
- * or else sending them will not work. No the core will not split messages for you because that
- * requires me to parse UTF-8.
+ ******************************************************************************/
+
+
+typedef enum TOX_PROXY_TYPE {
+ /**
+ * Don't use a proxy.
+ */
+ TOX_PROXY_TYPE_NONE,
+ /**
+ * HTTP proxy using CONNECT.
+ */
+ TOX_PROXY_TYPE_HTTP,
+ /**
+ * SOCKS proxy for simple socket pipes.
+ */
+ TOX_PROXY_TYPE_SOCKS5
+} TOX_PROXY_TYPE;
+
+
+/**
+ * This struct contains all the startup options for Tox. You can either allocate
+ * this object yourself, and pass it to tox_options_default, or call
+ * tox_options_new to get a new default options object.
+ */
+struct Tox_Options {
+ /**
+ * The type of socket to create.
+ *
+ * If this is set to false, an IPv4 socket is created, which subsequently
+ * only allows IPv4 communication.
+ * If it is set to true, an IPv6 socket is created, allowing both IPv4 and
+ * IPv6 communication.
+ */
+ bool ipv6_enabled;
+
+ /**
+ * Enable the use of UDP communication when available.
+ *
+ * Setting this to false will force Tox to use TCP only. Communications will
+ * need to be relayed through a TCP relay node, potentially slowing them down.
+ * Disabling UDP support is necessary when using anonymous proxies or Tor.
+ */
+ bool udp_enabled;
+
+ /**
+ * Pass communications through a proxy.
+ */
+ TOX_PROXY_TYPE proxy_type;
+
+ /**
+ * The IP address or DNS name of the proxy to be used.
+ *
+ * If used, this must be non-NULL and be a valid DNS name. The name must not
+ * exceed 255 characters, and be in a NUL-terminated C string format
+ * (255 chars + 1 NUL byte).
+ *
+ * This member is ignored (it can be NULL) if proxy_enabled is false.
+ */
+ const char *proxy_host;
+
+ /**
+ * The port to use to connect to the proxy server.
+ *
+ * Ports must be in the range (1, 65535). The value is ignored if
+ * proxy_enabled is false.
+ */
+ uint16_t proxy_port;
+
+ /**
+ * The start port of the inclusive port range to attempt to use.
+ *
+ * If both start_port and end_port are 0, the default port range will be
+ * used: [33445, 33545].
+ *
+ * If either start_port or end_port is 0 while the other is non-zero, the
+ * non-zero port will be the only port in the range.
+ *
+ * Having start_port > end_port will yield the same behavior as if start_port
+ * and end_port were swapped.
+ */
+ uint16_t start_port;
+
+ /**
+ * The end port of the inclusive port range to attempt to use.
+ */
+ uint16_t end_port;
+};
+
+
+/**
+ * Initialises a Tox_Options object with the default options.
+ *
+ * The result of this function is independent of the original options. All
+ * values will be overwritten, no values will be read (so it is permissible
+ * to pass an uninitialised object).
+ *
+ * If options is NULL, this function has no effect.
*
- * You will want to retain the return value, it will be passed to your read_receipt callback
- * if one is received.
+ * @param options An options object to be filled with default options.
*/
-uint32_t tox_send_message(Tox *tox, int32_t friendnumber, const uint8_t *message, uint32_t length);
+void tox_options_default(struct Tox_Options *options);
-/* Send an action to an online friend.
+
+typedef enum TOX_ERR_OPTIONS_NEW {
+ TOX_ERR_OPTIONS_NEW_OK,
+ /**
+ * The function failed to allocate enough memory for the options struct.
+ */
+ TOX_ERR_OPTIONS_NEW_MALLOC
+} TOX_ERR_OPTIONS_NEW;
+
+/**
+ * Allocates a new Tox_Options object and initialises it with the default
+ * options. This function can be used to preserve long term ABI compatibility by
+ * giving the responsibility of allocation and deallocation to the Tox library.
*
- * return the message id if packet was successfully put into the send queue.
- * return 0 if it was not.
+ * Objects returned from this function must be freed using the tox_options_free
+ * function.
*
- * maximum length of actions is TOX_MAX_MESSAGE_LENGTH, your client must split larger actions
- * or else sending them will not work. No the core will not split actions for you because that
- * requires me to parse UTF-8.
+ * @return A new Tox_Options object with default options or NULL on failure.
+ */
+struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error);
+
+
+/**
+ * Releases all resources associated with an options objects.
*
- * You will want to retain the return value, it will be passed to your read_receipt callback
- * if one is received.
+ * Passing a pointer that was not returned by tox_options_new results in
+ * undefined behaviour.
*/
-uint32_t tox_send_action(Tox *tox, int32_t friendnumber, const uint8_t *action, uint32_t length);
+void tox_options_free(struct Tox_Options *options);
-/* Set our nickname.
- * name must be a string of maximum MAX_NAME_LENGTH length.
- * length must be at least 1 byte.
- * length is the length of name.
+
+/*******************************************************************************
+ *
+ * :: Creation and destruction
+ *
+ ******************************************************************************/
+
+
+typedef enum TOX_ERR_NEW {
+ TOX_ERR_NEW_OK,
+ TOX_ERR_NEW_NULL,
+ /**
+ * The function was unable to allocate enough memory to store the internal
+ * structures for the Tox object.
+ */
+ TOX_ERR_NEW_MALLOC,
+ /**
+ * The function was unable to bind to a port. This may mean that all ports
+ * have already been bound, e.g. by other Tox instances, or it may mean
+ * a permission error. You may be able to gather more information from errno.
+ */
+ TOX_ERR_NEW_PORT_ALLOC,
+ /**
+ * proxy_type was invalid.
+ */
+ TOX_ERR_NEW_PROXY_BAD_TYPE,
+ /**
+ * proxy_type was valid but the proxy_host passed had an invalid format
+ * or was NULL.
+ */
+ TOX_ERR_NEW_PROXY_BAD_HOST,
+ /**
+ * proxy_type was valid, but the proxy_port was invalid.
+ */
+ TOX_ERR_NEW_PROXY_BAD_PORT,
+ /**
+ * The proxy host passed could not be resolved.
+ */
+ TOX_ERR_NEW_PROXY_NOT_FOUND,
+ /**
+ * The byte array to be loaded contained an encrypted save.
+ */
+ TOX_ERR_NEW_LOAD_ENCRYPTED,
+ /**
+ * The data format was invalid. This can happen when loading data that was
+ * saved by an older version of Tox, or when the data has been corrupted.
+ * When loading from badly formatted data, some data may have been loaded,
+ * and the rest is discarded. Passing an invalid length parameter also
+ * causes this error.
+ */
+ TOX_ERR_NEW_LOAD_BAD_FORMAT
+} TOX_ERR_NEW;
+
+
+/**
+ * @brief Creates and initialises a new Tox instance with the options passed.
+ *
+ * This function will bring the instance into a valid state. Running the event
+ * loop with a new instance will operate correctly.
*
- * return 0 if success.
- * return -1 if failure.
+ * If the data parameter is not NULL, this function will load the Tox instance
+ * from a byte array previously filled by tox_get_savedata.
+ *
+ * If loading failed or succeeded only partially, the new or partially loaded
+ * instance is returned and an error code is set.
+ *
+ * @param options An options object as described above. If this parameter is
+ * NULL, the default options are used.
+ * @param data A byte array containing data previously stored by tox_get_savedata.
+ * @param length The length of the byte array data. If this parameter is 0, the
+ * data parameter is ignored.
+ *
+ * @see tox_iteration for the event loop.
+ */
+Tox *tox_new(const struct Tox_Options *options, const uint8_t *data, size_t length, TOX_ERR_NEW *error);
+
+
+/**
+ * Releases all resources associated with the Tox instance and disconnects from
+ * the network.
+ *
+ * After calling this function, the Tox pointer becomes invalid. No other
+ * functions can be called, and the pointer value can no longer be read.
*/
-int tox_set_name(Tox *tox, const uint8_t *name, uint16_t length);
+void tox_kill(Tox *tox);
+
-/*
- * Get your nickname.
- * m - The messenger context to use.
- * name - needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
+/**
+ * Calculates the number of bytes required to store the tox instance with
+ * tox_get_savedata. This function cannot fail. The result is always greater
+ * than 0.
*
- * return length of name.
- * return 0 on error.
+ * @see threading for concurrency implications.
*/
-uint16_t tox_get_self_name(const Tox *tox, uint8_t *name);
+size_t tox_get_savedata_size(const Tox *tox);
-/* Get name of friendnumber and put it in name.
- * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
+/**
+ * Store all information associated with the tox instance to a byte array.
*
- * return length of name if success.
- * return -1 if failure.
+ * @param data A memory region large enough to store the tox instance data.
+ * Call tox_get_savedata_size to find the number of bytes required. If this parameter
+ * is NULL, this function has no effect.
*/
-int tox_get_name(const Tox *tox, int32_t friendnumber, uint8_t *name);
+void tox_get_savedata(const Tox *tox, uint8_t *data);
+
+
+/*******************************************************************************
+ *
+ * :: Connection lifecycle and event loop
+ *
+ ******************************************************************************/
-/* returns the length of name on success.
- * returns -1 on failure.
+
+typedef enum TOX_ERR_BOOTSTRAP {
+ TOX_ERR_BOOTSTRAP_OK,
+ TOX_ERR_BOOTSTRAP_NULL,
+ /**
+ * The host could not be resolved to an IP address, or the IP address
+ * passed was invalid.
+ */
+ TOX_ERR_BOOTSTRAP_BAD_HOST,
+ /**
+ * The port passed was invalid. The valid port range is (1, 65535).
+ */
+ TOX_ERR_BOOTSTRAP_BAD_PORT
+} TOX_ERR_BOOTSTRAP;
+
+/**
+ * Sends a "get nodes" request to the given bootstrap node with IP, port, and
+ * public key to setup connections.
+ *
+ * This function will attempt to connect to the node using UDP and TCP at the
+ * same time.
+ *
+ * Tox will use the node as a TCP relay in case Tox_Options.udp_enabled was
+ * false, and also to connect to friends that are in TCP-only mode. Tox will
+ * also use the TCP connection when NAT hole punching is slow, and later switch
+ * to UDP if hole punching succeeds.
+ *
+ * @param host The hostname or IP address (IPv4 or IPv6) of the node.
+ * @param port The port on the host on which the bootstrap Tox instance is
+ * listening.
+ * @param public_key The long term public key of the bootstrap node
+ * (TOX_PUBLIC_KEY_SIZE bytes).
+ * @return true on success.
*/
-int tox_get_name_size(const Tox *tox, int32_t friendnumber);
-int tox_get_self_name_size(const Tox *tox);
+bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error);
+
-/* Set our user status.
+/**
+ * Adds additional host:port pair as TCP relay.
*
- * userstatus must be one of TOX_USERSTATUS values.
- * max length of the status is TOX_MAX_STATUSMESSAGE_LENGTH.
+ * This function can be used to initiate TCP connections to different ports on
+ * the same bootstrap node, or to add TCP relays without using them as
+ * bootstrap nodes.
*
- * returns 0 on success.
- * returns -1 on failure.
+ * @param host The hostname or IP address (IPv4 or IPv6) of the TCP relay.
+ * @param port The port on the host on which the TCP relay is listening.
+ * @param public_key The long term public key of the TCP relay
+ * (TOX_PUBLIC_KEY_SIZE bytes).
+ * @return true on success.
*/
-int tox_set_status_message(Tox *tox, const uint8_t *status, uint16_t length);
-int tox_set_user_status(Tox *tox, uint8_t userstatus);
+bool tox_add_tcp_relay(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key,
+ TOX_ERR_BOOTSTRAP *error);
+
-/* returns the length of status message on success.
- * returns -1 on failure.
+typedef enum TOX_CONNECTION {
+ /**
+ * There is no connection. This instance, or the friend the state change is
+ * about, is now offline.
+ */
+ TOX_CONNECTION_NONE,
+ /**
+ * A TCP connection has been established. For the own instance, this means it
+ * is connected through a TCP relay, only. For a friend, this means that the
+ * connection to that particular friend goes through a TCP relay.
+ */
+ TOX_CONNECTION_TCP,
+ /**
+ * A UDP connection has been established. For the own instance, this means it
+ * is able to send UDP packets to DHT nodes, but may still be connected to
+ * a TCP relay. For a friend, this means that the connection to that
+ * particular friend was built using direct UDP packets.
+ */
+ TOX_CONNECTION_UDP
+} TOX_CONNECTION;
+
+
+/**
+ * Return whether we are connected to the DHT. The return value is equal to the
+ * last value received through the `self_connection_status` callback.
*/
-int tox_get_status_message_size(const Tox *tox, int32_t friendnumber);
-int tox_get_self_status_message_size(const Tox *tox);
+TOX_CONNECTION tox_self_get_connection_status(const Tox *tox);
-/* Copy friendnumber's status message into buf, truncating if size is over maxlen.
- * Get the size you need to allocate from m_get_statusmessage_size.
- * The self variant will copy our own status message.
+/**
+ * The function type for the `self_connection_status` callback.
*
- * returns the length of the copied data on success
- * retruns -1 on failure.
+ * @param connection_status Equal to the return value of
+ * tox_self_get_connection_status.
*/
-int tox_get_status_message(const Tox *tox, int32_t friendnumber, uint8_t *buf, uint32_t maxlen);
-int tox_get_self_status_message(const Tox *tox, uint8_t *buf, uint32_t maxlen);
+typedef void tox_self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data);
-/* return one of TOX_USERSTATUS values.
- * Values unknown to your application should be represented as TOX_USERSTATUS_NONE.
- * As above, the self variant will return our own TOX_USERSTATUS.
- * If friendnumber is invalid, this shall return TOX_USERSTATUS_INVALID.
+/**
+ * Set the callback for the `self_connection_status` event. Pass NULL to unset.
+ *
+ * This event is triggered whenever there is a change in the DHT connection
+ * state. When disconnected, a client may choose to call tox_bootstrap again, to
+ * reconnect to the DHT. Note that this state may frequently change for short
+ * amounts of time. Clients should therefore not immediately bootstrap on
+ * receiving a disconnect.
+ *
+ * TODO: how long should a client wait before bootstrapping again?
+ */
+void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *function, void *user_data);
+
+
+/**
+ * Return the time in milliseconds before tox_iteration() should be called again
+ * for optimal performance.
*/
-uint8_t tox_get_user_status(const Tox *tox, int32_t friendnumber);
-uint8_t tox_get_self_user_status(const Tox *tox);
+uint32_t tox_iteration_interval(const Tox *tox);
-/* returns timestamp of last time friendnumber was seen online, or 0 if never seen.
- * returns -1 on error.
+
+/**
+ * The main loop that needs to be run in intervals of tox_iteration_interval()
+ * milliseconds.
*/
-uint64_t tox_get_last_online(const Tox *tox, int32_t friendnumber);
+void tox_iterate(Tox *tox);
+
-/* Set our typing status for a friend.
- * You are responsible for turning it on or off.
+/*******************************************************************************
*
- * returns 0 on success.
- * returns -1 on failure.
- */
-int tox_set_user_is_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing);
+ * :: Internal client information (Tox address/id)
+ *
+ ******************************************************************************/
-/* Get the typing status of a friend.
+
+/**
+ * Writes the Tox friend address of the client to a byte array. The address is
+ * not in human-readable format. If a client wants to display the address,
+ * formatting is required.
*
- * returns 0 if friend is not typing.
- * returns 1 if friend is typing.
+ * @param address A memory region of at least TOX_ADDRESS_SIZE bytes. If this
+ * parameter is NULL, this function has no effect.
+ * @see TOX_ADDRESS_SIZE for the address format.
*/
-uint8_t tox_get_is_typing(const Tox *tox, int32_t friendnumber);
+void tox_self_get_address(const Tox *tox, uint8_t *address);
-/* Return the number of friends in the instance m.
- * You should use this to determine how much memory to allocate
- * for copy_friendlist. */
-uint32_t tox_count_friendlist(const Tox *tox);
-/* Return the number of online friends in the instance m. */
-uint32_t tox_get_num_online_friends(const Tox *tox);
+/**
+ * Set the 4-byte nospam part of the address.
+ *
+ * @param nospam Any 32 bit unsigned integer.
+ */
+void tox_self_set_nospam(Tox *tox, uint32_t nospam);
-/* Copy a list of valid friend IDs into the array out_list.
- * If out_list is NULL, returns 0.
- * Otherwise, returns the number of elements copied.
- * If the array was too small, the contents
- * of out_list will be truncated to list_size. */
-uint32_t tox_get_friendlist(const Tox *tox, int32_t *out_list, uint32_t list_size);
+/**
+ * Get the 4-byte nospam part of the address.
+ */
+uint32_t tox_self_get_nospam(const Tox *tox);
-/* Set the function that will be executed when a friend request is received.
- * Function format is function(Tox *tox, const uint8_t * public_key, const uint8_t * data, uint16_t length, void *userdata)
+/**
+ * Copy the Tox Public Key (long term public key) from the Tox object.
+ *
+ * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If
+ * this parameter is NULL, this function has no effect.
*/
-void tox_callback_friend_request(Tox *tox, void (*function)(Tox *tox, const uint8_t *, const uint8_t *, uint16_t,
- void *), void *userdata);
+void tox_self_get_public_key(const Tox *tox, uint8_t *public_key);
-/* Set the function that will be executed when a message from a friend is received.
- * Function format is: function(Tox *tox, int32_t friendnumber, const uint8_t * message, uint16_t length, void *userdata)
+/**
+ * Copy the secret key from the Tox object.
+ *
+ * @param secret_key A memory region of at least TOX_SECRET_KEY_SIZE bytes. If
+ * this parameter is NULL, this function has no effect.
*/
-void tox_callback_friend_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *),
- void *userdata);
+void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key);
+
-/* Set the function that will be executed when an action from a friend is received.
- * Function format is: function(Tox *tox, int32_t friendnumber, const uint8_t * action, uint16_t length, void *userdata)
+/*******************************************************************************
+ *
+ * :: User-visible client information (nickname/status)
+ *
+ ******************************************************************************/
+
+
+/**
+ * Common error codes for all functions that set a piece of user-visible
+ * client information.
*/
-void tox_callback_friend_action(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *),
- void *userdata);
+typedef enum TOX_ERR_SET_INFO {
+ TOX_ERR_SET_INFO_OK,
+ TOX_ERR_SET_INFO_NULL,
+ /**
+ * Information length exceeded maximum permissible size.
+ */
+ TOX_ERR_SET_INFO_TOO_LONG
+} TOX_ERR_SET_INFO;
-/* Set the callback for name changes.
- * function(Tox *tox, int32_t friendnumber, const uint8_t *newname, uint16_t length, void *userdata)
- * You are not responsible for freeing newname
+
+/**
+ * Set the nickname for the Tox client.
+ *
+ * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is 0, the name
+ * parameter is ignored (it can be NULL), and the nickname is set back to empty.
+ *
+ * @param name A byte array containing the new nickname.
+ * @param length The size of the name byte array.
+ *
+ * @return true on success.
*/
-void tox_callback_name_change(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *),
- void *userdata);
+bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error);
-/* Set the callback for status message changes.
- * function(Tox *tox, int32_t friendnumber, const uint8_t *newstatus, uint16_t length, void *userdata)
- * You are not responsible for freeing newstatus.
+/**
+ * Return the length of the current nickname as passed to tox_self_set_name.
+ *
+ * If no nickname was set before calling this function, the name is empty,
+ * and this function returns 0.
+ *
+ * @see threading for concurrency implications.
*/
-void tox_callback_status_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *),
- void *userdata);
+size_t tox_self_get_name_size(const Tox *tox);
-/* Set the callback for status type changes.
- * function(Tox *tox, int32_t friendnumber, uint8_t TOX_USERSTATUS, void *userdata)
+/**
+ * Write the nickname set by tox_self_set_name to a byte array.
+ *
+ * If no nickname was set before calling this function, the name is empty,
+ * and this function has no effect.
+ *
+ * Call tox_self_get_name_size to find out how much memory to allocate for
+ * the result.
+ *
+ * @param name A valid memory location large enough to hold the nickname.
+ * If this parameter is NULL, the function has no effect.
*/
-void tox_callback_user_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata);
+void tox_self_get_name(const Tox *tox, uint8_t *name);
-/* Set the callback for typing changes.
- * function (Tox *tox, int32_t friendnumber, uint8_t is_typing, void *userdata)
+/**
+ * Set the client's status message.
+ *
+ * Status message length cannot exceed TOX_MAX_STATUS_MESSAGE_LENGTH. If
+ * length is 0, the status parameter is ignored (it can be NULL), and the
+ * user status is set back to empty.
*/
-void tox_callback_typing_change(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata);
+bool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error);
-/* Set the callback for read receipts.
- * function(Tox *tox, int32_t friendnumber, uint32_t receipt, void *userdata)
+/**
+ * Return the length of the current status message as passed to
+ * tox_self_set_status_message.
+ *
+ * If no status message was set before calling this function, the status
+ * is empty, and this function returns 0.
*
- * If you are keeping a record of returns from m_sendmessage;
- * receipt might be one of those values, meaning the message
- * has been received on the other side.
- * Since core doesn't track ids for you, receipt may not correspond to any message.
- * In that case, you should discard it.
+ * @see threading for concurrency implications.
*/
-void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int32_t, uint32_t, void *), void *userdata);
+size_t tox_self_get_status_message_size(const Tox *tox);
-/* Set the callback for connection status changes.
- * function(Tox *tox, int32_t friendnumber, uint8_t status, void *userdata)
+/**
+ * Write the status message set by tox_self_set_status_message to a byte array.
*
- * Status:
- * 0 -- friend went offline after being previously online
- * 1 -- friend went online
+ * If no status message was set before calling this function, the status is
+ * empty, and this function has no effect.
*
- * NOTE: This callback is not called when adding friends, thus the "after
- * being previously online" part. it's assumed that when adding friends,
- * their connection status is offline.
+ * Call tox_self_status_message_size to find out how much memory to allocate for
+ * the result.
+ *
+ * @param status A valid memory location large enough to hold the status message.
+ * If this parameter is NULL, the function has no effect.
*/
-void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata);
+void tox_self_get_status_message(const Tox *tox, uint8_t *status);
-/**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/
+/**
+ * Set the client's user status.
+ *
+ * @param user_status One of the user statuses listed in the enumeration above.
+ */
+void tox_self_set_status(Tox *tox, TOX_USER_STATUS user_status);
-/* Functions to get/set the nospam part of the id.
+/**
+ * Returns the client's user status.
*/
-uint32_t tox_get_nospam(const Tox *tox);
-void tox_set_nospam(Tox *tox, uint32_t nospam);
+TOX_USER_STATUS tox_self_get_status(const Tox *tox);
+
-/* Copy the public and secret key from the Tox object.
- public_key and secret_key must be 32 bytes big.
- if the pointer is NULL, no data will be copied to it.*/
-void tox_get_keys(Tox *tox, uint8_t *public_key, uint8_t *secret_key);
+/*******************************************************************************
+ *
+ * :: Friend list management
+ *
+ ******************************************************************************/
-/* Maximum size of custom packets. */
-#define TOX_MAX_CUSTOM_PACKET_SIZE 1373
-/* Set handlers for custom lossy packets.
- * Set the function to be called when friend sends us a lossy packet starting with byte.
- * byte must be in the 200-254 range.
+typedef enum TOX_ERR_FRIEND_ADD {
+ TOX_ERR_FRIEND_ADD_OK,
+ TOX_ERR_FRIEND_ADD_NULL,
+ /**
+ * The length of the friend request message exceeded
+ * TOX_MAX_FRIEND_REQUEST_LENGTH.
+ */
+ TOX_ERR_FRIEND_ADD_TOO_LONG,
+ /**
+ * The friend request message was empty. This, and the TOO_LONG code will
+ * never be returned from tox_friend_add_norequest.
+ */
+ TOX_ERR_FRIEND_ADD_NO_MESSAGE,
+ /**
+ * The friend address belongs to the sending client.
+ */
+ TOX_ERR_FRIEND_ADD_OWN_KEY,
+ /**
+ * A friend request has already been sent, or the address belongs to a friend
+ * that is already on the friend list.
+ */
+ TOX_ERR_FRIEND_ADD_ALREADY_SENT,
+ /**
+ * The friend address checksum failed.
+ */
+ TOX_ERR_FRIEND_ADD_BAD_CHECKSUM,
+ /**
+ * The friend was already there, but the nospam value was different.
+ */
+ TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM,
+ /**
+ * A memory allocation failed when trying to increase the friend list size.
+ */
+ TOX_ERR_FRIEND_ADD_MALLOC
+} TOX_ERR_FRIEND_ADD;
+
+/**
+ * Add a friend to the friend list and send a friend request.
+ *
+ * A friend request message must be at least 1 byte long and at most
+ * TOX_MAX_FRIEND_REQUEST_LENGTH.
*
- * NOTE: lossy packets behave like UDP packets meaning they might never reach the other side
- * or might arrive more than once (if someone is messing with the connection) or might arrive
- * in the wrong order.
+ * Friend numbers are unique identifiers used in all functions that operate on
+ * friends. Once added, a friend number is stable for the lifetime of the Tox
+ * object. After saving the state and reloading it, the friend numbers may not
+ * be the same as before. Deleting a friend creates a gap in the friend number
+ * set, which is filled by the next adding of a friend. Any pattern in friend
+ * numbers should not be relied on.
*
- * Unless latency is an issue, it is recommended that you use lossless packets instead.
+ * If more than INT32_MAX friends are added, this function causes undefined
+ * behaviour.
*
- * return -1 on failure.
- * return 0 on success.
+ * @param address The address of the friend (returned by tox_self_get_address of
+ * the friend you wish to add) it must be TOX_ADDRESS_SIZE bytes.
+ * @param message The message that will be sent along with the friend request.
+ * @param length The length of the data byte array.
+ *
+ * @return the friend number on success, UINT32_MAX on failure.
*/
-int tox_lossy_packet_registerhandler(Tox *tox, int32_t friendnumber, uint8_t byte,
- int (*packet_handler_callback)(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t len, void *object),
- void *object);
+uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length,
+ TOX_ERR_FRIEND_ADD *error);
+
-/* Function to send custom lossy packets.
- * First byte of data must be in the range: 200-254.
+/**
+ * Add a friend without sending a friend request.
+ *
+ * This function is used to add a friend in response to a friend request. If the
+ * client receives a friend request, it can be reasonably sure that the other
+ * client added this client as a friend, eliminating the need for a friend
+ * request.
+ *
+ * This function is also useful in a situation where both instances are
+ * controlled by the same entity, so that this entity can perform the mutual
+ * friend adding. In this case, there is no need for a friend request, either.
*
- * return -1 on failure.
- * return 0 on success.
+ * @param public_key A byte array of length TOX_PUBLIC_KEY_SIZE containing the
+ * Public Key (not the Address) of the friend to add.
+ *
+ * @return the friend number on success, UINT32_MAX on failure.
+ * @see tox_friend_add for a more detailed description of friend numbers.
*/
-int tox_send_lossy_packet(const Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length);
+uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error);
+
-/* Set handlers for custom lossless packets.
- * Set the function to be called when friend sends us a lossless packet starting with byte.
- * byte must be in the 160-191 range.
+typedef enum TOX_ERR_FRIEND_DELETE {
+ TOX_ERR_FRIEND_DELETE_OK,
+ /**
+ * There was no friend with the given friend number. No friends were deleted.
+ */
+ TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND
+} TOX_ERR_FRIEND_DELETE;
+
+/**
+ * Remove a friend from the friend list.
+ * Other friend numbers are unchanged.
+ * The friend_number can be reused by toxcore as a friend number for a new friend.
+ *
+ * This does not notify the friend of their deletion. After calling this
+ * function, this client will appear offline to the friend and no communication
+ * can occur between the two.
*
- * Lossless packets behave kind of like TCP (reliability, arrive in order.) but with packets instead of a stream.
+ * @friend_number Friend number for the friend to be deleted.
*
- * return -1 on failure.
- * return 0 on success.
+ * @return true on success.
+ * @see tox_friend_add for detailed description of friend numbers.
*/
-int tox_lossless_packet_registerhandler(Tox *tox, int32_t friendnumber, uint8_t byte,
- int (*packet_handler_callback)(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t len, void *object),
- void *object);
+bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error);
-/* Function to send custom lossless packets.
- * First byte of data must be in the range: 160-191.
+
+/*******************************************************************************
*
- * return -1 on failure.
- * return 0 on success.
- */
-int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length);
+ * :: Friend list queries
+ *
+ ******************************************************************************/
+
-/**********GROUP CHAT FUNCTIONS: WARNING Group chats will be rewritten so this might change ************/
+typedef enum TOX_ERR_FRIEND_BY_PUBLIC_KEY {
+ TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK,
+ TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL,
+ /**
+ * No friend with the given Public Key exists on the friend list.
+ */
+ TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND
+} TOX_ERR_FRIEND_BY_PUBLIC_KEY;
-/* Group chat types for tox_callback_group_invite function.
+/**
+ * Return the friend number associated with that Public Key.
*
- * TOX_GROUPCHAT_TYPE_TEXT groupchats must be accepted with the tox_join_groupchat() function.
- * The function to accept TOX_GROUPCHAT_TYPE_AV is in toxav.
+ * @return the friend number on success, UINT32_MAX on failure.
+ * @param public_key A byte array containing the Public Key.
*/
-enum {
- TOX_GROUPCHAT_TYPE_TEXT,
- TOX_GROUPCHAT_TYPE_AV
-};
+uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error);
-/* Set the callback for group invites.
- *
- * Function(Tox *tox, int32_t friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)
+
+typedef enum TOX_ERR_FRIEND_GET_PUBLIC_KEY {
+ TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK,
+ /**
+ * No friend with the given number exists on the friend list.
+ */
+ TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND
+} TOX_ERR_FRIEND_GET_PUBLIC_KEY;
+
+/**
+ * Copies the Public Key associated with a given friend number to a byte array.
*
- * data of length is what needs to be passed to join_groupchat().
+ * @param friend_number The friend number you want the Public Key of.
+ * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If
+ * this parameter is NULL, this function has no effect.
*
- * for what type means see the enum right above this comment.
+ * @return true on success.
*/
-void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, const uint8_t *, uint16_t,
- void *), void *userdata);
+bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key,
+ TOX_ERR_FRIEND_GET_PUBLIC_KEY *error);
-/* Set the callback for group messages.
+
+/**
+ * Checks if a friend with the given friend number exists and returns true if
+ * it does.
+ */
+bool tox_friend_exists(const Tox *tox, uint32_t friend_number);
+
+typedef enum TOX_ERR_FRIEND_GET_LAST_ONLINE {
+ TOX_ERR_FRIEND_GET_LAST_ONLINE_OK,
+ /**
+ * No friend with the given number exists on the friend list.
+ */
+ TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND,
+} TOX_ERR_FRIEND_GET_LAST_ONLINE;
+
+/**
+ * Return a unix-time timestamp of the last time the friend associated with a given
+ * friend number was seen online. This function will return UINT64_MAX on error.
*
- * Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * message, uint16_t length, void *userdata)
+ * @param friend_number The friend number you want to query.
*/
-void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),
- void *userdata);
+uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error);
-/* Set the callback for group actions.
+/**
+ * Return the number of friends on the friend list.
*
- * Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * action, uint16_t length, void *userdata)
+ * This function can be used to determine how much memory to allocate for
+ * tox_self_get_friend_list.
*/
-void tox_callback_group_action(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),
- void *userdata);
+size_t tox_self_get_friend_list_size(const Tox *tox);
-/* Set callback function for title changes.
+
+/**
+ * Copy a list of valid friend numbers into an array.
+ *
+ * Call tox_self_get_friend_list_size to determine the number of elements to allocate.
*
- * Function(Tox *tox, int groupnumber, int peernumber, uint8_t * title, uint8_t length, void *userdata)
- * if peernumber == -1, then author is unknown (e.g. initial joining the group)
+ * @param list A memory region with enough space to hold the friend list. If
+ * this parameter is NULL, this function has no effect.
*/
-void tox_callback_group_title(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint8_t,
- void *), void *userdata);
+void tox_self_get_friend_list(const Tox *tox, uint32_t *list);
+
-/* Set callback function for peer name list changes.
+
+/*******************************************************************************
+ *
+ * :: Friend-specific state queries (can also be received through callbacks)
*
- * It gets called every time the name list changes(new peer/name, deleted peer)
- * Function(Tox *tox, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)
+ ******************************************************************************/
+
+
+/**
+ * Common error codes for friend state query functions.
*/
-typedef enum {
- TOX_CHAT_CHANGE_PEER_ADD,
- TOX_CHAT_CHANGE_PEER_DEL,
- TOX_CHAT_CHANGE_PEER_NAME,
-} TOX_CHAT_CHANGE;
+typedef enum TOX_ERR_FRIEND_QUERY {
+ TOX_ERR_FRIEND_QUERY_OK,
+ /**
+ * The pointer parameter for storing the query result (name, message) was
+ * NULL. Unlike the `_self_` variants of these functions, which have no effect
+ * when a parameter is NULL, these functions return an error in that case.
+ */
+ TOX_ERR_FRIEND_QUERY_NULL,
+ /**
+ * The friend_number did not designate a valid friend.
+ */
+ TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND
+} TOX_ERR_FRIEND_QUERY;
-void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *),
- void *userdata);
-/* Creates a new groupchat and puts it in the chats array.
+/**
+ * Return the length of the friend's name. If the friend number is invalid, the
+ * return value is SIZE_MAX.
*
- * return group number on success.
- * return -1 on failure.
+ * The return value is equal to the `length` argument received by the last
+ * `friend_name` callback.
*/
-int tox_add_groupchat(Tox *tox);
+size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);
-/* Delete a groupchat from the chats array.
+/**
+ * Write the name of the friend designated by the given friend number to a byte
+ * array.
*
- * return 0 on success.
- * return -1 if failure.
+ * Call tox_friend_get_name_size to determine the allocation size for the `name`
+ * parameter.
+ *
+ * The data written to `name` is equal to the data received by the last
+ * `friend_name` callback.
+ *
+ * @param name A valid memory region large enough to store the friend's name.
+ *
+ * @return true on success.
*/
-int tox_del_groupchat(Tox *tox, int groupnumber);
+bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error);
-/* Copy the name of peernumber who is in groupnumber to name.
- * name must be at least TOX_MAX_NAME_LENGTH long.
+/**
+ * The function type for the `friend_name` callback.
*
- * return length of name if success
- * return -1 if failure
+ * @param friend_number The friend number of the friend whose name changed.
+ * @param name A byte array containing the same data as
+ * tox_friend_get_name would write to its `name` parameter.
+ * @param length A value equal to the return value of
+ * tox_friend_get_name_size.
*/
-int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name);
+typedef void tox_friend_name_cb(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length, void *user_data);
-/* Copy the public key of peernumber who is in groupnumber to public_key.
- * public_key must be TOX_PUBLIC_KEY_SIZE long.
+/**
+ * Set the callback for the `friend_name` event. Pass NULL to unset.
*
- * returns 0 on success
- * returns -1 on failure
+ * This event is triggered when a friend changes their name.
*/
-int tox_group_peer_pubkey(const Tox *tox, int groupnumber, int peernumber, uint8_t *public_key);
+void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function, void *user_data);
+
-/* invite friendnumber to groupnumber
- * return 0 on success
- * return -1 on failure
+/**
+ * Return the length of the friend's status message. If the friend number is
+ * invalid, the return value is SIZE_MAX.
*/
-int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber);
+size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);
-/* Join a group (you need to have been invited first.) using data of length obtained
- * in the group invite callback.
+/**
+ * Write the name of the friend designated by the given friend number to a byte
+ * array.
*
- * returns group number on success
- * returns -1 on failure.
+ * Call tox_friend_get_name_size to determine the allocation size for the `name`
+ * parameter.
+ *
+ * The data written to `message` is equal to the data received by the last
+ * `friend_status_message` callback.
+ *
+ * @param name A valid memory region large enough to store the friend's name.
*/
-int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length);
+bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *message,
+ TOX_ERR_FRIEND_QUERY *error);
-/* send a group message
- * return 0 on success
- * return -1 on failure
+/**
+ * The function type for the `friend_status_message` callback.
+ *
+ * @param friend_number The friend number of the friend whose status message
+ * changed.
+ * @param message A byte array containing the same data as
+ * tox_friend_get_status_message would write to its `message` parameter.
+ * @param length A value equal to the return value of
+ * tox_friend_get_status_message_size.
*/
-int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length);
+typedef void tox_friend_status_message_cb(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length,
+ void *user_data);
-/* send a group action
- * return 0 on success
- * return -1 on failure
+/**
+ * Set the callback for the `friend_status_message` event. Pass NULL to unset.
+ *
+ * This event is triggered when a friend changes their status message.
*/
-int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length);
+void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function, void *user_data);
-/* set the group's title, limited to MAX_NAME_LENGTH
- * return 0 on success
- * return -1 on failure
- */
-int tox_group_set_title(Tox *tox, int groupnumber, const uint8_t *title, uint8_t length);
-/* Get group title from groupnumber and put it in title.
- * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.
+/**
+ * Return the friend's user status (away/busy/...). If the friend number is
+ * invalid, the return value is unspecified.
*
- * return length of copied title if success.
- * return -1 if failure.
+ * The status returned is equal to the last status received through the
+ * `friend_status` callback.
*/
-int tox_group_get_title(Tox *tox, int groupnumber, uint8_t *title, uint32_t max_length);
+TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);
-/* Check if the current peernumber corresponds to ours.
+/**
+ * The function type for the `friend_status` callback.
*
- * return 1 if the peernumber corresponds to ours.
- * return 0 on failure.
+ * @param friend_number The friend number of the friend whose user status
+ * changed.
+ * @param status The new user status.
*/
-unsigned int tox_group_peernumber_is_ours(const Tox *tox, int groupnumber, int peernumber);
+typedef void tox_friend_status_cb(Tox *tox, uint32_t friend_number, TOX_USER_STATUS status, void *user_data);
-/* Return the number of peers in the group chat on success.
- * return -1 on failure
+/**
+ * Set the callback for the `friend_status` event. Pass NULL to unset.
+ *
+ * This event is triggered when a friend changes their user status.
*/
-int tox_group_number_peers(const Tox *tox, int groupnumber);
+void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function, void *user_data);
-/* List all the peers in the group chat.
- *
- * Copies the names of the peers to the name[length][TOX_MAX_NAME_LENGTH] array.
+
+/**
+ * Check whether a friend is currently connected to this client.
*
- * Copies the lengths of the names to lengths[length]
+ * The result of this function is equal to the last value received by the
+ * `friend_connection_status` callback.
*
- * returns the number of peers on success.
+ * @param friend_number The friend number for which to query the connection
+ * status.
*
- * return -1 on failure.
+ * @return the friend's connection status as it was received through the
+ * `friend_connection_status` event.
*/
-int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[],
- uint16_t length);
-
-/* Return the number of chats in the instance m.
- * You should use this to determine how much memory to allocate
- * for copy_chatlist. */
-uint32_t tox_count_chatlist(const Tox *tox);
+TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);
-/* Copy a list of valid chat IDs into the array out_list.
- * If out_list is NULL, returns 0.
- * Otherwise, returns the number of elements copied.
- * If the array was too small, the contents
- * of out_list will be truncated to list_size. */
-uint32_t tox_get_chatlist(const Tox *tox, int32_t *out_list, uint32_t list_size);
-
-/* return the type of groupchat (TOX_GROUPCHAT_TYPE_) that groupnumber is.
+/**
+ * The function type for the `friend_connection_status` callback.
*
- * return -1 on failure.
- * return type on success.
+ * @param friend_number The friend number of the friend whose connection status
+ * changed.
+ * @param connection_status The result of calling
+ * tox_friend_get_connection_status on the passed friend_number.
*/
-int tox_group_get_type(const Tox *tox, int groupnumber);
-
-/****************AVATAR FUNCTIONS*****************/
+typedef void tox_friend_connection_status_cb(Tox *tox, uint32_t friend_number, TOX_CONNECTION connection_status,
+ void *user_data);
-/* Set the callback function for avatar information.
- * This callback will be called when avatar information are received from friends. These events
- * can arrive at anytime, but are usually received uppon connection and in reply of avatar
- * information requests.
+/**
+ * Set the callback for the `friend_connection_status` event. Pass NULL to
+ * unset.
*
- * Function format is:
- * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata)
- *
- * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT) and 'hash' is the hash of
- * the avatar data for caching purposes and it is exactly TOX_HASH_LENGTH long. If the image
- * format is NONE, the hash is zeroed.
+ * This event is triggered when a friend goes offline after having been online,
+ * or when a friend goes online.
*
+ * This callback is not called when adding friends. It is assumed that when
+ * adding friends, their connection status is offline.
*/
-void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *),
- void *userdata);
+void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data);
-/* Set the callback function for avatar data.
- * This callback will be called when the complete avatar data was correctly received from a
- * friend. This only happens in reply of a avatar data request (see tox_request_avatar_data);
+/**
+ * Check whether a friend is currently typing a message.
*
- * Function format is:
- * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)
+ * @param friend_number The friend number for which to query the typing status.
*
- * where 'format' is the avatar image format (see TOX_AVATAR_FORMAT); 'hash' is the
- * locally-calculated cryptographic hash of the avatar data and it is exactly
- * TOX_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length
- * of such data.
+ * @return true if the friend is typing.
+ * @return false if the friend is not typing, or the friend number was
+ * invalid. Inspect the error code to determine which case it is.
+ */
+bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);
+
+/**
+ * The function type for the `friend_typing` callback.
*
- * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is
- * always validated locally with the function tox_hash and ensured to match the image data,
- * so this value can be safely used to compare with cached avatars.
+ * @param friend_number The friend number of the friend who started or stopped
+ * typing.
+ * @param is_typing The result of calling tox_friend_get_typing on the passed
+ * friend_number.
+ */
+typedef void tox_friend_typing_cb(Tox *tox, uint32_t friend_number, bool is_typing, void *user_data);
+
+/**
+ * Set the callback for the `friend_typing` event. Pass NULL to unset.
*
- * WARNING: users MUST treat all avatar image data received from another peer as untrusted and
- * potentially malicious. The library only ensures that the data which arrived is the same the
- * other user sent, and does not interpret or validate any image data.
+ * This event is triggered when a friend starts or stops typing.
*/
-void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t,
- void *), void *userdata);
+void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data);
+
+
+/*******************************************************************************
+ *
+ * :: Sending private messages
+ *
+ ******************************************************************************/
+
+
+typedef enum TOX_ERR_SET_TYPING {
+ TOX_ERR_SET_TYPING_OK,
+ /**
+ * The friend number did not designate a valid friend.
+ */
+ TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND
+} TOX_ERR_SET_TYPING;
-/* Set the user avatar image data.
- * This should be made before connecting, so we will not announce that the user have no avatar
- * before setting and announcing a new one, forcing the peers to re-download it.
+/**
+ * Set the client's typing status for a friend.
*
- * Notice that the library treats the image as raw data and does not interpret it by any way.
+ * The client is responsible for turning it on or off.
*
- * Arguments:
- * format - Avatar image format or NONE for user with no avatar (see TOX_AVATAR_FORMAT);
- * data - pointer to the avatar data (may be NULL it the format is NONE);
- * length - length of image data. Must be <= TOX_AVATAR_MAX_DATA_LENGTH.
+ * @param friend_number The friend to which the client is typing a message.
+ * @param is_typing The typing status. True means the client is typing.
*
- * returns 0 on success
- * returns -1 on failure.
+ * @return true on success.
*/
-int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
+bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool is_typing, TOX_ERR_SET_TYPING *error);
-/* Unsets the user avatar.
- returns 0 on success (currently always returns 0) */
-int tox_unset_avatar(Tox *tox);
+typedef enum TOX_ERR_FRIEND_SEND_MESSAGE {
+ TOX_ERR_FRIEND_SEND_MESSAGE_OK,
+ TOX_ERR_FRIEND_SEND_MESSAGE_NULL,
+ /**
+ * The friend number did not designate a valid friend.
+ */
+ TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED,
+ /**
+ * An allocation error occurred while increasing the send queue size.
+ */
+ TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ,
+ /**
+ * Message length exceeded TOX_MAX_MESSAGE_LENGTH.
+ */
+ TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG,
+ /**
+ * Attempted to send a zero-length message.
+ */
+ TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY
+} TOX_ERR_FRIEND_SEND_MESSAGE;
-/* Get avatar data from the current user.
- * Copies the current user avatar data to the destination buffer and sets the image format
- * accordingly.
+/**
+ * Send a text chat message to an online friend.
*
- * If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and
- * 'length' is set to zero.
+ * This function creates a chat message packet and pushes it into the send
+ * queue.
*
- * If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored.
+ * Type corresponds to the message type, for a list of valid types see TOX_MESSAGE_TYPE.
*
- * Arguments:
- * format - destination pointer to the avatar image format (see TOX_AVATAR_FORMAT);
- * buf - destination buffer to the image data. Must have at least 'maxlen' bytes;
- * length - destination pointer to the image data length;
- * maxlen - length of the destination buffer 'buf';
- * hash - destination pointer to the avatar hash (it must be exactly TOX_HASH_LENGTH bytes long).
+ * The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages
+ * must be split by the client and sent as separate messages. Other clients can
+ * then reassemble the fragments. Messages may not be empty.
*
- * returns 0 on success;
- * returns -1 on failure.
+ * The return value of this function is the message ID. If a read receipt is
+ * received, the triggered `read_receipt` event will be passed this message ID.
*
+ * Message IDs are unique per friend. The first message ID is 0. Message IDs are
+ * incremented by 1 each time a message is sent. If UINT32_MAX messages were
+ * sent, the next message ID is 0.
*/
-int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
- uint8_t *hash);
+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);
-
-/* Generates a cryptographic hash of the given data.
- * This function may be used by clients for any purpose, but is provided primarily for
- * validating cached avatars. This use is highly recommended to avoid unnecessary avatar
- * updates.
- * This function is a wrapper to internal message-digest functions.
+/**
+ * The function type for the `read_receipt` callback.
*
- * Arguments:
- * hash - destination buffer for the hash data, it must be exactly TOX_HASH_LENGTH bytes long.
- * data - data to be hashed;
- * datalen - length of the data; for avatars, should be TOX_AVATAR_MAX_DATA_LENGTH
- *
- * returns 0 on success
- * returns -1 on failure.
+ * @param friend_number The friend number of the friend who received the message.
+ * @param message_id The message ID as returned from tox_friend_send_message
+ * corresponding to the message sent.
*/
-int tox_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen);
+typedef void tox_friend_read_receipt_cb(Tox *tox, uint32_t friend_number, uint32_t message_id, void *user_data);
-/* Request avatar information from a friend.
- * Asks a friend to provide their avatar information (image format and hash). The friend may
- * or may not answer this request and, if answered, the information will be provided through
- * the callback 'avatar_info'.
+/**
+ * Set the callback for the `read_receipt` event. Pass NULL to unset.
*
- * returns 0 on success
- * returns -1 on failure.
+ * This event is triggered when the friend receives the message sent with
+ * tox_friend_send_message with the corresponding message ID.
*/
-int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber);
+void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *function, void *user_data);
-/* Send an unrequested avatar information to a friend.
- * Sends our avatar format and hash to a friend; he/she can use this information to validate
- * an avatar from the cache and may (or not) reply with an avatar data request.
+/*******************************************************************************
*
- * Notice: it is NOT necessary to send these notification after changing the avatar or
- * connecting. The library already does this.
+ * :: Receiving private messages and friend requests
*
- * returns 0 on success
- * returns -1 on failure.
- */
-int tox_send_avatar_info(Tox *tox, const int32_t friendnumber);
+ ******************************************************************************/
-/* Request the avatar data from a friend.
- * Ask a friend to send their avatar data. The friend may or may not answer this request and,
- * if answered, the information will be provided in callback 'avatar_data'.
+/**
+ * The function type for the `friend_request` callback.
*
- * returns 0 on sucess
- * returns -1 on failure.
+ * @param public_key The Public Key of the user who sent the friend request.
+ * @param message The message they sent along with the request.
+ * @param length The size of the message byte array.
*/
-int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber);
+typedef void tox_friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
+ void *user_data);
-/****************FILE SENDING FUNCTIONS*****************/
-/* NOTE: This how to will be updated.
+/**
+ * Set the callback for the `friend_request` event. Pass NULL to unset.
*
- * HOW TO SEND FILES CORRECTLY:
- * 1. Use tox_new_file_sender(...) to create a new file sender.
- * 2. Wait for the callback set with tox_callback_file_control(...) to be called with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT
- * 3. Send the data with tox_file_send_data(...) with chunk size tox_file_data_size(...)
- * 4. When sending is done, send a tox_file_send_control(...) with send_receive = 0 and message_id = TOX_FILECONTROL_FINISHED
- * 5. when the callback set with tox_callback_file_control(...) is called with receive_send == 1 and control_type == TOX_FILECONTROL_FINISHED
- * the other person has received the file correctly.
+ * This event is triggered when a friend request is received.
+ */
+void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *function, void *user_data);
+
+
+/**
+ * The function type for the `friend_message` callback.
*
- * HOW TO RECEIVE FILES CORRECTLY:
- * 1. wait for the callback set with tox_callback_file_send_request(...)
- * 2. accept or refuse the connection with tox_file_send_control(...) with send_receive = 1 and message_id = TOX_FILECONTROL_ACCEPT or TOX_FILECONTROL_KILL
- * 3. save all the data received with the callback set with tox_callback_file_data(...) to a file.
- * 4. when the callback set with tox_callback_file_control(...) is called with receive_send == 0 and control_type == TOX_FILECONTROL_FINISHED
- * the file is done transferring.
- * 5. send a tox_file_send_control(...) with send_receive = 1 and message_id = TOX_FILECONTROL_FINISHED to confirm that we did receive the file.
+ * @param friend_number The friend number of the friend who sent the message.
+ * @param type The message type, for a list of valid types see TOX_MESSAGE_TYPE.
+ * @param message The message data they sent.
+ * @param length The size of the message byte array.
+ */
+typedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message,
+ size_t length, void *user_data);
+
+/**
+ * Set the callback for the `friend_message` event. Pass NULL to unset.
*
- * tox_file_data_remaining(...) can be used to know how many bytes are left to send/receive.
+ * This event is triggered when a message from a friend is received.
+ */
+void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function, void *user_data);
+
+
+/*******************************************************************************
*
- * If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back)
- * the receiver must send a control packet with send_receive == 1 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being
- * a uint64_t (in host byte order) containing the number of bytes received.
+ * :: File transmission: common between sending and receiving
*
- * If the sender receives this packet, he must send a control packet with send_receive == 0 and control_type == TOX_FILECONTROL_ACCEPT
- * then he must start sending file data from the position (data , uint64_t in host byte order) received in the TOX_FILECONTROL_RESUME_BROKEN packet.
+ ******************************************************************************/
+
+
+enum TOX_FILE_KIND {
+ /**
+ * Arbitrary file data. Clients can choose to handle it based on the file name
+ * or magic or any other way they choose.
+ */
+ TOX_FILE_KIND_DATA,
+ /**
+ * Avatar filename. This consists of tox_hash(image).
+ * Avatar data. This consists of the image data.
+ *
+ * Avatars can be sent at any time the client wishes. Generally, a client will
+ * send the avatar to a friend when that friend comes online, and to all
+ * friends when the avatar changed. A client can save some traffic by
+ * remembering which friend received the updated avatar already and only send
+ * it if the friend has an out of date avatar.
+ *
+ * Clients who receive avatar send requests can reject it (by sending
+ * TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by
+ * sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH bytes
+ * (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client can compare
+ * this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar
+ * transfer if it matches.
+ *
+ * When file_size is set to 0 in the transfer request it means that the client has no
+ * avatar.
+ */
+ TOX_FILE_KIND_AVATAR
+};
+
+
+/**
+ * Generates a cryptographic hash of the given data.
+ *
+ * This function may be used by clients for any purpose, but is provided
+ * primarily for validating cached avatars. This use is highly recommended to
+ * avoid unnecessary avatar updates.
*
- * To pause a file transfer send a control packet with control_type == TOX_FILECONTROL_PAUSE.
- * To unpause a file transfer send a control packet with control_type == TOX_FILECONTROL_ACCEPT.
+ * If length is zero or data is NULL, the hash will contain all zero. If hash is
+ * NULL, the function returns false, otherwise it returns true.
*
- * If you receive a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_PAUSE, you must stop sending filenumber until the other
- * person sends a control packet with send_receive == 0 and control_type == TOX_FILECONTROL_ACCEPT with the filenumber being a paused filenumber.
+ * This function is a wrapper to internal message-digest functions.
*
- * If you receive a control packet with receive_send == 0 and control_type == TOX_FILECONTROL_PAUSE, it means the sender of filenumber has paused the
- * transfer and will resume it later with a control packet with send_receive == 1 and control_type == TOX_FILECONTROL_ACCEPT for that file number.
+ * @param hash A valid memory location the hash data. It must be at least
+ * TOX_HASH_LENGTH bytes in size.
+ * @param data Data to be hashed or NULL.
+ * @param length Size of the data array or 0.
+ *
+ * @return true if hash was not NULL.
+ */
+bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length);
+
+
+typedef enum TOX_FILE_CONTROL {
+ /**
+ * Sent by the receiving side to accept a file send request. Also sent after a
+ * TOX_FILE_CONTROL_PAUSE command to continue sending or receiving.
+ */
+ TOX_FILE_CONTROL_RESUME,
+ /**
+ * Sent by clients to pause the file transfer. The initial state of a file
+ * transfer is always paused on the receiving side and running on the sending
+ * side. If both the sending and receiving side pause the transfer, then both
+ * need to send TOX_FILE_CONTROL_RESUME for the transfer to resume.
+ */
+ TOX_FILE_CONTROL_PAUSE,
+ /**
+ * Sent by the receiving side to reject a file send request before any other
+ * commands are sent. Also sent by either side to terminate a file transfer.
+ */
+ TOX_FILE_CONTROL_CANCEL
+} TOX_FILE_CONTROL;
+
+
+typedef enum TOX_ERR_FILE_CONTROL {
+ TOX_ERR_FILE_CONTROL_OK,
+ /**
+ * The friend_number passed did not designate a valid friend.
+ */
+ TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED,
+ /**
+ * No file transfer with the given file number was found for the given friend.
+ */
+ TOX_ERR_FILE_CONTROL_NOT_FOUND,
+ /**
+ * A RESUME control was sent, but the file transfer is running normally.
+ */
+ TOX_ERR_FILE_CONTROL_NOT_PAUSED,
+ /**
+ * A RESUME control was sent, but the file transfer was paused by the other
+ * party. Only the party that paused the transfer can resume it.
+ */
+ TOX_ERR_FILE_CONTROL_DENIED,
+ /**
+ * A PAUSE control was sent, but the file transfer was already paused.
+ */
+ TOX_ERR_FILE_CONTROL_ALREADY_PAUSED,
+ /**
+ * Packet queue is full.
+ */
+ TOX_ERR_FILE_CONTROL_SENDQ
+} TOX_ERR_FILE_CONTROL;
+
+/**
+ * Sends a file control command to a friend for a given file transfer.
+ *
+ * @param friend_number The friend number of the friend the file is being
+ * transferred to or received from.
+ * @param file_number The friend-specific identifier for the file transfer.
+ * @param control The control command to send.
+ *
+ * @return true on success.
+ */
+bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
+ TOX_ERR_FILE_CONTROL *error);
+
+
+/**
+ * The function type for the `file_control` callback.
+ *
+ * When receiving TOX_FILE_CONTROL_CANCEL, the client should release the
+ * resources associated with the file number and consider the transfer failed.
+ *
+ * @param friend_number The friend number of the friend who is sending the file.
+ * @param file_number The friend-specific file number the data received is
+ * associated with.
+ * @param control The file control command received.
+ */
+typedef void tox_file_recv_control_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
+ void *user_data);
+
+/**
+ * Set the callback for the `file_control` event. Pass NULL to unset.
+ *
+ * This event is triggered when a file control command is received from a
+ * friend.
+ */
+void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function, void *user_data);
+
+
+typedef enum TOX_ERR_FILE_SEEK {
+ TOX_ERR_FILE_SEEK_OK,
+ /**
+ * The friend_number passed did not designate a valid friend.
+ */
+ TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED,
+ /**
+ * No file transfer with the given file number was found for the given friend.
+ */
+ TOX_ERR_FILE_SEEK_NOT_FOUND,
+ /**
+ * File was not in a state where it could be seeked.
+ */
+ TOX_ERR_FILE_SEEK_DENIED,
+ /**
+ * Seek position was invalid
+ */
+ TOX_ERR_FILE_SEEK_INVALID_POSITION,
+ /**
+ * Packet queue is full.
+ */
+ TOX_ERR_FILE_SEEK_SENDQ
+} TOX_ERR_FILE_SEEK;
+
+/**
+ * Sends a file seek control command to a friend for a given file transfer.
+ *
+ * This function can only be called to resume a file transfer right before
+ * TOX_FILE_CONTROL_RESUME is sent.
+ *
+ * @param friend_number The friend number of the friend the file is being
+ * received from.
+ * @param file_number The friend-specific identifier for the file transfer.
+ * @param position The position that the file should be seeked to.
+ */
+bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
+ TOX_ERR_FILE_SEEK *error);
+
+typedef enum TOX_ERR_FILE_GET {
+ TOX_ERR_FILE_GET_OK,
+ /**
+ * The friend_number passed did not designate a valid friend.
+ */
+ TOX_ERR_FILE_GET_FRIEND_NOT_FOUND,
+ /**
+ * No file transfer with the given file number was found for the given friend.
+ */
+ TOX_ERR_FILE_GET_NOT_FOUND
+} TOX_ERR_FILE_GET;
+
+/**
+ * Copy the file id associated to the file transfer to a byte array.
+ *
+ * @param friend_number The friend number of the friend the file is being
+ * transferred to.
+ * @param file_number The friend-specific identifier for the file transfer.
+ * @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If
+ * this parameter is NULL, this function has no effect.
+ *
+ * @return true on success.
+ */
+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);
+
+/*******************************************************************************
+ *
+ * :: File transmission: sending
+ *
+ ******************************************************************************/
+
+
+typedef enum TOX_ERR_FILE_SEND {
+ TOX_ERR_FILE_SEND_OK,
+ TOX_ERR_FILE_SEND_NULL,
+ /**
+ * The friend_number passed did not designate a valid friend.
+ */
+ TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED,
+ /**
+ * Filename length exceeded TOX_MAX_FILENAME_LENGTH bytes.
+ */
+ TOX_ERR_FILE_SEND_NAME_TOO_LONG,
+ /**
+ * Too many ongoing transfers. The maximum number of concurrent file transfers
+ * is 256 per friend per direction (sending and receiving).
+ */
+ TOX_ERR_FILE_SEND_TOO_MANY
+} TOX_ERR_FILE_SEND;
+
+/**
+ * Send a file transmission request.
+ *
+ * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename should generally just be
+ * a file name, not a path with directory names.
+ *
+ * If a non-zero file size is provided, this can be used by both sides to
+ * determine the sending progress. File size can be set to zero for streaming
+ * data of unknown size.
+ *
+ * File transmission occurs in chunks, which are requested through the
+ * `file_chunk_request` event.
+ *
+ * When a friend goes offline, all file transfers associated with the friend are
+ * purged from core.
+ *
+ * If the file contents change during a transfer, the behaviour is unspecified
+ * in general. What will actually happen depends on the mode in which the file
+ * was modified and how the client determines the file size.
+ *
+ * - If the file size was increased
+ * - and sending mode was streaming (file_size = UINT64_MAX), the behaviour will be as
+ * expected.
+ * - and sending mode was file (file_size != UINT64_MAX), the file_chunk_request
+ * callback will receive length = 0 when Core thinks the file transfer has
+ * finished. If the client remembers the file size as it was when sending
+ * the request, it will terminate the transfer normally. If the client
+ * re-reads the size, it will think the friend cancelled the transfer.
+ * - If the file size was decreased
+ * - and sending mode was streaming, the behaviour is as expected.
+ * - and sending mode was file, the callback will return 0 at the new
+ * (earlier) end-of-file, signalling to the friend that the transfer was
+ * cancelled.
+ * - If the file contents were modified
+ * - at a position before the current read, the two files (local and remote)
+ * will differ after the transfer terminates.
+ * - at a position after the current read, the file transfer will succeed as
+ * expected.
+ * - In either case, both sides will regard the transfer as complete and
+ * successful.
+ *
+ * @param friend_number The friend number of the friend the file send request
+ * should be sent to.
+ * @param kind The meaning of the file to be sent.
+ * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if
+ * unknown or streaming.
+ * @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be used to
+ * uniquely identify file transfers across core restarts. If NULL, a random one will
+ * be generated by core. It can then be obtained by using tox_file_get_file_id().
+ * @param filename Name of the file. Does not need to be the actual name. This
+ * name will be sent along with the file send request.
+ * @param filename_length Size in bytes of the filename.
+ *
+ * @return A file number used as an identifier in subsequent callbacks. This
+ * number is per friend. File numbers are reused after a transfer terminates.
+ * on failure, this function returns UINT32_MAX. Any pattern in file numbers
+ * should not be relied on.
+ */
+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);
+
+
+typedef enum TOX_ERR_FILE_SEND_CHUNK {
+ TOX_ERR_FILE_SEND_CHUNK_OK,
+ /**
+ * The length parameter was non-zero, but data was NULL.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_NULL,
+ /**
+ * The friend_number passed did not designate a valid friend.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED,
+ /**
+ * No file transfer with the given file number was found for the given friend.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND,
+ /**
+ * File transfer was found but isn't in a transferring state: (paused, done,
+ * broken, etc...) (happens only when not called from the request chunk callback).
+ */
+ TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING,
+ /**
+ * Attempted to send more or less data than requested. The requested data size is
+ * adjusted according to maximum transmission unit and the expected end of
+ * the file. Trying to send less or more than requested will return this error.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH,
+ /**
+ * Packet queue is full.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_SENDQ,
+ /**
+ * Position parameter was wrong.
+ */
+ TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION
+} TOX_ERR_FILE_SEND_CHUNK;
+
+/**
+ * Send a chunk of file data to a friend.
+ *
+ * This function is called in response to the `file_chunk_request` callback. The
+ * length parameter should be equal to the one received though the callback.
+ * If it is zero, the transfer is assumed complete. For files with known size,
+ * Core will know that the transfer is complete after the last byte has been
+ * received, so it is not necessary (though not harmful) to send a zero-length
+ * chunk to terminate. For streams, core will know that the transfer is finished
+ * if a chunk with length less than the length requested in the callback is sent.
+ *
+ * @param friend_number The friend number of the receiving friend for this file.
+ * @param file_number The file transfer identifier returned by tox_file_send.
+ * @param position The file or stream position from which to continue reading.
+ * @return true on success.
+ */
+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);
+
+
+/**
+ * The function type for the `file_chunk_request` callback.
+ *
+ * If the length parameter is 0, the file transfer is finished, and the client's
+ * resources associated with the file number should be released. After a call
+ * with zero length, the file number can be reused for future file transfers.
+ *
+ * If the requested position is not equal to the client's idea of the current
+ * file or stream position, it will need to seek. In case of read-once streams,
+ * the client should keep the last read chunk so that a seek back can be
+ * supported. A seek-back only ever needs to read from the last requested chunk.
+ * This happens when a chunk was requested, but the send failed. A seek-back
+ * request can occur an arbitrary number of times for any given chunk.
+ *
+ * In response to receiving this callback, the client should call the function
+ * `tox_file_send_chunk` with the requested chunk. If the number of bytes sent
+ * through that function is zero, the file transfer is assumed complete. A
+ * client must send the full length of data requested with this callback.
*
- * More to come...
+ * @param friend_number The friend number of the receiving friend for this file.
+ * @param file_number The file transfer identifier returned by tox_file_send.
+ * @param position The file or stream position from which to continue reading.
+ * @param length The number of bytes requested for the current chunk.
*/
+typedef void tox_file_chunk_request_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
+ size_t length, void *user_data);
-enum {
- TOX_FILECONTROL_ACCEPT,
- TOX_FILECONTROL_PAUSE,
- TOX_FILECONTROL_KILL,
- TOX_FILECONTROL_FINISHED,
- TOX_FILECONTROL_RESUME_BROKEN
-};
-/* Set the callback for file send requests.
- *
- * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *filename, uint16_t filename_length, void *userdata)
+/**
+ * Set the callback for the `file_chunk_request` event. Pass NULL to unset.
*/
-void tox_callback_file_send_request(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint64_t, const uint8_t *,
- uint16_t, void *), void *userdata);
+void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *function, void *user_data);
+
-/* Set the callback for file control requests.
+/*******************************************************************************
*
- * receive_send is 1 if the message is for a slot on which we are currently sending a file and 0 if the message
- * is for a slot on which we are receiving the file
+ * :: File transmission: receiving
*
- * Function(Tox *tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata)
+ ******************************************************************************/
+
+
+/**
+ * The function type for the `file_receive` callback.
+ *
+ * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename should generally just be
+ * a file name, not a path with directory names.
+ *
+ * The client should acquire resources to be associated with the file transfer.
+ * Incoming file transfers start in the PAUSED state. After this callback
+ * returns, a transfer can be rejected by sending a TOX_FILE_CONTROL_CANCEL
+ * control command before any other control commands. It can be accepted by
+ * sending TOX_FILE_CONTROL_RESUME.
+ *
+ * @param friend_number The friend number of the friend who is sending the file
+ * transfer request.
+ * @param file_number The friend-specific file number the data received is
+ * associated with.
+ * @param kind The meaning of the file to be sent.
+ * @param file_size Size in bytes of the file about to be received from the client,
+ * UINT64_MAX if unknown or streaming.
+ * @param filename_length Size in bytes of the filename.
+ */
+typedef void tox_file_recv_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind,
+ uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data);
+
+/**
+ * Set the callback for the `file_receive` event. Pass NULL to unset.
*
+ * This event is triggered when a file transfer request is received.
*/
-void tox_callback_file_control(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *,
- uint16_t, void *), void *userdata);
+void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *function, void *user_data);
-/* Set the callback for file data.
+
+/**
+ * The function type for the `file_receive_chunk` callback.
+ *
+ * This function is first called when a file transfer request is received, and
+ * subsequently when a chunk of file data for an accepted request was received.
*
- * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata)
+ * When length is 0, the transfer is finished and the client should release the
+ * resources it acquired for the transfer. After a call with length = 0, the
+ * file number can be reused for new file transfers.
*
+ * If position is equal to file_size (received in the file_receive callback)
+ * when the transfer finishes, the file was received completely. Otherwise, if
+ * file_size was UINT64_MAX, streaming ended successfully when length is 0.
+ *
+ * @param friend_number The friend number of the friend who is sending the file.
+ * @param file_number The friend-specific file number the data received is
+ * associated with.
+ * @param position The file position of the first byte in data.
+ * @param data A byte array containing the received chunk.
+ * @param length The length of the received chunk.
*/
-void tox_callback_file_data(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, const uint8_t *, uint16_t length,
- void *), void *userdata);
-
+typedef void tox_file_recv_chunk_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
+ const uint8_t *data, size_t length, void *user_data);
-/* Send a file send request.
- * Maximum filename length is 255 bytes.
- * return file number on success
- * return -1 on failure
+/**
+ * Set the callback for the `file_receive_chunk` event. Pass NULL to unset.
*/
-int tox_new_file_sender(Tox *tox, int32_t friendnumber, uint64_t filesize, const uint8_t *filename,
- uint16_t filename_length);
+void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *function, void *user_data);
+
-/* Send a file control request.
+/*******************************************************************************
*
- * send_receive is 0 if we want the control packet to target a file we are currently sending,
- * 1 if it targets a file we are currently receiving.
+ * :: Group chat management
*
- * return 0 on success
- * return -1 on failure
- */
-int tox_file_send_control(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
- const uint8_t *data, uint16_t length);
+ ******************************************************************************/
+
-/* Send file data.
+/******************************************************************************
*
- * return 0 on success
- * return -1 on failure
- */
-int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length);
+ * :: Group chat message sending and receiving
+ *
+ ******************************************************************************/
-/* Returns the recommended/maximum size of the filedata you send with tox_file_send_data()
+/* See: tox_old.h for now. */
+
+/*******************************************************************************
*
- * return size on success
- * return -1 on failure (currently will never return -1)
- */
-int tox_file_data_size(const Tox *tox, int32_t friendnumber);
+ * :: Low-level custom packet sending and receiving
+ *
+ ******************************************************************************/
+
-/* Give the number of bytes left to be sent/received.
+typedef enum TOX_ERR_FRIEND_CUSTOM_PACKET {
+ TOX_ERR_FRIEND_CUSTOM_PACKET_OK,
+ TOX_ERR_FRIEND_CUSTOM_PACKET_NULL,
+ /**
+ * The friend number did not designate a valid friend.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND,
+ /**
+ * This client is currently not connected to the friend.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED,
+ /**
+ * The first byte of data was not in the specified range for the packet type.
+ * This range is 200-254 for lossy, and 160-191 for lossless packets.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID,
+ /**
+ * Attempted to send an empty packet.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY,
+ /**
+ * Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG,
+ /**
+ * Send queue size exceeded.
+ */
+ TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ
+} TOX_ERR_FRIEND_CUSTOM_PACKET;
+
+
+/**
+ * Send a custom lossy packet to a friend.
+ *
+ * The first byte of data must be in the range 200-254. Maximum length of a
+ * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE.
+ *
+ * Lossy packets behave like UDP packets, meaning they might never reach the
+ * other side or might arrive more than once (if someone is messing with the
+ * connection) or might arrive in the wrong order.
*
- * send_receive is 0 if we want the sending files, 1 if we want the receiving.
+ * Unless latency is an issue, it is recommended that you use lossless custom
+ * packets instead.
*
- * return number of bytes remaining to be sent/received on success
- * return 0 on failure
+ * @param friend_number The friend number of the friend this lossy packet
+ * should be sent to.
+ * @param data A byte array containing the packet data.
+ * @param length The length of the packet data byte array.
+ *
+ * @return true on success.
*/
-uint64_t tox_file_data_remaining(const Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive);
+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);
-/***************END OF FILE SENDING FUNCTIONS******************/
+/**
+ * The function type for the `friend_lossy_packet` callback.
+ *
+ * @param friend_number The friend number of the friend who sent a lossy packet.
+ * @param data A byte array containing the received packet data.
+ * @param length The length of the packet data byte array.
+ */
+typedef void tox_friend_lossy_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
+ void *user_data);
-/*
- * Use this function to bootstrap the client.
+/**
+ * Set the callback for the `friend_lossy_packet` event. Pass NULL to unset.
*/
+void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *function, void *user_data);
-/* Resolves address into an IP address. If successful, sends a "get nodes"
- * request to the given node with ip, port (in host byte order).
- * and public_key to setup connections
+
+/**
+ * Send a custom lossless packet to a friend.
+ *
+ * The first byte of data must be in the range 160-191. Maximum length of a
+ * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE.
*
- * address can be a hostname or an IP address (IPv4 or IPv6).
+ * Lossless packet behaviour is comparable to TCP (reliability, arrive in order)
+ * but with packets instead of a stream.
*
- * returns 1 if the address could be converted into an IP address
- * returns 0 otherwise
+ * @param friend_number The friend number of the friend this lossless packet
+ * should be sent to.
+ * @param data A byte array containing the packet data.
+ * @param length The length of the packet data byte array.
+ *
+ * @return true on success.
*/
-int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key);
+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);
-/* Like tox_bootstrap_from_address but for TCP relays only.
+/**
+ * The function type for the `friend_lossless_packet` callback.
*
- * return 0 on failure.
- * return 1 on success.
+ * @param friend_number The friend number of the friend who sent the packet.
+ * @param data A byte array containing the received packet data.
+ * @param length The length of the packet data byte array.
*/
-int tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key);
+typedef void tox_friend_lossless_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
+ void *user_data);
-/* return 0 if we are not connected to the DHT.
- * return 1 if we are.
+/**
+ * Set the callback for the `friend_lossless_packet` event. Pass NULL to unset.
*/
-int tox_isconnected(const Tox *tox);
-
-typedef enum {
- TOX_PROXY_NONE,
- TOX_PROXY_SOCKS5,
- TOX_PROXY_HTTP
-} TOX_PROXY_TYPE;
+void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *function, void *user_data);
-typedef struct {
- /*
- * The type of UDP socket created depends on ipv6enabled:
- * If set to 0 (zero), creates an IPv4 socket which subsequently only allows
- * IPv4 communication
- * If set to anything else (default), creates an IPv6 socket which allows both IPv4 AND
- * IPv6 communication
- */
- uint8_t ipv6enabled;
- /* Set to 1 to disable udp support. (default: 0)
- This will force Tox to use TCP only which may slow things down.
- Disabling udp support is necessary when using proxies or Tor.*/
- uint8_t udp_disabled;
- uint8_t proxy_type; /* a value from TOX_PROXY_TYPE */
- char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */
- uint16_t proxy_port; /* Proxy port in host byte order. */
-} Tox_Options;
-/*
- * Run this function at startup.
- *
- * Options are some options that can be passed to the Tox instance (see above struct).
+/*******************************************************************************
*
- * If options is NULL, tox_new() will use default settings.
+ * :: Low-level network information
*
- * Initializes a tox structure
- * return allocated instance of tox on success.
- * return NULL on failure.
- */
-Tox *tox_new(Tox_Options *options);
+ ******************************************************************************/
-/* Run this before closing shop.
- * Free all datastructures. */
-void tox_kill(Tox *tox);
-/* Return the time in milliseconds before tox_do() should be called again
- * for optimal performance.
+/**
+ * Writes the temporary DHT public key of this instance to a byte array.
+ *
+ * This can be used in combination with an externally accessible IP address and
+ * the bound port (from tox_get_udp_port) to run a temporary bootstrap node.
*
- * returns time (in ms) before the next tox_do() needs to be run on success.
+ * Be aware that every time a new instance is created, the DHT public key
+ * changes, meaning this cannot be used to run a permanent bootstrap node.
+ *
+ * @param dht_id A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If this
+ * parameter is NULL, this function has no effect.
*/
-uint32_t tox_do_interval(Tox *tox);
-
-/* The main loop that needs to be run in intervals of tox_do_interval() ms. */
-void tox_do(Tox *tox);
+void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id);
-/* SAVING AND LOADING FUNCTIONS: */
-/* return size of messenger data (for saving). */
-uint32_t tox_size(const Tox *tox);
+typedef enum TOX_ERR_GET_PORT {
+ TOX_ERR_GET_PORT_OK,
+ /**
+ * The instance was not bound to any port.
+ */
+ TOX_ERR_GET_PORT_NOT_BOUND
+} TOX_ERR_GET_PORT;
-/* Save the messenger in data (must be allocated memory of size Messenger_size()). */
-void tox_save(const Tox *tox, uint8_t *data);
+/**
+ * Return the UDP port this Tox instance is bound to.
+ */
+uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error);
-/* Load the messenger from data of size length.
- * NOTE: The Tox save format isn't stable yet meaning this function sometimes
- * returns -1 when loading older saves. This however does not mean nothing was
- * loaded from the save.
- *
- * returns 0 on success
- * returns -1 on failure
- * returns +1 on finding encrypted save data
+/**
+ * Return the TCP port this Tox instance is bound to. This is only relevant if
+ * the instance is acting as a TCP relay.
*/
-int tox_load(Tox *tox, const uint8_t *data, uint32_t length);
+uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error);
+
+#include "tox_old.h"
#ifdef __cplusplus
}
diff --git a/protocols/Tox/include/tox_old.h b/protocols/Tox/include/tox_old.h
new file mode 100644
index 0000000000..a926cdf70e
--- /dev/null
+++ b/protocols/Tox/include/tox_old.h
@@ -0,0 +1,173 @@
+/**********GROUP CHAT FUNCTIONS ************/
+
+/* Group chat types for tox_callback_group_invite function.
+ *
+ * TOX_GROUPCHAT_TYPE_TEXT groupchats must be accepted with the tox_join_groupchat() function.
+ * The function to accept TOX_GROUPCHAT_TYPE_AV is in toxav.
+ */
+enum {
+ TOX_GROUPCHAT_TYPE_TEXT,
+ TOX_GROUPCHAT_TYPE_AV
+};
+
+/* Set the callback for group invites.
+ *
+ * Function(Tox *tox, int32_t friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)
+ *
+ * data of length is what needs to be passed to join_groupchat().
+ *
+ * for what type means see the enum right above this comment.
+ */
+void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, const uint8_t *, uint16_t,
+ void *), void *userdata);
+
+/* Set the callback for group messages.
+ *
+ * Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * message, uint16_t length, void *userdata)
+ */
+void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),
+ void *userdata);
+
+/* Set the callback for group actions.
+ *
+ * Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * action, uint16_t length, void *userdata)
+ */
+void tox_callback_group_action(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),
+ void *userdata);
+
+/* Set callback function for title changes.
+ *
+ * Function(Tox *tox, int groupnumber, int peernumber, uint8_t * title, uint8_t length, void *userdata)
+ * if peernumber == -1, then author is unknown (e.g. initial joining the group)
+ */
+void tox_callback_group_title(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint8_t,
+ void *), void *userdata);
+
+/* Set callback function for peer name list changes.
+ *
+ * It gets called every time the name list changes(new peer/name, deleted peer)
+ * Function(Tox *tox, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)
+ */
+typedef enum {
+ TOX_CHAT_CHANGE_PEER_ADD,
+ TOX_CHAT_CHANGE_PEER_DEL,
+ TOX_CHAT_CHANGE_PEER_NAME,
+} TOX_CHAT_CHANGE;
+
+void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *),
+ void *userdata);
+
+/* Creates a new groupchat and puts it in the chats array.
+ *
+ * return group number on success.
+ * return -1 on failure.
+ */
+int tox_add_groupchat(Tox *tox);
+
+/* Delete a groupchat from the chats array.
+ *
+ * return 0 on success.
+ * return -1 if failure.
+ */
+int tox_del_groupchat(Tox *tox, int groupnumber);
+
+/* Copy the name of peernumber who is in groupnumber to name.
+ * name must be at least TOX_MAX_NAME_LENGTH long.
+ *
+ * return length of name if success
+ * return -1 if failure
+ */
+int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name);
+
+/* Copy the public key of peernumber who is in groupnumber to public_key.
+ * public_key must be TOX_PUBLIC_KEY_SIZE long.
+ *
+ * returns 0 on success
+ * returns -1 on failure
+ */
+int tox_group_peer_pubkey(const Tox *tox, int groupnumber, int peernumber, uint8_t *public_key);
+
+/* invite friendnumber to groupnumber
+ * return 0 on success
+ * return -1 on failure
+ */
+int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber);
+
+/* Join a group (you need to have been invited first.) using data of length obtained
+ * in the group invite callback.
+ *
+ * returns group number on success
+ * returns -1 on failure.
+ */
+int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length);
+
+/* send a group message
+ * return 0 on success
+ * return -1 on failure
+ */
+int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length);
+
+/* send a group action
+ * return 0 on success
+ * return -1 on failure
+ */
+int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length);
+
+/* set the group's title, limited to MAX_NAME_LENGTH
+ * return 0 on success
+ * return -1 on failure
+ */
+int tox_group_set_title(Tox *tox, int groupnumber, const uint8_t *title, uint8_t length);
+
+/* Get group title from groupnumber and put it in title.
+ * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.
+ *
+ * return length of copied title if success.
+ * return -1 if failure.
+ */
+int tox_group_get_title(Tox *tox, int groupnumber, uint8_t *title, uint32_t max_length);
+
+/* Check if the current peernumber corresponds to ours.
+ *
+ * return 1 if the peernumber corresponds to ours.
+ * return 0 on failure.
+ */
+unsigned int tox_group_peernumber_is_ours(const Tox *tox, int groupnumber, int peernumber);
+
+/* Return the number of peers in the group chat on success.
+ * return -1 on failure
+ */
+int tox_group_number_peers(const Tox *tox, int groupnumber);
+
+/* List all the peers in the group chat.
+ *
+ * Copies the names of the peers to the name[length][TOX_MAX_NAME_LENGTH] array.
+ *
+ * Copies the lengths of the names to lengths[length]
+ *
+ * returns the number of peers on success.
+ *
+ * return -1 on failure.
+ */
+int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[],
+ uint16_t length);
+
+/* Return the number of chats in the instance m.
+ * You should use this to determine how much memory to allocate
+ * for copy_chatlist. */
+uint32_t tox_count_chatlist(const Tox *tox);
+
+/* Copy a list of valid chat IDs into the array out_list.
+ * If out_list is NULL, returns 0.
+ * Otherwise, returns the number of elements copied.
+ * If the array was too small, the contents
+ * of out_list will be truncated to list_size. */
+uint32_t tox_get_chatlist(const Tox *tox, int32_t *out_list, uint32_t list_size);
+
+/* return the type of groupchat (TOX_GROUPCHAT_TYPE_) that groupnumber is.
+ *
+ * return -1 on failure.
+ * return type on success.
+ */
+int tox_group_get_type(const Tox *tox, int groupnumber);
+
diff --git a/protocols/Tox/include/toxav.h b/protocols/Tox/include/toxav.h
index 8881fdcf3a..7285f45cc6 100644
--- a/protocols/Tox/include/toxav.h
+++ b/protocols/Tox/include/toxav.h
@@ -22,6 +22,7 @@
#ifndef __TOXAV
#define __TOXAV
+#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
@@ -36,8 +37,8 @@ typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
typedef void ( *ToxAvAudioCallback ) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
typedef void ( *ToxAvVideoCallback ) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data);
-#ifndef __TOX_DEFINED__
-#define __TOX_DEFINED__
+#ifndef TOX_DEFINED
+#define TOX_DEFINED
typedef struct Tox Tox;
#endif
diff --git a/protocols/Tox/include/toxencryptsave.h b/protocols/Tox/include/toxencryptsave.h
index 169f736c0b..c077d899d2 100644
--- a/protocols/Tox/include/toxencryptsave.h
+++ b/protocols/Tox/include/toxencryptsave.h
@@ -29,27 +29,20 @@ extern "C" {
#endif
#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
-#ifndef __TOX_DEFINED__
-#define __TOX_DEFINED__
+#ifndef TOX_DEFINED
+#define TOX_DEFINED
typedef struct Tox Tox;
+struct Tox_Options;
#endif
-// these functions provide access to these defines in toxencryptsave.c, which
-// otherwise aren't actually available in clients...
-int tox_pass_encryption_extra_length();
+#define TOX_PASS_SALT_LENGTH 32
+#define TOX_PASS_KEY_LENGTH 32
+#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH 80
-int tox_pass_key_length();
-
-int tox_pass_salt_length();
-
-/* return size of the messenger data (for encrypted Messenger saving). */
-uint32_t tox_encrypted_size(const Tox *tox);
-
-/* This "module" provides functions analogous to tox_load and tox_save in toxcore,
- * as well as functions for encryption of arbitrary client data (e.g. chat logs).
- *
- * It is conceptually organized into two parts. The first part are the functions
+/* This module is conceptually organized into two parts. The first part are the functions
* with "key" in the name. To use these functions, first derive an encryption key
* from a password with tox_derive_key_from_pass, and use the returned key to
* encrypt the data. The second part takes the password itself instead of the key,
@@ -59,13 +52,83 @@ uint32_t tox_encrypted_size(const Tox *tox);
* favor using the first part intead of the second part.
*
* The encrypted data is prepended with a magic number, to aid validity checking
- * (no guarantees are made of course).
+ * (no guarantees are made of course). Any data to be decrypted must start with
+ * the magic number.
*
* Clients should consider alerting their users that, unlike plain data, if even one bit
* becomes corrupted, the data will be entirely unrecoverable.
* Ditto if they forget their password, there is no way to recover the data.
*/
+/* Since apparently no one actually bothered to learn about the module previously,
+ * the recently removed functions tox_encrypted_new and tox_get_encrypted_savedata
+ * may be trivially replaced by calls to tox_pass_decrypt -> tox_new or
+ * tox_get_savedata -> tox_pass_encrypt as appropriate. The removed functions
+ * were never more than 5 line wrappers of the other public API functions anyways.
+ * (As has always been, tox_pass_decrypt and tox_pass_encrypt are interchangeable
+ * with tox_pass_key_decrypt and tox_pass_key_encrypt, as the client program requires.)
+ */
+
+typedef enum TOX_ERR_KEY_DERIVATION {
+ TOX_ERR_KEY_DERIVATION_OK,
+ /**
+ * Some input data, or maybe the output pointer, was null.
+ */
+ TOX_ERR_KEY_DERIVATION_NULL,
+ /**
+ * The crypto lib was unable to derive a key from the given passphrase,
+ * which is usually a lack of memory issue. The functions accepting keys
+ * do not produce this error.
+ */
+ TOX_ERR_KEY_DERIVATION_FAILED
+} TOX_ERR_KEY_DERIVATION;
+
+typedef enum TOX_ERR_ENCRYPTION {
+ TOX_ERR_ENCRYPTION_OK,
+ /**
+ * Some input data, or maybe the output pointer, was null.
+ */
+ TOX_ERR_ENCRYPTION_NULL,
+ /**
+ * The crypto lib was unable to derive a key from the given passphrase,
+ * which is usually a lack of memory issue. The functions accepting keys
+ * do not produce this error.
+ */
+ TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED,
+ /**
+ * The encryption itself failed.
+ */
+ TOX_ERR_ENCRYPTION_FAILED
+} TOX_ERR_ENCRYPTION;
+
+typedef enum TOX_ERR_DECRYPTION {
+ TOX_ERR_DECRYPTION_OK,
+ /**
+ * Some input data, or maybe the output pointer, was null.
+ */
+ TOX_ERR_DECRYPTION_NULL,
+ /**
+ * The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes
+ */
+ TOX_ERR_DECRYPTION_INVALID_LENGTH,
+ /**
+ * The input data is missing the magic number (i.e. wasn't created by this
+ * module, or is corrupted)
+ */
+ TOX_ERR_DECRYPTION_BAD_FORMAT,
+ /**
+ * The crypto lib was unable to derive a key from the given passphrase,
+ * which is usually a lack of memory issue. The functions accepting keys
+ * do not produce this error.
+ */
+ TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED,
+ /**
+ * The encrypted byte array could not be decrypted. Either the data was
+ * corrupt or the password/key was incorrect.
+ */
+ TOX_ERR_DECRYPTION_FAILED
+} TOX_ERR_DECRYPTION;
+
/******************************* BEGIN PART 2 *******************************
* For simplicty, the second part of the module is presented first. The API for
@@ -75,41 +138,25 @@ uint32_t tox_encrypted_size(const Tox *tox);
*/
/* Encrypts the given data with the given passphrase. The output array must be
- * at least data_len + tox_pass_encryption_extra_length() bytes long. This delegates
+ * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates
* to tox_derive_key_from_pass and tox_pass_key_encrypt.
*
- * tox_encrypted_save() is a good example of how to use this function.
- *
- * returns 0 on success
- * returns -1 on failure
+ * returns true on success
*/
-int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out);
+bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, size_t pplength, uint8_t *out,
+ TOX_ERR_ENCRYPTION *error);
-/* Save the messenger data encrypted with the given password.
- * data must be at least tox_encrypted_size().
- *
- * returns 0 on success
- * returns -1 on failure
- */
-int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength);
/* Decrypts the given data with the given passphrase. The output array must be
- * at least data_len - tox_pass_encryption_extra_length() bytes long. This delegates
+ * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates
* to tox_pass_key_decrypt.
*
- * tox_encrypted_load() is a good example of how to use this function.
+ * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
*
- * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success
- * returns -1 on failure
+ * returns true on success
*/
-int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out);
-
-/* Load the messenger from encrypted data of size length.
- *
- * returns 0 on success
- * returns -1 on failure
- */
-int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength);
+bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, size_t pplength, uint8_t *out,
+ TOX_ERR_DECRYPTION *error);
/******************************* BEGIN PART 1 *******************************
@@ -117,8 +164,16 @@ int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *
* intensive than part one. The first 3 functions are for key handling.
*/
+/* This key structure's internals should not be used by any client program, even
+ * if they are straightforward here.
+ */
+typedef struct {
+ uint8_t salt[TOX_PASS_SALT_LENGTH];
+ uint8_t key[TOX_PASS_KEY_LENGTH];
+} TOX_PASS_KEY;
+
/* Generates a secret symmetric key from the given passphrase. out_key must be at least
- * tox_pass_key_length() bytes long.
+ * TOX_PASS_KEY_LENGTH bytes long.
* Be sure to not compromise the key! Only keep it in memory, do not write to disk.
* The password is zeroed after key derivation.
* The key should only be used with the other functions in this module, as it
@@ -126,68 +181,53 @@ int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *
* Note that this function is not deterministic; to derive the same key from a
* password, you also must know the random salt that was used. See below.
*
- * returns 0 on success
- * returns -1 on failure
+ * returns true on success
*/
-int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key);
+bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, TOX_PASS_KEY *out_key,
+ TOX_ERR_KEY_DERIVATION *error);
-/* Same as above, except with use the given salt for deterministic key derivation.
- * The salt must be tox_salt_length() bytes in length.
+/* Same as above, except use the given salt for deterministic key derivation.
+ * The salt must be TOX_PASS_SALT_LENGTH bytes in length.
*/
-int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key);
+bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, TOX_PASS_KEY *out_key,
+ TOX_ERR_KEY_DERIVATION *error);
/* This retrieves the salt used to encrypt the given data, which can then be passed to
* derive_key_with_salt to produce the same key as was previously used. Any encrpyted
* data with this module can be used as input.
*
- * returns -1 if the magic number is wrong
- * returns 0 otherwise (no guarantee about validity of data)
+ * returns true if magic number matches
+ * success does not say anything about the validity of the data, only that data of
+ * the appropriate size was copied
*/
-int tox_get_salt(uint8_t *data, uint8_t *salt);
+bool tox_get_salt(const uint8_t *data, uint8_t *salt);
/* Now come the functions that are analogous to the part 2 functions. */
-/* Encrypt arbitrary with a key produced by tox_derive_key_. The output
- * array must be at least data_len + tox_pass_encryption_extra_length() bytes long.
- * key must be tox_pass_key_length() bytes.
+/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output
+ * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long.
+ * key must be TOX_PASS_KEY_LENGTH bytes.
* If you already have a symmetric key from somewhere besides this module, simply
* call encrypt_data_symmetric in toxcore/crypto_core directly.
*
- * returns 0 on success
- * returns -1 on failure
+ * returns true on success
*/
-int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out);
-
-/* Save the messenger data encrypted with the given key from tox_derive_key.
- * data must be at least tox_encrypted_size().
- *
- * returns 0 on success
- * returns -1 on failure
- */
-int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key);
+bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const TOX_PASS_KEY *key, uint8_t *out,
+ TOX_ERR_ENCRYPTION *error);
/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by
* tox_derive_key_from_pass.
*
- * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success
- * returns -1 on failure
- */
-int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out);
-
-/* Load the messenger from encrypted data of size length, with key from tox_derive_key.
+ * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
*
- * returns 0 on success
- * returns -1 on failure
+ * returns true on success
*/
-int tox_encrypted_key_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *key);
+bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const TOX_PASS_KEY *key, uint8_t *out,
+ TOX_ERR_DECRYPTION *error);
/* Determines whether or not the given data is encrypted (by checking the magic number)
- *
- * returns 1 if it is encrypted
- * returns 0 otherwise
*/
-int tox_is_data_encrypted(const uint8_t *data);
-int tox_is_save_encrypted(const uint8_t *data); // poorly-named alias for backwards compat (oh irony...)
+bool tox_is_data_encrypted(const uint8_t *data);
#ifdef __cplusplus
}
diff --git a/protocols/Tox/res/resource.rc b/protocols/Tox/res/resource.rc
index 1f607c2aae..f6fc1c7c96 100644
--- a/protocols/Tox/res/resource.rc
+++ b/protocols/Tox/res/resource.rc
@@ -79,22 +79,23 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
// Dialog
//
-IDD_ACCOUNT_MANAGER DIALOGEX 0, 0, 199, 119
+IDD_ACCOUNT_MANAGER DIALOGEX 0, 0, 186, 119
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
- LTEXT "Name:",IDC_STATIC,12,24,54,12
- EDITTEXT IDC_NAME,66,23,120,12,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,12,40,54,12
- EDITTEXT IDC_TOXID,66,7,100,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Default group:",IDC_STATIC,12,56,54,12
- EDITTEXT IDC_GROUP,66,54,120,12,ES_AUTOHSCROLL
- PUSHBUTTON "C",IDC_CLIPBOARD,170,7,16,13
- LTEXT "Tox ID:",IDC_STATIC,12,9,54,8
- EDITTEXT IDC_PASSWORD,66,38,120,12,ES_PASSWORD | ES_AUTOHSCROLL
- PUSHBUTTON "Import tox profile",IDC_IMPORT_PROFILE,66,72,100,14,WS_DISABLED
- LTEXT "Tox profile contains your ID and friend list.\r\nYou may import existing profile from other tox client.",IDC_STATIC,12,91,174,21
+ LTEXT "Tox ID:",IDC_STATIC,0,5,49,8
+ EDITTEXT IDC_PASSWORD,49,52,135,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED
+ PUSHBUTTON "Create",IDC_PROFILE_NEW,49,19,65,13
+ PUSHBUTTON "Import",IDC_PROFILE_IMPORT,120,19,65,13
+ PUSHBUTTON "Copy ID",IDC_CLIPBOARD,49,19,65,13,NOT WS_VISIBLE
+ PUSHBUTTON "Export",IDC_PROFILE_EXPORT,120,19,65,13,NOT WS_VISIBLE
+ LTEXT "Name:",IDC_STATIC,0,38,49,12
+ EDITTEXT IDC_NAME,49,36,135,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Password:",IDC_STATIC,0,54,49,12,NOT WS_VISIBLE
+ EDITTEXT IDC_TOXID,49,3,135,12,ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED
+ LTEXT "Default group:",IDC_STATIC,0,70,49,12
+ EDITTEXT IDC_GROUP,49,68,135,12,ES_AUTOHSCROLL
END
IDD_OPTIONS_MAIN DIALOGEX 0, 0, 310, 230
@@ -102,22 +103,23 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
- LTEXT "Name:",IDC_STATIC,12,33,69,11
- EDITTEXT IDC_NAME,81,31,217,12,ES_AUTOHSCROLL
+ GROUPBOX "Tox",IDC_STATIC,7,7,296,116
LTEXT "Tox ID:",IDC_STATIC,12,17,69,11
- EDITTEXT IDC_TOXID,81,15,195,12,ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_TOXID,81,15,217,12,ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED
+ LTEXT "Name:",IDC_STATIC,12,48,69,11
+ EDITTEXT IDC_NAME,81,46,217,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Password:",IDC_STATIC,12,63,69,8,NOT WS_VISIBLE
+ EDITTEXT IDC_PASSWORD,81,62,217,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED
+ LTEXT "Default group:",IDC_STATIC,12,80,69,12
+ EDITTEXT IDC_GROUP,81,78,217,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Create tox profile",IDC_PROFILE_NEW,81,30,107,13
+ PUSHBUTTON "Import tox profile",IDC_PROFILE_IMPORT,191,30,107,13
+ PUSHBUTTON "Copy Tox ID",IDC_CLIPBOARD,81,30,107,13,NOT WS_VISIBLE
+ PUSHBUTTON "Export tox profile",IDC_PROFILE_EXPORT,191,30,107,13,NOT WS_VISIBLE
GROUPBOX "Connection settings",IDC_STATIC,7,123,296,40
- CONTROL "Disable UDP (force Tox to use TCP)",IDC_DISABLE_UDP,
+ CONTROL "Enable UDP (otherwise force Tox to use TCP)",IDC_ENABLE_UDP,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,135,286,10
- CONTROL "Disable IPv6",IDC_DISABLE_IPV6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,149,286,10
- GROUPBOX "Tox",IDC_STATIC,7,2,296,122
- LTEXT "Default group:",IDC_STATIC,12,66,69,12
- EDITTEXT IDC_GROUP,81,63,217,12,ES_AUTOHSCROLL
- PUSHBUTTON "C",IDC_CLIPBOARD,282,15,16,13
- LTEXT "Password:",IDC_STATIC,12,49,69,8
- EDITTEXT IDC_PASSWORD,81,47,217,12,ES_PASSWORD | ES_AUTOHSCROLL
- PUSHBUTTON "Import tox profile",IDC_IMPORT_PROFILE,81,78,100,14,WS_DISABLED
- LTEXT "Tox profile contains your ID and friend list.\r\nYou may import existing profile from other tox client.",IDC_STATIC,81,95,217,25
+ CONTROL "Enable IPv6",IDC_ENABLE_IPV6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,149,286,10
END
IDD_SEARCH DIALOGEX 0, 0, 109, 113
@@ -214,15 +216,9 @@ GUIDELINES DESIGNINFO
BEGIN
IDD_ACCOUNT_MANAGER, DIALOG
BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 192
- VERTGUIDE, 12
- VERTGUIDE, 66
- VERTGUIDE, 166
- VERTGUIDE, 170
- VERTGUIDE, 186
- TOPMARGIN, 7
+ VERTGUIDE, 49
BOTTOMMARGIN, 112
+ HORZGUIDE, 19
END
IDD_OPTIONS_MAIN, DIALOG
@@ -231,8 +227,6 @@ BEGIN
RIGHTMARGIN, 303
VERTGUIDE, 12
VERTGUIDE, 81
- VERTGUIDE, 276
- VERTGUIDE, 282
VERTGUIDE, 298
TOPMARGIN, 7
BOTTOMMARGIN, 228
diff --git a/protocols/Tox/src/api_avatars.cpp b/protocols/Tox/src/api_avatars.cpp
index 5b5aa0c487..e15773b94f 100644
--- a/protocols/Tox/src/api_avatars.cpp
+++ b/protocols/Tox/src/api_avatars.cpp
@@ -27,11 +27,6 @@ int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t
return CreateFunction<int(*)(const Tox*, uint8_t*, uint8_t*, uint32_t*, uint32_t, uint8_t*)>(__FUNCTION__)(tox, format, buf, length, maxlen, hash);
}
-int tox_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen)
-{
- return CreateFunction<int(*)(uint8_t*, const uint8_t*, const uint32_t)>(__FUNCTION__)(hash, data, datalen);
-}
-
int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber)
{
return CreateFunction<int(*)(const Tox*, const int32_t)>(__FUNCTION__)(tox, friendnumber);
diff --git a/protocols/Tox/src/api_connection.cpp b/protocols/Tox/src/api_connection.cpp
index 6a854612fb..7777755fd6 100644
--- a/protocols/Tox/src/api_connection.cpp
+++ b/protocols/Tox/src/api_connection.cpp
@@ -2,31 +2,27 @@
/* CONNECTION FUNCTIONS */
-int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key)
+bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)
{
- if (public_key == NULL)
- return 0;
- return CreateFunction<int(*)(Tox*, const char*, uint16_t, const uint8_t*)>(__FUNCTION__)(tox, address, port, public_key);
+ return CreateFunction<bool(*)(Tox*, const char*, uint16_t, const uint8_t*, TOX_ERR_BOOTSTRAP*)>(__FUNCTION__)(tox, host, port, public_key, error);
}
-int tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key)
+bool tox_add_tcp_relay(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)
{
- if (public_key == NULL)
- return 0;
- return CreateFunction<int(*)(Tox*, const char*, uint16_t, const uint8_t*)>(__FUNCTION__)(tox, address, port, public_key);
+ return CreateFunction<bool(*)(Tox*, const char*, uint16_t, const uint8_t*, TOX_ERR_BOOTSTRAP*)>(__FUNCTION__)(tox, host, port, public_key, error);
}
-int tox_isconnected(const Tox *tox)
+TOX_CONNECTION tox_self_get_connection_status(const Tox *tox)
{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
+ return CreateFunction<TOX_CONNECTION(*)(const Tox*)>(__FUNCTION__)(tox);
}
-uint32_t tox_do_interval(Tox *tox)
+uint32_t tox_iteration_interval(const Tox *tox)
{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
+ return CreateFunction<uint32_t(*)(const Tox*)>(__FUNCTION__)(tox);
}
-void tox_do(Tox *tox)
+void tox_iterate(Tox *tox)
{
CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
} \ No newline at end of file
diff --git a/protocols/Tox/src/api_encryption.cpp b/protocols/Tox/src/api_encryption.cpp
index 7125743096..f5fd2634e3 100644
--- a/protocols/Tox/src/api_encryption.cpp
+++ b/protocols/Tox/src/api_encryption.cpp
@@ -2,87 +2,17 @@
/* ENCRYPTION FUNCTIONS */
-int tox_pass_encryption_extra_length()
+bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_DECRYPTION *error)
{
- return CreateFunction<int(*)()>(__FUNCTION__)();
+ return CreateFunction<bool(*)(const uint8_t *, size_t, uint8_t*, size_t, uint8_t*, TOX_ERR_DECRYPTION*)>(__FUNCTION__)(data, length, passphrase, pplength, out, error);
}
-int tox_pass_key_length()
+bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_ENCRYPTION *error)
{
- return CreateFunction<int(*)()>(__FUNCTION__)();
+ return CreateFunction<bool(*)(const uint8_t *, size_t, uint8_t*, size_t, uint8_t*, TOX_ERR_ENCRYPTION*)>(__FUNCTION__)(data, data_len, passphrase, pplength, out, error);
}
-int tox_pass_salt_length()
+bool tox_is_data_encrypted(const uint8_t *data)
{
- return CreateFunction<int(*)()>(__FUNCTION__)();
-}
-
-uint32_t tox_encrypted_size(const Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out)
-{
- return CreateFunction<int(*)(const uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*)>(__FUNCTION__)(data, data_len, passphrase, pplength, out);
-}
-
-int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength)
-{
- return CreateFunction<int(*)(const Tox*, uint8_t*, uint8_t*, uint32_t)>(__FUNCTION__)(tox, data, passphrase, pplength);
-}
-
-int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out)
-{
- return CreateFunction<int(*)(const uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*)>(__FUNCTION__)(data, length, passphrase, pplength, out);
-}
-
-int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength)
-{
- return CreateFunction<int(*)(Tox*, const uint8_t*, uint32_t, uint8_t*, uint32_t)>(__FUNCTION__)(tox, data, length, passphrase, pplength);
-}
-
-int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key)
-{
- return CreateFunction<int(*)(uint8_t*, uint32_t, uint8_t*)>(__FUNCTION__)(passphrase, pplength, out_key);
-}
-
-int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key)
-{
- return CreateFunction<int(*)(uint8_t*, uint32_t, uint8_t*, uint8_t*)>(__FUNCTION__)(passphrase, pplength, salt, out_key);
-}
-
-int tox_get_salt(uint8_t *data, uint8_t *salt)
-{
- return CreateFunction<int(*)(uint8_t*, uint8_t*)>(__FUNCTION__)(data, salt);
-}
-
-int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out)
-{
- return CreateFunction<int(*)(const uint8_t*, uint32_t, const uint8_t*, uint8_t*)>(__FUNCTION__)(data, data_len, key, out);
-}
-
-int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key)
-{
- return CreateFunction<int(*)(const Tox*, uint8_t*, uint8_t*)>(__FUNCTION__)(tox, data, key);
-}
-
-int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out)
-{
- return CreateFunction<int(*)(const uint8_t*, uint32_t, const uint8_t*, uint8_t*)>(__FUNCTION__)(data, length, key, out);
-}
-
-int tox_encrypted_key_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *key)
-{
- return CreateFunction<int(*)(Tox*, const uint8_t*, uint32_t, uint8_t*)>(__FUNCTION__)(tox, data, length, key);
-}
-
-int tox_is_data_encrypted(const uint8_t *data)
-{
- return CreateFunction<int(*)(const uint8_t*)>(__FUNCTION__)(data);
-}
-
-int tox_is_save_encrypted(const uint8_t *data)
-{
- return CreateFunction<int(*)(const uint8_t*)>(__FUNCTION__)(data);
+ return CreateFunction<bool(*)(const uint8_t*)>(__FUNCTION__)(data);
} \ No newline at end of file
diff --git a/protocols/Tox/src/api_main.cpp b/protocols/Tox/src/api_main.cpp
index fc23165d44..19bb82f586 100644
--- a/protocols/Tox/src/api_main.cpp
+++ b/protocols/Tox/src/api_main.cpp
@@ -2,9 +2,19 @@
/* MAIN FUNCTIONS */
-Tox *tox_new(Tox_Options *options)
+struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error)
{
- return CreateFunction<Tox*(*)(void*)>(__FUNCTION__)(options);
+ return CreateFunction<struct Tox_Options*(*)(TOX_ERR_OPTIONS_NEW*)>(__FUNCTION__)(error);
+}
+
+void tox_options_free(struct Tox_Options *options)
+{
+ CreateFunction<void(*)(struct Tox_Options*)>(__FUNCTION__)(options);
+}
+
+Tox *tox_new(const struct Tox_Options *options, const uint8_t *data, size_t length, TOX_ERR_NEW *error)
+{
+ return CreateFunction<Tox*(*)(const struct Tox_Options*, const uint8_t*, size_t, TOX_ERR_NEW*)>(__FUNCTION__)(options, data, length, error);
}
void tox_kill(Tox *tox)
@@ -13,34 +23,34 @@ void tox_kill(Tox *tox)
tox = NULL;
}
-void tox_get_address(const Tox *tox, uint8_t *address)
+void tox_self_get_address(const Tox *tox, uint8_t *address)
{
CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, address);
}
-int32_t tox_add_friend(Tox *tox,const uint8_t *address, const uint8_t *data, uint16_t length)
+uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, TOX_ERR_FRIEND_ADD *error)
{
- return CreateFunction<int32_t(*)(Tox*, const uint8_t*, const uint8_t*, uint16_t)>(__FUNCTION__)(tox, address, data, length);
+ return CreateFunction<uint32_t(*)(Tox*, const uint8_t*, const uint8_t*, size_t, TOX_ERR_FRIEND_ADD*)>(__FUNCTION__)(tox, address, message, length, error);
}
-int32_t tox_add_friend_norequest(Tox *tox, const uint8_t *client_id)
+uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error)
{
- return CreateFunction<int32_t(*)(Tox*, const uint8_t*)>(__FUNCTION__)(tox, client_id);
+ return CreateFunction<uint32_t(*)(Tox*, const uint8_t*, TOX_ERR_FRIEND_ADD*)>(__FUNCTION__)(tox, public_key, error);
}
-int32_t tox_get_friend_number(const Tox *tox, const uint8_t *client_id)
+uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error)
{
- return CreateFunction<int32_t(*)(const Tox*, const uint8_t*)>(__FUNCTION__)(tox, client_id);
+ return CreateFunction<uint32_t(*)(const Tox*, const uint8_t*, TOX_ERR_FRIEND_BY_PUBLIC_KEY*)>(__FUNCTION__)(tox, public_key, error);
}
-int tox_get_client_id(const Tox *tox, int32_t friendnumber, uint8_t *client_id)
+bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, TOX_ERR_FRIEND_GET_PUBLIC_KEY *error)
{
- return CreateFunction<int(*)(const Tox*, int32_t, uint8_t*)>(__FUNCTION__)(tox, friendnumber, client_id);
+ return CreateFunction<bool(*)(const Tox*, int32_t, uint8_t*, TOX_ERR_FRIEND_GET_PUBLIC_KEY*)>(__FUNCTION__)(tox, friend_number, public_key, error);
}
-int tox_del_friend(Tox *tox, int32_t friendnumber)
+bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error)
{
- return CreateFunction<int(*)(Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
+ return CreateFunction<bool(*)(Tox*, uint32_t, TOX_ERR_FRIEND_DELETE*)>(__FUNCTION__)(tox, friend_number, error);
}
int tox_get_friend_connection_status(const Tox *tox, int32_t friendnumber)
@@ -53,34 +63,29 @@ int tox_friend_exists(const Tox *tox, int32_t friendnumber)
return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
}
-uint32_t tox_send_message(Tox *tox, int32_t friendnumber, const uint8_t *message, uint32_t length)
-{
- return CreateFunction<uint32_t(*)(Tox*, int32_t, const uint8_t*, uint32_t)>(__FUNCTION__)(tox, friendnumber, message, length);
-}
-
-uint32_t tox_send_action(Tox *tox, int32_t friendnumber, const uint8_t *action, uint32_t length)
+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)
{
- return CreateFunction<uint32_t(*)(Tox*, int32_t, const uint8_t*, uint32_t)>(__FUNCTION__)(tox, friendnumber, action, length);
+ return CreateFunction<uint32_t(*)(Tox*, uint32_t, TOX_MESSAGE_TYPE, const uint8_t*, size_t, TOX_ERR_FRIEND_SEND_MESSAGE*)>(__FUNCTION__)(tox, friend_number, type, message, length, error);
}
-int tox_set_name(Tox *tox, const uint8_t *name, uint16_t length)
+bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error)
{
- return CreateFunction<int(*)(Tox*, const uint8_t*, uint16_t)>(__FUNCTION__ )(tox, name, length);
+ return CreateFunction<bool(*)(Tox*, const uint8_t*, size_t, TOX_ERR_SET_INFO*)>(__FUNCTION__)(tox, name, length, error);
}
-uint16_t tox_get_self_name(const Tox *tox, uint8_t *name)
+void tox_self_get_name(const Tox *tox, uint8_t *name)
{
- return CreateFunction<uint16_t(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, name);
+ CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, name);
}
-int tox_get_name(const Tox *tox, int32_t friendnumber, uint8_t *name)
+bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error)
{
- return CreateFunction<int(*)(const Tox*, int32_t, uint8_t*)>(__FUNCTION__)(tox, friendnumber, name);
+ return CreateFunction<bool(*)(const Tox*, uint32_t, uint8_t*, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, name, error);
}
-int tox_get_name_size(const Tox *tox, int32_t friendnumber)
+size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
{
- return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
+ return CreateFunction<size_t(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
}
int tox_get_self_name_size(const Tox *tox)
@@ -88,14 +93,14 @@ int tox_get_self_name_size(const Tox *tox)
return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
}
-int tox_set_status_message(Tox *tox, const uint8_t *status, uint16_t length)
+bool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error)
{
- return CreateFunction<int(*)(Tox*, const uint8_t*, uint16_t)>(__FUNCTION__)(tox, status, length);
+ return CreateFunction<bool(*)(Tox*, const uint8_t*, size_t, TOX_ERR_SET_INFO*)>(__FUNCTION__)(tox, status, length, error);
}
-int tox_set_user_status(Tox *tox, uint8_t userstatus)
+void tox_self_set_status(Tox *tox, TOX_USER_STATUS user_status)
{
- return CreateFunction<int(*)(Tox*, uint8_t)>(__FUNCTION__)(tox, userstatus);
+ CreateFunction<void(*)(Tox*, TOX_USER_STATUS)>(__FUNCTION__)(tox, user_status);
}
int tox_get_status_message_size(const Tox *tox, int32_t friendnumber)
@@ -103,9 +108,9 @@ int tox_get_status_message_size(const Tox *tox, int32_t friendnumber)
return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
}
-int tox_get_self_status_message_size(const Tox *tox)
+void tox_self_get_status_message(const Tox *tox, uint8_t *status)
{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
+ CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, status);
}
int tox_get_status_message(const Tox *tox, int32_t friendnumber, uint8_t *buf, uint32_t maxlen)
@@ -128,24 +133,24 @@ uint8_t tox_get_self_user_status(const Tox *tox)
return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
}
-uint64_t tox_get_last_online(const Tox *tox, int32_t friendnumber)
+uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error)
{
- return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
+ return CreateFunction<uint64_t(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_GET_LAST_ONLINE*)>(__FUNCTION__)(tox, friend_number, error);
}
-int tox_set_user_is_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing)
+int tox_friend_get_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing)
{
return CreateFunction<int(*)(Tox*, int32_t, uint8_t)>(__FUNCTION__)(tox, friendnumber, is_typing);
}
-uint8_t tox_get_is_typing(const Tox *tox, int32_t friendnumber)
+bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool is_typing, TOX_ERR_SET_TYPING *error)
{
- return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
+ return CreateFunction<bool(*)(Tox*, uint32_t, bool, TOX_ERR_SET_TYPING*)>(__FUNCTION__)(tox, friend_number, is_typing, error);
}
-uint32_t tox_count_friendlist(const Tox *tox)
+size_t tox_self_get_friend_list_size(const Tox *tox)
{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
+ return CreateFunction<size_t(*)(const Tox*)>(__FUNCTION__)(tox);
}
uint32_t tox_get_num_online_friends(const Tox *tox)
@@ -153,64 +158,59 @@ uint32_t tox_get_num_online_friends(const Tox *tox)
return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
}
-uint32_t tox_get_friendlist(const Tox *tox, int32_t *out_list, uint32_t list_size)
+void tox_self_get_friend_list(const Tox *tox, uint32_t *list)
{
- return CreateFunction<int(*)(const Tox*, int32_t*, uint32_t)>(__FUNCTION__)(tox, out_list, list_size);
+ CreateFunction<void(*)(const Tox*, uint32_t*)>(__FUNCTION__)(tox, list);
}
-void tox_callback_friend_request(Tox *tox, void(*function)(Tox *tox, const uint8_t *, const uint8_t *, uint16_t, void *), void *userdata)
+void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, const uint8_t*, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_request_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_friend_message(Tox *tox, void(*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), void *userdata)
+void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_message_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_friend_action(Tox *tox, void(*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), void *userdata)
+void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*tox, tox_friend_name_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_name_change(Tox *tox, void(*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), void *userdata)
+void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*tox, void(*)(Tox*, int32_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_status_message_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_status_message(Tox *tox, void(*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), void *userdata)
+void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_status_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_user_status(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata)
+void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_read_receipt_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_typing_change(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata)
+void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_typing_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
-void tox_callback_read_receipt(Tox *tox, void(*function)(Tox *tox, int32_t, uint32_t, void *), void *userdata)
+void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint32_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
-}
-
-void tox_callback_connection_status(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata)
-{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ CreateFunction<void(*)(Tox*, tox_friend_connection_status_cb, void*)>(__FUNCTION__)(tox, function, user_data);
}
/* SAVING AND LOADING FUNCTIONS */
-uint32_t tox_size(const Tox *tox)
+size_t tox_get_savedata_size(const Tox *tox)
{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
+ return CreateFunction<size_t(*)(const Tox*)>(__FUNCTION__)(tox);
}
-void tox_save(const Tox *tox, uint8_t *data)
+void tox_get_savedata(const Tox *tox, uint8_t *data)
{
CreateFunction<int(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, data);
}
diff --git a/protocols/Tox/src/api_transfer.cpp b/protocols/Tox/src/api_transfer.cpp
index c5ba1b5f4a..f3aceab334 100644
--- a/protocols/Tox/src/api_transfer.cpp
+++ b/protocols/Tox/src/api_transfer.cpp
@@ -2,29 +2,49 @@
/* FILE SENDING FUNCTIONS */
-void tox_callback_file_send_request(Tox *tox, void(*function)(Tox *m, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *), void *userdata)
+bool tox_hash(uint8_t *hash, const uint8_t *data, size_t datalen)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, uint64_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ return CreateFunction<bool(*)(uint8_t*, const uint8_t*, size_t)>(__FUNCTION__)(hash, data, datalen);
}
-void tox_callback_file_control(Tox *tox, void(*function)(Tox *m, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *), void *userdata)
+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)
{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ return CreateFunction<bool(*)(const Tox*, uint32_t, uint32_t, uint8_t*, TOX_ERR_FILE_GET*)>(__FUNCTION__)(tox, friend_number, file_number, file_id, error);
}
-void tox_callback_file_data(Tox *tox, void(*function)(Tox *m, int32_t, uint8_t, const uint8_t *, uint16_t length, void *), void *userdata)
+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)
{
- CreateFunction<int(*)(Tox*tox, void(*)(Tox*, int32_t, uint8_t, const uint8_t *, uint16_t length, void*), void*)>(__FUNCTION__)(tox, function, userdata);
+ return CreateFunction<uint32_t(*)(Tox*, uint32_t, uint32_t, uint64_t, const uint8_t*, const uint8_t*, size_t, TOX_ERR_FILE_SEND*)>(__FUNCTION__)(tox, friend_number, kind, file_size, file_id, filename, filename_length, error);
}
-int tox_new_file_sender(Tox *tox, int32_t friendnumber, uint64_t filesize, const uint8_t *filename, uint16_t filename_length)
+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)
{
- return CreateFunction<int(*)(Tox*, int32_t, uint64_t, const uint8_t*, uint16_t)>(__FUNCTION__)(tox, friendnumber, filesize, filename, filename_length);
+ return CreateFunction<bool(*)(Tox*, uint32_t, uint32_t, uint64_t, const uint8_t*, size_t, TOX_ERR_FILE_SEND_CHUNK*)>(__FUNCTION__)(tox, friend_number, file_number, position, data, length, error);
}
-int tox_file_send_control(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, const uint8_t *data, uint16_t length)
+void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *function, void *user_data)
{
- return CreateFunction<int(*)(Tox*, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t*, uint16_t)>(__FUNCTION__)(tox, friendnumber, send_receive, filenumber, message_id, data, length);
+ CreateFunction<void(*)(Tox*, tox_file_chunk_request_cb, void*)>(__FUNCTION__)(tox, function, user_data);
+}
+
+void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *function, void *user_data)
+{
+ CreateFunction<void(*)(Tox*, tox_file_recv_cb, void*)>(__FUNCTION__)(tox, function, user_data);
+}
+
+void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function, void *user_data)
+{
+ CreateFunction<void(*)(Tox*, tox_file_recv_control_cb, void*)>(__FUNCTION__)(tox, function, user_data);
+}
+
+void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *function, void *user_data)
+{
+ CreateFunction<void(*)(Tox*, tox_file_recv_chunk_cb, void*)>(__FUNCTION__)(tox, function, user_data);
+}
+
+bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, TOX_ERR_FILE_CONTROL *error)
+{
+ return CreateFunction<bool(*)(Tox*, uint32_t, uint32_t, TOX_FILE_CONTROL, TOX_ERR_FILE_CONTROL*)>(__FUNCTION__)(tox, friend_number, file_number, control, error);
}
int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length)
diff --git a/protocols/Tox/src/common.h b/protocols/Tox/src/common.h
index a0fa494107..d5450728cc 100644
--- a/protocols/Tox/src/common.h
+++ b/protocols/Tox/src/common.h
@@ -33,6 +33,7 @@
#include <m_genmenu.h>
#include <m_clc.h>
#include <m_clistint.h>
+#include <m_gui.h>
#include <m_folders.h>
@@ -48,6 +49,7 @@ struct CToxProto;
#include "tox_icons.h"
#include "tox_menus.h"
#include "tox_address.h"
+#include "tox_dialogs.h"
#include "tox_options.h"
#include "tox_transfer.h"
#include "tox_chatrooms.h"
diff --git a/protocols/Tox/src/resource.h b/protocols/Tox/src/resource.h
index 241fda6951..69770bb555 100644
--- a/protocols/Tox/src/resource.h
+++ b/protocols/Tox/src/resource.h
@@ -2,7 +2,7 @@
// Microsoft Visual C++ generated include file.
// Used by e:\Projects\C++\MirandaNG\protocols\Tox\res\resource.rc
//
-#define IDD_CHATROOM_INVITE 16
+#define IDI_TOX 100
#define IDD_USER_INFO 101
#define IDD_PASSWORD 102
#define IDD_ACCOUNT_MANAGER 104
@@ -10,29 +10,31 @@
#define IDD_OPTIONS_MAIN 106
#define IDD_OPTIONS_NODES 107
#define IDD_ADDNODE 108
-#define IDD_NODE_EDITOR 108
-#define IDD_OPTIONS_AV 109
-#define IDI_TOX 120
+#define IDD_NODE_EDITOR 109
+#define IDD_OPTIONS_AV 110
+#define IDD_CHATROOM_INVITE 172
#define IDC_CCLIST 173
#define IDC_EDITSCR 174
#define IDC_TOXID 1001
#define IDC_CLIPBOARD 1002
-#define IDC_SEARCH 1004
-#define IDC_PASSWORD 1005
-#define IDC_NAME 1007
-#define IDC_GROUP 1008
-#define IDC_DISABLE_UDP 1009
-#define IDC_DISABLE_IPV6 1010
-#define IDC_DNS_ID 1011
+#define IDC_SEARCH 1003
+#define IDC_PASSWORD 1004
+#define IDC_NAME 1005
+#define IDC_GROUP 1006
+#define IDC_ENABLE_UDP 1007
+#define IDC_ENABLE_IPV6 1008
+#define IDC_PROFILE_EXPORT 1009
+#define IDC_DNS_ID 1010
+#define IDC_PROFILE_NEW 1011
#define IDC_SAVEPERMANENT 1012
-#define IDC_SAVEPERMANENTLY 1013
-#define IDC_NODESLIST 1014
-#define IDC_ADDNODE 1015
-#define IDC_IPV4 1016
-#define IDC_IPV6 1017
-#define IDC_PORT 1018
-#define IDC_PKEY 1019
-#define IDC_IMPORT_PROFILE 1020
+#define IDC_PROFILE_IMPORT 1013
+#define IDC_SAVEPERMANENTLY 1014
+#define IDC_NODESLIST 1015
+#define IDC_ADDNODE 1016
+#define IDC_IPV4 1017
+#define IDC_IPV6 1018
+#define IDC_PORT 1019
+#define IDC_PKEY 1020
#define IDC_COMBO_AUDIOINPUT 1021
#define IDC_COMBO_AUDIOOUTPUT 1022
#define IDC_AUDIOFILTER 1023
diff --git a/protocols/Tox/src/tox_accounts.cpp b/protocols/Tox/src/tox_accounts.cpp
index 618105dba7..228599866d 100644
--- a/protocols/Tox/src/tox_accounts.cpp
+++ b/protocols/Tox/src/tox_accounts.cpp
@@ -4,7 +4,7 @@ LIST<CToxProto> CToxProto::Accounts(1, CToxProto::CompareAccounts);
int CToxProto::CompareAccounts(const CToxProto *p1, const CToxProto *p2)
{
- return _tcscmp(p1->m_tszUserName, p2->m_tszUserName);
+ return mir_tstrcmp(p1->m_tszUserName, p2->m_tszUserName);
}
CToxProto* CToxProto::InitAccount(const char *protoName, const wchar_t *userName)
@@ -24,12 +24,8 @@ int CToxProto::UninitAccount(CToxProto *proto)
CToxProto* CToxProto::GetContactAccount(MCONTACT hContact)
{
for (int i = 0; i < Accounts.getCount(); i++)
- {
if (mir_strcmpi(GetContactProto(hContact), Accounts[i]->m_szModuleName) == 0)
- {
return Accounts[i];
- }
- }
return NULL;
}
@@ -58,10 +54,5 @@ int CToxProto::OnAccountRenamed(WPARAM, LPARAM)
INT_PTR CToxProto::OnAccountManagerInit(WPARAM, LPARAM lParam)
{
- return (INT_PTR)CreateDialogParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_ACCOUNT_MANAGER),
- (HWND)lParam,
- CToxProto::MainOptionsProc,
- (LPARAM)this);
+ return (INT_PTR)(CToxOptionsMain::CreateAccountManagerPage(this, (HWND)lParam))->GetHwnd();
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_address.h b/protocols/Tox/src/tox_address.h
index f9be08c767..265ed2f94e 100644
--- a/protocols/Tox/src/tox_address.h
+++ b/protocols/Tox/src/tox_address.h
@@ -10,12 +10,12 @@ private:
std::string hexData;
public:
ToxHexAddress(const ToxHexAddress &address) : hexData(address.hexData) { }
- ToxHexAddress(const char *hex, size_t size = TOX_FRIEND_ADDRESS_SIZE * 2) : hexData(hex, hex + size) { }
+ ToxHexAddress(const char *hex, size_t size = TOX_ADDRESS_SIZE * 2) : hexData(hex, hex + size) { }
ToxHexAddress(const std::string &hex)
{
this->ToxHexAddress::ToxHexAddress(hex.c_str(), hex.size());
}
- ToxHexAddress(const uint8_t *bin, size_t size = TOX_FRIEND_ADDRESS_SIZE)
+ ToxHexAddress(const uint8_t *bin, size_t size = TOX_ADDRESS_SIZE)
{
char *hex = (char*)mir_alloc(size * 2 + 1);
hexData = bin2hex(bin, size, hex);
@@ -56,9 +56,9 @@ private:
std::vector<uint8_t> binData;
public:
ToxBinAddress(const ToxBinAddress &address) : binData(address.binData) { }
- ToxBinAddress(const uint8_t *bin, size_t size = TOX_FRIEND_ADDRESS_SIZE) : binData(bin, bin + size) { }
- ToxBinAddress(const std::vector<uint8_t> &bin, size_t size = TOX_FRIEND_ADDRESS_SIZE) : binData(bin.begin(), bin.begin() + size) { }
- ToxBinAddress(const char *hex, size_t size = TOX_FRIEND_ADDRESS_SIZE * 2)
+ ToxBinAddress(const uint8_t *bin, size_t size = TOX_ADDRESS_SIZE) : binData(bin, bin + size) { }
+ ToxBinAddress(const std::vector<uint8_t> &bin, size_t size = TOX_ADDRESS_SIZE) : binData(bin.begin(), bin.begin() + size) { }
+ ToxBinAddress(const char *hex, size_t size = TOX_ADDRESS_SIZE * 2)
{
char *endptr;
const char *pos = hex;
diff --git a/protocols/Tox/src/tox_avatars.cpp b/protocols/Tox/src/tox_avatars.cpp
index 7ab5d4526d..6f2b1c6831 100644
--- a/protocols/Tox/src/tox_avatars.cpp
+++ b/protocols/Tox/src/tox_avatars.cpp
@@ -30,36 +30,28 @@ std::tstring CToxProto::GetAvatarFilePath(MCONTACT hContact)
void CToxProto::SetToxAvatar(std::tstring path, bool checkHash)
{
- /*if (!IsOnline())
- {
- return;
- }*/
-
- size_t length;
- uint8_t *data;
FILE *hFile = _tfopen(path.c_str(), L"rb");
if (!hFile)
{
- debugLogA("CToxProto::SetToxAvatar: failed to open avatar file");
+ debugLogA(__FUNCTION__": failed to open avatar file");
return;
}
fseek(hFile, 0, SEEK_END);
- length = ftell(hFile);
+ size_t length = ftell(hFile);
rewind(hFile);
- if (length > TOX_AVATAR_MAX_DATA_LENGTH)
+ if (length > 1024 * 1024)
{
fclose(hFile);
- debugLogA("CToxProto::SetToxAvatar: new avatar size is excessive");
+ debugLogA(__FUNCTION__": new avatar size is excessive");
return;
}
- data = (uint8_t*)mir_alloc(length);
- size_t read = fread(data, sizeof(uint8_t), length, hFile);
- if (read != length)
+ uint8_t *data = (uint8_t*)mir_alloc(length);
+ if (fread(data, sizeof(uint8_t), length, hFile) != length)
{
fclose(hFile);
- debugLogA("CToxProto::SetToxAvatar: failed to read avatar file");
+ debugLogA(__FUNCTION__": failed to read avatar file");
return;
}
fclose(hFile);
@@ -73,18 +65,42 @@ void CToxProto::SetToxAvatar(std::tstring path, bool checkHash)
{
db_free(&dbv);
mir_free(data);
- debugLogA("CToxProto::SetToxAvatar: new avatar is same with old");
+ debugLogA(__FUNCTION__": new avatar is same with old");
return;
}
db_free(&dbv);
}
- if (tox_set_avatar(tox, TOX_AVATAR_FORMAT_PNG, data, length) == TOX_ERROR)
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
{
- mir_free(data);
- debugLogA("CToxProto::SetToxAvatar: failed to set new avatar");
- return;
+ if (GetContactStatus(hContact) == ID_STATUS_OFFLINE)
+ continue;
+
+ int32_t friendNumber = GetToxFriendNumber(hContact);
+ if (friendNumber == UINT32_MAX)
+ {
+ mir_free(data);
+ debugLogA(__FUNCTION__": failed to set new avatar");
+ return;
+ }
+
+ TOX_ERR_FILE_SEND error;
+ uint32_t fileNumber = tox_file_send(tox, friendNumber, TOX_FILE_KIND_AVATAR, length, NULL, hash, TOX_HASH_LENGTH, &error);
+ if (error != TOX_ERR_FILE_SEND_OK)
+ {
+ mir_free(data);
+ debugLogA(__FUNCTION__": failed to set new avatar");
+ return;
+ }
+
+ FileTransferParam *transfer = new FileTransferParam(friendNumber, fileNumber, _T("avatar"), length);
+ transfer->pfts.hContact = hContact;
+ transfer->pfts.flags |= PFTS_SENDING;
+ //transfer->pfts.tszWorkingDir = fileDir;
+ transfer->hFile = hFile;
+ transfers.Add(transfer);
}
+
mir_free(data);
if (checkHash)
@@ -106,7 +122,7 @@ INT_PTR CToxProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
size->y = 300;
}
}
- break;
+ break;
case AF_ENABLED:
return 1;
@@ -115,7 +131,7 @@ INT_PTR CToxProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
return lParam == PA_FORMAT_PNG;
case AF_MAXFILESIZE:
- return TOX_AVATAR_MAX_DATA_LENGTH;
+ return 1024 * 1024;
}
return 0;
@@ -171,14 +187,32 @@ INT_PTR CToxProto::SetMyAvatar(WPARAM, LPARAM lParam)
return -1;
}
- SetToxAvatar(avatarPath, true);
+ if (IsOnline())
+ SetToxAvatar(avatarPath, true);
}
else
{
- if (tox_unset_avatar(tox) == TOX_ERROR)
+ if (IsOnline())
{
- debugLogA("CToxProto::SetMyAvatar: failed to unset avatar");
- return -1;
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
+ {
+ if (GetContactStatus(hContact) == ID_STATUS_OFFLINE)
+ continue;
+
+ int32_t friendNumber = GetToxFriendNumber(hContact);
+ if (friendNumber == UINT32_MAX)
+ {
+ debugLogA(__FUNCTION__": failed to unset avatar");
+ return -1;
+ }
+
+ TOX_ERR_FILE_SEND error;
+ if (!tox_file_send(tox, NULL, TOX_FILE_KIND_AVATAR, 0, NULL, NULL, 0, &error))
+ {
+ debugLogA(__FUNCTION__": failed to unset avatar");
+ return -1;
+ }
+ }
}
if (IsFileExists(avatarPath))
@@ -192,65 +226,60 @@ INT_PTR CToxProto::SetMyAvatar(WPARAM, LPARAM lParam)
return 0;
}
-void CToxProto::OnGotFriendAvatarInfo(Tox *, int32_t number, uint8_t format, uint8_t *hash, void *arg)
+void CToxProto::OnGotFriendAvatarInfo(FileTransferParam *transfer, const uint8_t *hash)
{
- CToxProto *proto = (CToxProto*)arg;
-
- MCONTACT hContact = proto->GetContact(number);
- if (hContact)
+ MCONTACT hContact = transfer->pfts.hContact;
+ std::tstring path = GetAvatarFilePath();
+ if (transfer->pfts.totalBytes == 0)
{
- std::tstring path = proto->GetAvatarFilePath(hContact);
- if (format == TOX_AVATAR_FORMAT_NONE)
+ delSetting(hContact, TOX_SETTINGS_AVATAR_HASH);
+ ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, 0, 0);
+ if (IsFileExists(path))
{
- proto->delSetting(hContact, TOX_SETTINGS_AVATAR_HASH);
- proto->ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, 0, 0);
- if (IsFileExists(path))
- {
- DeleteFile(path.c_str());
- }
+ DeleteFile(path.c_str());
}
- else
+ OnFileCancel(hContact, transfer);
+ }
+ else
+ {
+ DBVARIANT dbv;
+ if (!db_get(transfer->pfts.hContact, m_szModuleName, TOX_SETTINGS_AVATAR_HASH, &dbv))
{
- DBVARIANT dbv;
- if (!db_get(hContact, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, &dbv))
+ if (memcmp(hash, dbv.pbVal, TOX_HASH_LENGTH) == 0)
{
- if (memcmp(hash, dbv.pbVal, TOX_HASH_LENGTH) != 0)
- {
- tox_request_avatar_data(proto->tox, number);
- }
db_free(&dbv);
+ OnFileCancel(hContact, transfer);
+ return;
}
- else
- {
- tox_request_avatar_data(proto->tox, number);
- }
+ db_free(&dbv);
}
+ OnFileAllow(hContact, transfer, path.c_str());
}
}
-void CToxProto::OnGotFriendAvatarData(Tox *, int32_t number, uint8_t, uint8_t *hash, uint8_t *data, uint32_t length, void *arg)
+/*void CToxProto::OnGotFriendAvatarData(Tox *, int32_t number, uint8_t, uint8_t *hash, uint8_t *data, uint32_t length, void *arg)
{
- CToxProto *proto = (CToxProto*)arg;
+CToxProto *proto = (CToxProto*)arg;
- MCONTACT hContact = proto->GetContact(number);
- if (hContact)
- {
- db_set_blob(hContact, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, hash, TOX_HASH_LENGTH);
+MCONTACT hContact = proto->GetContact(number);
+if (hContact)
+{
+db_set_blob(hContact, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, hash, TOX_HASH_LENGTH);
- std::tstring path = proto->GetAvatarFilePath(hContact);
- FILE *hFile = _tfopen(path.c_str(), L"wb");
- if (hFile)
- {
- if (fwrite(data, sizeof(uint8_t), length, hFile) == length)
- {
- PROTO_AVATAR_INFORMATIONW pai = { sizeof(pai) };
- pai.format = PA_FORMAT_PNG;
- pai.hContact = hContact;
- _tcscpy(pai.filename, path.c_str());
+std::tstring path = proto->GetAvatarFilePath(hContact);
+FILE *hFile = _tfopen(path.c_str(), L"wb");
+if (hFile)
+{
+if (fwrite(data, sizeof(uint8_t), length, hFile) == length)
+{
+PROTO_AVATAR_INFORMATIONW pai = { sizeof(pai) };
+pai.format = PA_FORMAT_PNG;
+pai.hContact = hContact;
+_tcscpy(pai.filename, path.c_str());
- proto->ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0);
- }
- fclose(hFile);
- }
- }
-} \ No newline at end of file
+proto->ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0);
+}
+fclose(hFile);
+}
+}
+}*/ \ No newline at end of file
diff --git a/protocols/Tox/src/tox_chatrooms.cpp b/protocols/Tox/src/tox_chatrooms.cpp
index d4b134faed..deb0ad7f48 100644
--- a/protocols/Tox/src/tox_chatrooms.cpp
+++ b/protocols/Tox/src/tox_chatrooms.cpp
@@ -115,11 +115,6 @@ INT_PTR CToxProto::OnLeaveChatRoom(WPARAM hContact, LPARAM)
INT_PTR CToxProto::OnCreateChatRoom(WPARAM, LPARAM)
{
- if (!IsToxCoreInited())
- {
- return 1;
- }
-
ChatRoomInviteParam param = { this };
if (DialogBoxParam(
diff --git a/protocols/Tox/src/tox_contacts.cpp b/protocols/Tox/src/tox_contacts.cpp
index c972a2c07c..a735903756 100644
--- a/protocols/Tox/src/tox_contacts.cpp
+++ b/protocols/Tox/src/tox_contacts.cpp
@@ -44,7 +44,12 @@ MCONTACT CToxProto::GetContactFromAuthEvent(MEVENT hEvent)
MCONTACT CToxProto::GetContact(const int friendNumber)
{
uint8_t data[TOX_PUBLIC_KEY_SIZE];
- tox_get_client_id(tox, friendNumber, data);
+ TOX_ERR_FRIEND_GET_PUBLIC_KEY error;
+ if (!tox_friend_get_public_key(tox, friendNumber, data, &error))
+ {
+ debugLogA(__FUNCTION__": failed to get friend public key (%d)", error);
+ return NULL;
+ }
ToxHexAddress pubKey(data, TOX_PUBLIC_KEY_SIZE);
return GetContact(pubKey);
}
@@ -97,30 +102,36 @@ MCONTACT CToxProto::AddContact(const char *address, const std::tstring &dnsId, b
return hContact;
}
-int32_t CToxProto::GetToxFriendNumber(MCONTACT hContact)
+uint32_t CToxProto::GetToxFriendNumber(MCONTACT hContact)
{
ToxBinAddress pubKey = ptrA(getStringA(hContact, TOX_SETTINGS_ID));
- int32_t friendNumber = tox_get_friend_number(tox, pubKey);
- if (friendNumber == TOX_ERROR)
+ TOX_ERR_FRIEND_BY_PUBLIC_KEY error;
+ uint32_t friendNumber = tox_friend_by_public_key(tox, pubKey, &error);
+ if (error != TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK)
{
- debugLogA("CToxProto::GetToxFriendNumber: failed to get friend number");
+ debugLogA(__FUNCTION__": failed to get friend number (%d)", error);
}
return friendNumber;
}
void CToxProto::LoadFriendList(void*)
{
- uint32_t count = tox_count_friendlist(tox);
+ size_t count = tox_self_get_friend_list_size(tox);
if (count > 0)
{
- int32_t *friends = (int32_t*)mir_alloc(count * sizeof(int32_t));
- tox_get_friendlist(tox, friends, count);
+ uint32_t *friends = (uint32_t*)mir_alloc(count * sizeof(uint32_t));
+ tox_self_get_friend_list(tox, friends);
uint8_t data[TOX_PUBLIC_KEY_SIZE];
- for (uint32_t i = 0; i < count; i++)
+ for (size_t i = 0; i < count; i++)
{
uint32_t friendNumber = friends[i];
- tox_get_client_id(tox, friendNumber, data);
+ TOX_ERR_FRIEND_GET_PUBLIC_KEY getPublicKeyResult;
+ if (!tox_friend_get_public_key(tox, friendNumber, data, &getPublicKeyResult))
+ {
+ debugLogA(__FUNCTION__": failed to get friend public key (%d)", getPublicKeyResult);
+ continue;
+ }
ToxHexAddress pubKey(data, TOX_PUBLIC_KEY_SIZE);
MCONTACT hContact = AddContact(pubKey, _T(""));
if (hContact)
@@ -128,46 +139,42 @@ void CToxProto::LoadFriendList(void*)
delSetting(hContact, "Auth");
delSetting(hContact, "Grant");
- int size = tox_get_name_size(tox, friendNumber);
- if (size != TOX_ERROR)
- {
- std::string nick(size, 0);
- tox_get_name(tox, friendNumber, (uint8_t*)nick.data());
- setWString(hContact, "Nick", ptrT(Utf8DecodeT(nick.c_str())));
- }
+ TOX_ERR_FRIEND_QUERY getNameResult;
+ uint8_t nick[TOX_MAX_NAME_LENGTH] = { 0 };
+ if (tox_friend_get_name(tox, friendNumber, nick, &getNameResult))
+ setWString(hContact, "Nick", ptrT(mir_utf8decodeW((char*)nick)));
+ else
+ debugLogA(__FUNCTION__": failed to get friend name (%d)", getNameResult);
- uint64_t timestamp = tox_get_last_online(tox, friendNumber);
- if (timestamp > getDword(hContact, "LastEventDateTS", 0))
- {
+ TOX_ERR_FRIEND_GET_LAST_ONLINE getLastOnlineResult;
+ uint64_t timestamp = tox_friend_get_last_online(tox, friendNumber, &getLastOnlineResult);
+ if (getLastOnlineResult == TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
setDword(hContact, "LastEventDateTS", timestamp);
- }
+ else
+ debugLogA(__FUNCTION__": failed to get friend last online (%d)", getLastOnlineResult);
}
}
-
mir_free(friends);
}
- else
- {
- debugLogA("CToxProto::LoadContactList: your friend list is empty");
- }
}
INT_PTR CToxProto::OnRequestAuth(WPARAM hContact, LPARAM lParam)
{
if (!IsOnline())
{
- return 1;
+ return -1; // ???
}
char *reason = lParam ? (char*)lParam : " ";
size_t length = mir_strlen(reason);
ToxBinAddress address(ptrA(getStringA(hContact, TOX_SETTINGS_ID)));
- int32_t friendNumber = tox_add_friend(tox, address, (uint8_t*)reason, length);
- if (friendNumber <= TOX_ERROR)
+ TOX_ERR_FRIEND_ADD addFriendResult;
+ int32_t friendNumber = tox_friend_add(tox, address, (uint8_t*)reason, length, &addFriendResult);
+ if (addFriendResult != TOX_ERR_FRIEND_ADD_OK)
{
- debugLogA("CToxProto::OnRequestAuth: failed to request auth");
- return 2;
+ debugLogA(__FUNCTION__": failed to request auth (%d)", addFriendResult);
+ return addFriendResult;
}
// trim address to public key
@@ -175,9 +182,12 @@ INT_PTR CToxProto::OnRequestAuth(WPARAM hContact, LPARAM lParam)
db_unset(hContact, "CList", "NotOnList");
delSetting(hContact, "Grant");
- std::string nick("", TOX_MAX_NAME_LENGTH);
- tox_get_name(tox, friendNumber, (uint8_t*)&nick[0]);
- setString(hContact, "Nick", nick.c_str());
+ uint8_t nick[TOX_MAX_NAME_LENGTH] = { 0 };
+ TOX_ERR_FRIEND_QUERY errorFriendQuery;
+ if (tox_friend_get_name(tox, friendNumber, nick, &errorFriendQuery))
+ setWString(hContact, "Nick", ptrT(mir_utf8decodeW((char*)nick)));
+ else
+ debugLogA(__FUNCTION__": failed to get friend name (%d)", errorFriendQuery);
return 0;
}
@@ -186,14 +196,16 @@ INT_PTR CToxProto::OnGrantAuth(WPARAM hContact, LPARAM)
{
if (!IsOnline())
{
- return 1;
+ return -1;
}
- ToxBinAddress pubKey(ptrA(getStringA(hContact, TOX_SETTINGS_ID)), TOX_CLIENT_ID_SIZE * 2);
- if (tox_add_friend_norequest(tox, pubKey) == TOX_ERROR)
+ ToxBinAddress pubKey(ptrA(getStringA(hContact, TOX_SETTINGS_ID)), TOX_PUBLIC_KEY_SIZE * 2);
+ TOX_ERR_FRIEND_ADD error;
+ tox_friend_add_norequest(tox, pubKey, &error);
+ if (error != TOX_ERR_FRIEND_ADD_OK)
{
- debugLogA("CToxProto::OnGrantAuth: failed to grant auth");
- return 2;
+ debugLogA(__FUNCTION__": failed to grant auth (%d)", error);
+ return error;
}
// trim address to public key
@@ -204,15 +216,16 @@ INT_PTR CToxProto::OnGrantAuth(WPARAM hContact, LPARAM)
return 0;
}
-void CToxProto::OnFriendRequest(Tox *, const uint8_t *data, const uint8_t *message, const uint16_t messageSize, void *arg)
+void CToxProto::OnFriendRequest(Tox*, const uint8_t *pubKey, const uint8_t *message, size_t length, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
- ToxHexAddress address(data, TOX_FRIEND_ADDRESS_SIZE);
+ ToxHexAddress address(pubKey, TOX_ADDRESS_SIZE);
MCONTACT hContact = proto->AddContact(address, _T(""));
if (!hContact)
{
- proto->debugLogA("CToxProto::OnFriendRequest: failed to create contact");
+ proto->debugLogA(__FUNCTION__": failed to create contact");
+ return;
}
proto->delSetting(hContact, "Auth");
@@ -220,7 +233,7 @@ void CToxProto::OnFriendRequest(Tox *, const uint8_t *data, const uint8_t *messa
PROTORECVEVENT pre = { 0 };
pre.flags = PREF_UTF;
pre.timestamp = time(NULL);
- pre.lParam = (DWORD)(sizeof(DWORD) * 2 + address.GetLength() + messageSize + 5);
+ pre.lParam = (DWORD)(sizeof(DWORD) * 2 + address.GetLength() + length + 5);
/*blob is: 0(DWORD), hContact(DWORD), nick(ASCIIZ), firstName(ASCIIZ), lastName(ASCIIZ), id(ASCIIZ), reason(ASCIIZ)*/
PBYTE pBlob, pCurBlob;
@@ -239,71 +252,120 @@ void CToxProto::OnFriendRequest(Tox *, const uint8_t *data, const uint8_t *messa
ProtoChainRecv(hContact, PSR_AUTH, 0, (LPARAM)&pre);
}
-void CToxProto::OnFriendNameChange(Tox *, const int friendNumber, const uint8_t *name, const uint16_t, void *arg)
+void CToxProto::OnFriendNameChange(Tox*, uint32_t friendNumber, const uint8_t *name, size_t length, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact)
+ if (MCONTACT hContact = proto->GetContact(friendNumber))
{
- proto->setString(hContact, "Nick", (char*)name);
+ ptrA rawName((char*)mir_alloc(length + 1));
+ memcpy(rawName, name, length);
+ rawName[length] = 0;
+
+ ptrT nickname(mir_utf8decodeW(rawName));
+ proto->setTString(hContact, "Nick", nickname);
}
}
-void CToxProto::OnStatusMessageChanged(Tox *, const int friendNumber, const uint8_t* message, const uint16_t, void *arg)
+void CToxProto::OnStatusMessageChanged(Tox*, uint32_t friendNumber, const uint8_t *message, size_t length, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact)
+ if (MCONTACT hContact = proto->GetContact(friendNumber))
{
- ptrW statusMessage(mir_utf8decodeW((char*)message));
- db_set_ws(hContact, "CList", "StatusMsg", statusMessage);
+ ptrA rawMessage((char*)mir_alloc(length + 1));
+ memcpy(rawMessage, message, length);
+ rawMessage[length] = 0;
+
+ ptrT statusMessage(mir_utf8decodeT(rawMessage));
+ db_set_ts(hContact, "CList", "StatusMsg", statusMessage);
}
}
-void CToxProto::OnUserStatusChanged(Tox *, int32_t friendNumber, uint8_t usertatus, void *arg)
+void CToxProto::OnUserStatusChanged(Tox*, uint32_t friendNumber, TOX_USER_STATUS userstatus, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
MCONTACT hContact = proto->GetContact(friendNumber);
if (hContact)
{
- TOX_USERSTATUS userstatus = (TOX_USERSTATUS)usertatus;
int status = proto->ToxToMirandaStatus(userstatus);
proto->SetContactStatus(hContact, status);
}
}
-void CToxProto::OnConnectionStatusChanged(Tox *tox, const int friendNumber, const uint8_t status, void *arg)
+void CToxProto::OnConnectionStatusChanged(Tox*, uint32_t friendNumber, TOX_CONNECTION status, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
MCONTACT hContact = proto->GetContact(friendNumber);
if (hContact)
{
- int newStatus = status ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
- proto->SetContactStatus(hContact, newStatus);
- if (status)
+ if (status != TOX_CONNECTION_NONE)
{
- tox_send_avatar_info(proto->tox, friendNumber);
+ proto->SetContactStatus(hContact, ID_STATUS_OFFLINE);
+
proto->delSetting(hContact, "Auth");
proto->delSetting(hContact, "Grant");
+ // resume transfers
for (size_t i = 0; i < proto->transfers.Count(); i++)
{
// only for receiving
FileTransferParam *transfer = proto->transfers.GetAt(i);
if (transfer->friendNumber == friendNumber && transfer->GetDirection() == 1)
{
- proto->debugLogA("CToxProto::OnConnectionStatusChanged: sending ask to resume the transfer of file (%d)", transfer->fileNumber);
+ proto->debugLogA(__FUNCTION__": sending ask to resume the transfer of file (%d)", transfer->fileNumber);
transfer->status = STARTED;
- if (tox_file_send_control(tox, friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_RESUME_BROKEN, (uint8_t*)&transfer->pfts.currentFileProgress, sizeof(transfer->pfts.currentFileProgress)) == TOX_ERROR)
+ TOX_ERR_FILE_CONTROL error;
+ if (!tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error))
{
- tox_file_send_control(tox, friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ proto->debugLogA(__FUNCTION__": failed to resume the transfer (%d)", error);
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, NULL);
}
}
}
+
+ // update avatar
+ std::tstring avatarPath = proto->GetAvatarFilePath();
+ if (IsFileExists(avatarPath))
+ {
+ FILE *hFile = _tfopen(avatarPath.c_str(), L"rb");
+ if (!hFile)
+ {
+ proto->debugLogA(__FUNCTION__": failed to open avatar file");
+ return;
+ }
+
+ fseek(hFile, 0, SEEK_END);
+ size_t length = ftell(hFile);
+ rewind(hFile);
+
+ uint8_t hash[TOX_HASH_LENGTH];
+ DBVARIANT dbv;
+ if (!db_get(NULL, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, &dbv))
+ {
+ memcpy(hash, dbv.pbVal, TOX_HASH_LENGTH);
+ db_free(&dbv);
+ }
+
+ TOX_ERR_FILE_SEND error;
+ uint32_t fileNumber = tox_file_send(proto->tox, friendNumber, TOX_FILE_KIND_AVATAR, length, NULL, hash, TOX_HASH_LENGTH, &error);
+ if (error != TOX_ERR_FILE_SEND_OK)
+ {
+ proto->debugLogA(__FUNCTION__": failed to set new avatar");
+ return;
+ }
+
+ FileTransferParam *transfer = new FileTransferParam(friendNumber, fileNumber, _T("avatar"), length);
+ transfer->pfts.hContact = hContact;
+ transfer->pfts.flags |= PFTS_SENDING;
+ //transfer->pfts.tszWorkingDir = fileDir;
+ transfer->hFile = hFile;
+ proto->transfers.Add(transfer);
+ }
+ else
+ tox_file_send(proto->tox, NULL, TOX_FILE_KIND_AVATAR, 0, NULL, NULL, 0, NULL);
}
else
{
@@ -313,9 +375,7 @@ void CToxProto::OnConnectionStatusChanged(Tox *tox, const int friendNumber, cons
{
FileTransferParam *transfer = proto->transfers.GetAt(i);
if (transfer->friendNumber == friendNumber)
- {
transfer->status = BROKEN;
- }
}
}
}
diff --git a/protocols/Tox/src/tox_core.cpp b/protocols/Tox/src/tox_core.cpp
index 5e1eae29d1..6ca63506b0 100644
--- a/protocols/Tox/src/tox_core.cpp
+++ b/protocols/Tox/src/tox_core.cpp
@@ -1,17 +1,18 @@
#include "common.h"
-bool CToxProto::IsToxCoreInited()
-{
- return tox != NULL;
-}
-
bool CToxProto::InitToxCore()
{
- debugLogA("CToxProto::InitToxCore: initializing tox core");
+ debugLogA(__FUNCTION__": initializing tox core");
- Tox_Options options = { 0 };
- options.udp_disabled = getBool("DisableUDP", 0);
- options.ipv6enabled = !getBool("DisableIPv6", 0);
+ TOX_ERR_OPTIONS_NEW error;
+ Tox_Options *options = tox_options_new(&error);
+ if (error != TOX_ERR_OPTIONS_NEW::TOX_ERR_OPTIONS_NEW_OK)
+ {
+ debugLogA(__FUNCTION__": failed to initialize tox options (%d)", error);
+ return false;
+ }
+ options->udp_enabled = getBool("EnableUDP", 1);
+ options->ipv6_enabled = getBool("EnableIPv6", 0);
if (hNetlib != NULL)
{
@@ -23,114 +24,91 @@ bool CToxProto::InitToxCore()
if (nlus.proxyType == PROXYTYPE_HTTP || nlus.proxyType == PROXYTYPE_HTTPS)
{
debugLogA("CToxProto::InitToxCore: setting http user proxy config");
- options.proxy_type = TOX_PROXY_HTTP;
- strcpy(&options.proxy_address[0], nlus.szProxyServer);
- options.proxy_port = nlus.wProxyPort;
+ options->proxy_type = TOX_PROXY_TYPE_HTTP;
+ mir_strcpy((char*)&options->proxy_host[0], nlus.szProxyServer);
+ options->proxy_port = nlus.wProxyPort;
}
if (nlus.proxyType == PROXYTYPE_SOCKS4 || nlus.proxyType == PROXYTYPE_SOCKS5)
{
debugLogA("CToxProto::InitToxCore: setting socks user proxy config");
- options.proxy_type = TOX_PROXY_SOCKS5;
- strcpy(&options.proxy_address[0], nlus.szProxyServer);
- options.proxy_port = nlus.wProxyPort;
+ options->proxy_type = TOX_PROXY_TYPE_SOCKS5;
+ mir_strcpy((char*)&options->proxy_host[0], nlus.szProxyServer);
+ options->proxy_port = nlus.wProxyPort;
}
}
}
debugLogA("CToxProto::InitToxCore: loading tox profile");
- tox = tox_new(&options);
- password = mir_utf8encodeW(ptrT(getTStringA("Password")));
- bool isProfileLoaded = LoadToxProfile();
- if (isProfileLoaded)
+ if (LoadToxProfile(options))
{
- debugLogA("CToxProto::InitToxCore: tox profile load successfully");
-
tox_callback_friend_request(tox, OnFriendRequest, this);
tox_callback_friend_message(tox, OnFriendMessage, this);
- tox_callback_friend_action(tox, OnFriendAction, this);
- tox_callback_typing_change(tox, OnTypingChanged, this);
- tox_callback_name_change(tox, OnFriendNameChange, this);
- tox_callback_status_message(tox, OnStatusMessageChanged, this);
- tox_callback_user_status(tox, OnUserStatusChanged, this);
- tox_callback_read_receipt(tox, OnReadReceipt, this);
- tox_callback_connection_status(tox, OnConnectionStatusChanged, this);
+ tox_callback_friend_read_receipt(tox, OnReadReceipt, this);
+ tox_callback_friend_typing(tox, OnTypingChanged, this);
+ tox_callback_friend_name(tox, OnFriendNameChange, this);
+ tox_callback_friend_status_message(tox, OnStatusMessageChanged, this);
+ tox_callback_friend_status(tox, OnUserStatusChanged, this);
+ tox_callback_friend_connection_status(tox, OnConnectionStatusChanged, this);
// file transfers
- tox_callback_file_control(tox, OnFileRequest, this);
- tox_callback_file_send_request(tox, OnFriendFile, this);
- tox_callback_file_data(tox, OnFileData, this);
- // avatars
- tox_callback_avatar_info(tox, OnGotFriendAvatarInfo, this);
- tox_callback_avatar_data(tox, OnGotFriendAvatarData, this);
+ tox_callback_file_recv_control(tox, OnFileRequest, this);
+ tox_callback_file_recv(tox, OnFriendFile, this);
+ tox_callback_file_recv_chunk(tox, OnFileReceiveData, this);
+ tox_callback_file_chunk_request(tox, OnFileSendData, this);
// group chats
- tox_callback_group_invite(tox, OnGroupChatInvite, this);
+ //tox_callback_group_invite(tox, OnGroupChatInvite, this);
- uint8_t data[TOX_FRIEND_ADDRESS_SIZE];
- tox_get_address(tox, data);
- ToxHexAddress address(data, TOX_FRIEND_ADDRESS_SIZE);
+ uint8_t data[TOX_ADDRESS_SIZE];
+ tox_self_get_address(tox, data);
+ ToxHexAddress address(data, TOX_ADDRESS_SIZE);
setString(TOX_SETTINGS_ID, address);
- int size = tox_get_self_name_size(tox);
- std::string nick(size, 0);
- tox_get_self_name(tox, (uint8_t*)nick.data());
- setWString("Nick", ptrW(Utf8DecodeW(nick.c_str())));
+ uint8_t nick[TOX_MAX_NAME_LENGTH] = { 0 };
+ tox_self_get_name(tox, nick);
+ setWString("Nick", ptrW(Utf8DecodeW((char*)nick)));
- //temporary
- size = tox_get_self_status_message_size(tox);
- std::string statusmes(size, 0);
- tox_get_self_status_message(tox, (uint8_t*)statusmes.data(), size);
- setWString("StatusMsg", ptrW(Utf8DecodeW(statusmes.c_str())));
+ uint8_t statusMessage[TOX_MAX_STATUS_MESSAGE_LENGTH] = { 0 };
+ tox_self_get_status_message(tox, statusMessage);
+ setWString("StatusMsg", ptrW(Utf8DecodeW((char*)statusMessage)));
- std::tstring avatarPath = GetAvatarFilePath();
- if (IsFileExists(avatarPath))
- {
- SetToxAvatar(avatarPath);
- }
+ return true;
}
- else
- {
- debugLogA("CToxProto::InitToxCore: failed to load tox profile");
- if (password != NULL)
- {
- mir_free(password);
- password = NULL;
- }
- tox_kill(tox);
- tox = NULL;
- }
+ tox_options_free(options);
- return isProfileLoaded;
+ return false;
}
void CToxProto::UninitToxCore()
{
- for (size_t i = 0; i < transfers.Count(); i++)
- {
- FileTransferParam *transfer = transfers.GetAt(i);
- transfer->status = CANCELED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0);
- transfers.Remove(transfer);
- }
+ if (tox) {
+ for (size_t i = 0; i < transfers.Count(); i++)
+ {
+ FileTransferParam *transfer = transfers.GetAt(i);
+ transfer->status = CANCELED;
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
+ ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0);
+ transfers.Remove(transfer);
+ }
- if (IsToxCoreInited())
- {
- ptrA nickname(mir_utf8encodeW(ptrT(getTStringA("Nick"))));
- tox_set_name(tox, (uint8_t*)(char*)nickname, mir_strlen(nickname));
+ //if (IsToxCoreInited())
+ //{
+ // ptrA nickname(mir_utf8encodeW(ptrT(getTStringA("Nick"))));
+ // tox_set_name(tox, (uint8_t*)(char*)nickname, mir_strlen(nickname));
- //temporary
- ptrA statusmes(mir_utf8encodeW(ptrT(getTStringA("StatusMsg"))));
- tox_set_status_message(tox, (uint8_t*)(char*)statusmes, mir_strlen(statusmes));
- }
+ // //temporary
+ // ptrA statusmes(mir_utf8encodeW(ptrT(getTStringA("StatusMsg"))));
+ // tox_set_status_message(tox, (uint8_t*)(char*)statusmes, mir_strlen(statusmes));
+ //}
- SaveToxProfile();
- if (password != NULL)
- {
- mir_free(password);
- password = NULL;
+ SaveToxProfile();
+ if (password != NULL)
+ {
+ mir_free(password);
+ password = NULL;
+ }
+ tox_kill(tox);
+ tox = NULL;
}
- tox_kill(tox);
- tox = NULL;
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_dialogs.h b/protocols/Tox/src/tox_dialogs.h
new file mode 100644
index 0000000000..c78c7a8943
--- /dev/null
+++ b/protocols/Tox/src/tox_dialogs.h
@@ -0,0 +1,21 @@
+#ifndef _TOX_DIALOGS_H_
+#define _TOX_DIALOGS_H_
+
+typedef CProtoDlgBase<CToxProto> CToxDlgBase;
+
+class CToxPasswordEditor : public CToxDlgBase
+{
+private:
+ CCtrlEdit password;
+ CCtrlCheck savePermanently;
+
+ CCtrlButton ok;
+
+protected:
+ void OnOk(CCtrlButton*);
+
+public:
+ CToxPasswordEditor(CToxProto *proto);
+};
+
+#endif //_TOX_DIALOGS_H_ \ No newline at end of file
diff --git a/protocols/Tox/src/tox_events.cpp b/protocols/Tox/src/tox_events.cpp
index fb1ce6ba43..406999549a 100644
--- a/protocols/Tox/src/tox_events.cpp
+++ b/protocols/Tox/src/tox_events.cpp
@@ -11,18 +11,20 @@ int CToxProto::OnContactDeleted(MCONTACT hContact, LPARAM)
{
if (!IsOnline())
{
- return 1;
+ return -1;
}
if (!isChatRoom(hContact))
{
int32_t friendNumber = GetToxFriendNumber(hContact);
- if (friendNumber == TOX_ERROR || tox_del_friend(tox, friendNumber) == TOX_ERROR)
+ TOX_ERR_FRIEND_DELETE error;
+ if (!tox_friend_delete(tox, friendNumber, &error))
{
- return 1;
+ debugLogA(__FUNCTION__": failed to delete friend (%d)", error);
+ return error;
}
}
- else
+ /*else
{
OnLeaveChatRoom(hContact, 0);
int groupNumber = 0; // ???
@@ -30,7 +32,7 @@ int CToxProto::OnContactDeleted(MCONTACT hContact, LPARAM)
{
return 1;
}
- }
+ }*/
return 0;
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_menus.cpp b/protocols/Tox/src/tox_menus.cpp
index 22398b3a01..9b6cc1b875 100644
--- a/protocols/Tox/src/tox_menus.cpp
+++ b/protocols/Tox/src/tox_menus.cpp
@@ -29,9 +29,7 @@ int CToxProto::OnPrebuildContactMenu(WPARAM hContact, LPARAM)
int CToxProto::PrebuildContactMenu(WPARAM hContact, LPARAM lParam)
{
for (int i = 0; i < SIZEOF(ContactMenuItems); i++)
- {
- Menu_ShowItem(ContactMenuItems[i], false);
- }
+ Menu_ShowItem(ContactMenuItems[i], FALSE);
CToxProto *proto = CToxProto::GetContactAccount(hContact);
return proto ? proto->OnPrebuildContactMenu(hContact, lParam) : 0;
}
@@ -103,13 +101,14 @@ int CToxProto::OnInitStatusMenu()
mi.position = SMI_POSITION + SMI_TOXID_COPY;
Menu_AddProtoMenuItem(&mi);
+
// Create group chat command
/*mir_strcpy(tDest, "/CreateChatRoom");
CreateProtoService(tDest, &CToxProto::OnCreateChatRoom);
mi.ptszName = LPGENT("Create group chat");
mi.position = SMI_POSITION + SMI_GROUPCHAT_CREATE;
mi.icolibItem = GetSkinIconHandle("conference");
- Menu_AddProtoMenuItem(&mi);*/
+ HGENMENU hCreateChatRoom = Menu_AddProtoMenuItem(&mi);*/
return 0;
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_menus.h b/protocols/Tox/src/tox_menus.h
index e75f9c8b45..bd3308afdd 100644
--- a/protocols/Tox/src/tox_menus.h
+++ b/protocols/Tox/src/tox_menus.h
@@ -2,12 +2,14 @@
#define _TOX_MENUS_H_
#define CMI_POSITION -201001000
-#define CMI_AUTH_REQUEST 1
-#define CMI_AUTH_GRANT 2
-#define CMI_MAX 3 // this item shall be the last one
+
+#define CMI_AUTH_REQUEST 0
+#define CMI_AUTH_GRANT 1
+#define CMI_MAX 2 // this item shall be the last one
#define SMI_POSITION 200000
-#define SMI_TOXID_COPY 1
-#define SMI_GROUPCHAT_CREATE 2
+
+#define SMI_TOXID_COPY 0
+#define SMI_GROUPCHAT_CREATE 1
#endif //_TOX_MENUS_H_ \ No newline at end of file
diff --git a/protocols/Tox/src/tox_messages.cpp b/protocols/Tox/src/tox_messages.cpp
index 13d0adffcd..a73aec2f7c 100644
--- a/protocols/Tox/src/tox_messages.cpp
+++ b/protocols/Tox/src/tox_messages.cpp
@@ -3,42 +3,23 @@
/* MESSAGE RECEIVING */
// incoming message flow
-void CToxProto::OnFriendMessage(Tox*, const int friendNumber, const uint8_t *message, const uint16_t messageSize, void *arg)
+void CToxProto::OnFriendMessage(Tox*, uint32_t friendNumber, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
MCONTACT hContact = proto->GetContact(friendNumber);
if (hContact)
{
- ptrA szMessage((char*)mir_alloc(messageSize + 1));
- mir_strncpy(szMessage, (const char*)message, messageSize + 1);
+ std::string test((char*)message);
+ ptrA szMessage((char*)mir_alloc(length + 1));
+ mir_strncpy(szMessage, (const char*)message, length);
PROTORECVEVENT recv = { 0 };
recv.flags = PREF_UTF;
recv.timestamp = time(NULL);
recv.szMessage = szMessage;
- recv.lParam = EVENTTYPE_MESSAGE;
-
- ProtoChainRecvMsg(hContact, &recv);
- }
-}
-
-// incoming action flow
-void CToxProto::OnFriendAction(Tox*, const int friendNumber, const uint8_t *action, const uint16_t actionSize, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact)
- {
- ptrA szMessage((char*)mir_alloc(actionSize + 1));
- mir_strncpy(szMessage, (const char*)action, actionSize + 1);
-
- PROTORECVEVENT recv = { 0 };
- recv.flags = PREF_UTF;
- recv.timestamp = time(NULL);
- recv.szMessage = szMessage;
- recv.lParam = TOX_DB_EVENT_TYPE_ACTION;
+ recv.lParam = type == TOX_MESSAGE_TYPE_NORMAL
+ ? EVENTTYPE_MESSAGE : TOX_DB_EVENT_TYPE_ACTION;
ProtoChainRecvMsg(hContact, &recv);
}
@@ -68,62 +49,51 @@ int CToxProto::OnReceiveMessage(MCONTACT hContact, PROTORECVEVENT *pre)
int CToxProto::OnSendMessage(MCONTACT hContact, int flags, const char *szMessage)
{
int32_t friendNumber = GetToxFriendNumber(hContact);
- if (friendNumber == TOX_ERROR)
- {
+ if (friendNumber == UINT32_MAX)
return 0;
- }
ptrA message;
if (flags & PREF_UNICODE)
- {
message = mir_utf8encodeW((wchar_t*)&szMessage[mir_strlen(szMessage) + 1]);
- }
else if (flags & PREF_UTF)
- {
message = mir_strdup(szMessage);
- }
else
- {
message = mir_utf8encode(szMessage);
- }
- int receipt = 0;
- if (strncmp(message, "/me ", 4) != 0)
- {
- receipt = tox_send_message(tox, friendNumber, (uint8_t*)(char*)message, mir_strlen(message));
- }
- else
+ size_t msgLen = mir_strlen(message);
+ uint8_t *msg = (uint8_t*)(char*)message;
+ TOX_MESSAGE_TYPE type = TOX_MESSAGE_TYPE_NORMAL;
+ if (strncmp(message, "/me ", 4) == 0)
{
- receipt = tox_send_action(tox, friendNumber, (uint8_t*)&message[4], mir_strlen(message) - 4);
+ msg += 4; msgLen -= 4;
+ type = TOX_MESSAGE_TYPE_ACTION;
}
- if (receipt == TOX_ERROR)
+ TOX_ERR_FRIEND_SEND_MESSAGE error;
+ int messageId = tox_friend_send_message(tox, friendNumber, type, msg, msgLen, &error);
+ if (error != TOX_ERR_FRIEND_SEND_MESSAGE_OK)
{
- debugLogA("CToxProto::OnSendMessage: failed to send message");
+ debugLogA(__FUNCTION__": failed to send message (%d)", error);
}
- return receipt;
+ return messageId;
}
// message is received by the other side
-void CToxProto::OnReadReceipt(Tox*, int32_t friendNumber, uint32_t receipt, void *arg)
+void CToxProto::OnReadReceipt(Tox*, uint32_t friendNumber, uint32_t messageId, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
MCONTACT hContact = proto->GetContact(friendNumber);
if (hContact)
- {
proto->ProtoBroadcastAck(
- hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)receipt, 0);
- }
+ hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)messageId, 0);
}
// preparing message/action to writing into db
int CToxProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
{
MessageWindowEvent *evt = (MessageWindowEvent*)lParam;
- if (strcmp(GetContactProto(evt->hContact), m_szModuleName))
- {
+ if (mir_strcmp(GetContactProto(evt->hContact), m_szModuleName))
return 0;
- }
char *message = (char*)evt->dbei->pBlob;
if (strncmp(message, "/me ", 4) == 0)
@@ -141,28 +111,26 @@ int CToxProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
/* TYPING */
-void CToxProto::OnTypingChanged(Tox*, const int number, uint8_t isTyping, void *arg)
+int CToxProto::OnUserIsTyping(MCONTACT hContact, int type)
{
- CToxProto *proto = (CToxProto*)arg;
+ int32_t friendNumber = GetToxFriendNumber(hContact);
+ if (friendNumber == UINT32_MAX)
+ return 0;
+
+ TOX_ERR_SET_TYPING error;
+ if (!tox_self_set_typing(tox, friendNumber, type == PROTOTYPE_SELFTYPING_ON, &error))
+ debugLogA(__FUNCTION__": failed to send typing (%d)", error);
- MCONTACT hContact = proto->GetContact(number);
- if (hContact)
- {
- CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)isTyping);
- }
+ return 0;
}
-int CToxProto::UserIsTyping(MCONTACT hContact, int type)
+void CToxProto::OnTypingChanged(Tox*, uint32_t friendNumber, bool isTyping, void *arg)
{
- if (hContact && IsOnline())
+ CToxProto *proto = (CToxProto*)arg;
+
+ if (MCONTACT hContact = proto->GetContact(friendNumber))
{
- int32_t friendNumber = GetToxFriendNumber(hContact);
- if (friendNumber >= 0)
- {
- tox_set_user_is_typing(tox, friendNumber, type);
- return 0;
- }
+ int typingStatus = (isTyping ? PROTOTYPE_CONTACTTYPING_INFINITE : PROTOTYPE_CONTACTTYPING_OFF);
+ CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)typingStatus);
}
-
- return 1;
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_network.cpp b/protocols/Tox/src/tox_network.cpp
index 86ba7fff37..29e261e0cd 100644
--- a/protocols/Tox/src/tox_network.cpp
+++ b/protocols/Tox/src/tox_network.cpp
@@ -7,9 +7,10 @@ bool CToxProto::IsOnline()
void CToxProto::BootstrapNode(const char *address, int port, const uint8_t *pubKey)
{
- if (!tox_bootstrap_from_address(tox, address, port, pubKey))
+ TOX_ERR_BOOTSTRAP error;
+ if (!tox_bootstrap(tox, address, port, pubKey, &error))
{
- debugLogA("CToxProto::BootstrapNode: failed to bootstrap node %s:%d (%s)", address, port, (const char*)ToxHexAddress(pubKey));
+ debugLogA("CToxProto::BootstrapNode: failed to bootstrap node %s:%d \"%s\" (%d)", address, port, (const char*)ToxHexAddress(pubKey), error);
}
}
@@ -74,31 +75,31 @@ void CToxProto::BootstrapNodesFromIni(bool isIPv6)
void CToxProto::BootstrapNodes()
{
- debugLogA("CToxProto::BootstrapDht: bootstraping DHT");
- bool isIPv6 = !getBool("DisableIPv6", 0);
+ debugLogA(__FUNCTION__": bootstraping DHT");
+ bool isIPv6 = getBool("EnableIPv6", 0);
BootstrapNodesFromDb(isIPv6);
BootstrapNodesFromIni(isIPv6);
}
void CToxProto::TryConnect()
{
- if (tox_isconnected(tox))
+ if (tox_self_get_connection_status(tox) != TOX_CONNECTION_NONE)
{
isConnected = true;
- debugLogA("CToxProto::PollingThread: successfuly connected to DHT");
+ debugLogA(__FUNCTION__": successfuly connected to DHT");
ForkThread(&CToxProto::LoadFriendList, NULL);
m_iStatus = m_iDesiredStatus;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus);
- tox_set_user_status(tox, MirandaToToxStatus(m_iStatus));
- debugLogA("CToxProto::PollingThread: changing status from %i to %i", ID_STATUS_CONNECTING, m_iDesiredStatus);
+ tox_self_set_status(tox, MirandaToToxStatus(m_iStatus));
+ debugLogA(__FUNCTION__": changing status from %i to %i", ID_STATUS_CONNECTING, m_iDesiredStatus);
}
else if (m_iStatus++ > TOX_MAX_CONNECT_RETRIES)
{
SetStatus(ID_STATUS_OFFLINE);
ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, (HANDLE)NULL, LOGINERR_NONETWORK);
- debugLogA("CToxProto::PollingThread: failed to connect to DHT");
+ debugLogA(__FUNCTION__": failed to connect to DHT");
}
}
@@ -108,11 +109,11 @@ void CToxProto::CheckConnection(int &retriesCount)
{
TryConnect();
}
- else if (tox_isconnected(tox))
+ else if (tox_self_get_connection_status(tox) != TOX_CONNECTION_NONE)
{
if (retriesCount < TOX_MAX_DISCONNECT_RETRIES)
{
- debugLogA("CToxProto::CheckConnection: restored connection with DHT");
+ debugLogA(__FUNCTION__": restored connection with DHT");
retriesCount = TOX_MAX_DISCONNECT_RETRIES;
}
}
@@ -121,7 +122,7 @@ void CToxProto::CheckConnection(int &retriesCount)
if (retriesCount == TOX_MAX_DISCONNECT_RETRIES)
{
retriesCount--;
- debugLogA("CToxProto::CheckConnection: lost connection with DHT");
+ debugLogA(__FUNCTION__": lost connection with DHT");
}
else if (retriesCount % 50 == 0)
{
@@ -131,7 +132,7 @@ void CToxProto::CheckConnection(int &retriesCount)
else if (!(--retriesCount))
{
isConnected = false;
- debugLogA("CToxProto::CheckConnection: disconnected from DHT");
+ debugLogA(__FUNCTION__": disconnected from DHT");
SetStatus(ID_STATUS_OFFLINE);
}
}
@@ -141,21 +142,21 @@ void CToxProto::DoTox()
{
{
mir_cslock lock(toxLock);
- tox_do(tox);
+ tox_iterate(tox);
}
- uint32_t interval = tox_do_interval(tox);
+ uint32_t interval = tox_iteration_interval(tox);
Sleep(interval);
}
void CToxProto::PollingThread(void*)
{
- debugLogA("CToxProto::PollingThread: entering");
+ debugLogA(__FUNCTION__": entering");
if (!InitToxCore())
{
SetStatus(ID_STATUS_OFFLINE);
ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, (HANDLE)NULL, LOGINERR_WRONGPASSWORD);
- debugLogA("CToxProto::PollingThread: leaving");
+ debugLogA(__FUNCTION__": leaving");
return;
}
@@ -172,5 +173,5 @@ void CToxProto::PollingThread(void*)
UninitToxCore();
isConnected = false;
- debugLogA("CToxProto::PollingThread: leaving");
+ debugLogA(__FUNCTION__": leaving");
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_options.cpp b/protocols/Tox/src/tox_options.cpp
index f282c0cbd0..4e7fb3103e 100644
--- a/protocols/Tox/src/tox_options.cpp
+++ b/protocols/Tox/src/tox_options.cpp
@@ -1,665 +1,476 @@
#include "common.h"
-INT_PTR CToxProto::MainOptionsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+CToxOptionsMain::CToxOptionsMain(CToxProto *proto, int idDialog, HWND hwndParent)
+ : CToxDlgBase(proto, idDialog, hwndParent, false),
+ m_toxAddress(this, IDC_TOXID), m_toxAddressCopy(this, IDC_CLIPBOARD),
+ m_profileCreate(this, IDC_PROFILE_NEW), m_profileImport(this, IDC_PROFILE_IMPORT),
+ m_profileExport(this, IDC_PROFILE_EXPORT), m_nickname(this, IDC_NAME),
+ m_password(this, IDC_PASSWORD), m_group(this, IDC_GROUP),
+ m_enableUdp(this, IDC_ENABLE_UDP), m_enableIPv6(this, IDC_ENABLE_IPV6)
{
- CToxProto *proto = (CToxProto*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ CreateLink(m_toxAddress, TOX_SETTINGS_ID, _T(""));
+ CreateLink(m_nickname, "Nick", _T(""));
+ CreateLink(m_password, "Password", _T(""));
+ CreateLink(m_group, TOX_SETTINGS_GROUP, _T("Tox"));
+ CreateLink(m_enableUdp, "EnableUDP", DBVT_BYTE, TRUE);
+ CreateLink(m_enableIPv6, "EnableIPv6", DBVT_BYTE, FALSE);
+
+ m_toxAddressCopy.OnClick = Callback(this, &CToxOptionsMain::ToxAddressCopy_OnClick);
+ m_profileCreate.OnClick = Callback(this, &CToxOptionsMain::ProfileCreate_OnClick);
+ m_profileImport.OnClick = Callback(this, &CToxOptionsMain::ProfileImport_OnClick);
+ m_profileExport.OnClick = Callback(this, &CToxOptionsMain::ProfileExport_OnClick);
+}
- switch (uMsg)
- {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwnd);
- {
- proto = (CToxProto*)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+void CToxOptionsMain::OnInitDialog()
+{
+ CToxDlgBase::OnInitDialog();
- ptrT nick(proto->getTStringA("Nick"));
- SetDlgItemText(hwnd, IDC_NAME, nick);
+ std::tstring profilePath = m_proto->GetToxProfilePath();
+ if (CToxProto::IsFileExists(profilePath))
+ {
+ m_toxAddress.Enable();
- ptrT pass(proto->getTStringA("Password"));
- SetDlgItemText(hwnd, IDC_PASSWORD, pass);
+ ShowWindow(m_profileCreate.GetHwnd(), FALSE);
+ ShowWindow(m_profileImport.GetHwnd(), FALSE);
- ptrA address(proto->getStringA(TOX_SETTINGS_ID));
- if (address != NULL)
- {
- SetDlgItemTextA(hwnd, IDC_TOXID, address);
- }
+ ShowWindow(m_toxAddressCopy.GetHwnd(), TRUE);
+ //ShowWindow(m_profileExport.GetHwnd(), TRUE);
+ }
- ptrT group(proto->getTStringA(TOX_SETTINGS_GROUP));
- SetDlgItemText(hwnd, IDC_GROUP, group ? group : _T("Tox"));
- SendDlgItemMessage(hwnd, IDC_GROUP, EM_LIMITTEXT, 64, 0);
+ if (m_proto->IsOnline())
+ {
+ EnableWindow(m_nickname.GetHwnd(), TRUE);
+ EnableWindow(m_password.GetHwnd(), TRUE);
+ }
- CheckDlgButton(hwnd, IDC_DISABLE_UDP, proto->getBool("DisableUDP", 0));
- CheckDlgButton(hwnd, IDC_DISABLE_IPV6, proto->getBool("DisableIPv6", 0));
- if (!proto->IsToxCoreInited())
- {
- EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_PROFILE), TRUE);
- }
- }
- return TRUE;
+ SendMessage(m_toxAddress.GetHwnd(), EM_LIMITTEXT, TOX_ADDRESS_SIZE * 2, 0);
+ SendMessage(m_nickname.GetHwnd(), EM_LIMITTEXT, TOX_MAX_NAME_LENGTH, 0);
+ SendMessage(m_password.GetHwnd(), EM_LIMITTEXT, 32, 0);
+ SendMessage(m_group.GetHwnd(), EM_LIMITTEXT, 64, 0);
+}
- case WM_COMMAND:
+void CToxOptionsMain::ToxAddressCopy_OnClick(CCtrlButton*)
+{
+ char *toxAddress = m_toxAddress.GetTextA();
+ int toxAddressLength = mir_strlen(toxAddress) + 1;
+ if (OpenClipboard(m_toxAddress.GetHwnd()))
{
- switch (LOWORD(wParam))
- {
- case IDC_NAME:
- case IDC_GROUP:
- case IDC_PASSWORD:
- if ((HWND)lParam == GetFocus())
- {
- if (HIWORD(wParam) != EN_CHANGE) return 0;
- SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
- }
- break;
+ EmptyClipboard();
+ HGLOBAL hMemory = GlobalAlloc(GMEM_FIXED, toxAddressLength);
+ memcpy(GlobalLock(hMemory), toxAddress, toxAddressLength);
+ GlobalUnlock(hMemory);
+ SetClipboardData(CF_TEXT, hMemory);
+ CloseClipboard();
+ }
+}
- case IDC_DISABLE_UDP:
- case IDC_DISABLE_IPV6:
- SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
- break;
+void CToxOptionsMain::ProfileCreate_OnClick(CCtrlButton*)
+{
+ if (m_proto->InitToxCore())
+ {
+ TCHAR *group = m_group.GetText();
+ if (mir_tstrlen(group) > 0 && Clist_GroupExists(group))
+ Clist_CreateGroup(0, group);
- case IDC_CLIPBOARD:
- {
- char toxId[TOX_FRIEND_ADDRESS_SIZE * 2 + 1];
- GetDlgItemTextA(hwnd, IDC_TOXID, toxId, SIZEOF(toxId));
- if (OpenClipboard(GetDlgItem(hwnd, IDC_TOXID)))
- {
- EmptyClipboard();
- HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, sizeof(toxId));
- memcpy(GlobalLock(hMem), toxId, sizeof(toxId));
- GlobalUnlock(hMem);
- SetClipboardData(CF_TEXT, hMem);
- CloseClipboard();
- }
- }
- break;
+ m_proto->LoadFriendList(NULL);
+ m_proto->UninitToxCore();
- case IDC_IMPORT_PROFILE:
- {
- TCHAR filter[MAX_PATH];
- mir_sntprintf(filter, SIZEOF(filter), _T("%s(*.tox)%c*.tox%c%s(*.*)%c*.*%c%c"),
- TranslateT("Tox profile"), 0, 0, TranslateT("All files"), 0, 0, 0);
-
- TCHAR profilePath[MAX_PATH] = { 0 };
-
- OPENFILENAME ofn = { sizeof(ofn) };
- ofn.hwndOwner = hwnd;
- ofn.lpstrFilter = filter;
- ofn.nFilterIndex = 1;
- ofn.lpstrFile = profilePath;
- ofn.lpstrTitle = TranslateT("Select tox profile");
- ofn.nMaxFile = MAX_PATH;
- ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
- ofn.lpstrInitialDir = _T("%APPDATA%\\Tox");
-
- if (GetOpenFileName(&ofn))
- {
- if (!proto->IsToxCoreInited())
- {
- std::tstring defaultProfilePath = GetToxProfilePath(proto->accountName);
- if (CToxProto::IsFileExists(defaultProfilePath.c_str()))
- {
- if (MessageBox(
- hwnd,
- TranslateT("You have existing profile. Do you want remove it with all tox contacts and history and continue import?"),
- TranslateT("Tox profile import"),
- MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDYES)
- {
- while (MCONTACT hContact = db_find_first(proto->m_szModuleName))
- {
- CallService(MS_DB_CONTACT_DELETE, hContact, 0);
- }
- }
- else break;
- }
- if (profilePath && _tcslen(profilePath))
- {
- if (_tcsicmp(profilePath, defaultProfilePath.c_str()) != 0)
- {
- CopyFile(profilePath, defaultProfilePath.c_str(), FALSE);
- }
- }
-
- if (proto->InitToxCore())
- {
- TCHAR group[64];
- GetDlgItemText(hwnd, IDC_GROUP, group, SIZEOF(group));
- if (_tcslen(group) > 0)
- {
- proto->setTString(TOX_SETTINGS_GROUP, group);
- Clist_CreateGroup(0, group);
- }
- else
- {
- proto->delSetting(TOX_SETTINGS_GROUP);
- }
- proto->LoadFriendList(NULL);
- proto->UninitToxCore();
-
- ptrT nick(proto->getTStringA("Nick"));
- SetDlgItemText(hwnd, IDC_NAME, nick);
-
- ptrT pass(proto->getTStringA("Password"));
- SetDlgItemText(hwnd, IDC_PASSWORD, pass);
-
- ptrA address(proto->getStringA(TOX_SETTINGS_ID));
- if (address != NULL)
- {
- SetDlgItemTextA(hwnd, IDC_TOXID, address);
- }
- }
- }
- }
- }
- break;
- }
- }
- break;
+ m_toxAddress.Enable();
+ m_toxAddress.SetTextA(ptrA(m_proto->getStringA(TOX_SETTINGS_ID)));
- case WM_NOTIFY:
- if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY)
- {
- TCHAR nick[TOX_MAX_NAME_LENGTH];
- GetDlgItemText(hwnd, IDC_NAME, nick, TOX_MAX_NAME_LENGTH);
- CallProtoService(proto->m_szModuleName, PS_SETMYNICKNAME, SMNN_TCHAR, (LPARAM)nick);
-
- TCHAR password[MAX_PATH];
- GetDlgItemText(hwnd, IDC_PASSWORD, password, SIZEOF(password));
- proto->setTString("Password", password);
- if (proto->password != NULL)
- {
- mir_free(proto->password);
- proto->password = NULL;
- }
- proto->password = mir_utf8encodeW(password);
+ m_nickname.SetText(ptrT(m_proto->getTStringA("Nick")));
+ m_password.SetText(ptrT(m_proto->getTStringA("Password")));
+ m_group.SetText(ptrT(m_proto->getTStringA(TOX_SETTINGS_GROUP)));
- TCHAR group[64];
- GetDlgItemText(hwnd, IDC_GROUP, group, SIZEOF(group));
- if (_tcslen(group) > 0)
- {
- proto->setTString(TOX_SETTINGS_GROUP, group);
- Clist_CreateGroup(0, group);
- }
- else
- {
- proto->delSetting(NULL, TOX_SETTINGS_GROUP);
- }
+ ShowWindow(m_profileCreate.GetHwnd(), FALSE);
+ ShowWindow(m_profileImport.GetHwnd(), FALSE);
- proto->setByte("DisableUDP", (BYTE)IsDlgButtonChecked(hwnd, IDC_DISABLE_UDP));
- proto->setByte("DisableIPv6", (BYTE)IsDlgButtonChecked(hwnd, IDC_DISABLE_IPV6));
+ ShowWindow(m_toxAddressCopy.GetHwnd(), TRUE);
+ //ShowWindow(m_profileExport.GetHwnd(), TRUE);
+ }
+}
- if (proto->IsOnline())
- {
- //proto->SaveToxProfile();
- }
+void CToxOptionsMain::ProfileImport_OnClick(CCtrlButton*)
+{
+ TCHAR filter[MAX_PATH];
+ mir_sntprintf(filter, SIZEOF(filter), _T("%s(*.tox)%c*.tox%c%s(*.*)%c*.*%c%c"),
+ TranslateT("Tox profile"), 0, 0, TranslateT("All files"), 0, 0, 0);
+
+ TCHAR profilePath[MAX_PATH] = { 0 };
+
+ OPENFILENAME ofn = { sizeof(ofn) };
+ ofn.hwndOwner = m_hwnd;
+ ofn.lpstrFilter = filter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = profilePath;
+ ofn.lpstrTitle = TranslateT("Select tox profile");
+ ofn.nMaxFile = MAX_PATH;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
+ ofn.lpstrInitialDir = _T("%APPDATA%\\Tox");
+
+ if (!GetOpenFileName(&ofn))
+ {
+ return;
+ }
- return TRUE;
- }
- break;
+ std::tstring defaultProfilePath = m_proto->GetToxProfilePath();
+ if (_tcsicmp(profilePath, defaultProfilePath.c_str()) != 0)
+ {
+ CopyFile(profilePath, defaultProfilePath.c_str(), FALSE);
}
- return FALSE;
+ m_profileCreate.OnClick(&m_profileCreate);
}
-int AddItemToListView(HWND hwndList, UINT mask, int iGroupId, int iItem, int iSubItem, char *pszText, int iImage = -1)
+void CToxOptionsMain::ProfileExport_OnClick(CCtrlButton*)
{
- LVITEMA lvi = { 0 };
- lvi.mask = mask;
- lvi.iItem = iItem;
- lvi.iSubItem = iSubItem;
- lvi.iGroupId = iGroupId;
- lvi.iImage = iImage;
- lvi.pszText = mir_strdup(pszText);
- return SendMessage(hwndList, LVM_INSERTITEMA, 0, (LPARAM)&lvi);
}
-int SetSubItemToListView(HWND hwndList, UINT mask, int iGroupId, int iItem, int iSubItem, char *pszText, int iImage = -1)
+void CToxOptionsMain::OnApply()
{
- LVITEMA lvi = { 0 };
- lvi.mask = mask;
- lvi.iItem = iItem;
- lvi.iSubItem = iSubItem;
- lvi.iGroupId = iGroupId;
- lvi.iImage = iImage;
- lvi.pszText = mir_strdup(pszText);
- return SendMessage(hwndList, LVM_SETITEMA, 0, (LPARAM)&lvi);
+ TCHAR *group = m_group.GetText();
+ if (mir_tstrlen(group) > 0 && Clist_GroupExists(group))
+ Clist_CreateGroup(0, group);
+
+ if (m_proto->IsOnline())
+ {
+ CallProtoService(m_proto->m_szModuleName, PS_SETMYNICKNAME, SMNN_TCHAR, (LPARAM)m_nickname.GetText());
+
+ if (m_proto->password != NULL)
+ mir_free(m_proto->password);
+ m_proto->password = mir_utf8encodeW(ptrT(m_password.GetText()));
+
+ m_proto->SaveToxProfile();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+CToxNodeEditor::CToxNodeEditor(int iItem, CCtrlListView *m_nodes)
+ : CSuper(g_hInstance, IDD_NODE_EDITOR, NULL),
+ m_ipv4(this, IDC_IPV4), m_ipv6(this, IDC_IPV6),
+ m_port(this, IDC_PORT), m_pkey(this, IDC_PKEY),
+ m_ok(this, IDOK), m_iItem(iItem)
+{
+ m_list = m_nodes;
+ m_ok.OnClick = Callback(this, &CToxNodeEditor::OnOk);
}
-INT_PTR CALLBACK EditNodeDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+void CToxNodeEditor::OnInitDialog()
{
- ItemInfo *itemInfo = (ItemInfo*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ SetWindowText(m_hwnd, m_iItem == -1 ? TranslateT("Add node") : TranslateT("Change node"));
- switch (msg)
+ if (m_iItem > -1)
{
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- {
- itemInfo = (ItemInfo*)lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = m_iItem;
+ lvi.cchTextMax = MAX_PATH;
+ lvi.pszText = (TCHAR*)mir_alloc(MAX_PATH * sizeof(TCHAR));
- SendDlgItemMessage(hwndDlg, IDC_IPV4, EM_SETLIMITTEXT, MAX_PATH, 0);
- SendDlgItemMessage(hwndDlg, IDC_IPV6, EM_SETLIMITTEXT, 39, 0);
- SendDlgItemMessage(hwndDlg, IDC_PORT, EM_SETLIMITTEXT, 5, 0);
- SendDlgItemMessage(hwndDlg, IDC_PKEY, EM_SETLIMITTEXT, TOX_PUBLIC_KEY_SIZE * 2, 0);
+ lvi.iSubItem = 0;
+ m_list->GetItem(&lvi);
+ m_ipv4.SetText(lvi.pszText);
- if (itemInfo->iItem == -1)
- {
- SetWindowText(hwndDlg, TranslateT("Add node"));
- }
- else
- {
- SetWindowText(hwndDlg, TranslateT("Change node"));
+ lvi.iSubItem = 1;
+ m_list->GetItem(&lvi);
+ m_ipv6.SetText(lvi.pszText);
- LVITEMA lvi = { 0 };
- lvi.mask = LVIF_TEXT;
- lvi.iItem = itemInfo->iItem;
- lvi.cchTextMax = MAX_PATH;
- lvi.pszText = (char*)mir_alloc(MAX_PATH);
+ lvi.iSubItem = 2;
+ m_list->GetItem(&lvi);
+ m_port.SetText(lvi.pszText);
- lvi.iSubItem = 0;
- SendMessage(itemInfo->hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- SetDlgItemTextA(hwndDlg, IDC_IPV4, lvi.pszText);
+ lvi.iSubItem = 3;
+ m_list->GetItem(&lvi);
+ m_pkey.SetText(lvi.pszText);
- lvi.iSubItem = 1;
- SendMessage(itemInfo->hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
+ mir_free(lvi.pszText);
+ }
- SetDlgItemTextA(hwndDlg, IDC_IPV6, lvi.pszText);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULE, "EditNodeDlg");
+}
- lvi.iSubItem = 2;
- SendMessage(itemInfo->hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- SetDlgItemTextA(hwndDlg, IDC_PORT, lvi.pszText);
+void CToxNodeEditor::OnOk(CCtrlBase*)
+{
+ if (!m_ipv4.GetInt())
+ {
+ MessageBox(m_hwnd, TranslateT("Enter IPv4"), TranslateT("Error"), MB_OK);
+ return;
+ }
+ if (!m_pkey.GetInt())
+ {
+ MessageBox(m_hwnd, TranslateT("Enter public key"), TranslateT("Error"), MB_OK);
+ return;
+ }
- lvi.iSubItem = 3;
- SendMessage(itemInfo->hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- SetDlgItemTextA(hwndDlg, IDC_PKEY, lvi.pszText);
+ ptrT ipv4(m_ipv4.GetText());
+ if (m_iItem == -1)
+ {
+ m_iItem = m_list->AddItem(ipv4, -1, NULL, 1);
+ m_list->SetItemState(m_iItem, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);
+ m_list->EnsureVisible(m_iItem, TRUE);
+ }
+ else
+ m_list->SetItem(m_iItem, 0, ipv4);
+ m_list->SetItem(m_iItem, 1, ptrT(m_ipv6.GetText()));
+ m_list->SetItem(m_iItem, 2, ptrT(m_port.GetText()));
+ m_list->SetItem(m_iItem, 3, ptrT(m_pkey.GetText()));
+ m_list->SetItem(m_iItem, 4, _T(""), 0);
+ m_list->SetItem(m_iItem, 5, _T(""), 1);
+
+ EndDialog(m_hwnd, 1);
+}
- mir_free(lvi.pszText);
- }
+void CToxNodeEditor::OnClose()
+{
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULE, "EditNodeDlg");
+}
- Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, MODULE, "EditNodeDlg");
- }
+/****************************************/
+
+CCtrlNodeList::CCtrlNodeList(CDlgBase* dlg, int ctrlId)
+ : CCtrlListView(dlg, ctrlId)
+{
+}
+
+BOOL CCtrlNodeList::OnNotify(int idCtrl, NMHDR *pnmh)
+{
+ if (pnmh->code == NM_CLICK)
+ {
+ TEventInfo evt = { this, pnmh };
+ OnClick(&evt);
return TRUE;
+ }
+ return CCtrlListView::OnNotify(idCtrl, pnmh);
+}
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case IDOK:
+/****************************************/
+
+CToxOptionsNodeList::CToxOptionsNodeList(CToxProto *proto)
+ : CSuper(proto, IDD_OPTIONS_NODES, NULL, false),
+ m_nodes(this, IDC_NODESLIST), m_addNode(this, IDC_ADDNODE)
+{
+ m_addNode.OnClick = Callback(this, &CToxOptionsNodeList::OnAddNode);
+ m_nodes.OnClick = Callback(this, &CToxOptionsNodeList::OnNodeListClick);
+ m_nodes.OnDoubleClick = Callback(this, &CToxOptionsNodeList::OnNodeListDoubleClick);
+ m_nodes.OnKeyDown = Callback(this, &CToxOptionsNodeList::OnNodeListKeyDown);
+}
+
+void CToxOptionsNodeList::OnInitDialog()
+{
+ m_nodes.SetExtendedListViewStyle(LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
+
+ HIMAGELIST hImageList = m_nodes.CreateImageList(LVSIL_SMALL);
+ HICON icon = LoadSkinnedIcon(SKINICON_OTHER_TYPING);
+ ImageList_AddIcon(hImageList, icon); Skin_ReleaseIcon(icon);
+ icon = LoadSkinnedIcon(SKINICON_OTHER_DELETE);
+ ImageList_AddIcon(hImageList, icon); Skin_ReleaseIcon(icon);
+
+ m_nodes.AddColumn(0, _T("IPv4"), 100);
+ m_nodes.AddColumn(1, _T("IPv6"), 100);
+ m_nodes.AddColumn(2, TranslateT("Port"), 50);
+ m_nodes.AddColumn(3, TranslateT("Public key"), 130);
+ m_nodes.AddColumn(4, _T(""), 32 - GetSystemMetrics(SM_CXVSCROLL));
+ m_nodes.AddColumn(5, _T(""), 32 - GetSystemMetrics(SM_CXVSCROLL));
+
+ m_nodes.EnableGroupView(TRUE);
+ m_nodes.AddGroup(0, TranslateT("Common nodes"));
+ m_nodes.AddGroup(1, TranslateT("User nodes"));
+
+ ////////////////////////////////////////
+
+ int iItem = -1;
+
+ if (CToxProto::IsFileExists((TCHAR*)VARST(_T(TOX_INI_PATH))))
+ {
+ char fileName[MAX_PATH];
+ mir_strcpy(fileName, VARS(TOX_INI_PATH));
+
+ char *section, sections[MAX_PATH], value[MAX_PATH];
+ GetPrivateProfileSectionNamesA(sections, SIZEOF(sections), fileName);
+ section = sections;
+ while (*section != NULL)
{
- char value[MAX_PATH];
- if (!GetDlgItemTextA(hwndDlg, IDC_IPV4, value, SIZEOF(value)))
- {
- MessageBox(hwndDlg, TranslateT("Enter IPv4"), TranslateT("Error"), MB_OK);
- break;
- }
- if (!GetDlgItemTextA(hwndDlg, IDC_PKEY, value, SIZEOF(value)))
+ if (strstr(section, TOX_SETTINGS_NODE_PREFIX) == section)
{
- MessageBox(hwndDlg, TranslateT("Enter public key"), TranslateT("Error"), MB_OK);
- break;
- }
+ GetPrivateProfileStringA(section, "IPv4", NULL, value, SIZEOF(value), fileName);
+ iItem = m_nodes.AddItem(mir_a2t(value), -1, NULL, 0);
- GetDlgItemTextA(hwndDlg, IDC_IPV4, value, SIZEOF(value));
- int iItem = itemInfo->iItem;
- if (iItem == -1)
- {
- iItem = ListView_GetItemCount(itemInfo->hwndList);
- AddItemToListView(itemInfo->hwndList, LVIF_GROUPID | LVIF_TEXT | LVIF_IMAGE, 1, iItem, 0, value);
- ListView_SetItemState(itemInfo->hwndList, iItem, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);
- ListView_EnsureVisible(itemInfo->hwndList, iItem, TRUE);
- }
- else
- {
- SetSubItemToListView(itemInfo->hwndList, LVIF_TEXT, 1, iItem, 0, value);
+ GetPrivateProfileStringA(section, "IPv6", NULL, value, SIZEOF(value), fileName);
+ m_nodes.SetItem(iItem, 1, mir_a2t(value));
+
+ GetPrivateProfileStringA(section, "Port", NULL, value, SIZEOF(value), fileName);
+ m_nodes.SetItem(iItem, 2, mir_a2t(value));
+
+ GetPrivateProfileStringA(section, "PubKey", NULL, value, SIZEOF(value), fileName);
+ m_nodes.SetItem(iItem, 3, mir_a2t(value));
}
- GetDlgItemTextA(hwndDlg, IDC_IPV6, value, SIZEOF(value));
- SetSubItemToListView(itemInfo->hwndList, LVIF_TEXT, 1, iItem, 1, value);
- GetDlgItemTextA(hwndDlg, IDC_PORT, value, SIZEOF(value));
- SetSubItemToListView(itemInfo->hwndList, LVIF_TEXT, 1, iItem, 2, value);
- GetDlgItemTextA(hwndDlg, IDC_PKEY, value, SIZEOF(value));
- SetSubItemToListView(itemInfo->hwndList, LVIF_TEXT, 1, iItem, 3, value);
- SetSubItemToListView(itemInfo->hwndList, LVIF_IMAGE, 1, iItem, 4, value, 0);
- SetSubItemToListView(itemInfo->hwndList, LVIF_IMAGE, 1, iItem, 5, value, 1);
-
- EndDialog(hwndDlg, IDOK);
+ section += strlen(section) + 1;
}
- break;
+ }
+
+ char module[MAX_PATH], setting[MAX_PATH];
+ mir_snprintf(module, SIZEOF(module), "%s_Nodes", m_proto->m_szModuleName);
+ int nodeCount = db_get_w(NULL, module, TOX_SETTINGS_NODE_COUNT, 0);
+ for (int i = 0; i < nodeCount; i++)
+ {
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, i);
+ ptrT value(db_get_tsa(NULL, module, setting));
+ iItem = m_nodes.AddItem(value, -1, NULL, 1);
+
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, i);
+ value = db_get_tsa(NULL, module, setting);
+ m_nodes.SetItem(iItem, 1, value);
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, i);
+ int port = db_get_w(NULL, module, setting, 0);
+ if (port > 0)
+ {
+ char portNum[10];
+ itoa(port, portNum, 10);
+ m_nodes.SetItem(iItem, 2, mir_a2t(portNum));
}
- break;
- case WM_DESTROY:
- Utils_SaveWindowPosition(hwndDlg, NULL, MODULE, "EditNodeDlg");
- break;
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, i);
+ value = db_get_tsa(NULL, module, setting);
+ m_nodes.SetItem(iItem, 3, value);
+
+ m_nodes.SetItem(iItem, 4, _T(""), 0);
+ m_nodes.SetItem(iItem, 5, _T(""), 1);
}
+}
- return FALSE;
+void CToxOptionsNodeList::OnAddNode(CCtrlBase*)
+{
+ CToxNodeEditor nodeEditor(-1, &m_nodes);
+ if (nodeEditor.DoModal())
+ SendMessage(GetParent(m_hwnd), PSM_CHANGED, 0, 0);
}
-INT_PTR CALLBACK NodeListSubProc(HWND hwndList, UINT uMsg, WPARAM wParam, LPARAM lParam)
+void CToxOptionsNodeList::OnNodeListDoubleClick(CCtrlBase*)
{
- LVITEMA lvi = { 0 };
+ int iItem = m_nodes.GetNextItem(-1, LVNI_SELECTED);
- switch (uMsg)
- {
- case WM_INITDIALOG:
+ LVITEM lvi = { 0 };
+ lvi.iItem = iItem;
+ lvi.mask = LVIF_GROUPID;
+ m_nodes.GetItem(&lvi);
+ if (lvi.iGroupId || (lvi.iGroupId == 0 && lvi.iItem == -1))
{
- TCHAR *userName = (TCHAR*)lParam;
-
- HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 2, 0);
- HICON icon = LoadSkinnedIcon(SKINICON_OTHER_TYPING);
- ImageList_AddIcon(hImageList, icon); Skin_ReleaseIcon(icon);
- icon = LoadSkinnedIcon(SKINICON_OTHER_DELETE);
- ImageList_AddIcon(hImageList, icon); Skin_ReleaseIcon(icon);
- ListView_SetImageList(hwndList, hImageList, LVSIL_SMALL);
-
- LVCOLUMN lvc = { 0 };
- lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
-
- lvc.iOrder = 0;
- lvc.pszText = L"IPv4";
- lvc.cx = 100;
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- lvc.iOrder = 1;
- lvc.pszText = L"IPv6";
- lvc.cx = 100;
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- lvc.iOrder = 2;
- lvc.pszText = TranslateT("Port");
- lvc.cx = 50;
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- lvc.iOrder = 3;
- lvc.pszText = TranslateT("Public key");
- lvc.cx = 130;
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- lvc.iOrder = 4;
- lvc.pszText = NULL;
- lvc.cx = 32 - GetSystemMetrics(SM_CXVSCROLL);
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- lvc.iOrder = 5;
- lvc.cx = 32 - GetSystemMetrics(SM_CXVSCROLL);
- ListView_InsertColumn(hwndList, lvc.iOrder, (LPARAM)&lvc);
-
- LVGROUP lvg = { sizeof(LVGROUP) };
- lvg.mask = LVGF_HEADER | LVGF_GROUPID;
-
- lvg.pszHeader = TranslateT("Common nodes");
- lvg.iGroupId = 0;
- ListView_InsertGroup(hwndList, lvg.iGroupId, &lvg);
-
- TCHAR userGroupName[MAX_PATH];
- mir_sntprintf(userGroupName, SIZEOF(userGroupName), _T("%s %s"), userName, TranslateT("nodes"));
- lvg.pszHeader = mir_tstrdup(userGroupName);
- lvg.iGroupId = 1;
- ListView_InsertGroup(hwndList, lvg.iGroupId, &lvg);
-
- ListView_EnableGroupView(hwndList, TRUE);
-
- ListView_SetExtendedListViewStyle(hwndList, LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
- ListView_DeleteAllItems(hwndList);
+ CToxNodeEditor nodeEditor(lvi.iItem, &m_nodes);
+ if (nodeEditor.DoModal())
+ SendMessage(GetParent(m_hwnd), PSM_CHANGED, 0, 0);
}
- break;
-
- case WM_NOTIFY:
- switch (((NMHDR*)lParam)->code)
- {
- case NM_CLICK:
- {
- lvi.iItem = ((NMITEMACTIVATE*)lParam)->iItem;
- lvi.mask = LVIF_GROUPID;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- lvi.iSubItem = ((NMITEMACTIVATE*)lParam)->iSubItem;
- if (lvi.iGroupId && lvi.iSubItem == 4)
- {
- ItemInfo itemInfo = { lvi.iItem, hwndList };
- if (DialogBoxParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_ADDNODE),
- GetParent(hwndList), EditNodeDlgProc,
- (LPARAM)&itemInfo) == IDOK)
- {
- SendMessage(GetParent(GetParent(hwndList)), PSM_CHANGED, 0, 0);
- }
- }
- else if (lvi.iGroupId && lvi.iSubItem == 5)
- {
- if (MessageBox(hwndList, TranslateT("Are you sure?"), TranslateT("Node deleting"), MB_YESNO | MB_ICONWARNING) == IDYES)
- {
- ListView_DeleteItem(hwndList, lvi.iItem);
- SendMessage(GetParent(GetParent(hwndList)), PSM_CHANGED, 0, 0);
- }
- }
- }
- break;
-
- case NM_DBLCLK:
- {
- lvi.iItem = ((NMITEMACTIVATE*)lParam)->iItem;
- lvi.mask = LVIF_GROUPID;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- if (lvi.iGroupId || (lvi.iGroupId == 0 && lvi.iItem == -1))
- {
- ItemInfo itemInfo = { lvi.iItem, hwndList };
- if (DialogBoxParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_ADDNODE),
- GetParent(hwndList), EditNodeDlgProc,
- (LPARAM)&itemInfo) == IDOK)
- {
- SendMessage(GetParent(GetParent(hwndList)), PSM_CHANGED, 0, 0);
- }
- }
- }
- break;
+}
- case LVN_KEYDOWN:
+void CToxOptionsNodeList::OnNodeListClick(CCtrlListView::TEventInfo *evt)
+{
+ LVITEM lvi = { 0 };
+ lvi.iItem = evt->nmlvia->iItem;
+ lvi.mask = LVIF_GROUPID;
+ m_nodes.GetItem(&lvi);
+ lvi.iSubItem = evt->nmlvia->iSubItem;
+ if (lvi.iGroupId && lvi.iSubItem == 4)
+ {
+ CToxNodeEditor nodeEditor(lvi.iItem, &m_nodes);
+ if (nodeEditor.DoModal())
+ SendMessage(GetParent(GetParent(m_hwnd)), PSM_CHANGED, 0, 0);
+ }
+ else if (lvi.iGroupId && lvi.iSubItem == 5)
+ {
+ if (MessageBox(m_hwnd, TranslateT("Are you sure?"), TranslateT("Node deleting"), MB_YESNO | MB_ICONWARNING) == IDYES)
{
- lvi.iItem = ListView_GetSelectionMark(hwndList);
- lvi.mask = LVIF_GROUPID;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- if (lvi.iGroupId && lvi.iItem != -1 && ((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
- {
- if (MessageBox(
- GetParent(hwndList),
- TranslateT("Are you sure?"),
- TranslateT("Node deleting"),
- MB_YESNO | MB_ICONWARNING) == IDYES)
- {
- ListView_DeleteItem(hwndList, lvi.iItem);
- SendMessage(GetParent(GetParent(hwndList)), PSM_CHANGED, 0, 0);
- }
- }
- }
- break;
+ m_nodes.DeleteItem(lvi.iItem);
+ SendMessage(GetParent(GetParent(m_hwnd)), PSM_CHANGED, 0, 0);
}
- break;
-
- default:
- return CallWindowProc((WNDPROC)GetClassLongPtr(hwndList, GCLP_WNDPROC), hwndList, uMsg, wParam, lParam);
}
- return FALSE;
}
-INT_PTR CALLBACK CToxProto::NodesOptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+void CToxOptionsNodeList::OnNodeListKeyDown(CCtrlListView::TEventInfo *evt)
{
- CToxProto *proto = (CToxProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- HWND hwndList = GetDlgItem(hwndDlg, IDC_NODESLIST);
+ LVITEM lvi = { 0 };
+ lvi.iItem = m_nodes.GetSelectionMark();
+ lvi.mask = LVIF_GROUPID;
+ m_nodes.GetItem(&lvi);
- switch (uMsg)
+ if (lvi.iGroupId && lvi.iItem != -1 && (evt->nmlvkey)->wVKey == VK_DELETE)
{
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
+ if (MessageBox(
+ GetParent(m_hwnd),
+ TranslateT("Are you sure?"),
+ TranslateT("Node deleting"),
+ MB_YESNO | MB_ICONWARNING) == IDYES)
{
- proto = (CToxProto*)lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
-
- CallWindowProc((WNDPROC)NodeListSubProc, hwndList, WM_INITDIALOG, wParam, (LPARAM)proto->m_tszUserName);
+ m_nodes.DeleteItem(lvi.iItem);
+ SendMessage(GetParent(GetParent(m_hwnd)), PSM_CHANGED, 0, 0);
+ }
+ }
+}
- int iItem = 0;
+void CToxOptionsNodeList::OnApply()
+{
+ char setting[MAX_PATH];
- if (IsFileExists((TCHAR*)VARST(_T(TOX_INI_PATH))))
- {
- char fileName[MAX_PATH];
- mir_strcpy(fileName, VARS(TOX_INI_PATH));
-
- char *section, sections[MAX_PATH], value[MAX_PATH];
- GetPrivateProfileSectionNamesA(sections, SIZEOF(sections), fileName);
- section = sections;
- while (*section != NULL)
- {
- if (strstr(section, TOX_SETTINGS_NODE_PREFIX) == section)
- {
- GetPrivateProfileStringA(section, "IPv4", NULL, value, SIZEOF(value), fileName);
- AddItemToListView(hwndList, LVIF_GROUPID | LVIF_TEXT | LVIF_IMAGE, 0, iItem, 0, value);
-
- GetPrivateProfileStringA(section, "IPv6", NULL, value, SIZEOF(value), fileName);
- SetSubItemToListView(hwndList, LVIF_TEXT, 0, iItem, 1, value);
-
- GetPrivateProfileStringA(section, "Port", NULL, value, SIZEOF(value), fileName);
- SetSubItemToListView(hwndList, LVIF_TEXT, 0, iItem, 2, value);
-
- GetPrivateProfileStringA(section, "PubKey", NULL, value, SIZEOF(value), fileName);
- SetSubItemToListView(hwndList, LVIF_TEXT, 0, iItem, 3, value);
-
- iItem++;
- }
- section += strlen(section) + 1;
- }
- }
+ LVITEM lvi = { 0 };
+ lvi.cchTextMax = MAX_PATH;
+ lvi.pszText = (TCHAR*)mir_alloc(MAX_PATH * sizeof(TCHAR));
- char module[MAX_PATH], setting[MAX_PATH];
- mir_snprintf(module, SIZEOF(module), "%s_Nodes", proto->m_szModuleName);
- int nodeCount = db_get_w(NULL, module, TOX_SETTINGS_NODE_COUNT, 0);
- for (int i = 0; i < nodeCount; i++, iItem++)
- {
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, i);
- ptrA value(db_get_sa(NULL, module, setting));
- AddItemToListView(hwndList, LVIF_GROUPID | LVIF_TEXT | LVIF_IMAGE, 1, iItem, 0, value);
-
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, i);
- value = db_get_sa(NULL, module, setting);
- SetSubItemToListView(hwndList, LVIF_TEXT, 1, iItem, 1, value);
-
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, i);
- int port = db_get_w(NULL, module, setting, 0);
- if (port > 0)
- {
- char portNum[10];
- itoa(port, portNum, 10);
- SetSubItemToListView(hwndList, LVIF_TEXT, 1, iItem, 2, portNum);
- }
-
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, i);
- value = db_get_sa(NULL, module, setting);
- SetSubItemToListView(hwndList, LVIF_TEXT, 1, iItem, 3, value);
-
- SetSubItemToListView(hwndList, LVIF_IMAGE, 1, iItem, 4, value, 0);
- SetSubItemToListView(hwndList, LVIF_IMAGE, 1, iItem, 5, value, 1);
- }
- }
- return TRUE;
+ char module[MAX_PATH];
+ mir_snprintf(module, SIZEOF(module), "%s_Nodes", m_proto->m_szModuleName);
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case IDC_ADDNODE:
+ int iItem = 0;
+ int itemCount = m_nodes.GetItemCount();
+ for (int i = 0; i < itemCount; i++)
+ {
+ lvi.iItem = i;
+ lvi.mask = LVIF_GROUPID;
+ m_nodes.GetItem(&lvi);
+ if (lvi.iGroupId == 0)
{
- ItemInfo itemInfo = { -1, hwndList };
- if (DialogBoxParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_ADDNODE),
- GetParent(hwndList), EditNodeDlgProc,
- (LPARAM)&itemInfo) == IDOK)
- {
- SendMessage(GetParent(GetParent(hwndList)), PSM_CHANGED, 0, 0);
- }
- }
+ continue;
}
- break;
- case WM_NOTIFY:
- switch (((LPNMHDR)lParam)->code)
- {
- case NM_CLICK:
- case NM_DBLCLK:
- case LVN_KEYDOWN:
- if (((NMHDR*)lParam)->hwndFrom == hwndList)
- {
- return CallWindowProc((WNDPROC)NodeListSubProc, hwndList, uMsg, wParam, lParam);
- }
- break;
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 0;
+ m_nodes.GetItem(&lvi);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, iItem);
+ db_set_s(NULL, module, setting, _T2A(lvi.pszText));
- case PSN_APPLY:
- {
- char setting[MAX_PATH];
+ lvi.iSubItem = 1;
+ m_nodes.GetItem(&lvi);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, iItem);
+ db_set_s(NULL, module, setting, _T2A(lvi.pszText));
- LVITEMA lvi = { 0 };
- lvi.cchTextMax = MAX_PATH;
- lvi.pszText = (char*)mir_alloc(MAX_PATH);
+ lvi.iSubItem = 2;
+ m_nodes.GetItem(&lvi);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, iItem);
+ db_set_w(NULL, module, setting, _ttoi(lvi.pszText));
- char module[MAX_PATH];
- mir_snprintf(module, SIZEOF(module), "%s_Nodes", proto->m_szModuleName);
+ lvi.iSubItem = 3;
+ m_nodes.GetItem(&lvi);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, iItem);
+ db_set_s(NULL, module, setting, _T2A(lvi.pszText));
- int iItem = 0;
- int itemCount = ListView_GetItemCount(hwndList);
- for (int i = 0; i < itemCount; i++)
- {
- lvi.iItem = i;
- lvi.mask = LVIF_GROUPID;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- if (lvi.iGroupId == 0)
- {
- continue;
- }
-
- lvi.mask = LVIF_TEXT;
- lvi.iSubItem = 0;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, iItem);
- db_set_s(NULL, module, setting, lvi.pszText);
-
- lvi.iSubItem = 1;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, iItem);
- db_set_s(NULL, module, setting, lvi.pszText);
-
- lvi.iSubItem = 2;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, iItem);
- db_set_w(NULL, module, setting, atoi(lvi.pszText));
-
- lvi.iSubItem = 3;
- SendMessage(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvi);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, iItem);
- db_set_s(NULL, module, setting, lvi.pszText);
-
- iItem++;
- }
- itemCount = iItem;
- int nodeCount = db_get_b(NULL, module, TOX_SETTINGS_NODE_COUNT, 0);
- for (iItem = itemCount; iItem < nodeCount; iItem++)
- {
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, iItem);
- db_unset(NULL, module, setting);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, iItem);
- db_unset(NULL, module, setting);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, iItem);
- db_unset(NULL, module, setting);
- mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, iItem);
- db_unset(NULL, module, setting);
- }
- db_set_b(NULL, module, TOX_SETTINGS_NODE_COUNT, itemCount);
- }
- return TRUE;
- }
+ iItem++;
+ }
+ itemCount = iItem;
+ int nodeCount = db_get_b(NULL, module, TOX_SETTINGS_NODE_COUNT, 0);
+ for (iItem = itemCount; iItem < nodeCount; iItem++)
+ {
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV4, iItem);
+ db_unset(NULL, module, setting);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_IPV6, iItem);
+ db_unset(NULL, module, setting);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PORT, iItem);
+ db_unset(NULL, module, setting);
+ mir_snprintf(setting, SIZEOF(setting), TOX_SETTINGS_NODE_PKEY, iItem);
+ db_unset(NULL, module, setting);
}
- return FALSE;
+ db_set_b(NULL, module, TOX_SETTINGS_NODE_COUNT, itemCount);
}
+/////////////////////////////////////////////////////////////////////////////////
+
int CToxProto::OnOptionsInit(WPARAM wParam, LPARAM)
{
char *title = mir_t2a(m_tszUserName);
@@ -667,23 +478,23 @@ int CToxProto::OnOptionsInit(WPARAM wParam, LPARAM)
OPTIONSDIALOGPAGE odp = { sizeof(odp) };
odp.hInstance = g_hInstance;
odp.pszTitle = title;
- odp.dwInitParam = (LPARAM)this;
odp.flags = ODPF_BOLDGROUPS;
odp.pszGroup = LPGEN("Network");
odp.pszTab = LPGEN("Account");
odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_MAIN);
- odp.pfnDlgProc = MainOptionsProc;
+ odp.pfnDlgProc = CDlgBase::DynamicDlgProc;
+ odp.dwInitParam = (LPARAM)&ToxMainOptions;
+ ToxMainOptions.create = CToxOptionsMain::CreateOptionsPage;
+ ToxMainOptions.param = this;
Options_AddPage(wParam, &odp);
- /*odp.pszTab = LPGEN("Audio/Video");
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_AV);
- odp.pfnDlgProc = AVOptionsProc;
- Options_AddPage(wParam, &odp);*/
-
odp.pszTab = LPGEN("Nodes");
odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_NODES);
- odp.pfnDlgProc = NodesOptionsProc;
+ odp.pfnDlgProc = CDlgBase::DynamicDlgProc;
+ odp.dwInitParam = (LPARAM)&ToxNodeListOptions;
+ ToxNodeListOptions.create = CToxOptionsNodeList::CreateOptionsPage;
+ ToxNodeListOptions.param = this;
Options_AddPage(wParam, &odp);
mir_free(title);
diff --git a/protocols/Tox/src/tox_options.h b/protocols/Tox/src/tox_options.h
index 19b61d6710..0b0e111513 100644
--- a/protocols/Tox/src/tox_options.h
+++ b/protocols/Tox/src/tox_options.h
@@ -1,10 +1,112 @@
#ifndef _TOX_OPTIONS_H_
#define _TOX_OPTIONS_H_
-struct ItemInfo
+class CToxOptionsMain : public CToxDlgBase
{
- int iItem;
- HWND hwndList;
+private:
+ typedef CToxDlgBase CSuper;
+
+ CCtrlEdit m_toxAddress;
+ CCtrlButton m_toxAddressCopy;
+ CCtrlButton m_profileCreate;
+ CCtrlButton m_profileImport;
+ CCtrlButton m_profileExport;
+
+ CCtrlEdit m_nickname;
+ CCtrlEdit m_password;
+ CCtrlEdit m_group;
+
+ CCtrlCheck m_enableUdp;
+ CCtrlCheck m_enableIPv6;
+
+protected:
+ void OnInitDialog();
+
+ void ToxAddressCopy_OnClick(CCtrlButton*);
+ void ProfileCreate_OnClick(CCtrlButton*);
+ void ProfileImport_OnClick(CCtrlButton*);
+ void ProfileExport_OnClick(CCtrlButton*);
+
+ void OnApply();
+
+public:
+ CToxOptionsMain(CToxProto *proto, int idDialog, HWND hwndParent = NULL);
+
+ static CDlgBase *CreateAccountManagerPage(void *param, HWND owner)
+ {
+ CToxOptionsMain *page = new CToxOptionsMain((CToxProto*)param, IDD_ACCOUNT_MANAGER, owner);
+ page->Show();
+ return page;
+ }
+
+ static CDlgBase *CreateOptionsPage(void *param) { return new CToxOptionsMain((CToxProto*)param, IDD_OPTIONS_MAIN); }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class CToxNodeEditor : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ int m_iItem;
+ CCtrlListView *m_list;
+
+ CCtrlEdit m_ipv4;
+ CCtrlEdit m_ipv6;
+ CCtrlEdit m_port;
+ CCtrlEdit m_pkey;
+
+ CCtrlButton m_ok;
+
+protected:
+ void OnInitDialog();
+ void OnOk(CCtrlBase*);
+ void OnClose();
+
+public:
+ CToxNodeEditor(int iItem, CCtrlListView *m_list);
+};
+
+/****************************************/
+
+class CCtrlNodeList : public CCtrlListView
+{
+private:
+ typedef CCtrlListView CSuper;
+
+protected:
+ BOOL OnNotify(int idCtrl, NMHDR *pnmh);
+
+public:
+ CCtrlNodeList(CDlgBase* dlg, int ctrlId);
+
+ CCallback<TEventInfo> OnClick;
+};
+
+/****************************************/
+
+class CToxOptionsNodeList : public CToxDlgBase
+{
+private:
+ typedef CToxDlgBase CSuper;
+
+ CCtrlNodeList m_nodes;
+ CCtrlButton m_addNode;
+
+protected:
+ CToxOptionsNodeList(CToxProto *proto);
+
+ void OnInitDialog();
+ void OnApply();
+
+ void OnAddNode(CCtrlBase*);
+ void OnNodeListDoubleClick(CCtrlBase*);
+ void OnNodeListClick(CCtrlListView::TEventInfo *evt);
+ void OnNodeListKeyDown(CCtrlListView::TEventInfo *evt);
+
+public:
+ static CDlgBase *CreateOptionsPage(void *param) { return new CToxOptionsNodeList((CToxProto*)param); }
};
#endif //_TOX_OPTIONS_H_ \ No newline at end of file
diff --git a/protocols/Tox/src/tox_profile.cpp b/protocols/Tox/src/tox_profile.cpp
index 29c84fb040..8ca4bf84a4 100644
--- a/protocols/Tox/src/tox_profile.cpp
+++ b/protocols/Tox/src/tox_profile.cpp
@@ -16,114 +16,101 @@ std::tstring CToxProto::GetToxProfilePath(const TCHAR *accountName)
return profilePath;
}
-bool CToxProto::LoadToxProfile()
+bool CToxProto::LoadToxProfile(Tox_Options *options)
{
- std::tstring profilePath = GetToxProfilePath();
- if (!IsFileExists(profilePath))
- {
- return true;
- }
+ debugLogA(__FUNCTION__": loading tox profile");
- FILE *profile = _tfopen(profilePath.c_str(), _T("rb"));
- if (profile == NULL)
+ size_t size = 0;
+ uint8_t *data = NULL;
+ std::tstring profilePath = GetToxProfilePath();
+ if (IsFileExists(profilePath))
{
- debugLogA("CToxProto::LoadToxData: could not open tox profile");
- return false;
- }
+ FILE *profile = _tfopen(profilePath.c_str(), _T("rb"));
+ if (profile == NULL)
+ {
+ debugLogA(__FUNCTION__": failed to open tox profile");
+ return false;
+ }
- fseek(profile, 0, SEEK_END);
- size_t size = ftell(profile);
- rewind(profile);
- if (size == 0)
- {
- fclose(profile);
- debugLogA("CToxProto::LoadToxData: tox profile is empty");
- return true;
- }
+ fseek(profile, 0, SEEK_END);
+ size = ftell(profile);
+ rewind(profile);
+ if (size == 0)
+ {
+ fclose(profile);
+ debugLogA(__FUNCTION__": tox profile is empty");
+ return true;
+ }
- uint8_t *data = (uint8_t*)mir_calloc(size);
- if (fread((char*)data, sizeof(char), size, profile) != size)
- {
+ data = (uint8_t*)mir_calloc(size);
+ if (fread((char*)data, sizeof(char), size, profile) != size)
+ {
+ fclose(profile);
+ debugLogA(__FUNCTION__": failed to read tox profile");
+ mir_free(data);
+ return false;
+ }
fclose(profile);
- debugLogA("CToxProto::LoadToxData: could not read tox profile");
- mir_free(data);
- return false;
}
- fclose(profile);
- if (tox_is_data_encrypted(data))
+ if (data != NULL && tox_is_data_encrypted(data))
{
- if (password == NULL || strlen(password) == 0)
+ password = mir_utf8encodeW(ptrT(getTStringA("Password")));
+ if (password == NULL || mir_strlen(password) == 0)
{
- if (!DialogBoxParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_PASSWORD),
- NULL,
- ToxProfilePasswordProc,
- (LPARAM)this))
+ CToxPasswordEditor passwordEditor(this);
+ if (!passwordEditor.DoModal())
{
+ mir_free(data);
return false;
}
}
-
- if (tox_encrypted_load(tox, data, size, (uint8_t*)password, mir_strlen(password)) == TOX_ERROR)
+ TOX_ERR_DECRYPTION coreDecryptError;
+ if (!tox_pass_decrypt(data, size, (uint8_t*)password, mir_strlen(password), data, &coreDecryptError))
{
- debugLogA("CToxProto::LoadToxData: could not decrypt tox profile");
+ debugLogA(__FUNCTION__": failed to load tox profile (%d)", coreDecryptError);
mir_free(data);
return false;
}
+ size -= TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
}
- else
+
+ TOX_ERR_NEW initError;
+ tox = tox_new(options, data, size, &initError);
+ if (initError != TOX_ERR_NEW_OK)
{
- // it return -1 but load, wtf?
- if (tox_load(tox, data, size) > 0)
- {
- debugLogA("CToxProto::LoadToxData: could not load tox profile");
- mir_free(data);
- return false;
- }
+ debugLogA(__FUNCTION__": failed to load tox profile (%d)", initError);
+ mir_free(data);
+ return false;
}
- mir_free(data);
+ debugLogA(__FUNCTION__": tox profile load successfully");
return true;
}
void CToxProto::SaveToxProfile()
{
- size_t size = 0;
- uint8_t *data = NULL;
+ size_t size = tox_get_savedata_size(tox);
+ uint8_t *data = (uint8_t*)mir_calloc(size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
+ tox_get_savedata(tox, data);
+ if (password && strlen(password))
{
- mir_cslock lock(toxLock);
-
- if (password && strlen(password))
+ TOX_ERR_ENCRYPTION coreEncryptError;
+ if (!tox_pass_encrypt(data, size, (uint8_t*)password, strlen(password), data, &coreEncryptError))
{
- size = tox_encrypted_size(tox);
- data = (uint8_t*)mir_calloc(size);
- if (tox_encrypted_save(tox, data, (uint8_t*)password, strlen(password)) == TOX_ERROR)
- {
- debugLogA("CToxProto::LoadToxData: could not encrypt tox profile");
- mir_free(data);
- return;
- }
- }
- else
- {
- size = tox_size(tox);
- data = (uint8_t*)mir_calloc(size);
- tox_save(tox, data);
+ debugLogA(__FUNCTION__": failed to encrypt tox profile");
+ mir_free(data);
+ return;
}
+ size += TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
}
- /*size_t size = tox_size(tox);
- uint8_t *data = (uint8_t*)mir_calloc(size);
- tox_save(tox, data);*/
-
std::tstring profilePath = GetToxProfilePath();
FILE *profile = _tfopen(profilePath.c_str(), _T("wb"));
if (profile == NULL)
{
- debugLogA("CToxProto::LoadToxData: could not open tox profile");
+ debugLogA(__FUNCTION__": failed to open tox profile");
return;
}
@@ -131,7 +118,7 @@ void CToxProto::SaveToxProfile()
if (size != written)
{
fclose(profile);
- debugLogA("CToxProto::LoadToxData: could not write tox profile");
+ debugLogA(__FUNCTION__": failed to write tox profile");
}
fclose(profile);
@@ -145,56 +132,29 @@ INT_PTR CToxProto::OnCopyToxID(WPARAM, LPARAM)
if (OpenClipboard(NULL))
{
EmptyClipboard();
- HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, length);
- memcpy(GlobalLock(hMem), address, length);
- GlobalUnlock(hMem);
- SetClipboardData(CF_TEXT, hMem);
+ HGLOBAL hMemory = GlobalAlloc(GMEM_FIXED, length);
+ memcpy(GlobalLock(hMemory), address, length);
+ GlobalUnlock(hMemory);
+ SetClipboardData(CF_TEXT, hMemory);
CloseClipboard();
}
return 0;
}
-INT_PTR CToxProto::ToxProfilePasswordProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+CToxPasswordEditor::CToxPasswordEditor(CToxProto *proto) :
+ CToxDlgBase(proto, IDD_PASSWORD, NULL, false), ok(this, IDOK),
+ password(this, IDC_PASSWORD), savePermanently(this, IDC_SAVEPERMANENTLY)
{
- CToxProto *proto = (CToxProto*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- switch (uMsg)
- {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwnd);
- {
- proto = (CToxProto*)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
- }
- return TRUE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case IDOK:
- {
- TCHAR password[MAX_PATH];
- GetDlgItemText(hwnd, IDC_PASSWORD, password, SIZEOF(password));
- if (IsDlgButtonChecked(hwnd, IDC_SAVEPERMANENTLY))
- {
- proto->setTString("Password", password);
- }
- if (proto->password != NULL)
- {
- mir_free(proto->password);
- }
- proto->password = mir_utf8encodeW(password);
-
- EndDialog(hwnd, 1);
- }
- break;
+ ok.OnClick = Callback(this, &CToxPasswordEditor::OnOk);
+}
- case IDCANCEL:
- EndDialog(hwnd, 0);
- break;
- }
- break;
- }
+void CToxPasswordEditor::OnOk(CCtrlButton*)
+{
+ if (savePermanently.Enabled())
+ m_proto->setTString("Password", password.GetText());
+ if (m_proto->password != NULL)
+ mir_free(m_proto->password);
+ m_proto->password = mir_utf8encodeW(password.GetText());
- return FALSE;
-} \ No newline at end of file
+ EndDialog(m_hwnd, 1);
+}
diff --git a/protocols/Tox/src/tox_proto.cpp b/protocols/Tox/src/tox_proto.cpp
index 045cf3117e..98a048d6d7 100644
--- a/protocols/Tox/src/tox_proto.cpp
+++ b/protocols/Tox/src/tox_proto.cpp
@@ -35,7 +35,7 @@ CToxProto::~CToxProto()
UninitNetlib();
}
-DWORD_PTR __cdecl CToxProto::GetCaps(int type, MCONTACT)
+DWORD_PTR CToxProto::GetCaps(int type, MCONTACT)
{
switch (type)
{
@@ -59,26 +59,26 @@ DWORD_PTR __cdecl CToxProto::GetCaps(int type, MCONTACT)
return 0;
}
-MCONTACT __cdecl CToxProto::AddToList(int flags, PROTOSEARCHRESULT *psr)
+MCONTACT CToxProto::AddToList(int flags, PROTOSEARCHRESULT *psr)
{
- std::string address(ptrA(mir_t2a(psr->id)));
+ ptrA address(mir_t2a(psr->id));
ptrA myAddress(getStringA(NULL, TOX_SETTINGS_ID));
- if (strnicmp(address.c_str(), myAddress, TOX_PUBLIC_KEY_SIZE) == 0)
+ if (strnicmp(address, myAddress, TOX_PUBLIC_KEY_SIZE) == 0)
{
ShowNotification(TranslateT("You cannot add yourself to your contact list"), 0);
return NULL;
}
- MCONTACT hContact = GetContact(address.c_str());
+ MCONTACT hContact = GetContact((char*)address);
if (hContact)
{
ShowNotification(TranslateT("Contact already in your contact list"), 0, hContact);
return NULL;
}
// set tox address as contact public key
- return AddContact(address.c_str(), _T(""), flags & PALF_TEMPORARY);
+ return AddContact(address, _T(""), flags & PALF_TEMPORARY);
}
-int __cdecl CToxProto::Authorize(MEVENT hDbEvent)
+int CToxProto::Authorize(MEVENT hDbEvent)
{
MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
if (hContact == INVALID_CONTACT_ID)
@@ -87,28 +87,48 @@ int __cdecl CToxProto::Authorize(MEVENT hDbEvent)
return OnGrantAuth(hContact, 0);
}
-int __cdecl CToxProto::AuthRecv(MCONTACT, PROTORECVEVENT* pre)
+int CToxProto::AuthRecv(MCONTACT, PROTORECVEVENT* pre)
{
return Proto_AuthRecv(m_szModuleName, pre);
}
-int __cdecl CToxProto::AuthRequest(MCONTACT hContact, const PROTOCHAR *szMessage)
+int CToxProto::AuthRequest(MCONTACT hContact, const PROTOCHAR *szMessage)
{
ptrA reason(mir_utf8encodeW(szMessage));
return OnRequestAuth(hContact, (LPARAM)reason);
}
-HWND __cdecl CToxProto::SearchAdvanced(HWND owner)
+HANDLE CToxProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *tszPath)
+{
+ return OnFileAllow(hContact, hTransfer, tszPath);
+}
+
+int CToxProto::FileCancel(MCONTACT hContact, HANDLE hTransfer)
+{
+ return OnFileCancel(hContact, hTransfer);
+}
+
+int CToxProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR*)
+{
+ return FileCancel(hContact, hTransfer);
+}
+
+int CToxProto::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR **szFilename)
+{
+ return OnFileResume(hTransfer, action, szFilename);
+}
+
+HWND CToxProto::SearchAdvanced(HWND owner)
{
return OnSearchAdvanced(owner);
}
-HWND __cdecl CToxProto::CreateExtendedSearchUI(HWND owner)
+HWND CToxProto::CreateExtendedSearchUI(HWND owner)
{
return OnCreateExtendedSearchUI(owner);
}
-int __cdecl CToxProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre)
+int CToxProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre)
{
return OnReceiveMessage(hContact, pre);
}
@@ -118,7 +138,12 @@ int CToxProto::SendMsg(MCONTACT hContact, int flags, const char *msg)
return OnSendMessage(hContact, flags, msg);
}
-int __cdecl CToxProto::SetStatus(int iNewStatus)
+HANDLE CToxProto::SendFile(MCONTACT hContact, const PROTOCHAR *msg, PROTOCHAR **ppszFiles)
+{
+ return OnSendFile(hContact, msg, ppszFiles);
+}
+
+int CToxProto::SetStatus(int iNewStatus)
{
if (iNewStatus == m_iDesiredStatus)
return 0;
@@ -178,10 +203,7 @@ int __cdecl CToxProto::SetStatus(int iNewStatus)
{
// set tox status
m_iStatus = iNewStatus;
- if (tox_set_user_status(tox, MirandaToToxStatus(iNewStatus)) == TOX_ERROR)
- {
- debugLogA("CToxProto::SetStatus: failed to change status from %i", m_iStatus, iNewStatus);
- }
+ tox_self_set_status(tox, MirandaToToxStatus(iNewStatus));
}
}
@@ -189,23 +211,29 @@ int __cdecl CToxProto::SetStatus(int iNewStatus)
return 0;
}
-HANDLE __cdecl CToxProto::GetAwayMsg(MCONTACT) { return 0; }
+HANDLE CToxProto::GetAwayMsg(MCONTACT) { return 0; }
-int __cdecl CToxProto::SetAwayMsg(int, const PROTOCHAR *msg)
+int CToxProto::SetAwayMsg(int, const PROTOCHAR *msg)
{
if (IsOnline())
{
ptrA statusMessage(msg == NULL ? mir_strdup("") : mir_utf8encodeT(msg));
- if (tox_set_status_message(tox, (uint8_t*)(char*)statusMessage, min(TOX_MAX_STATUSMESSAGE_LENGTH, mir_strlen(statusMessage))) == TOX_ERROR)
+ TOX_ERR_SET_INFO error;
+ if (tox_self_set_status_message(tox, (uint8_t*)(char*)statusMessage, min(TOX_MAX_STATUS_MESSAGE_LENGTH, mir_strlen(statusMessage)), &error))
{
- debugLogA("CToxProto::SetAwayMsg: failed to set status status message %s", msg);
+ debugLogA("CToxProto::SetAwayMsg: failed to set status status message %s (%d)", msg, error);
}
}
return 0;
}
-int __cdecl CToxProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam)
+int CToxProto::UserIsTyping(MCONTACT hContact, int type)
+{
+ return OnUserIsTyping(hContact, type);
+}
+
+int CToxProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam)
{
switch (iEventType)
{
diff --git a/protocols/Tox/src/tox_proto.h b/protocols/Tox/src/tox_proto.h
index 39b67e761f..a329252fda 100644
--- a/protocols/Tox/src/tox_proto.h
+++ b/protocols/Tox/src/tox_proto.h
@@ -3,6 +3,10 @@
struct CToxProto : public PROTO<CToxProto>
{
+ friend CToxPasswordEditor;
+ friend CToxOptionsMain;
+ friend CToxOptionsNodeList;
+
public:
//////////////////////////////////////////////////////////////////////////////////////
@@ -74,17 +78,12 @@ private:
std::tstring GetToxProfilePath();
static std::tstring CToxProto::GetToxProfilePath(const TCHAR *accountName);
- bool LoadToxProfile();
+ bool LoadToxProfile(Tox_Options *options);
void SaveToxProfile();
INT_PTR __cdecl OnCopyToxID(WPARAM, LPARAM);
- static INT_PTR CALLBACK ToxProfileImportProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- static INT_PTR CALLBACK ToxProfilePasswordProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
// tox core
- bool IsToxCoreInited();
-
bool InitToxCore();
void UninitToxCore();
@@ -132,8 +131,8 @@ private:
INT_PTR __cdecl CToxProto::SetMyNickname(WPARAM wParam, LPARAM lParam);
// options
- static INT_PTR CALLBACK MainOptionsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- static INT_PTR CALLBACK NodesOptionsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+ CToxDlgBase::CreateParam ToxMainOptions;
+ CToxDlgBase::CreateParam ToxNodeListOptions;
int __cdecl OnOptionsInit(WPARAM wParam, LPARAM lParam);
@@ -156,18 +155,18 @@ private:
MCONTACT GetContactFromAuthEvent(MEVENT hEvent);
- int32_t GetToxFriendNumber(MCONTACT hContact);
+ uint32_t GetToxFriendNumber(MCONTACT hContact);
void __cdecl LoadFriendList(void*);
INT_PTR __cdecl OnRequestAuth(WPARAM hContact, LPARAM lParam);
INT_PTR __cdecl OnGrantAuth(WPARAM hContact, LPARAM);
- static void OnFriendRequest(Tox *tox, const uint8_t *pubKey, const uint8_t *message, const uint16_t messageSize, void *arg);
- static void OnFriendNameChange(Tox *tox, const int friendNumber, const uint8_t *name, const uint16_t nameSize, void *arg);
- static void OnStatusMessageChanged(Tox *tox, const int friendNumber, const uint8_t* message, const uint16_t messageSize, void *arg);
- static void OnUserStatusChanged(Tox *tox, int32_t friendNumber, uint8_t usertatus, void *arg);
- static void OnConnectionStatusChanged(Tox *tox, const int friendNumber, const uint8_t status, void *arg);
+ static void OnFriendRequest(Tox *tox, const uint8_t *pubKey, const uint8_t *message, size_t length, void *arg);
+ static void OnFriendNameChange(Tox *tox, uint32_t friendNumber, const uint8_t *name, size_t length, void *arg);
+ static void OnStatusMessageChanged(Tox *tox, uint32_t friendNumber, const uint8_t *message, size_t length, void *arg);
+ static void OnUserStatusChanged(Tox *tox, uint32_t friendNumber, TOX_USER_STATUS status, void *arg);
+ static void OnConnectionStatusChanged(Tox *tox, uint32_t friendNumber, TOX_CONNECTION status, void *arg);
// contacts search
void __cdecl SearchByNameAsync(void* arg);
@@ -208,20 +207,25 @@ private:
int OnReceiveMessage(MCONTACT hContact, PROTORECVEVENT *pre);
int OnSendMessage(MCONTACT hContact, int flags, const char *message);
- static void OnFriendMessage(Tox *tox, const int friendNumber, const uint8_t *message, const uint16_t messageSize, void *arg);
- static void OnFriendAction(Tox *tox, const int friendNumber, const uint8_t *action, const uint16_t actionSize, void *arg);
- static void OnTypingChanged(Tox *tox, const int friendNumber, uint8_t isTyping, void *arg);
- static void OnReadReceipt(Tox *tox, int32_t friendNumber, uint32_t receipt, void *arg);
+ static void OnFriendMessage(Tox *tox, uint32_t friendNumber, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, void *arg);
+ static void OnReadReceipt(Tox *tox, uint32_t friendNumber, uint32_t messageId, void *arg);
+
+ int OnUserIsTyping(MCONTACT hContact, int type);
+ static void OnTypingChanged(Tox *tox, uint32_t friendNumber, bool isTyping, void *arg);
int __cdecl OnPreCreateMessage(WPARAM wParam, LPARAM lParam);
// transfer
- void __cdecl SendFileAsync(void* arg);
+ HANDLE OnFileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *tszPath);
+ int OnFileResume(HANDLE hTransfer, int *action, const PROTOCHAR **szFilename);
+ int OnFileCancel(MCONTACT hContact, HANDLE hTransfer);
+ HANDLE OnSendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHAR **ppszFiles);
+
+ static void OnFileRequest(Tox *tox, uint32_t friendNumber, uint32_t fileNumber, TOX_FILE_CONTROL control, void *arg);
+ static void OnFriendFile(Tox *tox, uint32_t friendNumber, uint32_t fileNumber, uint32_t kind, uint64_t fileSize, const uint8_t *fileName, size_t filenameLength, void *arg);
+ static void OnFileReceiveData(Tox *tox, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, const uint8_t *data, size_t length, void *arg);
- //static void OnFileControlCallback(Tox *tox, int32_t number, uint8_t hFile, uint64_t fileSize, uint8_t *name, uint16_t nameSize, void *arg);
- static void OnFileRequest(Tox *tox, int32_t friendNumber, uint8_t receive_send, uint8_t fileNumber, uint8_t type, const uint8_t *data, uint16_t length, void *arg);
- static void OnFriendFile(Tox *tox, int32_t friendNumber, uint8_t fileNumber, uint64_t fileSize, const uint8_t *fileName, uint16_t length, void *arg);
- static void OnFileData(Tox *tox, int32_t friendNumber, uint8_t fileNumber, const uint8_t *data, uint16_t length, void *arg);
+ static void OnFileSendData(Tox *tox, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, size_t length, void *arg);
// avatars
std::tstring GetAvatarFilePath(MCONTACT hContact = NULL);
@@ -232,14 +236,13 @@ private:
INT_PTR __cdecl GetMyAvatar(WPARAM wParam, LPARAM lParam);
INT_PTR __cdecl SetMyAvatar(WPARAM wParam, LPARAM lParam);
- static void OnGotFriendAvatarInfo(Tox *tox, int32_t number, uint8_t format, uint8_t *hash, void *arg);
- static void OnGotFriendAvatarData(Tox *tox, int32_t number, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t length, void *arg);
+ void OnGotFriendAvatarInfo(FileTransferParam *transfer, const uint8_t *hash);
// folders
// utils
- TOX_USERSTATUS MirandaToToxStatus(int status);
- int ToxToMirandaStatus(TOX_USERSTATUS userstatus);
+ TOX_USER_STATUS MirandaToToxStatus(int status);
+ int ToxToMirandaStatus(TOX_USER_STATUS userstatus);
static void ShowNotification(const TCHAR *message, int flags = 0, MCONTACT hContact = NULL);
static void ShowNotification(const TCHAR *caption, const TCHAR *message, int flags = 0, MCONTACT hContact = NULL);
diff --git a/protocols/Tox/src/tox_search.cpp b/protocols/Tox/src/tox_search.cpp
index ea2a571a32..f5d5b001b3 100644
--- a/protocols/Tox/src/tox_search.cpp
+++ b/protocols/Tox/src/tox_search.cpp
@@ -29,10 +29,10 @@ ToxHexAddress ResolveToxAddressFromDnsRecordV3(void *dns, uint32_t requestId, co
if (std::regex_search(dnsRecord, match, regex))
{
std::string id = match[1];
- uint8_t data[TOX_FRIEND_ADDRESS_SIZE];
+ uint8_t data[TOX_ADDRESS_SIZE];
if (tox_decrypt_dns3_TXT(dns, data, (uint8_t*)id.c_str(), id.length(), requestId) != TOX_ERROR)
{
- return ToxHexAddress(data, TOX_FRIEND_ADDRESS_SIZE);
+ return ToxHexAddress(data, TOX_ADDRESS_SIZE);
}
}
return ToxHexAddress::Empty();
diff --git a/protocols/Tox/src/tox_services.cpp b/protocols/Tox/src/tox_services.cpp
index 136c7baa5b..cf3d3f142f 100644
--- a/protocols/Tox/src/tox_services.cpp
+++ b/protocols/Tox/src/tox_services.cpp
@@ -1,13 +1,16 @@
#include "common.h"
-INT_PTR __cdecl CToxProto::SetMyNickname(WPARAM wParam, LPARAM lParam)
+INT_PTR CToxProto::SetMyNickname(WPARAM wParam, LPARAM lParam)
{
ptrT nickname((wParam & SMNN_UNICODE) ? mir_u2t((TCHAR*)lParam) : mir_a2t((char*)lParam));
setTString("Nick", nickname);
- if (IsToxCoreInited())
+ TOX_ERR_SET_INFO error;
+ if (!tox_self_set_name(tox, (uint8_t*)(char*)ptrA(mir_utf8encodeT(nickname)), mir_tstrlen(nickname), &error))
{
- tox_set_name(tox, (uint8_t*)(char*)ptrA(mir_utf8encodeT(nickname)), mir_tstrlen(nickname));
+ debugLogA(__FUNCTION__": failed to set nick name");
+ return 1;
}
+
return 0;
}
diff --git a/protocols/Tox/src/tox_transfer.cpp b/protocols/Tox/src/tox_transfer.cpp
index 7b5a011786..c2cbad33cd 100644
--- a/protocols/Tox/src/tox_transfer.cpp
+++ b/protocols/Tox/src/tox_transfer.cpp
@@ -3,40 +3,56 @@
/* FILE RECEIVING */
// incoming file flow
-void CToxProto::OnFriendFile(Tox *, int32_t friendNumber, uint8_t fileNumber, uint64_t fileSize, const uint8_t *fileName, uint16_t, void *arg)
+void CToxProto::OnFriendFile(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint32_t kind, uint64_t fileSize, const uint8_t *fileName, size_t filenameLength, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
MCONTACT hContact = proto->GetContact(friendNumber);
if (hContact)
{
- TCHAR *name = mir_utf8decodeT((char*)fileName);
- if (name == NULL)
+ switch (kind)
{
- // uTox send file name in ansi
- name = mir_a2u((char*)fileName);
+ case TOX_FILE_KIND_AVATAR:
+ case TOX_FILE_KIND_DATA:
+ {
+ ptrA rawName((char*)mir_alloc(filenameLength + 1));
+ memcpy(rawName, fileName, filenameLength);
+ rawName[filenameLength] = 0;
+ TCHAR *name = mir_utf8decodeT(rawName);
+
+ FileTransferParam *transfer = new FileTransferParam(friendNumber, fileNumber, name, fileSize);
+ transfer->pfts.hContact = hContact;
+ transfer->pfts.flags |= PFTS_RECEIVING;
+ proto->transfers.Add(transfer);
+
+ if (kind == TOX_FILE_KIND_AVATAR)
+ {
+ proto->OnGotFriendAvatarInfo(transfer, fileName);
+ return;
+ }
+
+ PROTORECVFILET pre = { 0 };
+ pre.flags = PREF_TCHAR;
+ pre.fileCount = 1;
+ pre.timestamp = time(NULL);
+ pre.tszDescription = _T("");
+ pre.ptszFiles = (TCHAR**)mir_alloc(sizeof(TCHAR*) * 2);
+ pre.ptszFiles[0] = name;
+ pre.ptszFiles[1] = NULL;
+ pre.lParam = (LPARAM)transfer;
+ ProtoChainRecvFile(hContact, &pre);
}
+ break;
- FileTransferParam *transfer = new FileTransferParam(friendNumber, fileNumber, name, fileSize);
- transfer->pfts.hContact = hContact;
- transfer->pfts.flags |= PFTS_RECEIVING;
- proto->transfers.Add(transfer);
-
- PROTORECVFILET pre = { 0 };
- pre.flags = PREF_TCHAR;
- pre.fileCount = 1;
- pre.timestamp = time(NULL);
- pre.tszDescription = _T("");
- pre.ptszFiles = (TCHAR**)mir_alloc(sizeof(TCHAR*)*2);
- pre.ptszFiles[0] = name;
- pre.ptszFiles[1] = NULL;
- pre.lParam = (LPARAM)transfer;
- ProtoChainRecvFile(hContact, &pre);
+ default:
+ proto->debugLogA(__FUNCTION__": unknown file kind (%d)", kind);
+ return;
+ }
}
}
// file request is allowed
-HANDLE __cdecl CToxProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *tszPath)
+HANDLE CToxProto::OnFileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *tszPath)
{
FileTransferParam *transfer = (FileTransferParam*)hTransfer;
transfer->pfts.tszWorkingDir = mir_tstrdup(tszPath);
@@ -52,17 +68,18 @@ HANDLE __cdecl CToxProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const P
{
debugLogA("CToxProto::FileAllow: failed to open file (%d)", transfer->fileNumber);
transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
transfers.Remove(transfer);
return NULL;
}
debugLogA("CToxProto::FileAllow: start receiving file (%d)", transfer->fileNumber);
transfer->status = STARTED;
- if (tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_ACCEPT, NULL, 0) == TOX_ERROR)
+ TOX_ERR_FILE_CONTROL error;
+ if (!tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error))
{
- debugLogA("CToxProto::FileAllow: failed to start the transfer of file (%d)", transfer->fileNumber);
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ debugLogA("CToxProto::FileAllow: failed to start the transfer (%d)", error);
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
}
}
@@ -70,7 +87,7 @@ HANDLE __cdecl CToxProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const P
}
// if file is exists
-int __cdecl CToxProto::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR **szFilename)
+int CToxProto::OnFileResume(HANDLE hTransfer, int *action, const PROTOCHAR **szFilename)
{
bool result = false;
FileTransferParam *transfer = (FileTransferParam*)hTransfer;
@@ -92,20 +109,21 @@ int __cdecl CToxProto::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR
break;
}
+ TOX_ERR_FILE_CONTROL error;
if (result)
{
debugLogA("CToxProto::FileResume: start receiving file (%d)", transfer->fileNumber);
transfer->status = STARTED;
- if (tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_ACCEPT, NULL, 0) == TOX_ERROR)
+ if (!tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error))
{
- debugLogA("CToxProto::FileResume: failed to start the transfer of file (%d)", transfer->fileNumber);
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ debugLogA("CToxProto::FileResume: failed to start the transfer (%d)", error);
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, &error);
}
}
else
{
transfer->status = CANCELED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, &error);
transfers.Remove(transfer);
}
ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, result ? ACKRESULT_CONNECTED : ACKRESULT_DENIED, (HANDLE)transfer, 0);
@@ -114,50 +132,60 @@ int __cdecl CToxProto::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR
}
// getting the file data
-void CToxProto::OnFileData(Tox *tox, int32_t friendNumber, uint8_t fileNumber, const uint8_t *data, uint16_t size, void *arg)
+void CToxProto::OnFileReceiveData(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, const uint8_t *data, size_t length, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
+ FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber);
+ if (transfer == NULL)
{
- proto->debugLogA("CToxProto::OnFileData: cannot find contact by number (%d)", friendNumber);
- tox_file_send_control(tox, friendNumber, 1, fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
- FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber);
- if (transfer == NULL)
+ if (length == 0 || (length == 0 && position == UINT64_MAX))
{
- proto->debugLogA("CToxProto::OnFileData: cannot find transfer by number (%d)", fileNumber);
- transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ //receiving is finished
+ proto->debugLogA(__FUNCTION__": finised the transfer of file (%d)", fileNumber);
+ bool isFileFullyTransfered = transfer->pfts.currentFileProgress == transfer->pfts.currentFileSize;
+ transfer->status = isFileFullyTransfered ? FINISHED : FAILED;
+ if (!isFileFullyTransfered)
+ {
+ proto->debugLogA(__FUNCTION__": file (%d) is transferred not completely", fileNumber);
+ }
+ proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, isFileFullyTransfered ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)transfer, 0);
+ proto->transfers.Remove(transfer);
+ }
+
+ MCONTACT hContact = proto->GetContact(friendNumber);
+ if (hContact == NULL)
+ {
+ proto->debugLogA("CToxProto::OnFileData: cannot find contact by number (%d)", friendNumber);
+ tox_file_control(proto->tox, friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
- if (fwrite(data, sizeof(uint8_t), size, transfer->hFile) != size)
+ if (fwrite(data, sizeof(uint8_t), length, transfer->hFile) != length)
{
- proto->debugLogA("CToxProto::OnFileData: cannot write to file (%d)", fileNumber);
+ proto->debugLogA(__FUNCTION__": failed write to file (%d)", fileNumber);
proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(proto->tox, friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
- transfer->pfts.totalProgress = transfer->pfts.currentFileProgress += size;
+ transfer->pfts.totalProgress = transfer->pfts.currentFileProgress += length;
proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)transfer, (LPARAM)&transfer->pfts);
}
/* FILE SENDING */
// outcoming file flow
-HANDLE __cdecl CToxProto::SendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHAR **ppszFiles)
+HANDLE CToxProto::OnSendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHAR **ppszFiles)
{
int32_t friendNumber = GetToxFriendNumber(hContact);
- if (friendNumber == TOX_ERROR)
- {
+ if (friendNumber == UINT32_MAX)
return NULL;
- }
TCHAR *fileName = _tcsrchr(ppszFiles[0], '\\') + 1;
@@ -169,7 +197,7 @@ HANDLE __cdecl CToxProto::SendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHA
FILE *hFile = _tfopen(ppszFiles[0], _T("rb"));
if (hFile == NULL)
{
- debugLogA("CToxProto::SendFilesAsync: cannot open file");
+ debugLogA(__FUNCTION__": cannot open file");
return NULL;
}
@@ -178,10 +206,11 @@ HANDLE __cdecl CToxProto::SendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHA
rewind(hFile);
char *name = mir_utf8encodeW(fileName);
- int fileNumber = tox_new_file_sender(tox, friendNumber, fileSize, (uint8_t*)name, (uint16_t)mir_strlen(name));
- if (fileNumber == TOX_ERROR)
+ TOX_ERR_FILE_SEND sendError;
+ uint32_t fileNumber = tox_file_send(tox, friendNumber, TOX_FILE_KIND_DATA, fileSize, NULL, (uint8_t*)name, mir_strlen(name), &sendError);
+ if (sendError != TOX_ERR_FILE_SEND_OK)
{
- debugLogA("CToxProto::SendFilesAsync: cannot send file");
+ debugLogA(__FUNCTION__": failed to send file (%d)", sendError);
return NULL;
}
@@ -195,85 +224,76 @@ HANDLE __cdecl CToxProto::SendFile(MCONTACT hContact, const PROTOCHAR*, PROTOCHA
return (HANDLE)transfer;
}
-// start sending
-void CToxProto::SendFileAsync(void *arg)
+void CToxProto::OnFileSendData(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, size_t length, void *arg)
{
- FileTransferParam *transfer = (FileTransferParam*)arg;
- transfer->status = STARTED;
+ CToxProto *proto = (CToxProto*)arg;
- size_t dataSize = 0;
- uint64_t fileProgress = transfer->pfts.currentFileProgress;
- uint64_t fileSize = transfer->pfts.currentFileSize;
- int chunkSize = min(tox_file_data_size(tox, transfer->friendNumber), fileSize);
- uint8_t *data = (uint8_t*)mir_alloc(chunkSize);
+ FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber);
+ if (transfer == NULL)
+ {
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
+ return;
+ }
- while (transfer->status == STARTED && transfer->hFile != NULL && fileProgress < fileSize)
+ if (length == 0)
{
- if (dataSize == 0)
+ // file sending is finished
+ proto->debugLogA(__FUNCTION__": finised the transfer of file (%d)", fileNumber);
+ bool isFileFullyTransfered = transfer->pfts.currentFileProgress == transfer->pfts.currentFileSize;
+ transfer->status = isFileFullyTransfered ? FINISHED : FAILED;
+ if (!isFileFullyTransfered)
{
- dataSize = min(chunkSize, fileSize - fileProgress);
- size_t read = fread(data, sizeof(uint8_t), dataSize, transfer->hFile);
- if (read != dataSize)
- {
- debugLogA("CToxProto::SendFileAsync: failed to read from file (%d)", transfer->fileNumber);
- debugLogA("CToxProto::SendFileAsync: read %d of %d (%d)", read, dataSize, transfer->fileNumber);
- debugLogA("CToxProto::SendFileAsync: sent %llu of %llu of file (%d)", transfer->pfts.currentFileProgress, transfer->pfts.currentFileSize, transfer->fileNumber);
- ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
- transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- return;
- }
+ proto->debugLogA(__FUNCTION__": file (%d) is transferred not completely", fileNumber);
}
+ proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, isFileFullyTransfered ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)transfer, 0);
+ proto->transfers.Remove(transfer);
+ return;
+ }
- int sendResult = TOX_ERROR;
- {
- mir_cslock lock(toxLock);
- sendResult = tox_file_send_data(tox, transfer->friendNumber, transfer->fileNumber, data, (uint16_t)dataSize);
- }
- if (sendResult == TOX_ERROR)
- {
- Sleep(100);
- continue;
- }
+ uint64_t sentBytes = _ftelli64(transfer->hFile);
+ if (sentBytes != position)
+ _fseeki64(transfer->hFile, position, SEEK_SET);
- transfer->pfts.totalProgress = transfer->pfts.currentFileProgress = fileProgress += dataSize;
- ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)transfer, (LPARAM)&transfer->pfts);
- dataSize = 0;
+ uint8_t *data = (uint8_t*)mir_alloc(length);
+ if (fread(data, sizeof(uint8_t), length, transfer->hFile) != length)
+ {
+ proto->debugLogA(__FUNCTION__": failed to read from file (%d)", transfer->fileNumber);
+ proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
+ transfer->status = FAILED;
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
+ return;
}
- mir_free(data);
-
- if (transfer->status == STARTED && fileProgress == fileSize)
+ TOX_ERR_FILE_SEND_CHUNK error;
+ if (!tox_file_send_chunk(proto->tox, friendNumber, fileNumber, position, data, length, &error))
{
- transfer->status = FINISHED;
- if (tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_FINISHED, NULL, 0) == TOX_ERROR)
- {
- debugLogA("CToxProto::SendFileAsync: failed to finish the transfer of file (%d)", transfer->fileNumber);
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- }
+ proto->debugLogA(__FUNCTION__": failed to send file chunk (%d)", error);
+ proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
+ transfer->status = FAILED;
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
+ mir_free(data);
+ return;
}
+
+ transfer->pfts.totalProgress = transfer->pfts.currentFileProgress = length;
+
+ mir_free(data);
}
/* COMMON */
// file request is cancelled
-int __cdecl CToxProto::FileCancel(MCONTACT, HANDLE hTransfer)
+int CToxProto::OnFileCancel(MCONTACT, HANDLE hTransfer)
{
FileTransferParam *transfer = (FileTransferParam*)hTransfer;
transfer->status = CANCELED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
transfers.Remove(transfer);
return 0;
}
-// file request is denied
-int __cdecl CToxProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR*)
-{
- return FileCancel(hContact, hTransfer);
-}
-
-void CToxProto::OnFileRequest(Tox *tox, int32_t friendNumber, uint8_t receive_send, uint8_t fileNumber, uint8_t type, const uint8_t *data, uint16_t length, void *arg)
+void CToxProto::OnFileRequest(Tox*, uint32_t friendNumber, uint32_t fileNumber, TOX_FILE_CONTROL control, void *arg)
{
CToxProto *proto = (CToxProto*)arg;
@@ -283,81 +303,26 @@ void CToxProto::OnFileRequest(Tox *tox, int32_t friendNumber, uint8_t receive_se
FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber);
if (transfer == NULL)
{
- tox_file_send_control(tox, friendNumber, receive_send, fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
+ tox_file_control(proto->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
- switch (type)
+ switch (control)
{
- case TOX_FILECONTROL_ACCEPT:
- // receiver allowed the transfer
- if (receive_send == 1)
- {
- proto->debugLogA("CToxProto::OnFileRequest: start the transfer of file (%d)", transfer->fileNumber);
- // start file sending
- proto->ForkThread(&CToxProto::SendFileAsync, transfer);
- }
- break;
-
- case TOX_FILECONTROL_PAUSE:
+ case TOX_FILE_CONTROL_PAUSE:
transfer->status = PAUSED;
break;
- case TOX_FILECONTROL_RESUME_BROKEN:
- // receiver asked to resume transfer
- if (receive_send == 1)
- {
- uint64_t progress = *(uint64_t*)data;
- if (progress >= transfer->pfts.currentFileSize || length != sizeof(uint64_t))
- {
- transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- }
- if (tox_file_send_control(tox, friendNumber, transfer->GetDirection(), fileNumber, TOX_FILECONTROL_ACCEPT, NULL, 0) == TOX_ERROR)
- {
- proto->debugLogA("CToxProto::OnFileRequest: failed to resume the transfer of file (%d)", transfer->fileNumber);
- proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
- transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- break;
- }
- if (transfer->pfts.currentFileProgress != progress)
- {
- transfer->pfts.totalProgress = transfer->pfts.currentFileProgress = progress;
- if (_fseeki64(transfer->hFile, progress, SEEK_SET))
- {
- proto->debugLogA("CToxProto::OnFileRequest: failed to change file position from %llu to %llu of file (%d)",
- transfer->pfts.currentFileProgress, progress, transfer->fileNumber);
- transfer->status = FAILED;
- tox_file_send_control(tox, transfer->friendNumber, transfer->GetDirection(), transfer->fileNumber, TOX_FILECONTROL_KILL, NULL, 0);
- }
- }
- proto->debugLogA("CToxProto::SendFileAsync: resume the transfer of file (%d)", transfer->fileNumber);
- // resume file sending
- proto->ForkThread(&CToxProto::SendFileAsync, transfer);
- }
+ case TOX_FILE_CONTROL_RESUME:
+ transfer->status = STARTED;
+ proto->debugLogA("CToxProto::OnFileRequest: start/resume the transfer of file (%d)", transfer->fileNumber);
break;
- case TOX_FILECONTROL_KILL:
+ case TOX_FILE_CONTROL_CANCEL:
transfer->status = CANCELED;
proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0);
proto->transfers.Remove(transfer);
break;
-
- case TOX_FILECONTROL_FINISHED:
- {
- proto->debugLogA("CToxProto::SendFileAsync: finish the transfer of file (%d)", transfer->fileNumber);
- bool isFileFullyTransfered = transfer->pfts.currentFileProgress == transfer->pfts.currentFileSize;
- transfer->status = isFileFullyTransfered ? FINISHED : FAILED;
- if (!isFileFullyTransfered)
- {
- proto->debugLogA("CToxProto::SendFileAsync: file (%d) is transferred not completely", transfer->fileNumber);
- }
- tox_file_send_control(tox, friendNumber, transfer->GetDirection(), fileNumber, isFileFullyTransfered ? TOX_FILECONTROL_FINISHED : TOX_FILECONTROL_KILL, NULL, 0);
- proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, isFileFullyTransfered ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)transfer, 0);
- proto->transfers.Remove(transfer);
- }
- break;
}
}
} \ No newline at end of file
diff --git a/protocols/Tox/src/tox_transfer.h b/protocols/Tox/src/tox_transfer.h
index 41c6e1a4c6..c185209091 100644
--- a/protocols/Tox/src/tox_transfer.h
+++ b/protocols/Tox/src/tox_transfer.h
@@ -18,11 +18,11 @@ struct FileTransferParam
PROTOFILETRANSFERSTATUS pfts;
FILE_TRANSFER_STATUS status;
FILE *hFile;
- int32_t friendNumber;
- uint8_t fileNumber;
- int64_t transferNumber;
+ uint32_t friendNumber;
+ uint32_t fileNumber;
+ uint64_t transferNumber;
- FileTransferParam(int32_t friendNumber, uint8_t fileNumber, const TCHAR *fileName, uint64_t fileSize)
+ FileTransferParam(uint32_t friendNumber, uint32_t fileNumber, const TCHAR *fileName, uint64_t fileSize)
{
status = NONE;
hFile = NULL;
@@ -94,7 +94,7 @@ public:
}
}
- FileTransferParam* Get(int32_t friendNumber, uint8_t fileNumber)
+ FileTransferParam* Get(uint32_t friendNumber, uint32_t fileNumber)
{
int64_t transferNumber = (((int64_t)friendNumber) << 32) | ((int64_t)fileNumber);
if (transfers.find(transferNumber) != transfers.end())
@@ -115,7 +115,7 @@ public:
return NULL;
}
- void Remove(int32_t friendNumber, uint8_t fileNumber)
+ void Remove(uint32_t friendNumber, uint32_t fileNumber)
{
int64_t transferNumber = (((int64_t)friendNumber) << 32) | ((int64_t)fileNumber);
if (transfers.find(transferNumber) != transfers.end())
diff --git a/protocols/Tox/src/tox_utils.cpp b/protocols/Tox/src/tox_utils.cpp
index ccbb41effd..29e43d425b 100644
--- a/protocols/Tox/src/tox_utils.cpp
+++ b/protocols/Tox/src/tox_utils.cpp
@@ -1,32 +1,32 @@
#include "common.h"
-TOX_USERSTATUS CToxProto::MirandaToToxStatus(int status)
+TOX_USER_STATUS CToxProto::MirandaToToxStatus(int status)
{
- TOX_USERSTATUS userstatus = TOX_USERSTATUS_NONE;
+ TOX_USER_STATUS userstatus = TOX_USER_STATUS_NONE;
switch (status)
{
case ID_STATUS_AWAY:
- userstatus = TOX_USERSTATUS_AWAY;
+ userstatus = TOX_USER_STATUS_AWAY;
break;
case ID_STATUS_OCCUPIED:
- userstatus = TOX_USERSTATUS_BUSY;
+ userstatus = TOX_USER_STATUS_BUSY;
break;
}
return userstatus;
}
-int CToxProto::ToxToMirandaStatus(TOX_USERSTATUS userstatus)
+int CToxProto::ToxToMirandaStatus(TOX_USER_STATUS userstatus)
{
int status = ID_STATUS_OFFLINE;
switch (userstatus)
{
- case TOX_USERSTATUS_NONE:
+ case TOX_USER_STATUS_NONE:
status = ID_STATUS_ONLINE;
break;
- case TOX_USERSTATUS_AWAY:
+ case TOX_USER_STATUS_AWAY:
status = ID_STATUS_AWAY;
break;
- case TOX_USERSTATUS_BUSY:
+ case TOX_USER_STATUS_BUSY:
status = ID_STATUS_OCCUPIED;
break;
}
@@ -62,13 +62,5 @@ void CToxProto::ShowNotification(const TCHAR *message, int flags, MCONTACT hCont
bool CToxProto::IsFileExists(std::tstring path)
{
- //return ::GetFileAttributes(fileName) != DWORD(-1)
- WIN32_FIND_DATA wfd;
- HANDLE hFind = FindFirstFile(path.c_str(), &wfd);
- if (INVALID_HANDLE_VALUE != hFind)
- {
- FindClose(hFind);
- return true;
- }
- return false;
+ return _taccess(path.c_str(), 0) == 0;
} \ No newline at end of file
diff --git a/protocols/Tox/src/version.h b/protocols/Tox/src/version.h
index e3ec1bf9d5..d9040b8af6 100644
--- a/protocols/Tox/src/version.h
+++ b/protocols/Tox/src/version.h
@@ -1,7 +1,7 @@
#define __MAJOR_VERSION 0
#define __MINOR_VERSION 11
-#define __RELEASE_NUM 0
-#define __BUILD_NUM 8
+#define __RELEASE_NUM 1
+#define __BUILD_NUM 0
#include <stdver.h>