mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Merge branch 'ittner-update-avatar-docs-2'
This commit is contained in:
commit
fbe9fd0610
|
@ -11,8 +11,8 @@ way for one user to identify another in the friend list.
|
||||||
This document describes the implementation of avatars in the Tox protocol,
|
This document describes the implementation of avatars in the Tox protocol,
|
||||||
according to the following design considerations:
|
according to the following design considerations:
|
||||||
|
|
||||||
- Avatars are handled as private information, i.e., they are only exchanged over
|
- Avatars are handled as private information, i.e., they are only exchanged
|
||||||
Tox encrypted channels among previously authenticated friends;
|
over Tox encrypted channels among previously authenticated friends;
|
||||||
|
|
||||||
- The library treats all images as blobs and does not interpret or
|
- The library treats all images as blobs and does not interpret or
|
||||||
understand image formats. It only ensures that the avatar data sent by
|
understand image formats. It only ensures that the avatar data sent by
|
||||||
|
@ -85,14 +85,15 @@ Tox protocol:
|
||||||
connects to the network, changes his avatar, or in reply to an **avatar
|
connects to the network, changes his avatar, or in reply to an **avatar
|
||||||
information request**. They are delivered by a very lightweight message
|
information request**. They are delivered by a very lightweight message
|
||||||
but with information enough to allow a user to validate or discard an
|
but with information enough to allow a user to validate or discard an
|
||||||
avatar from the local cache and to decide if it is interesting to request the
|
avatar from the local cache and to decide if it is interesting to request
|
||||||
avatar data from the peer.
|
the avatar data from the peer.
|
||||||
|
|
||||||
This event contains two data fields: (1) the image format, and (2) the
|
This event contains two data fields: (1) the image format, and (2) the
|
||||||
cryptographic hash of the actual image data. The image format may be NONE
|
cryptographic hash of the current image data. The image format may be
|
||||||
(for users who have no avatar or removed their avatars) or PNG. The
|
NONE (for users who have no avatar or removed their avatars) or PNG. The
|
||||||
cryptographic hash is intended to be compared with the hash of the
|
cryptographic hash is intended to be compared with the hash of the
|
||||||
currently cached avatar (if any) in order to check if it is still up to date.
|
currently cached avatar (if any) in order to check if it is still up to
|
||||||
|
date.
|
||||||
|
|
||||||
- **Avatar Information Requests** are very lightweight messages sent by a
|
- **Avatar Information Requests** are very lightweight messages sent by a
|
||||||
user asking for an **avatar information notification**. They may be sent
|
user asking for an **avatar information notification**. They may be sent
|
||||||
|
@ -145,6 +146,9 @@ TOX_AVATAR_FORMAT;
|
||||||
/* Set the user avatar image data. */
|
/* Set the user avatar image data. */
|
||||||
int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
|
int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
/* Removes the user avatar image data. */
|
||||||
|
int tox_unset_avatar(Tox *tox);
|
||||||
|
|
||||||
/* Get avatar data from the current user. */
|
/* Get avatar data from the current user. */
|
||||||
int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash);
|
int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash);
|
||||||
|
|
||||||
|
@ -201,6 +205,11 @@ void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint
|
||||||
* A client may not understand a particular image format and ignore
|
* A client may not understand a particular image format and ignore
|
||||||
avatars using it, but request and handle other formats;
|
avatars using it, but request and handle other formats;
|
||||||
|
|
||||||
|
* A client on a slow mobile network may ask for avatar information to
|
||||||
|
ensure its cached avatars are still valid, but do not request avatar
|
||||||
|
data. The same client may start asking for avatar data once it
|
||||||
|
connects through a fast network.
|
||||||
|
|
||||||
- Clients SHOULD implement a local cache of avatars and do not request
|
- Clients SHOULD implement a local cache of avatars and do not request
|
||||||
avatar data from other peers unless necessary;
|
avatar data from other peers unless necessary;
|
||||||
|
|
||||||
|
@ -244,7 +253,7 @@ already downloaded by other clients can be reused.
|
||||||
Given the Tox data directory described in STS Draft v0.1.0:
|
Given the Tox data directory described in STS Draft v0.1.0:
|
||||||
|
|
||||||
- Avatars are stored in a directory called "avatars" and named
|
- Avatars are stored in a directory called "avatars" and named
|
||||||
as "xxxxx.png", where "xxxxx" is the complete client id (but not friend
|
as "xxxxx.png", where "xxxxx" is the complete public key (but not friend
|
||||||
address!) encoded as an uppercase hexadecimal string and "png" is the
|
address!) encoded as an uppercase hexadecimal string and "png" is the
|
||||||
extension for the PNG avatar. As new image formats may be used in the
|
extension for the PNG avatar. As new image formats may be used in the
|
||||||
future, clients should ensure no other file "xxxxx.*" exists. No file
|
future, clients should ensure no other file "xxxxx.*" exists. No file
|
||||||
|
@ -253,7 +262,7 @@ Given the Tox data directory described in STS Draft v0.1.0:
|
||||||
- The client's own avatar is not special and is stored like any other. This
|
- The client's own avatar is not special and is stored like any other. This
|
||||||
is partially for simplicity, and partially in anticipation of profiles.
|
is partially for simplicity, and partially in anticipation of profiles.
|
||||||
|
|
||||||
- The avatar should be stored as its recieved, before any modifications by
|
- The avatar should be stored as its received, before any modifications by
|
||||||
the client for display purposes.
|
the client for display purposes.
|
||||||
|
|
||||||
- The hash, as calculated by toxcore and passed in to the data callback,
|
- The hash, as calculated by toxcore and passed in to the data callback,
|
||||||
|
@ -269,7 +278,7 @@ Example for Linux and other Unix systems, assuming an user called "gildor":
|
||||||
Tox data directory: /home/gildor/.config/tox/
|
Tox data directory: /home/gildor/.config/tox/
|
||||||
Tox data file: /home/gildor/.config/tox/data
|
Tox data file: /home/gildor/.config/tox/data
|
||||||
Avatar data dir: /home/gildor/.config/tox/avatars/
|
Avatar data dir: /home/gildor/.config/tox/avatars/
|
||||||
Gildor's avatar: /home/gildor/.config/tox/avatars/E5809EEF5F11AB29B9BDF543C05B58DDF454AB9CA176C235C7699FDC2757DC33.png
|
Gildor's avatar: /home/gildor/.config/tox/avatars/446F4E6F744D6564646C65496E546865416666616972734F6657697A61726473.png
|
||||||
Elrond's avatar: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png
|
Elrond's avatar: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png
|
||||||
Elrond's hash: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.hash
|
Elrond's hash: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.hash
|
||||||
Elladan's avatar: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png
|
Elladan's avatar: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png
|
||||||
|
@ -313,7 +322,12 @@ notifications and unnecessary data transfers.
|
||||||
|
|
||||||
#### Removing the avatar from the current user
|
#### Removing the avatar from the current user
|
||||||
|
|
||||||
To remove an avatar, an application must set it to `TOX_AVATAR_FORMAT_NONE`.
|
To remove the current avatar, an application must call
|
||||||
|
|
||||||
|
tox_unset_avatar(tox);
|
||||||
|
|
||||||
|
the effect is the same as setting the avatar format to `TOX_AVATAR_FORMAT_NONE`
|
||||||
|
and with no data:
|
||||||
|
|
||||||
tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0);
|
tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0);
|
||||||
|
|
||||||
|
@ -408,7 +422,7 @@ calls:
|
||||||
|
|
||||||
In the previous examples, implementation of the functions to check, store
|
In the previous examples, implementation of the functions to check, store
|
||||||
and retrieve data from the cache were omitted for brevity. These functions
|
and retrieve data from the cache were omitted for brevity. These functions
|
||||||
will also need to get the friend client ID (public key) from they friend
|
will also need to get the friend public key (client id) from they friend
|
||||||
number and, usually, convert it from a byte string to a hexadecimal
|
number and, usually, convert it from a byte string to a hexadecimal
|
||||||
string. A complete, yet more complex, example is available in the file
|
string. A complete, yet more complex, example is available in the file
|
||||||
`testing/test_avatars.c`.
|
`testing/test_avatars.c`.
|
||||||
|
@ -555,7 +569,7 @@ from a client "B":
|
||||||
If valid, "A" updates the 'bytes_received' counter and concatenates the
|
If valid, "A" updates the 'bytes_received' counter and concatenates the
|
||||||
newly arrived data to the buffer.
|
newly arrived data to the buffer.
|
||||||
|
|
||||||
The "A" checks if all the data was already received by comparing the
|
Then "A" checks if all the data was already received by comparing the
|
||||||
counter 'bytes_received' with the field 'total_length'. If they are
|
counter 'bytes_received' with the field 'total_length'. If they are
|
||||||
equal, "A" takes a SHA-256 hash of the data and compares it with the
|
equal, "A" takes a SHA-256 hash of the data and compares it with the
|
||||||
hash stored in the field 'hash' received from the first
|
hash stored in the field 'hash' received from the first
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* Data dir MAY have:
|
* Data dir MAY have:
|
||||||
*
|
*
|
||||||
* - A directory named "avatars" with the user's avatar and cached avatars.
|
* - A directory named "avatars" with the user's avatar and cached avatars.
|
||||||
* The user avatar must be named in the format: "<uppercase user id>.png"
|
* The user avatar must be named in the format: "<uppercase pub key>.png"
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The bot will answer to these commands:
|
* The bot will answer to these commands:
|
||||||
|
@ -163,14 +163,14 @@ static void byte_to_hex_str(const uint8_t *buf, const size_t buflen, char *dst)
|
||||||
dst[j++] = '\0';
|
dst[j++] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the cache file name for a avatar of the given format for the given
|
/* Make the cache file name for an avatar of the given format for the given
|
||||||
* client id.
|
* public key.
|
||||||
*/
|
*/
|
||||||
static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir,
|
static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir,
|
||||||
const uint8_t format, uint8_t *client_id)
|
const uint8_t format, uint8_t *public_key)
|
||||||
{
|
{
|
||||||
char client_id_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char public_key_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
byte_to_hex_str(client_id, TOX_CLIENT_ID_SIZE, client_id_str);
|
byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, public_key_str);
|
||||||
|
|
||||||
const char *suffix = get_avatar_suffix_from_format(format);
|
const char *suffix = get_avatar_suffix_from_format(format);
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir
|
||||||
return -1; /* Error */
|
return -1; /* Error */
|
||||||
|
|
||||||
int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME,
|
int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME,
|
||||||
client_id_str, suffix);
|
public_key_str, suffix);
|
||||||
dst[dst_len - 1] = '\0';
|
dst[dst_len - 1] = '\0';
|
||||||
|
|
||||||
if (n >= dst_len)
|
if (n >= dst_len)
|
||||||
|
@ -196,7 +196,7 @@ static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir
|
||||||
static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
||||||
uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen)
|
uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen)
|
||||||
{
|
{
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
||||||
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
||||||
|
@ -224,14 +224,14 @@ static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save a user avatar into the cache. Gets the file name from client id and
|
/* Save a user avatar into the cache. Gets the file name from the public key
|
||||||
* the given data format.
|
* and the given data format.
|
||||||
* Returns 0 on success, or -1 on error.
|
* Returns 0 on success, or -1 on error.
|
||||||
*/
|
*/
|
||||||
static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
||||||
uint8_t format, uint8_t *data, uint32_t datalen)
|
uint8_t format, uint8_t *data, uint32_t datalen)
|
||||||
{
|
{
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
||||||
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
||||||
|
@ -252,7 +252,7 @@ static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
|
||||||
/* Delete all cached avatars for a given user */
|
/* Delete all cached avatars for a given user */
|
||||||
static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
|
static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
|
||||||
{
|
{
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
if (tox_get_client_id(tox, friendnum, addr) != 0) {
|
||||||
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
DEBUG("Bad client id, friendnumber=%d", friendnum);
|
||||||
|
@ -288,11 +288,11 @@ static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
|
||||||
|
|
||||||
static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
|
static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
|
||||||
{
|
{
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, n, addr) == 0) {
|
if (tox_get_client_id(tox, n, addr) == 0) {
|
||||||
byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
|
byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
|
||||||
printf("Receiving status from %s: %u\n", addr_str, status);
|
printf("Receiving status from %s: %u\n", addr_str, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,12 +300,12 @@ static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
|
||||||
static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud)
|
static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud)
|
||||||
{
|
{
|
||||||
char *base_dir = (char *) ud;
|
char *base_dir = (char *) ud;
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
char hash_str[2 * TOX_HASH_LENGTH + 1];
|
char hash_str[2 * TOX_HASH_LENGTH + 1];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, n, addr) == 0) {
|
if (tox_get_client_id(tox, n, addr) == 0) {
|
||||||
byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
|
byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
|
||||||
printf("Receiving avatar information from %s.\n", addr_str);
|
printf("Receiving avatar information from %s.\n", addr_str);
|
||||||
} else {
|
} else {
|
||||||
DEBUG("tox_get_client_id failed");
|
DEBUG("tox_get_client_id failed");
|
||||||
|
@ -350,12 +350,12 @@ static void friend_avatar_data_cb(Tox *tox, int32_t n, uint8_t format,
|
||||||
uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud)
|
uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud)
|
||||||
{
|
{
|
||||||
char *base_dir = (char *) ud;
|
char *base_dir = (char *) ud;
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
char hash_str[2 * TOX_HASH_LENGTH + 1];
|
char hash_str[2 * TOX_HASH_LENGTH + 1];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, n, addr) == 0) {
|
if (tox_get_client_id(tox, n, addr) == 0) {
|
||||||
byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
|
byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
|
||||||
printf("Receiving avatar data from %s.\n", addr_str);
|
printf("Receiving avatar data from %s.\n", addr_str);
|
||||||
} else {
|
} else {
|
||||||
DEBUG("tox_get_client_id failed");
|
DEBUG("tox_get_client_id failed");
|
||||||
|
@ -382,8 +382,8 @@ static void friend_msg_cb(Tox *tox, int n, const uint8_t *msg, uint16_t len, voi
|
||||||
{
|
{
|
||||||
const char *base_dir = (char *) ud;
|
const char *base_dir = (char *) ud;
|
||||||
const char *msg_str = (char *) msg;
|
const char *msg_str = (char *) msg;
|
||||||
uint8_t addr[TOX_CLIENT_ID_SIZE];
|
uint8_t addr[TOX_PUBLIC_KEY_SIZE];
|
||||||
char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
|
|
||||||
if (tox_get_client_id(tox, n, addr) == 0) {
|
if (tox_get_client_id(tox, n, addr) == 0) {
|
||||||
byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str);
|
byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str);
|
||||||
|
@ -428,8 +428,8 @@ static void friend_msg_cb(Tox *tox, int n, const uint8_t *msg, uint16_t len, voi
|
||||||
static void friend_request_cb(Tox *tox, const uint8_t *public_key,
|
static void friend_request_cb(Tox *tox, const uint8_t *public_key,
|
||||||
const uint8_t *data, uint16_t length, void *ud)
|
const uint8_t *data, uint16_t length, void *ud)
|
||||||
{
|
{
|
||||||
char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
|
char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
|
||||||
byte_to_hex_str(public_key, TOX_CLIENT_ID_SIZE, addr_str);
|
byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, addr_str);
|
||||||
printf("Accepting friend request from %s.\n %s\n", addr_str, data);
|
printf("Accepting friend request from %s.\n %s\n", addr_str, data);
|
||||||
tox_add_friend_norequest(tox, public_key);
|
tox_add_friend_norequest(tox, public_key);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user