diff options
Diffstat (limited to 'toxcore/Messenger.c')
-rw-r--r-- | toxcore/Messenger.c | 469 |
1 files changed, 469 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 @@ | |||
42 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); | 42 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); |
43 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, | 43 | static 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); |
45 | static 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 |
47 | static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) | 48 | static 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 | ||
573 | int 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 | |||
609 | int 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 | |||
631 | int 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 | |||
641 | int 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 | |||
652 | int 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 | |||
669 | int 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 | ||
943 | void 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 | |||
950 | void 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 | |||
809 | static void break_files(const Messenger *m, int32_t friendnumber); | 957 | static void break_files(const Messenger *m, int32_t friendnumber); |
810 | static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status) | 958 | static 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 | */ | ||
2143 | static 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 | |||
2154 | static 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 | |||
2267 | static 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 | |||
2340 | static 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 | |||
1981 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | 2409 | static 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; |