Merge branch 'ittner-update-avatar-docs-2'

This commit is contained in:
irungentoo 2015-02-01 20:16:49 -05:00
commit fbe9fd0610
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
2 changed files with 52 additions and 38 deletions

View File

@ -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

View File

@ -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);
} }