summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-09-22 15:07:14 -0400
committerirungentoo <irungentoo@gmail.com>2014-09-22 15:07:14 -0400
commitb52da45aebe79b54bbd00564a050fcdaca028617 (patch)
tree0eb8011d0e808a57ed024d735690f99df601eda7 /toxcore
parent900d72f9511790add88313f31b17d6ca8d81a49c (diff)
parentb52eb48c15a06fe198c7c5e0d765cfef8ff4fbdf (diff)
Merge branch 'avatars' of https://github.com/ittner/toxcore
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/Messenger.c469
-rw-r--r--toxcore/Messenger.h195
-rw-r--r--toxcore/tox.c54
-rw-r--r--toxcore/tox.h145
4 files changed, 863 insertions, 0 deletions
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 21cb2671..108159a3 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -42,6 +42,7 @@
42static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); 42static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status);
43static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, 43static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
44 uint32_t length, uint8_t congestion_control); 44 uint32_t length, uint8_t congestion_control);
45static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, uint8_t op);
45 46
46// friend_not_valid determines if the friendnumber passed is valid in the Messenger object 47// friend_not_valid determines if the friendnumber passed is valid in the Messenger object
47static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) 48static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber)
@@ -247,6 +248,10 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u
247 m->friendlist[i].statusmessage = calloc(1, 1); 248 m->friendlist[i].statusmessage = calloc(1, 1);
248 m->friendlist[i].statusmessage_length = 1; 249 m->friendlist[i].statusmessage_length = 1;
249 m->friendlist[i].userstatus = USERSTATUS_NONE; 250 m->friendlist[i].userstatus = USERSTATUS_NONE;
251 m->friendlist[i].avatar_info_sent = 0;
252 m->friendlist[i].avatar_recv_data = NULL;
253 m->friendlist[i].avatar_send_data.bytes_sent = 0;
254 m->friendlist[i].avatar_send_data.last_reset = 0;
250 m->friendlist[i].is_typing = 0; 255 m->friendlist[i].is_typing = 0;
251 memcpy(m->friendlist[i].info, data, length); 256 memcpy(m->friendlist[i].info, data, length);
252 m->friendlist[i].info_size = length; 257 m->friendlist[i].info_size = length;
@@ -330,6 +335,7 @@ int m_delfriend(Messenger *m, int32_t friendnumber)
330 onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); 335 onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum);
331 crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); 336 crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id);
332 free(m->friendlist[friendnumber].statusmessage); 337 free(m->friendlist[friendnumber].statusmessage);
338 free(m->friendlist[friendnumber].avatar_recv_data);
333 remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); 339 remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id);
334 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); 340 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));
335 uint32_t i; 341 uint32_t i;
@@ -564,6 +570,134 @@ int m_set_userstatus(Messenger *m, uint8_t status)
564 return 0; 570 return 0;
565} 571}
566 572
573int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length)
574{
575 if (length > MAX_AVATAR_DATA_LENGTH)
576 return -1;
577
578 if (format == AVATARFORMAT_NONE) {
579 free(m->avatar_data);
580 m->avatar_data = NULL;
581 m->avatar_data_length = 0;
582 m->avatar_format = format;
583 memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH);
584 } else {
585 if (length == 0 || data == NULL)
586 return -1;
587
588 uint8_t *tmp = realloc(m->avatar_data, length);
589
590 if (tmp == NULL)
591 return -1;
592
593 m->avatar_format = format;
594 m->avatar_data = tmp;
595 m->avatar_data_length = length;
596 memcpy(m->avatar_data, data, length);
597
598 m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length);
599 }
600
601 uint32_t i;
602
603 for (i = 0; i < m->numfriends; ++i)
604 m->friendlist[i].avatar_info_sent = 0;
605
606 return 0;
607}
608
609int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
610 uint8_t *hash)
611{
612 if (format)
613 *format = m->avatar_format;
614
615 if (length)
616 *length = m->avatar_data_length;
617
618 if (hash)
619 memcpy(hash, m->avatar_hash, AVATAR_HASH_LENGTH);
620
621 if (buf != NULL && maxlen > 0) {
622 if (m->avatar_data_length <= maxlen)
623 memcpy(buf, m->avatar_data, m->avatar_data_length);
624 else
625 return -1;
626 }
627
628 return 0;
629}
630
631int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen)
632{
633 if (hash == NULL)
634 return -1;
635
636 crypto_hash_sha256(hash, data, datalen);
637 return 0;
638}
639
640
641int m_request_avatar_info(const Messenger *m, const int32_t friendnumber)
642{
643 if (friend_not_valid(m, friendnumber))
644 return -1;
645
646 if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO_REQ, 0, 0, 0) >= 0)
647 return 0;
648 else
649 return -1;
650}
651
652int m_send_avatar_info(const Messenger *m, const int32_t friendnumber)
653{
654 if (friend_not_valid(m, friendnumber))
655 return -1;
656
657 uint8_t data[sizeof(uint8_t) + AVATAR_HASH_LENGTH];
658 data[0] = m->avatar_format;
659 memcpy(data + 1, m->avatar_hash, AVATAR_HASH_LENGTH);
660
661 int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO, data, sizeof(data), 0);
662
663 if (ret >= 0)
664 return 0;
665 else
666 return -1;
667}
668
669int m_request_avatar_data(const Messenger *m, const int32_t friendnumber)
670{
671 if (friend_not_valid(m, friendnumber))
672 return -1;
673
674 AVATARRECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
675
676 if (avrd == NULL) {
677 avrd = malloc(sizeof(AVATARRECEIVEDATA));
678
679 if (avrd == NULL)
680 return -1;
681
682 memset(avrd, 0, sizeof(AVATARRECEIVEDATA));
683 avrd->started = 0;
684 m->friendlist[friendnumber].avatar_recv_data = avrd;
685 }
686
687 if (avrd->started) {
688 LOGGER_DEBUG("Resetting already started data request. "
689 "friendnumber == %u", friendnumber);
690 }
691
692 avrd->started = 0;
693 avrd->bytes_received = 0;
694 avrd->total_length = 0;
695 avrd->format = AVATARFORMAT_NONE;
696
697 return send_avatar_data_control(m, friendnumber, AVATARDATACONTROL_REQ);
698}
699
700
567/* return the size of friendnumber's user status. 701/* return the size of friendnumber's user status.
568 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. 702 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
569 */ 703 */
@@ -806,6 +940,20 @@ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Mess
806 m->friend_connectionstatuschange_internal_userdata = userdata; 940 m->friend_connectionstatuschange_internal_userdata = userdata;
807} 941}
808 942
943void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t *, void *),
944 void *userdata)
945{
946 m->avatar_info_recv = function;
947 m->avatar_info_recv_userdata = userdata;
948}
949
950void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *,
951 uint32_t, void *), void *userdata)
952{
953 m->avatar_data_recv = function;
954 m->avatar_data_recv_userdata = userdata;
955}
956
809static void break_files(const Messenger *m, int32_t friendnumber); 957static void break_files(const Messenger *m, int32_t friendnumber);
810static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status) 958static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status)
811{ 959{
@@ -1857,6 +2005,9 @@ Messenger *new_messenger(Messenger_Options *options)
1857 m->net = new_networking(ip, TOX_PORT_DEFAULT); 2005 m->net = new_networking(ip, TOX_PORT_DEFAULT);
1858 } 2006 }
1859 2007
2008 m->avatar_format = AVATARFORMAT_NONE;
2009 m->avatar_data = NULL;
2010
1860 if (m->net == NULL) { 2011 if (m->net == NULL) {
1861 free(m); 2012 free(m);
1862 return NULL; 2013 return NULL;
@@ -1934,6 +2085,7 @@ void kill_messenger(Messenger *m)
1934 free(m->friendlist[i].statusmessage); 2085 free(m->friendlist[i].statusmessage);
1935 } 2086 }
1936 2087
2088 free(m->avatar_data);
1937 free(m->friendlist); 2089 free(m->friendlist);
1938 free(m); 2090 free(m);
1939} 2091}
@@ -1973,11 +2125,287 @@ static int handle_status(void *object, int i, uint8_t status)
1973 if (m->friendlist[i].status == FRIEND_ONLINE) { 2125 if (m->friendlist[i].status == FRIEND_ONLINE) {
1974 set_friend_status(m, i, FRIEND_CONFIRMED); 2126 set_friend_status(m, i, FRIEND_CONFIRMED);
1975 } 2127 }
2128
2129 /* Clear avatar transfer state */
2130 if (m->friendlist[i].avatar_recv_data) {
2131 free(m->friendlist[i].avatar_recv_data);
2132 m->friendlist[i].avatar_recv_data = NULL;
2133 }
2134 }
2135
2136 return 0;
2137}
2138
2139
2140/* Sends an avatar data control packet to the peer. Usually to return status
2141 * values or request data.
2142 */
2143static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber,
2144 uint8_t op)
2145{
2146 int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_CONTROL,
2147 &op, sizeof(op), 0);
2148 LOGGER_DEBUG("friendnumber = %u, op = %u, ret = %d",
2149 friendnumber, op, ret);
2150 return (ret >= 0) ? 0 : -1;
2151}
2152
2153
2154static int handle_avatar_data_control(Messenger *m, uint32_t friendnumber,
2155 uint8_t *data, uint32_t data_length)
2156{
2157 if (data_length != 1) {
2158 LOGGER_DEBUG("Error: PACKET_ID_AVATAR_DATA_CONTROL with bad "
2159 "data_length = %u, friendnumber = %u",
2160 data_length, friendnumber);
2161 send_avatar_data_control(m, friendnumber, AVATARDATACONTROL_ERROR);
2162 return -1; /* Error */
2163 }
2164
2165 LOGGER_DEBUG("friendnumber = %u, op = %u", friendnumber, data[0]);
2166
2167 switch (data[0]) {
2168 case AVATARDATACONTROL_REQ: {
2169
2170 /* Check data transfer limits for this friend */
2171 AVATARSENDDATA *const avsd = &(m->friendlist[friendnumber].avatar_send_data);
2172
2173 if (avsd->bytes_sent >= AVATAR_DATA_TRANSFER_LIMIT) {
2174 /* User reached data limit. Check timeout */
2175 uint64_t now = unix_time();
2176
2177 if (avsd->last_reset > 0
2178 && (avsd->last_reset + AVATAR_DATA_TRANSFER_TIMEOUT < now)) {
2179 avsd->bytes_sent = 0;
2180 avsd->last_reset = now;
2181 } else {
2182 /* Friend still rate-limitted. Send an error and stops. */
2183 LOGGER_DEBUG("Avatar data transfer limit reached. "
2184 "friendnumber = %u", friendnumber);
2185 send_avatar_data_control(m, friendnumber, AVATARDATACONTROL_ERROR);
2186 return 0;
2187 }
2188 }
2189
2190 /* Start the transmission with a DATA_START message. Format:
2191 * uint8_t format
2192 * uint8_t hash[AVATAR_HASH_LENGTH]
2193 * uint32_t total_length
2194 */
2195 LOGGER_DEBUG("Sending start msg to friend number %u. "
2196 "m->avatar_format = %u, m->avatar_data_length = %u",
2197 friendnumber, m->avatar_format, m->avatar_data_length);
2198 uint8_t start_data[1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)];
2199 uint32_t avatar_len = htonl(m->avatar_data_length);
2200
2201 start_data[0] = m->avatar_format;
2202 memcpy(start_data + 1, m->avatar_hash, AVATAR_HASH_LENGTH);
2203 memcpy(start_data + 1 + AVATAR_HASH_LENGTH, &avatar_len, sizeof(uint32_t));
2204
2205 avsd->bytes_sent += sizeof(start_data); /* For rate limit */
2206
2207 int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_START,
2208 start_data, sizeof(start_data), 0);
2209
2210 if (ret < 0) {
2211 /* Something went wrong, try to signal the error so the friend
2212 * can clear up the state. */
2213 send_avatar_data_control(m, friendnumber, AVATARDATACONTROL_ERROR);
2214 return 0;
2215 }
2216
2217 /* User have no avatar data, nothing more to do. */
2218 if (m->avatar_format == AVATARFORMAT_NONE)
2219 return 0;
2220
2221 /* Send the actual avatar data. */
2222 uint32_t offset = 0;
2223
2224 while (offset < m->avatar_data_length) {
2225 uint32_t chunk_len = m->avatar_data_length - offset;
2226
2227 if (chunk_len > AVATAR_DATA_MAX_CHUNK_SIZE)
2228 chunk_len = AVATAR_DATA_MAX_CHUNK_SIZE;
2229
2230 uint8_t chunk[AVATAR_DATA_MAX_CHUNK_SIZE];
2231 memcpy(chunk, m->avatar_data + offset, chunk_len);
2232 offset += chunk_len;
2233 avsd->bytes_sent += chunk_len; /* For rate limit */
2234
2235 int ret = write_cryptpacket_id(m, friendnumber,
2236 PACKET_ID_AVATAR_DATA_PUSH,
2237 chunk, chunk_len, 0);
2238
2239 if (ret < 0) {
2240 LOGGER_DEBUG("write_cryptpacket_id failed. ret = %d, "
2241 "friendnumber = %u, offset = %u",
2242 ret, friendnumber, offset);
2243 send_avatar_data_control(m, friendnumber, AVATARDATACONTROL_ERROR);
2244 return -1;
2245 }
2246 }
2247
2248 return 0;
2249 }
2250
2251 case AVATARDATACONTROL_ERROR: {
2252 if (m->friendlist[friendnumber].avatar_recv_data) {
2253 /* We were receiving the data, sender detected an error
2254 (eg. changing avatar) and asked us to stop. */
2255 free(m->friendlist[friendnumber].avatar_recv_data);
2256 m->friendlist[friendnumber].avatar_recv_data = NULL;
2257 }
2258
2259 return 0;
2260 }
2261 }
2262
2263 return -1;
2264}
2265
2266
2267static int handle_avatar_data_start(Messenger *m, uint32_t friendnumber,
2268 uint8_t *data, uint32_t data_length)
2269{
2270 LOGGER_DEBUG("data_length = %u, friendnumber = %u", data_length, friendnumber);
2271
2272 if (data_length != 1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)) {
2273 LOGGER_DEBUG("Invalid msg length = %u, friendnumber = %u",
2274 data_length, friendnumber);
2275 return -1;
2276 }
2277
2278 AVATARRECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
2279
2280 if (avrd == NULL) {
2281 LOGGER_DEBUG("Received an unrequested DATA_START, friendnumber = %u",
2282 friendnumber);
2283 return -1;
2284 }
2285
2286 if (avrd->started) {
2287 /* Already receiving data from this friend. Must be an error
2288 * or an malicious request, because we zeroed the started bit
2289 * when we requested the data. */
2290 LOGGER_DEBUG("Received an unrequested duplicated DATA_START, "
2291 "friendnumber = %u", friendnumber);
2292 return -1;
2293 }
2294
2295 /* Copy data from message to our control structure */
2296 avrd->started = 1;
2297 avrd->format = data[0];
2298 memcpy(avrd->hash, data + 1, AVATAR_HASH_LENGTH);
2299 uint32_t tmp_len;
2300 memcpy(&tmp_len, data + 1 + AVATAR_HASH_LENGTH, sizeof(uint32_t));
2301 avrd->total_length = ntohl(tmp_len);
2302 avrd->bytes_received = 0;
2303
2304 LOGGER_DEBUG("friendnumber = %u, avrd->format = %u, "
2305 "avrd->total_length = %u, avrd->bytes_received = %u",
2306 friendnumber, avrd->format, avrd->total_length,
2307 avrd->bytes_received);
2308
2309 if (avrd->total_length > MAX_AVATAR_DATA_LENGTH) {
2310 /* Invalid data length. Stops. */
2311 LOGGER_DEBUG("Error: total_length > MAX_AVATAR_DATA_LENGTH, "
2312 "friendnumber = %u", friendnumber);
2313 free(avrd);
2314 avrd = NULL;
2315 m->friendlist[friendnumber].avatar_recv_data = NULL;
2316 return 0;
2317 }
2318
2319 if (avrd->format == AVATARFORMAT_NONE || avrd->total_length == 0) {
2320 /* No real data to receive. Run callback function and finish. */
2321 LOGGER_DEBUG("format == NONE, friendnumber = %u", friendnumber);
2322
2323 if (m->avatar_data_recv) {
2324 memset(avrd->hash, 0, AVATAR_HASH_LENGTH);
2325 (m->avatar_data_recv)(m, friendnumber, avrd->format, avrd->hash,
2326 NULL, 0, m->avatar_data_recv_userdata);
2327 }
2328
2329 free(avrd);
2330 avrd = NULL;
2331 m->friendlist[friendnumber].avatar_recv_data = NULL;
2332 return 0;
2333 }
2334
2335 /* Waits for more data to be received */
2336 return 0;
2337}
2338
2339
2340static int handle_avatar_data_push(Messenger *m, uint32_t friendnumber,
2341 uint8_t *data, uint32_t data_length)
2342{
2343 LOGGER_DEBUG("friendnumber = %u, data_length = %u", friendnumber, data_length);
2344
2345 AVATARRECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
2346
2347 if (avrd == NULL) {
2348 /* No active transfer. It must be an error or a malicious request,
2349 * because we set the avatar_recv_data on the first DATA_START. */
2350 LOGGER_DEBUG("Error: avrd == NULL, friendnumber = %u", friendnumber);
2351 return -1; /* Error */
2352 }
2353
2354 if (avrd->started == 0) {
2355 /* Receiving data for a non-started request. Must be an error
2356 * or an malicious request. */
2357 LOGGER_DEBUG("Received an data push for a yet non started data "
2358 "request. friendnumber = %u", friendnumber);
2359 return -1; /* Error */
2360 }
2361
2362 uint32_t new_length = avrd->bytes_received + data_length;
2363
2364 if (new_length > avrd->total_length
2365 || new_length >= MAX_AVATAR_DATA_LENGTH) {
2366 /* Invalid data length due to error or malice. Stops. */
2367 LOGGER_DEBUG("Invalid data length. friendnumber = %u, "
2368 "new_length = %u, avrd->total_length = %u",
2369 friendnumber, new_length, avrd->total_length);
2370 free(avrd);
2371 m->friendlist[friendnumber].avatar_recv_data = NULL;
2372 return 0;
2373 }
2374
2375 memcpy(avrd->data + avrd->bytes_received, data, data_length);
2376 avrd->bytes_received += data_length;
2377
2378 if (avrd->bytes_received == avrd->total_length) {
2379 LOGGER_DEBUG("All data received. friendnumber = %u", friendnumber);
2380
2381 /* All data was received. Check if the hashes match. It the
2382 * requester's responsability to do this. The sender may have done
2383 * anything with its avatar data between the DATA_START and now.
2384 */
2385 uint8_t cur_hash[AVATAR_HASH_LENGTH];
2386 m_avatar_hash(cur_hash, avrd->data, avrd->bytes_received);
2387
2388 if (memcmp(cur_hash, avrd->hash, AVATAR_HASH_LENGTH) == 0) {
2389 /* Avatar successfuly received! */
2390 if (m->avatar_data_recv) {
2391 (m->avatar_data_recv)(m, friendnumber, avrd->format, cur_hash,
2392 avrd->data, avrd->bytes_received, m->avatar_data_recv_userdata);
2393 }
2394 } else {
2395 LOGGER_DEBUG("Avatar hash error. friendnumber = %u", friendnumber);
2396 }
2397
2398 free(avrd);
2399 m->friendlist[friendnumber].avatar_recv_data = NULL;
2400 return 0;
1976 } 2401 }
1977 2402
2403 /* Waits for more data to be received */
1978 return 0; 2404 return 0;
1979} 2405}
1980 2406
2407
2408
1981static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) 2409static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
1982{ 2410{
1983 if (len == 0) 2411 if (len == 0)
@@ -2115,6 +2543,42 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
2115 break; 2543 break;
2116 } 2544 }
2117 2545
2546 case PACKET_ID_AVATAR_INFO_REQ: {
2547 /* Send our avatar information */
2548 m_send_avatar_info(m, i);
2549 break;
2550 }
2551
2552 case PACKET_ID_AVATAR_INFO: {
2553 if (m->avatar_info_recv) {
2554 /*
2555 * A malicious user may send an incomplete avatar info message.
2556 * Check if it have the correct size for the format:
2557 * [1 uint8_t: avatar format] [32 uint8_t: hash]
2558 */
2559 if (data_length == AVATAR_HASH_LENGTH + 1) {
2560 (m->avatar_info_recv)(m, i, data[0], data + 1, m->avatar_info_recv_userdata);
2561 }
2562 }
2563
2564 break;
2565 }
2566
2567 case PACKET_ID_AVATAR_DATA_CONTROL: {
2568 handle_avatar_data_control(m, i, data, data_length);
2569 break;
2570 }
2571
2572 case PACKET_ID_AVATAR_DATA_START: {
2573 handle_avatar_data_start(m, i, data, data_length);
2574 break;
2575 }
2576
2577 case PACKET_ID_AVATAR_DATA_PUSH: {
2578 handle_avatar_data_push(m, i, data, data_length);
2579 break;
2580 }
2581
2118 case PACKET_ID_RECEIPT: { 2582 case PACKET_ID_RECEIPT: {
2119 uint32_t msgid; 2583 uint32_t msgid;
2120 2584
@@ -2343,6 +2807,11 @@ void do_friends(Messenger *m)
2343 m->friendlist[i].userstatus_sent = 1; 2807 m->friendlist[i].userstatus_sent = 1;
2344 } 2808 }
2345 2809
2810 if (m->friendlist[i].avatar_info_sent == 0) {
2811 if (m_send_avatar_info(m, i) == 0)
2812 m->friendlist[i].avatar_info_sent = 1;
2813 }
2814
2346 if (m->friendlist[i].user_istyping_sent == 0) { 2815 if (m->friendlist[i].user_istyping_sent == 0) {
2347 if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) 2816 if (send_user_istyping(m, i, m->friendlist[i].user_istyping))
2348 m->friendlist[i].user_istyping_sent = 1; 2817 m->friendlist[i].user_istyping_sent = 1;
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 6c641a9a..01632126 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -36,6 +36,9 @@
36#define MAX_NAME_LENGTH 128 36#define MAX_NAME_LENGTH 128
37/* TODO: this must depend on other variable. */ 37/* TODO: this must depend on other variable. */
38#define MAX_STATUSMESSAGE_LENGTH 1007 38#define MAX_STATUSMESSAGE_LENGTH 1007
39#define MAX_AVATAR_DATA_LENGTH 16384
40#define AVATAR_HASH_LENGTH 32
41
39 42
40#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) 43#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t))
41 44
@@ -46,6 +49,11 @@
46#define PACKET_ID_STATUSMESSAGE 49 49#define PACKET_ID_STATUSMESSAGE 49
47#define PACKET_ID_USERSTATUS 50 50#define PACKET_ID_USERSTATUS 50
48#define PACKET_ID_TYPING 51 51#define PACKET_ID_TYPING 51
52#define PACKET_ID_AVATAR_INFO_REQ 52
53#define PACKET_ID_AVATAR_INFO 53
54#define PACKET_ID_AVATAR_DATA_CONTROL 54
55#define PACKET_ID_AVATAR_DATA_START 55
56#define PACKET_ID_AVATAR_DATA_PUSH 56
49#define PACKET_ID_RECEIPT 63 57#define PACKET_ID_RECEIPT 63
50#define PACKET_ID_MESSAGE 64 58#define PACKET_ID_MESSAGE 64
51#define PACKET_ID_ACTION 65 59#define PACKET_ID_ACTION 65
@@ -109,6 +117,13 @@ enum {
109/* If no packets are received from friend in this time interval, kill the connection. */ 117/* If no packets are received from friend in this time interval, kill the connection. */
110#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) 118#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3)
111 119
120/* Must be < MAX_CRYPTO_DATA_SIZE */
121#define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1)
122
123/* Per-friend data limit for avatar data requests */
124#define AVATAR_DATA_TRANSFER_LIMIT (10*MAX_AVATAR_DATA_LENGTH)
125#define AVATAR_DATA_TRANSFER_TIMEOUT (20*60)
126
112 127
113/* USERSTATUS - 128/* USERSTATUS -
114 * Represents userstatuses someone can have. 129 * Represents userstatuses someone can have.
@@ -122,6 +137,42 @@ typedef enum {
122} 137}
123USERSTATUS; 138USERSTATUS;
124 139
140/* AVATARFORMAT -
141 * Data formats for user avatar images
142 */
143typedef enum {
144 AVATARFORMAT_NONE,
145 AVATARFORMAT_PNG
146}
147AVATARFORMAT;
148
149/* AVATARDATACONTROL
150 * To control avatar data requests (PACKET_ID_AVATAR_DATA_CONTROL)
151 */
152typedef enum {
153 AVATARDATACONTROL_REQ,
154 AVATARDATACONTROL_ERROR
155}
156AVATARDATACONTROL;
157
158typedef struct {
159 uint8_t started;
160 AVATARFORMAT format;
161 uint8_t hash[AVATAR_HASH_LENGTH];
162 uint32_t total_length;
163 uint32_t bytes_received;
164 uint8_t data[MAX_AVATAR_DATA_LENGTH];
165}
166AVATARRECEIVEDATA;
167
168typedef struct {
169 /* Fields only used to limit the network usage from a given friend */
170 uint32_t bytes_sent; /* Total bytes send to this user */
171 uint64_t last_reset; /* Time the data counter was last reset */
172}
173AVATARSENDDATA;
174
175
125struct File_Transfers { 176struct File_Transfers {
126 uint64_t size; 177 uint64_t size;
127 uint64_t transferred; 178 uint64_t transferred;
@@ -163,6 +214,7 @@ typedef struct {
163 uint8_t statusmessage_sent; 214 uint8_t statusmessage_sent;
164 USERSTATUS userstatus; 215 USERSTATUS userstatus;
165 uint8_t userstatus_sent; 216 uint8_t userstatus_sent;
217 uint8_t avatar_info_sent;
166 uint8_t user_istyping; 218 uint8_t user_istyping;
167 uint8_t user_istyping_sent; 219 uint8_t user_istyping_sent;
168 uint8_t is_typing; 220 uint8_t is_typing;
@@ -178,6 +230,9 @@ typedef struct {
178 int invited_groups[MAX_INVITED_GROUPS]; 230 int invited_groups[MAX_INVITED_GROUPS];
179 uint16_t invited_groups_num; 231 uint16_t invited_groups_num;
180 232
233 AVATARSENDDATA avatar_send_data;
234 AVATARRECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend.
235
181 struct { 236 struct {
182 int (*function)(void *object, const uint8_t *data, uint32_t len); 237 int (*function)(void *object, const uint8_t *data, uint32_t len);
183 void *object; 238 void *object;
@@ -209,6 +264,11 @@ typedef struct Messenger {
209 264
210 USERSTATUS userstatus; 265 USERSTATUS userstatus;
211 266
267 AVATARFORMAT avatar_format;
268 uint8_t *avatar_data;
269 uint32_t avatar_data_length;
270 uint8_t avatar_hash[AVATAR_HASH_LENGTH];
271
212 Friend *friendlist; 272 Friend *friendlist;
213 uint32_t numfriends; 273 uint32_t numfriends;
214 274
@@ -243,6 +303,10 @@ typedef struct Messenger {
243 void *friend_connectionstatuschange_userdata; 303 void *friend_connectionstatuschange_userdata;
244 void (*friend_connectionstatuschange_internal)(struct Messenger *m, int32_t, uint8_t, void *); 304 void (*friend_connectionstatuschange_internal)(struct Messenger *m, int32_t, uint8_t, void *);
245 void *friend_connectionstatuschange_internal_userdata; 305 void *friend_connectionstatuschange_internal_userdata;
306 void *avatar_info_recv_userdata;
307 void (*avatar_info_recv)(struct Messenger *m, int32_t, uint8_t, uint8_t *, void *);
308 void *avatar_data_recv_userdata;
309 void (*avatar_data_recv)(struct Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *);
246 310
247 void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, void *); 311 void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, void *);
248 void *group_invite_userdata; 312 void *group_invite_userdata;
@@ -437,6 +501,94 @@ int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen)
437uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); 501uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);
438uint8_t m_get_self_userstatus(const Messenger *m); 502uint8_t m_get_self_userstatus(const Messenger *m);
439 503
504
505/* Set the user avatar image data.
506 * This should be made before connecting, so we will not announce that the user have no avatar
507 * before setting and announcing a new one, forcing the peers to re-download it.
508 *
509 * Notice that the library treats the image as raw data and does not interpret it by any way.
510 *
511 * Arguments:
512 * format - Avatar image format or NONE for user with no avatar (see AVATARFORMAT);
513 * data - pointer to the avatar data (may be NULL it the format is NONE);
514 * length - length of image data. Must be <= MAX_AVATAR_DATA_LENGTH.
515 *
516 * returns 0 on success
517 * returns -1 on failure.
518 */
519int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length);
520
521/* Get avatar data from the current user.
522 * Copies the current user avatar data to the destination buffer and sets the image format
523 * accordingly.
524 *
525 * If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and
526 * 'length' is set to zero.
527 *
528 * If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored.
529 *
530 * Arguments:
531 * format - destination pointer to the avatar image format (see AVATARFORMAT);
532 * buf - destination buffer to the image data. Must have at least 'maxlen' bytes;
533 * length - destination pointer to the image data length;
534 * maxlen - length of the destination buffer 'buf';
535 * hash - destination pointer to the avatar hash (it must be exactly AVATAR_HASH_LENGTH bytes long).
536 *
537 * returns 0 on success;
538 * returns -1 on failure.
539 *
540 */
541int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
542 uint8_t *hash);
543
544/* Generates a cryptographic hash of the given avatar data.
545 * This function is a wrapper to internal message-digest functions and specifically provided
546 * to generate hashes from user avatars that may be memcmp()ed with the values returned by the
547 * other avatar functions. It is specially important to validate cached avatars.
548 *
549 * Arguments:
550 * hash - destination buffer for the hash data, it must be exactly AVATAR_HASH_LENGTH bytes long.
551 * data - avatar image data;
552 * datalen - length of the avatar image data; it must be <= MAX_AVATAR_DATA_LENGTH.
553 *
554 * returns 0 on success
555 * returns -1 on failure.
556 */
557int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen);
558
559/* Request avatar information from a friend.
560 * Asks a friend to provide their avatar information (image format and hash). The friend may
561 * or may not answer this request and, if answered, the information will be provided through
562 * the callback 'avatar_info'.
563 *
564 * returns 0 on success
565 * returns -1 on failure.
566 */
567int m_request_avatar_info(const Messenger *m, const int32_t friendnumber);
568
569/* Send an unrequested avatar information to a friend.
570 * Sends our avatar format and hash to a friend; he/she can use this information to validate
571 * an avatar from the cache and may (or not) reply with an avatar data request.
572 *
573 * Notice: it is NOT necessary to send these notification after changing the avatar or
574 * connecting. The library already does this.
575 *
576 * returns 0 on success
577 * returns -1 on failure.
578 */
579int m_send_avatar_info(const Messenger *m, const int32_t friendnumber);
580
581
582/* Request the avatar data from a friend.
583 * Ask a friend to send their avatar data. The friend may or may not answer this request and,
584 * if answered, the information will be provided in callback 'avatar_data'.
585 *
586 * returns 0 on sucess
587 * returns -1 on failure.
588 */
589int m_request_avatar_data(const Messenger *m, const int32_t friendnumber);
590
591
440/* returns timestamp of last time friendnumber was seen online, or 0 if never seen. 592/* returns timestamp of last time friendnumber was seen online, or 0 if never seen.
441 * returns -1 on error. 593 * returns -1 on error.
442 */ 594 */
@@ -533,6 +685,49 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in
533void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), 685void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *),
534 void *userdata); 686 void *userdata);
535 687
688
689/* Set the callback function for avatar information.
690 * This callback will be called when avatar information are received from friends. These events
691 * can arrive at anytime, but are usually received uppon connection and in reply of avatar
692 * information requests.
693 *
694 * Function format is:
695 * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata)
696 *
697 * where 'format' is the avatar image format (see AVATARFORMAT) and 'hash' is the hash of
698 * the avatar data for caching purposes and it is exactly AVATAR_HASH_LENGTH long. If the
699 * image format is NONE, the hash is zeroed.
700 *
701 */
702void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t *, void *),
703 void *userdata);
704
705
706/* Set the callback function for avatar data.
707 * This callback will be called when the complete avatar data was correctly received from a
708 * friend. This only happens in reply of a avatar data request (see tox_request_avatar_data);
709 *
710 * Function format is:
711 * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)
712 *
713 * where 'format' is the avatar image format (see AVATARFORMAT); 'hash' is the
714 * locally-calculated cryptographic hash of the avatar data and it is exactly
715 * AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length
716 * of such data.
717 *
718 * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is
719 * always validated locally with the function tox_avatar_hash and ensured to match the image
720 * data, so this value can be safely used to compare with cached avatars.
721 *
722 * WARNING: users MUST treat all avatar image data received from another peer as untrusted and
723 * potentially malicious. The library only ensures that the data which arrived is the same the
724 * other user sent, and does not interpret or validate any image data.
725 */
726void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *,
727 uint32_t, void *), void *userdata);
728
729
730
536/**********GROUP CHATS************/ 731/**********GROUP CHATS************/
537 732
538/* Set the callback for group invites. 733/* Set the callback for group invites.
diff --git a/toxcore/tox.c b/toxcore/tox.c
index a4413c4f..c5bea846 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -275,6 +275,42 @@ uint8_t tox_get_self_user_status(const Tox *tox)
275 return m_get_self_userstatus(m); 275 return m_get_self_userstatus(m);
276} 276}
277 277
278int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length)
279{
280 Messenger *m = tox;
281 return m_set_avatar(m, format, data, length);
282}
283
284int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash)
285{
286 const Messenger *m = tox;
287 return m_get_self_avatar(m, format, buf, length, maxlen, hash);
288}
289
290int tox_avatar_hash(const Tox *tox, uint8_t *hash, const uint8_t *data, const uint32_t datalen)
291{
292 return m_avatar_hash(hash, data, datalen);
293}
294
295int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber)
296{
297 const Messenger *m = tox;
298 return m_request_avatar_info(m, friendnumber);
299}
300
301int tox_send_avatar_info(Tox *tox, const int32_t friendnumber)
302{
303 const Messenger *m = tox;
304 return m_send_avatar_info(m, friendnumber);
305}
306
307int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber)
308{
309 const Messenger *m = tox;
310 return m_request_avatar_data(m, friendnumber);
311}
312
313
278/* returns timestamp of last time friendnumber was seen online, or 0 if never seen. 314/* returns timestamp of last time friendnumber was seen online, or 0 if never seen.
279 * returns -1 on error. 315 * returns -1 on error.
280 */ 316 */
@@ -439,6 +475,24 @@ void tox_callback_connection_status(Tox *tox, void (*function)(Messenger *tox, i
439 m_callback_connectionstatus(m, function, userdata); 475 m_callback_connectionstatus(m, function, userdata);
440} 476}
441 477
478void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *), void *userdata)
479{
480 Messenger *m = tox;
481 m_callback_avatar_info(m, function, userdata);
482}
483
484
485void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t,
486 void *), void *userdata)
487{
488 Messenger *m = tox;
489 m_callback_avatar_data(m, function, userdata);
490}
491
492
493
494
495
442/**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/ 496/**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/
443 497
444/* Functions to get/set the nospam part of the id. 498/* Functions to get/set the nospam part of the id.
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 278a19cd..8f54697f 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -37,6 +37,8 @@ extern "C" {
37#define TOX_MAX_MESSAGE_LENGTH 1368 37#define TOX_MAX_MESSAGE_LENGTH 1368
38#define TOX_MAX_STATUSMESSAGE_LENGTH 1007 38#define TOX_MAX_STATUSMESSAGE_LENGTH 1007
39#define TOX_CLIENT_ID_SIZE 32 39#define TOX_CLIENT_ID_SIZE 32
40#define TOX_MAX_AVATAR_DATA_LENGTH 16384
41#define TOX_AVATAR_HASH_LENGTH 32
40 42
41#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) 43#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
42 44
@@ -70,6 +72,16 @@ typedef enum {
70} 72}
71TOX_USERSTATUS; 73TOX_USERSTATUS;
72 74
75
76/* AVATARFORMAT -
77 * Data formats for user avatar images
78 */
79typedef enum {
80 TOX_AVATARFORMAT_NONE,
81 TOX_AVATARFORMAT_PNG
82}
83TOX_AVATARFORMAT;
84
73#ifndef __TOX_DEFINED__ 85#ifndef __TOX_DEFINED__
74#define __TOX_DEFINED__ 86#define __TOX_DEFINED__
75typedef struct Tox Tox; 87typedef struct Tox Tox;
@@ -243,6 +255,97 @@ uint8_t tox_get_user_status(const Tox *tox, int32_t friendnumber);
243uint8_t tox_get_self_user_status(const Tox *tox); 255uint8_t tox_get_self_user_status(const Tox *tox);
244 256
245 257
258/* Set the user avatar image data.
259 * This should be made before connecting, so we will not announce that the user have no avatar
260 * before setting and announcing a new one, forcing the peers to re-download it.
261 *
262 * Notice that the library treats the image as raw data and does not interpret it by any way.
263 *
264 * Arguments:
265 * format - Avatar image format or NONE for user with no avatar (see TOX_AVATARFORMAT);
266 * data - pointer to the avatar data (may be NULL it the format is NONE);
267 * length - length of image data. Must be <= TOX_MAX_AVATAR_DATA_LENGTH.
268 *
269 * returns 0 on success
270 * returns -1 on failure.
271 */
272int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
273
274
275/* Get avatar data from the current user.
276 * Copies the current user avatar data to the destination buffer and sets the image format
277 * accordingly.
278 *
279 * If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and
280 * 'length' is set to zero.
281 *
282 * If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored.
283 *
284 * Arguments:
285 * format - destination pointer to the avatar image format (see TOX_AVATARFORMAT);
286 * buf - destination buffer to the image data. Must have at least 'maxlen' bytes;
287 * length - destination pointer to the image data length;
288 * maxlen - length of the destination buffer 'buf';
289 * hash - destination pointer to the avatar hash (it must be exactly TOX_AVATAR_HASH_LENGTH bytes long).
290 *
291 * returns 0 on success;
292 * returns -1 on failure.
293 *
294 */
295int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
296 uint8_t *hash);
297
298
299/* Generates a cryptographic hash of the given avatar data.
300 * This function is a wrapper to internal message-digest functions and specifically provided
301 * to generate hashes from user avatars that may be memcmp()ed with the values returned by the
302 * other avatar functions. It is specially important to validate cached avatars.
303 *
304 * Arguments:
305 * hash - destination buffer for the hash data, it must be exactly TOX_AVATAR_HASH_LENGTH bytes long.
306 * data - avatar image data;
307 * datalen - length of the avatar image data; it must be <= TOX_MAX_AVATAR_DATA_LENGTH.
308 *
309 * returns 0 on success
310 * returns -1 on failure.
311 */
312int tox_avatar_hash(const Tox *tox, uint8_t *hash, const uint8_t *data, const uint32_t datalen);
313
314
315/* Request avatar information from a friend.
316 * Asks a friend to provide their avatar information (image format and hash). The friend may
317 * or may not answer this request and, if answered, the information will be provided through
318 * the callback 'avatar_info'.
319 *
320 * returns 0 on success
321 * returns -1 on failure.
322 */
323int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber);
324
325
326/* Send an unrequested avatar information to a friend.
327 * Sends our avatar format and hash to a friend; he/she can use this information to validate
328 * an avatar from the cache and may (or not) reply with an avatar data request.
329 *
330 * Notice: it is NOT necessary to send these notification after changing the avatar or
331 * connecting. The library already does this.
332 *
333 * returns 0 on success
334 * returns -1 on failure.
335 */
336int tox_send_avatar_info(Tox *tox, const int32_t friendnumber);
337
338
339/* Request the avatar data from a friend.
340 * Ask a friend to send their avatar data. The friend may or may not answer this request and,
341 * if answered, the information will be provided in callback 'avatar_data'.
342 *
343 * returns 0 on sucess
344 * returns -1 on failure.
345 */
346int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber);
347
348
246/* returns timestamp of last time friendnumber was seen online, or 0 if never seen. 349/* returns timestamp of last time friendnumber was seen online, or 0 if never seen.
247 * returns -1 on error. 350 * returns -1 on error.
248 */ 351 */
@@ -344,6 +447,48 @@ void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int32_t, uin
344 */ 447 */
345void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); 448void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata);
346 449
450/* Set the callback function for avatar information.
451 * This callback will be called when avatar information are received from friends. These events
452 * can arrive at anytime, but are usually received uppon connection and in reply of avatar
453 * information requests.
454 *
455 * Function format is:
456 * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata)
457 *
458 * where 'format' is the avatar image format (see TOX_AVATARFORMAT) and 'hash' is the hash of
459 * the avatar data for caching purposes and it is exactly TOX_AVATAR_HASH_LENGTH long. If the
460 * image format is NONE, the hash is zeroed.
461 *
462 */
463void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *),
464 void *userdata);
465
466
467/* Set the callback function for avatar data.
468 * This callback will be called when the complete avatar data was correctly received from a
469 * friend. This only happens in reply of a avatar data request (see tox_request_avatar_data);
470 *
471 * Function format is:
472 * function(Tox *tox, int32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)
473 *
474 * where 'format' is the avatar image format (see TOX_AVATARFORMAT); 'hash' is the
475 * locally-calculated cryptographic hash of the avatar data and it is exactly
476 * TOX_AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length
477 * of such data.
478 *
479 * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is
480 * always validated locally with the function tox_avatar_hash and ensured to match the image
481 * data, so this value can be safely used to compare with cached avatars.
482 *
483 * WARNING: users MUST treat all avatar image data received from another peer as untrusted and
484 * potentially malicious. The library only ensures that the data which arrived is the same the
485 * other user sent, and does not interpret or validate any image data.
486 */
487void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t,
488 void *), void *userdata);
489
490
491
347 492
348/**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/ 493/**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/
349 494