summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/Avatars.md40
-rw-r--r--testing/test_avatars.c50
2 files changed, 52 insertions, 38 deletions
diff --git a/docs/Avatars.md b/docs/Avatars.md
index 1dcbba96..31138af7 100644
--- a/docs/Avatars.md
+++ b/docs/Avatars.md
@@ -11,8 +11,8 @@ way for one user to identify another in the friend list.
11This document describes the implementation of avatars in the Tox protocol, 11This document describes the implementation of avatars in the Tox protocol,
12according to the following design considerations: 12according to the following design considerations:
13 13
14 - Avatars are handled as private information, i.e., they are only exchanged over 14 - Avatars are handled as private information, i.e., they are only exchanged
15 Tox encrypted channels among previously authenticated friends; 15 over Tox encrypted channels among previously authenticated friends;
16 16
17 - The library treats all images as blobs and does not interpret or 17 - The library treats all images as blobs and does not interpret or
18 understand image formats. It only ensures that the avatar data sent by 18 understand image formats. It only ensures that the avatar data sent by
@@ -85,14 +85,15 @@ Tox protocol:
85 connects to the network, changes his avatar, or in reply to an **avatar 85 connects to the network, changes his avatar, or in reply to an **avatar
86 information request**. They are delivered by a very lightweight message 86 information request**. They are delivered by a very lightweight message
87 but with information enough to allow a user to validate or discard an 87 but with information enough to allow a user to validate or discard an
88 avatar from the local cache and to decide if it is interesting to request the 88 avatar from the local cache and to decide if it is interesting to request
89 avatar data from the peer. 89 the avatar data from the peer.
90 90
91 This event contains two data fields: (1) the image format, and (2) the 91 This event contains two data fields: (1) the image format, and (2) the
92 cryptographic hash of the actual image data. The image format may be NONE 92 cryptographic hash of the current image data. The image format may be
93 (for users who have no avatar or removed their avatars) or PNG. The 93 NONE (for users who have no avatar or removed their avatars) or PNG. The
94 cryptographic hash is intended to be compared with the hash of the 94 cryptographic hash is intended to be compared with the hash of the
95 currently cached avatar (if any) in order to check if it is still up to date. 95 currently cached avatar (if any) in order to check if it is still up to
96 date.
96 97
97 - **Avatar Information Requests** are very lightweight messages sent by a 98 - **Avatar Information Requests** are very lightweight messages sent by a
98 user asking for an **avatar information notification**. They may be sent 99 user asking for an **avatar information notification**. They may be sent
@@ -145,6 +146,9 @@ TOX_AVATAR_FORMAT;
145/* Set the user avatar image data. */ 146/* Set the user avatar image data. */
146int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length); 147int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
147 148
149/* Removes the user avatar image data. */
150int tox_unset_avatar(Tox *tox);
151
148/* Get avatar data from the current user. */ 152/* Get avatar data from the current user. */
149int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash); 153int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash);
150 154
@@ -201,6 +205,11 @@ void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint
201 * A client may not understand a particular image format and ignore 205 * A client may not understand a particular image format and ignore
202 avatars using it, but request and handle other formats; 206 avatars using it, but request and handle other formats;
203 207
208 * A client on a slow mobile network may ask for avatar information to
209 ensure its cached avatars are still valid, but do not request avatar
210 data. The same client may start asking for avatar data once it
211 connects through a fast network.
212
204 - Clients SHOULD implement a local cache of avatars and do not request 213 - Clients SHOULD implement a local cache of avatars and do not request
205 avatar data from other peers unless necessary; 214 avatar data from other peers unless necessary;
206 215
@@ -244,7 +253,7 @@ already downloaded by other clients can be reused.
244Given the Tox data directory described in STS Draft v0.1.0: 253Given the Tox data directory described in STS Draft v0.1.0:
245 254
246 - Avatars are stored in a directory called "avatars" and named 255 - Avatars are stored in a directory called "avatars" and named
247 as "xxxxx.png", where "xxxxx" is the complete client id (but not friend 256 as "xxxxx.png", where "xxxxx" is the complete public key (but not friend
248 address!) encoded as an uppercase hexadecimal string and "png" is the 257 address!) encoded as an uppercase hexadecimal string and "png" is the
249 extension for the PNG avatar. As new image formats may be used in the 258 extension for the PNG avatar. As new image formats may be used in the
250 future, clients should ensure no other file "xxxxx.*" exists. No file 259 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:
253 - The client's own avatar is not special and is stored like any other. This 262 - The client's own avatar is not special and is stored like any other. This
254 is partially for simplicity, and partially in anticipation of profiles. 263 is partially for simplicity, and partially in anticipation of profiles.
255 264
256 - The avatar should be stored as its recieved, before any modifications by 265 - The avatar should be stored as its received, before any modifications by
257 the client for display purposes. 266 the client for display purposes.
258 267
259 - The hash, as calculated by toxcore and passed in to the data callback, 268 - 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":
269 Tox data directory: /home/gildor/.config/tox/ 278 Tox data directory: /home/gildor/.config/tox/
270 Tox data file: /home/gildor/.config/tox/data 279 Tox data file: /home/gildor/.config/tox/data
271 Avatar data dir: /home/gildor/.config/tox/avatars/ 280 Avatar data dir: /home/gildor/.config/tox/avatars/
272 Gildor's avatar: /home/gildor/.config/tox/avatars/E5809EEF5F11AB29B9BDF543C05B58DDF454AB9CA176C235C7699FDC2757DC33.png 281 Gildor's avatar: /home/gildor/.config/tox/avatars/446F4E6F744D6564646C65496E546865416666616972734F6657697A61726473.png
273 Elrond's avatar: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png 282 Elrond's avatar: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png
274 Elrond's hash: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.hash 283 Elrond's hash: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.hash
275 Elladan's avatar: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png 284 Elladan's avatar: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png
@@ -313,7 +322,12 @@ notifications and unnecessary data transfers.
313 322
314#### Removing the avatar from the current user 323#### Removing the avatar from the current user
315 324
316To remove an avatar, an application must set it to `TOX_AVATAR_FORMAT_NONE`. 325To remove the current avatar, an application must call
326
327 tox_unset_avatar(tox);
328
329the effect is the same as setting the avatar format to `TOX_AVATAR_FORMAT_NONE`
330and with no data:
317 331
318 tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0); 332 tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0);
319 333
@@ -408,7 +422,7 @@ calls:
408 422
409In the previous examples, implementation of the functions to check, store 423In the previous examples, implementation of the functions to check, store
410and retrieve data from the cache were omitted for brevity. These functions 424and retrieve data from the cache were omitted for brevity. These functions
411will also need to get the friend client ID (public key) from they friend 425will also need to get the friend public key (client id) from they friend
412number and, usually, convert it from a byte string to a hexadecimal 426number and, usually, convert it from a byte string to a hexadecimal
413string. A complete, yet more complex, example is available in the file 427string. A complete, yet more complex, example is available in the file
414`testing/test_avatars.c`. 428`testing/test_avatars.c`.
@@ -555,7 +569,7 @@ from a client "B":
555 If valid, "A" updates the 'bytes_received' counter and concatenates the 569 If valid, "A" updates the 'bytes_received' counter and concatenates the
556 newly arrived data to the buffer. 570 newly arrived data to the buffer.
557 571
558 The "A" checks if all the data was already received by comparing the 572 Then "A" checks if all the data was already received by comparing the
559 counter 'bytes_received' with the field 'total_length'. If they are 573 counter 'bytes_received' with the field 'total_length'. If they are
560 equal, "A" takes a SHA-256 hash of the data and compares it with the 574 equal, "A" takes a SHA-256 hash of the data and compares it with the
561 hash stored in the field 'hash' received from the first 575 hash stored in the field 'hash' received from the first
diff --git a/testing/test_avatars.c b/testing/test_avatars.c
index 71a0330e..b4adc48f 100644
--- a/testing/test_avatars.c
+++ b/testing/test_avatars.c
@@ -18,7 +18,7 @@
18 * Data dir MAY have: 18 * Data dir MAY have:
19 * 19 *
20 * - A directory named "avatars" with the user's avatar and cached avatars. 20 * - A directory named "avatars" with the user's avatar and cached avatars.
21 * The user avatar must be named in the format: "<uppercase user id>.png" 21 * The user avatar must be named in the format: "<uppercase pub key>.png"
22 * 22 *
23 * 23 *
24 * The bot will answer to these commands: 24 * 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)
163 dst[j++] = '\0'; 163 dst[j++] = '\0';
164} 164}
165 165
166/* Make the cache file name for a avatar of the given format for the given 166/* Make the cache file name for an avatar of the given format for the given
167 * client id. 167 * public key.
168 */ 168 */
169static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir, 169static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir,
170 const uint8_t format, uint8_t *client_id) 170 const uint8_t format, uint8_t *public_key)
171{ 171{
172 char client_id_str[2 * TOX_CLIENT_ID_SIZE + 1]; 172 char public_key_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
173 byte_to_hex_str(client_id, TOX_CLIENT_ID_SIZE, client_id_str); 173 byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, public_key_str);
174 174
175 const char *suffix = get_avatar_suffix_from_format(format); 175 const char *suffix = get_avatar_suffix_from_format(format);
176 176
@@ -178,7 +178,7 @@ static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir
178 return -1; /* Error */ 178 return -1; /* Error */
179 179
180 int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME, 180 int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME,
181 client_id_str, suffix); 181 public_key_str, suffix);
182 dst[dst_len - 1] = '\0'; 182 dst[dst_len - 1] = '\0';
183 183
184 if (n >= dst_len) 184 if (n >= dst_len)
@@ -196,7 +196,7 @@ static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir
196static int load_user_avatar(Tox *tox, char *base_dir, int friendnum, 196static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
197 uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen) 197 uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen)
198{ 198{
199 uint8_t addr[TOX_CLIENT_ID_SIZE]; 199 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
200 200
201 if (tox_get_client_id(tox, friendnum, addr) != 0) { 201 if (tox_get_client_id(tox, friendnum, addr) != 0) {
202 DEBUG("Bad client id, friendnumber=%d", friendnum); 202 DEBUG("Bad client id, friendnumber=%d", friendnum);
@@ -224,14 +224,14 @@ static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
224 return 0; 224 return 0;
225} 225}
226 226
227/* Save a user avatar into the cache. Gets the file name from client id and 227/* Save a user avatar into the cache. Gets the file name from the public key
228 * the given data format. 228 * and the given data format.
229 * Returns 0 on success, or -1 on error. 229 * Returns 0 on success, or -1 on error.
230 */ 230 */
231static int save_user_avatar(Tox *tox, char *base_dir, int friendnum, 231static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
232 uint8_t format, uint8_t *data, uint32_t datalen) 232 uint8_t format, uint8_t *data, uint32_t datalen)
233{ 233{
234 uint8_t addr[TOX_CLIENT_ID_SIZE]; 234 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
235 235
236 if (tox_get_client_id(tox, friendnum, addr) != 0) { 236 if (tox_get_client_id(tox, friendnum, addr) != 0) {
237 DEBUG("Bad client id, friendnumber=%d", friendnum); 237 DEBUG("Bad client id, friendnumber=%d", friendnum);
@@ -252,7 +252,7 @@ static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
252/* Delete all cached avatars for a given user */ 252/* Delete all cached avatars for a given user */
253static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum) 253static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
254{ 254{
255 uint8_t addr[TOX_CLIENT_ID_SIZE]; 255 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
256 256
257 if (tox_get_client_id(tox, friendnum, addr) != 0) { 257 if (tox_get_client_id(tox, friendnum, addr) != 0) {
258 DEBUG("Bad client id, friendnumber=%d", friendnum); 258 DEBUG("Bad client id, friendnumber=%d", friendnum);
@@ -288,11 +288,11 @@ static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
288 288
289static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud) 289static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
290{ 290{
291 uint8_t addr[TOX_CLIENT_ID_SIZE]; 291 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
292 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1]; 292 char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
293 293
294 if (tox_get_client_id(tox, n, addr) == 0) { 294 if (tox_get_client_id(tox, n, addr) == 0) {
295 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str); 295 byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
296 printf("Receiving status from %s: %u\n", addr_str, status); 296 printf("Receiving status from %s: %u\n", addr_str, status);
297 } 297 }
298} 298}
@@ -300,12 +300,12 @@ static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
300static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud) 300static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud)
301{ 301{
302 char *base_dir = (char *) ud; 302 char *base_dir = (char *) ud;
303 uint8_t addr[TOX_CLIENT_ID_SIZE]; 303 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
304 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1]; 304 char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
305 char hash_str[2 * TOX_HASH_LENGTH + 1]; 305 char hash_str[2 * TOX_HASH_LENGTH + 1];
306 306
307 if (tox_get_client_id(tox, n, addr) == 0) { 307 if (tox_get_client_id(tox, n, addr) == 0) {
308 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str); 308 byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
309 printf("Receiving avatar information from %s.\n", addr_str); 309 printf("Receiving avatar information from %s.\n", addr_str);
310 } else { 310 } else {
311 DEBUG("tox_get_client_id failed"); 311 DEBUG("tox_get_client_id failed");
@@ -350,12 +350,12 @@ static void friend_avatar_data_cb(Tox *tox, int32_t n, uint8_t format,
350 uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud) 350 uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud)
351{ 351{
352 char *base_dir = (char *) ud; 352 char *base_dir = (char *) ud;
353 uint8_t addr[TOX_CLIENT_ID_SIZE]; 353 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
354 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1]; 354 char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
355 char hash_str[2 * TOX_HASH_LENGTH + 1]; 355 char hash_str[2 * TOX_HASH_LENGTH + 1];
356 356
357 if (tox_get_client_id(tox, n, addr) == 0) { 357 if (tox_get_client_id(tox, n, addr) == 0) {
358 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str); 358 byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str);
359 printf("Receiving avatar data from %s.\n", addr_str); 359 printf("Receiving avatar data from %s.\n", addr_str);
360 } else { 360 } else {
361 DEBUG("tox_get_client_id failed"); 361 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
382{ 382{
383 const char *base_dir = (char *) ud; 383 const char *base_dir = (char *) ud;
384 const char *msg_str = (char *) msg; 384 const char *msg_str = (char *) msg;
385 uint8_t addr[TOX_CLIENT_ID_SIZE]; 385 uint8_t addr[TOX_PUBLIC_KEY_SIZE];
386 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1]; 386 char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
387 387
388 if (tox_get_client_id(tox, n, addr) == 0) { 388 if (tox_get_client_id(tox, n, addr) == 0) {
389 byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str); 389 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
428static void friend_request_cb(Tox *tox, const uint8_t *public_key, 428static void friend_request_cb(Tox *tox, const uint8_t *public_key,
429 const uint8_t *data, uint16_t length, void *ud) 429 const uint8_t *data, uint16_t length, void *ud)
430{ 430{
431 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1]; 431 char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1];
432 byte_to_hex_str(public_key, TOX_CLIENT_ID_SIZE, addr_str); 432 byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, addr_str);
433 printf("Accepting friend request from %s.\n %s\n", addr_str, data); 433 printf("Accepting friend request from %s.\n %s\n", addr_str, data);
434 tox_add_friend_norequest(tox, public_key); 434 tox_add_friend_norequest(tox, public_key);
435} 435}