diff options
Diffstat (limited to 'toxcore')
-rw-r--r-- | toxcore/Messenger.c | 486 | ||||
-rw-r--r-- | toxcore/Messenger.h | 213 |
2 files changed, 0 insertions, 699 deletions
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index e5298b31..863259ac 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -39,7 +39,6 @@ | |||
39 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); | 39 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); |
40 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, | 40 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, |
41 | uint32_t length, uint8_t congestion_control); | 41 | uint32_t length, uint8_t congestion_control); |
42 | static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, uint8_t op); | ||
43 | 42 | ||
44 | // friend_not_valid determines if the friendnumber passed is valid in the Messenger object | 43 | // friend_not_valid determines if the friendnumber passed is valid in the Messenger object |
45 | static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) | 44 | static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) |
@@ -208,10 +207,6 @@ static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t sta | |||
208 | id_copy(m->friendlist[i].real_pk, real_pk); | 207 | id_copy(m->friendlist[i].real_pk, real_pk); |
209 | m->friendlist[i].statusmessage_length = 0; | 208 | m->friendlist[i].statusmessage_length = 0; |
210 | m->friendlist[i].userstatus = USERSTATUS_NONE; | 209 | m->friendlist[i].userstatus = USERSTATUS_NONE; |
211 | m->friendlist[i].avatar_info_sent = 0; | ||
212 | m->friendlist[i].avatar_recv_data = NULL; | ||
213 | m->friendlist[i].avatar_send_data.bytes_sent = 0; | ||
214 | m->friendlist[i].avatar_send_data.last_reset = 0; | ||
215 | m->friendlist[i].is_typing = 0; | 210 | m->friendlist[i].is_typing = 0; |
216 | m->friendlist[i].message_id = 0; | 211 | m->friendlist[i].message_id = 0; |
217 | friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, | 212 | friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, |
@@ -397,7 +392,6 @@ int m_delfriend(Messenger *m, int32_t friendnumber) | |||
397 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | 392 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) |
398 | remove_online_friend(m, friendnumber); | 393 | remove_online_friend(m, friendnumber); |
399 | 394 | ||
400 | free(m->friendlist[friendnumber].avatar_recv_data); | ||
401 | clear_receipts(m, friendnumber); | 395 | clear_receipts(m, friendnumber); |
402 | remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); | 396 | remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); |
403 | friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); | 397 | friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); |
@@ -656,149 +650,6 @@ int m_set_userstatus(Messenger *m, uint8_t status) | |||
656 | return 0; | 650 | return 0; |
657 | } | 651 | } |
658 | 652 | ||
659 | int m_unset_avatar(Messenger *m) | ||
660 | { | ||
661 | if (m->avatar_data != NULL) | ||
662 | free(m->avatar_data); | ||
663 | |||
664 | m->avatar_data = NULL; | ||
665 | m->avatar_data_length = 0; | ||
666 | m->avatar_format = AVATAR_FORMAT_NONE; | ||
667 | memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH); | ||
668 | |||
669 | uint32_t i; | ||
670 | |||
671 | for (i = 0; i < m->numfriends; ++i) | ||
672 | m->friendlist[i].avatar_info_sent = 0; | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length) | ||
678 | { | ||
679 | if (format == AVATAR_FORMAT_NONE) { | ||
680 | m_unset_avatar(m); | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | if (length > AVATAR_MAX_DATA_LENGTH || length == 0) | ||
685 | return -1; | ||
686 | |||
687 | if (data == NULL) | ||
688 | return -1; | ||
689 | |||
690 | uint8_t *tmp = realloc(m->avatar_data, length); | ||
691 | |||
692 | if (tmp == NULL) | ||
693 | return -1; | ||
694 | |||
695 | m->avatar_format = format; | ||
696 | m->avatar_data = tmp; | ||
697 | m->avatar_data_length = length; | ||
698 | memcpy(m->avatar_data, data, length); | ||
699 | |||
700 | m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length); | ||
701 | |||
702 | uint32_t i; | ||
703 | |||
704 | for (i = 0; i < m->numfriends; ++i) | ||
705 | m->friendlist[i].avatar_info_sent = 0; | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, | ||
711 | uint8_t *hash) | ||
712 | { | ||
713 | if (format) | ||
714 | *format = m->avatar_format; | ||
715 | |||
716 | if (length) | ||
717 | *length = m->avatar_data_length; | ||
718 | |||
719 | if (hash) | ||
720 | memcpy(hash, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
721 | |||
722 | if (buf != NULL && maxlen > 0) { | ||
723 | if (m->avatar_data_length <= maxlen) | ||
724 | memcpy(buf, m->avatar_data, m->avatar_data_length); | ||
725 | else | ||
726 | return -1; | ||
727 | } | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen) | ||
733 | { | ||
734 | if (hash == NULL) | ||
735 | return -1; | ||
736 | |||
737 | return crypto_hash_sha256(hash, data, datalen); | ||
738 | } | ||
739 | |||
740 | int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen) | ||
741 | { | ||
742 | return m_hash(hash, data, datalen); | ||
743 | } | ||
744 | |||
745 | int m_request_avatar_info(const Messenger *m, const int32_t friendnumber) | ||
746 | { | ||
747 | if (friend_not_valid(m, friendnumber)) | ||
748 | return -1; | ||
749 | |||
750 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO_REQ, 0, 0, 0)) | ||
751 | return 0; | ||
752 | else | ||
753 | return -1; | ||
754 | } | ||
755 | |||
756 | int m_send_avatar_info(const Messenger *m, const int32_t friendnumber) | ||
757 | { | ||
758 | if (friend_not_valid(m, friendnumber)) | ||
759 | return -1; | ||
760 | |||
761 | uint8_t data[sizeof(uint8_t) + AVATAR_HASH_LENGTH]; | ||
762 | data[0] = m->avatar_format; | ||
763 | memcpy(data + 1, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
764 | |||
765 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO, data, sizeof(data), 0)) | ||
766 | return 0; | ||
767 | else | ||
768 | return -1; | ||
769 | } | ||
770 | |||
771 | int m_request_avatar_data(const Messenger *m, const int32_t friendnumber) | ||
772 | { | ||
773 | if (friend_not_valid(m, friendnumber)) | ||
774 | return -1; | ||
775 | |||
776 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
777 | |||
778 | if (avrd == NULL) { | ||
779 | avrd = calloc(sizeof(AVATAR_RECEIVEDATA), 1); | ||
780 | |||
781 | if (avrd == NULL) | ||
782 | return -1; | ||
783 | |||
784 | avrd->started = 0; | ||
785 | m->friendlist[friendnumber].avatar_recv_data = avrd; | ||
786 | } | ||
787 | |||
788 | if (avrd->started) { | ||
789 | LOGGER_DEBUG("Resetting already started data request. " | ||
790 | "friendnumber == %u", friendnumber); | ||
791 | } | ||
792 | |||
793 | avrd->started = 0; | ||
794 | avrd->bytes_received = 0; | ||
795 | avrd->total_length = 0; | ||
796 | avrd->format = AVATAR_FORMAT_NONE; | ||
797 | |||
798 | return send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_REQ); | ||
799 | } | ||
800 | |||
801 | |||
802 | /* return the size of friendnumber's user status. | 653 | /* return the size of friendnumber's user status. |
803 | * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. | 654 | * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. |
804 | */ | 655 | */ |
@@ -1021,20 +872,6 @@ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Mess | |||
1021 | m->friend_connectionstatuschange_internal_userdata = userdata; | 872 | m->friend_connectionstatuschange_internal_userdata = userdata; |
1022 | } | 873 | } |
1023 | 874 | ||
1024 | void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *), | ||
1025 | void *userdata) | ||
1026 | { | ||
1027 | m->avatar_info_recv = function; | ||
1028 | m->avatar_info_recv_userdata = userdata; | ||
1029 | } | ||
1030 | |||
1031 | void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, | ||
1032 | uint32_t, void *), void *userdata) | ||
1033 | { | ||
1034 | m->avatar_data_recv = function; | ||
1035 | m->avatar_data_recv_userdata = userdata; | ||
1036 | } | ||
1037 | |||
1038 | static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber) | 875 | static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber) |
1039 | { | 876 | { |
1040 | int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; | 877 | int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; |
@@ -1646,9 +1483,6 @@ Messenger *new_messenger(Messenger_Options *options) | |||
1646 | m->net = new_networking(ip, TOX_PORT_DEFAULT); | 1483 | m->net = new_networking(ip, TOX_PORT_DEFAULT); |
1647 | } | 1484 | } |
1648 | 1485 | ||
1649 | m->avatar_format = AVATAR_FORMAT_NONE; | ||
1650 | m->avatar_data = NULL; | ||
1651 | |||
1652 | if (m->net == NULL) { | 1486 | if (m->net == NULL) { |
1653 | free(m); | 1487 | free(m); |
1654 | return NULL; | 1488 | return NULL; |
@@ -1714,11 +1548,9 @@ void kill_messenger(Messenger *m) | |||
1714 | kill_networking(m->net); | 1548 | kill_networking(m->net); |
1715 | 1549 | ||
1716 | for (i = 0; i < m->numfriends; ++i) { | 1550 | for (i = 0; i < m->numfriends; ++i) { |
1717 | free(m->friendlist[i].avatar_recv_data); | ||
1718 | clear_receipts(m, i); | 1551 | clear_receipts(m, i); |
1719 | } | 1552 | } |
1720 | 1553 | ||
1721 | free(m->avatar_data); | ||
1722 | free(m->friendlist); | 1554 | free(m->friendlist); |
1723 | free(m); | 1555 | free(m); |
1724 | } | 1556 | } |
@@ -1752,293 +1584,16 @@ static int handle_status(void *object, int i, uint8_t status) | |||
1752 | m->friendlist[i].userstatus_sent = 0; | 1584 | m->friendlist[i].userstatus_sent = 0; |
1753 | m->friendlist[i].statusmessage_sent = 0; | 1585 | m->friendlist[i].statusmessage_sent = 0; |
1754 | m->friendlist[i].user_istyping_sent = 0; | 1586 | m->friendlist[i].user_istyping_sent = 0; |
1755 | m->friendlist[i].avatar_info_sent = 0; | ||
1756 | m->friendlist[i].ping_lastrecv = temp_time; | 1587 | m->friendlist[i].ping_lastrecv = temp_time; |
1757 | } else { /* Went offline. */ | 1588 | } else { /* Went offline. */ |
1758 | if (m->friendlist[i].status == FRIEND_ONLINE) { | 1589 | if (m->friendlist[i].status == FRIEND_ONLINE) { |
1759 | set_friend_status(m, i, FRIEND_CONFIRMED); | 1590 | set_friend_status(m, i, FRIEND_CONFIRMED); |
1760 | } | 1591 | } |
1761 | |||
1762 | /* Clear avatar transfer state */ | ||
1763 | if (m->friendlist[i].avatar_recv_data) { | ||
1764 | free(m->friendlist[i].avatar_recv_data); | ||
1765 | m->friendlist[i].avatar_recv_data = NULL; | ||
1766 | } | ||
1767 | } | ||
1768 | |||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | |||
1773 | /* Sends an avatar data control packet to the peer. Usually to return status | ||
1774 | * values or request data. | ||
1775 | */ | ||
1776 | static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, | ||
1777 | uint8_t op) | ||
1778 | { | ||
1779 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_CONTROL, | ||
1780 | &op, sizeof(op), 0); | ||
1781 | LOGGER_DEBUG("friendnumber = %u, op = %u, ret = %d", | ||
1782 | friendnumber, op, ret); | ||
1783 | return ret ? 0 : -1; | ||
1784 | } | ||
1785 | |||
1786 | |||
1787 | static int handle_avatar_data_control(Messenger *m, uint32_t friendnumber, | ||
1788 | uint8_t *data, uint32_t data_length) | ||
1789 | { | ||
1790 | if (data_length != 1) { | ||
1791 | LOGGER_DEBUG("Error: PACKET_ID_AVATAR_DATA_CONTROL with bad " | ||
1792 | "data_length = %u, friendnumber = %u", | ||
1793 | data_length, friendnumber); | ||
1794 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1795 | return -1; /* Error */ | ||
1796 | } | ||
1797 | |||
1798 | LOGGER_DEBUG("friendnumber = %u, op = %u", friendnumber, data[0]); | ||
1799 | |||
1800 | switch (data[0]) { | ||
1801 | case AVATAR_DATACONTROL_REQ: { | ||
1802 | |||
1803 | /* Check data transfer limits for this friend */ | ||
1804 | AVATAR_SENDDATA *const avsd = &(m->friendlist[friendnumber].avatar_send_data); | ||
1805 | |||
1806 | if (avsd->bytes_sent >= AVATAR_DATA_TRANSFER_LIMIT) { | ||
1807 | /* User reached data limit. Check timeout */ | ||
1808 | uint64_t now = unix_time(); | ||
1809 | |||
1810 | if (avsd->last_reset > 0 | ||
1811 | && (avsd->last_reset + AVATAR_DATA_TRANSFER_TIMEOUT < now)) { | ||
1812 | avsd->bytes_sent = 0; | ||
1813 | avsd->last_reset = now; | ||
1814 | } else { | ||
1815 | /* Friend still rate-limitted. Send an error and stops. */ | ||
1816 | LOGGER_DEBUG("Avatar data transfer limit reached. " | ||
1817 | "friendnumber = %u", friendnumber); | ||
1818 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1819 | return 0; | ||
1820 | } | ||
1821 | } | ||
1822 | |||
1823 | /* Start the transmission with a DATA_START message. Format: | ||
1824 | * uint8_t format | ||
1825 | * uint8_t hash[AVATAR_HASH_LENGTH] | ||
1826 | * uint32_t total_length | ||
1827 | */ | ||
1828 | LOGGER_DEBUG("Sending start msg to friend number %u. " | ||
1829 | "m->avatar_format = %u, m->avatar_data_length = %u", | ||
1830 | friendnumber, m->avatar_format, m->avatar_data_length); | ||
1831 | uint8_t start_data[1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)]; | ||
1832 | uint32_t avatar_len = htonl(m->avatar_data_length); | ||
1833 | |||
1834 | start_data[0] = m->avatar_format; | ||
1835 | memcpy(start_data + 1, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
1836 | memcpy(start_data + 1 + AVATAR_HASH_LENGTH, &avatar_len, sizeof(uint32_t)); | ||
1837 | |||
1838 | avsd->bytes_sent += sizeof(start_data); /* For rate limit */ | ||
1839 | |||
1840 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_START, | ||
1841 | start_data, sizeof(start_data), 0); | ||
1842 | |||
1843 | if (!ret) { | ||
1844 | /* Something went wrong, try to signal the error so the friend | ||
1845 | * can clear up the state. */ | ||
1846 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1847 | return 0; | ||
1848 | } | ||
1849 | |||
1850 | /* User have no avatar data, nothing more to do. */ | ||
1851 | if (m->avatar_format == AVATAR_FORMAT_NONE) | ||
1852 | return 0; | ||
1853 | |||
1854 | /* Send the actual avatar data. */ | ||
1855 | uint32_t offset = 0; | ||
1856 | |||
1857 | while (offset < m->avatar_data_length) { | ||
1858 | uint32_t chunk_len = m->avatar_data_length - offset; | ||
1859 | |||
1860 | if (chunk_len > AVATAR_DATA_MAX_CHUNK_SIZE) | ||
1861 | chunk_len = AVATAR_DATA_MAX_CHUNK_SIZE; | ||
1862 | |||
1863 | uint8_t chunk[AVATAR_DATA_MAX_CHUNK_SIZE]; | ||
1864 | memcpy(chunk, m->avatar_data + offset, chunk_len); | ||
1865 | offset += chunk_len; | ||
1866 | avsd->bytes_sent += chunk_len; /* For rate limit */ | ||
1867 | |||
1868 | int ret = write_cryptpacket_id(m, friendnumber, | ||
1869 | PACKET_ID_AVATAR_DATA_PUSH, | ||
1870 | chunk, chunk_len, 0); | ||
1871 | |||
1872 | if (!ret) { | ||
1873 | LOGGER_DEBUG("write_cryptpacket_id failed. ret = %d, " | ||
1874 | "friendnumber = %u, offset = %u", | ||
1875 | ret, friendnumber, offset); | ||
1876 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1877 | return -1; | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | return 0; | ||
1882 | } | ||
1883 | |||
1884 | case AVATAR_DATACONTROL_ERROR: { | ||
1885 | if (m->friendlist[friendnumber].avatar_recv_data) { | ||
1886 | /* We were receiving the data, sender detected an error | ||
1887 | (eg. changing avatar) and asked us to stop. */ | ||
1888 | free(m->friendlist[friendnumber].avatar_recv_data); | ||
1889 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1890 | } | ||
1891 | |||
1892 | return 0; | ||
1893 | } | ||
1894 | } | ||
1895 | |||
1896 | return -1; | ||
1897 | } | ||
1898 | |||
1899 | |||
1900 | static int handle_avatar_data_start(Messenger *m, uint32_t friendnumber, | ||
1901 | uint8_t *data, uint32_t data_length) | ||
1902 | { | ||
1903 | LOGGER_DEBUG("data_length = %u, friendnumber = %u", data_length, friendnumber); | ||
1904 | |||
1905 | if (data_length != 1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)) { | ||
1906 | LOGGER_DEBUG("Invalid msg length = %u, friendnumber = %u", | ||
1907 | data_length, friendnumber); | ||
1908 | return -1; | ||
1909 | } | 1592 | } |
1910 | 1593 | ||
1911 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
1912 | |||
1913 | if (avrd == NULL) { | ||
1914 | LOGGER_DEBUG("Received an unrequested DATA_START, friendnumber = %u", | ||
1915 | friendnumber); | ||
1916 | return -1; | ||
1917 | } | ||
1918 | |||
1919 | if (avrd->started) { | ||
1920 | /* Already receiving data from this friend. Must be an error | ||
1921 | * or an malicious request, because we zeroed the started bit | ||
1922 | * when we requested the data. */ | ||
1923 | LOGGER_DEBUG("Received an unrequested duplicated DATA_START, " | ||
1924 | "friendnumber = %u", friendnumber); | ||
1925 | return -1; | ||
1926 | } | ||
1927 | |||
1928 | /* Copy data from message to our control structure */ | ||
1929 | avrd->started = 1; | ||
1930 | avrd->format = data[0]; | ||
1931 | memcpy(avrd->hash, data + 1, AVATAR_HASH_LENGTH); | ||
1932 | uint32_t tmp_len; | ||
1933 | memcpy(&tmp_len, data + 1 + AVATAR_HASH_LENGTH, sizeof(uint32_t)); | ||
1934 | avrd->total_length = ntohl(tmp_len); | ||
1935 | avrd->bytes_received = 0; | ||
1936 | |||
1937 | LOGGER_DEBUG("friendnumber = %u, avrd->format = %u, " | ||
1938 | "avrd->total_length = %u, avrd->bytes_received = %u", | ||
1939 | friendnumber, avrd->format, avrd->total_length, | ||
1940 | avrd->bytes_received); | ||
1941 | |||
1942 | if (avrd->total_length > AVATAR_MAX_DATA_LENGTH) { | ||
1943 | /* Invalid data length. Stops. */ | ||
1944 | LOGGER_DEBUG("Error: total_length > MAX_AVATAR_DATA_LENGTH, " | ||
1945 | "friendnumber = %u", friendnumber); | ||
1946 | free(avrd); | ||
1947 | avrd = NULL; | ||
1948 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1949 | return 0; | ||
1950 | } | ||
1951 | |||
1952 | if (avrd->format == AVATAR_FORMAT_NONE || avrd->total_length == 0) { | ||
1953 | /* No real data to receive. Run callback function and finish. */ | ||
1954 | LOGGER_DEBUG("format == NONE, friendnumber = %u", friendnumber); | ||
1955 | |||
1956 | if (m->avatar_data_recv) { | ||
1957 | memset(avrd->hash, 0, AVATAR_HASH_LENGTH); | ||
1958 | (m->avatar_data_recv)(m, friendnumber, avrd->format, avrd->hash, | ||
1959 | NULL, 0, m->avatar_data_recv_userdata); | ||
1960 | } | ||
1961 | |||
1962 | free(avrd); | ||
1963 | avrd = NULL; | ||
1964 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1965 | return 0; | ||
1966 | } | ||
1967 | |||
1968 | /* Waits for more data to be received */ | ||
1969 | return 0; | ||
1970 | } | ||
1971 | |||
1972 | |||
1973 | static int handle_avatar_data_push(Messenger *m, uint32_t friendnumber, | ||
1974 | uint8_t *data, uint32_t data_length) | ||
1975 | { | ||
1976 | LOGGER_DEBUG("friendnumber = %u, data_length = %u", friendnumber, data_length); | ||
1977 | |||
1978 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
1979 | |||
1980 | if (avrd == NULL) { | ||
1981 | /* No active transfer. It must be an error or a malicious request, | ||
1982 | * because we set the avatar_recv_data on the first DATA_START. */ | ||
1983 | LOGGER_DEBUG("Error: avrd == NULL, friendnumber = %u", friendnumber); | ||
1984 | return -1; /* Error */ | ||
1985 | } | ||
1986 | |||
1987 | if (avrd->started == 0) { | ||
1988 | /* Receiving data for a non-started request. Must be an error | ||
1989 | * or an malicious request. */ | ||
1990 | LOGGER_DEBUG("Received an data push for a yet non started data " | ||
1991 | "request. friendnumber = %u", friendnumber); | ||
1992 | return -1; /* Error */ | ||
1993 | } | ||
1994 | |||
1995 | uint32_t new_length = avrd->bytes_received + data_length; | ||
1996 | |||
1997 | if (new_length > avrd->total_length | ||
1998 | || new_length >= AVATAR_MAX_DATA_LENGTH) { | ||
1999 | /* Invalid data length due to error or malice. Stops. */ | ||
2000 | LOGGER_DEBUG("Invalid data length. friendnumber = %u, " | ||
2001 | "new_length = %u, avrd->total_length = %u", | ||
2002 | friendnumber, new_length, avrd->total_length); | ||
2003 | free(avrd); | ||
2004 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | memcpy(avrd->data + avrd->bytes_received, data, data_length); | ||
2009 | avrd->bytes_received += data_length; | ||
2010 | |||
2011 | if (avrd->bytes_received == avrd->total_length) { | ||
2012 | LOGGER_DEBUG("All data received. friendnumber = %u", friendnumber); | ||
2013 | |||
2014 | /* All data was received. Check if the hashes match. It the | ||
2015 | * requester's responsability to do this. The sender may have done | ||
2016 | * anything with its avatar data between the DATA_START and now. | ||
2017 | */ | ||
2018 | uint8_t cur_hash[AVATAR_HASH_LENGTH]; | ||
2019 | m_avatar_hash(cur_hash, avrd->data, avrd->bytes_received); | ||
2020 | |||
2021 | if (memcmp(cur_hash, avrd->hash, AVATAR_HASH_LENGTH) == 0) { | ||
2022 | /* Avatar successfuly received! */ | ||
2023 | if (m->avatar_data_recv) { | ||
2024 | (m->avatar_data_recv)(m, friendnumber, avrd->format, cur_hash, | ||
2025 | avrd->data, avrd->bytes_received, m->avatar_data_recv_userdata); | ||
2026 | } | ||
2027 | } else { | ||
2028 | LOGGER_DEBUG("Avatar hash error. friendnumber = %u", friendnumber); | ||
2029 | } | ||
2030 | |||
2031 | free(avrd); | ||
2032 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
2033 | return 0; | ||
2034 | } | ||
2035 | |||
2036 | /* Waits for more data to be received */ | ||
2037 | return 0; | 1594 | return 0; |
2038 | } | 1595 | } |
2039 | 1596 | ||
2040 | |||
2041 | |||
2042 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | 1597 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) |
2043 | { | 1598 | { |
2044 | if (len == 0) | 1599 | if (len == 0) |
@@ -2178,42 +1733,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2178 | break; | 1733 | break; |
2179 | } | 1734 | } |
2180 | 1735 | ||
2181 | case PACKET_ID_AVATAR_INFO_REQ: { | ||
2182 | /* Send our avatar information */ | ||
2183 | m_send_avatar_info(m, i); | ||
2184 | break; | ||
2185 | } | ||
2186 | |||
2187 | case PACKET_ID_AVATAR_INFO: { | ||
2188 | if (m->avatar_info_recv) { | ||
2189 | /* | ||
2190 | * A malicious user may send an incomplete avatar info message. | ||
2191 | * Check if it have the correct size for the format: | ||
2192 | * [1 uint8_t: avatar format] [32 uint8_t: hash] | ||
2193 | */ | ||
2194 | if (data_length == AVATAR_HASH_LENGTH + 1) { | ||
2195 | (m->avatar_info_recv)(m, i, data[0], data + 1, m->avatar_info_recv_userdata); | ||
2196 | } | ||
2197 | } | ||
2198 | |||
2199 | break; | ||
2200 | } | ||
2201 | |||
2202 | case PACKET_ID_AVATAR_DATA_CONTROL: { | ||
2203 | handle_avatar_data_control(m, i, data, data_length); | ||
2204 | break; | ||
2205 | } | ||
2206 | |||
2207 | case PACKET_ID_AVATAR_DATA_START: { | ||
2208 | handle_avatar_data_start(m, i, data, data_length); | ||
2209 | break; | ||
2210 | } | ||
2211 | |||
2212 | case PACKET_ID_AVATAR_DATA_PUSH: { | ||
2213 | handle_avatar_data_push(m, i, data, data_length); | ||
2214 | break; | ||
2215 | } | ||
2216 | |||
2217 | case PACKET_ID_INVITE_GROUPCHAT: { | 1736 | case PACKET_ID_INVITE_GROUPCHAT: { |
2218 | if (data_length == 0) | 1737 | if (data_length == 0) |
2219 | break; | 1738 | break; |
@@ -2362,11 +1881,6 @@ void do_friends(Messenger *m) | |||
2362 | m->friendlist[i].userstatus_sent = 1; | 1881 | m->friendlist[i].userstatus_sent = 1; |
2363 | } | 1882 | } |
2364 | 1883 | ||
2365 | if (m->friendlist[i].avatar_info_sent == 0) { | ||
2366 | if (m_send_avatar_info(m, i) == 0) | ||
2367 | m->friendlist[i].avatar_info_sent = 1; | ||
2368 | } | ||
2369 | |||
2370 | if (m->friendlist[i].user_istyping_sent == 0) { | 1884 | if (m->friendlist[i].user_istyping_sent == 0) { |
2371 | if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) | 1885 | if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) |
2372 | m->friendlist[i].user_istyping_sent = 1; | 1886 | m->friendlist[i].user_istyping_sent = 1; |
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 4e011a57..48235900 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -33,8 +33,6 @@ | |||
33 | #define MAX_NAME_LENGTH 128 | 33 | #define MAX_NAME_LENGTH 128 |
34 | /* TODO: this must depend on other variable. */ | 34 | /* TODO: this must depend on other variable. */ |
35 | #define MAX_STATUSMESSAGE_LENGTH 1007 | 35 | #define MAX_STATUSMESSAGE_LENGTH 1007 |
36 | #define AVATAR_MAX_DATA_LENGTH 16384 | ||
37 | #define AVATAR_HASH_LENGTH crypto_hash_sha256_BYTES | ||
38 | 36 | ||
39 | 37 | ||
40 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) | 38 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) |
@@ -47,11 +45,6 @@ | |||
47 | #define PACKET_ID_STATUSMESSAGE 49 | 45 | #define PACKET_ID_STATUSMESSAGE 49 |
48 | #define PACKET_ID_USERSTATUS 50 | 46 | #define PACKET_ID_USERSTATUS 50 |
49 | #define PACKET_ID_TYPING 51 | 47 | #define PACKET_ID_TYPING 51 |
50 | #define PACKET_ID_AVATAR_INFO_REQ 52 | ||
51 | #define PACKET_ID_AVATAR_INFO 53 | ||
52 | #define PACKET_ID_AVATAR_DATA_CONTROL 54 | ||
53 | #define PACKET_ID_AVATAR_DATA_START 55 | ||
54 | #define PACKET_ID_AVATAR_DATA_PUSH 56 | ||
55 | #define PACKET_ID_MESSAGE 64 | 48 | #define PACKET_ID_MESSAGE 64 |
56 | #define PACKET_ID_ACTION 65 | 49 | #define PACKET_ID_ACTION 65 |
57 | #define PACKET_ID_MSI 69 | 50 | #define PACKET_ID_MSI 69 |
@@ -112,14 +105,6 @@ enum { | |||
112 | /* Interval between the sending of tcp relay information */ | 105 | /* Interval between the sending of tcp relay information */ |
113 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) | 106 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) |
114 | 107 | ||
115 | /* Must be < MAX_CRYPTO_DATA_SIZE */ | ||
116 | #define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) | ||
117 | |||
118 | /* Per-friend data limit for avatar data requests */ | ||
119 | #define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH) | ||
120 | #define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */ | ||
121 | |||
122 | |||
123 | enum { | 108 | enum { |
124 | CONNECTION_NONE, | 109 | CONNECTION_NONE, |
125 | CONNECTION_TCP, | 110 | CONNECTION_TCP, |
@@ -138,42 +123,6 @@ typedef enum { | |||
138 | } | 123 | } |
139 | USERSTATUS; | 124 | USERSTATUS; |
140 | 125 | ||
141 | /* AVATAR_FORMAT - | ||
142 | * Data formats for user avatar images | ||
143 | */ | ||
144 | typedef enum { | ||
145 | AVATAR_FORMAT_NONE = 0, | ||
146 | AVATAR_FORMAT_PNG | ||
147 | } | ||
148 | AVATAR_FORMAT; | ||
149 | |||
150 | /* AVATAR_DATACONTROL | ||
151 | * To control avatar data requests (PACKET_ID_AVATAR_DATA_CONTROL) | ||
152 | */ | ||
153 | typedef enum { | ||
154 | AVATAR_DATACONTROL_REQ, | ||
155 | AVATAR_DATACONTROL_ERROR | ||
156 | } | ||
157 | AVATAR_DATACONTROL; | ||
158 | |||
159 | typedef struct { | ||
160 | uint8_t started; | ||
161 | AVATAR_FORMAT format; | ||
162 | uint8_t hash[AVATAR_HASH_LENGTH]; | ||
163 | uint32_t total_length; | ||
164 | uint32_t bytes_received; | ||
165 | uint8_t data[AVATAR_MAX_DATA_LENGTH]; | ||
166 | } | ||
167 | AVATAR_RECEIVEDATA; | ||
168 | |||
169 | typedef struct { | ||
170 | /* Fields only used to limit the network usage from a given friend */ | ||
171 | uint32_t bytes_sent; /* Total bytes send to this user */ | ||
172 | uint64_t last_reset; /* Time the data counter was last reset */ | ||
173 | } | ||
174 | AVATAR_SENDDATA; | ||
175 | |||
176 | |||
177 | struct File_Transfers { | 126 | struct File_Transfers { |
178 | uint64_t size; | 127 | uint64_t size; |
179 | uint64_t transferred; | 128 | uint64_t transferred; |
@@ -217,7 +166,6 @@ typedef struct { | |||
217 | uint8_t statusmessage_sent; | 166 | uint8_t statusmessage_sent; |
218 | USERSTATUS userstatus; | 167 | USERSTATUS userstatus; |
219 | uint8_t userstatus_sent; | 168 | uint8_t userstatus_sent; |
220 | uint8_t avatar_info_sent; | ||
221 | uint8_t user_istyping; | 169 | uint8_t user_istyping; |
222 | uint8_t user_istyping_sent; | 170 | uint8_t user_istyping_sent; |
223 | uint8_t is_typing; | 171 | uint8_t is_typing; |
@@ -230,9 +178,6 @@ typedef struct { | |||
230 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; | 178 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; |
231 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 179 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
232 | 180 | ||
233 | AVATAR_SENDDATA avatar_send_data; | ||
234 | AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend. | ||
235 | |||
236 | struct { | 181 | struct { |
237 | int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object); | 182 | int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object); |
238 | void *object; | 183 | void *object; |
@@ -269,11 +214,6 @@ struct Messenger { | |||
269 | 214 | ||
270 | USERSTATUS userstatus; | 215 | USERSTATUS userstatus; |
271 | 216 | ||
272 | AVATAR_FORMAT avatar_format; | ||
273 | uint8_t *avatar_data; | ||
274 | uint32_t avatar_data_length; | ||
275 | uint8_t avatar_hash[AVATAR_HASH_LENGTH]; | ||
276 | |||
277 | Friend *friendlist; | 217 | Friend *friendlist; |
278 | uint32_t numfriends; | 218 | uint32_t numfriends; |
279 | 219 | ||
@@ -305,10 +245,6 @@ struct Messenger { | |||
305 | void *friend_connectionstatuschange_userdata; | 245 | void *friend_connectionstatuschange_userdata; |
306 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); | 246 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); |
307 | void *friend_connectionstatuschange_internal_userdata; | 247 | void *friend_connectionstatuschange_internal_userdata; |
308 | void *avatar_info_recv_userdata; | ||
309 | void (*avatar_info_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, void *); | ||
310 | void *avatar_data_recv_userdata; | ||
311 | void (*avatar_data_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *); | ||
312 | 248 | ||
313 | void *group_chat_object; /* Set by new_groupchats()*/ | 249 | void *group_chat_object; /* Set by new_groupchats()*/ |
314 | void (*group_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t); | 250 | void (*group_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t); |
@@ -503,113 +439,6 @@ uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); | |||
503 | uint8_t m_get_self_userstatus(const Messenger *m); | 439 | uint8_t m_get_self_userstatus(const Messenger *m); |
504 | 440 | ||
505 | 441 | ||
506 | /* Set the user avatar image data. | ||
507 | * This should be made before connecting, so we will not announce that the user have no avatar | ||
508 | * before setting and announcing a new one, forcing the peers to re-download it. | ||
509 | * | ||
510 | * Notice that the library treats the image as raw data and does not interpret it by any way. | ||
511 | * | ||
512 | * Arguments: | ||
513 | * format - Avatar image format or NONE for user with no avatar (see AVATAR_FORMAT); | ||
514 | * data - pointer to the avatar data (may be NULL it the format is NONE); | ||
515 | * length - length of image data. Must be <= MAX_AVATAR_DATA_LENGTH. | ||
516 | * | ||
517 | * returns 0 on success | ||
518 | * returns -1 on failure. | ||
519 | */ | ||
520 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length); | ||
521 | |||
522 | /* Unsets the user avatar. | ||
523 | |||
524 | returns 0 on success (currently always returns 0) */ | ||
525 | int m_unset_avatar(Messenger *m); | ||
526 | |||
527 | /* Get avatar data from the current user. | ||
528 | * Copies the current user avatar data to the destination buffer and sets the image format | ||
529 | * accordingly. | ||
530 | * | ||
531 | * If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and | ||
532 | * 'length' is set to zero. | ||
533 | * | ||
534 | * If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored. | ||
535 | * | ||
536 | * Arguments: | ||
537 | * format - destination pointer to the avatar image format (see AVATAR_FORMAT); | ||
538 | * buf - destination buffer to the image data. Must have at least 'maxlen' bytes; | ||
539 | * length - destination pointer to the image data length; | ||
540 | * maxlen - length of the destination buffer 'buf'; | ||
541 | * hash - destination pointer to the avatar hash (it must be exactly AVATAR_HASH_LENGTH bytes long). | ||
542 | * | ||
543 | * returns 0 on success; | ||
544 | * returns -1 on failure. | ||
545 | * | ||
546 | */ | ||
547 | int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, | ||
548 | uint8_t *hash); | ||
549 | |||
550 | /* Generates a cryptographic hash of the given data. | ||
551 | * This function may be used by clients for any purpose, but is provided primarily for | ||
552 | * validating cached avatars. | ||
553 | * This function is a wrapper to internal message-digest functions. | ||
554 | * | ||
555 | * Arguments: | ||
556 | * hash - destination buffer for the hash data, it must be exactly crypto_hash_sha256_BYTES bytes long. | ||
557 | * data - data to be hashed; | ||
558 | * datalen - length of the data; | ||
559 | * | ||
560 | * returns 0 on success | ||
561 | * returns -1 on failure. | ||
562 | */ | ||
563 | int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); | ||
564 | |||
565 | /* Generates a cryptographic hash of the given avatar data. | ||
566 | * This function is a wrapper to m_hash and specifically provided | ||
567 | * to generate hashes from user avatars that may be memcmp()ed with the values returned by the | ||
568 | * other avatar functions. It is specially important to validate cached avatars. | ||
569 | * | ||
570 | * Arguments: | ||
571 | * hash - destination buffer for the hash data, it must be exactly AVATAR_HASH_LENGTH bytes long. | ||
572 | * data - avatar image data; | ||
573 | * datalen - length of the avatar image data; it must be <= MAX_AVATAR_DATA_LENGTH. | ||
574 | * | ||
575 | * returns 0 on success | ||
576 | * returns -1 on failure. | ||
577 | */ | ||
578 | int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); | ||
579 | |||
580 | /* Request avatar information from a friend. | ||
581 | * Asks a friend to provide their avatar information (image format and hash). The friend may | ||
582 | * or may not answer this request and, if answered, the information will be provided through | ||
583 | * the callback 'avatar_info'. | ||
584 | * | ||
585 | * returns 0 on success | ||
586 | * returns -1 on failure. | ||
587 | */ | ||
588 | int m_request_avatar_info(const Messenger *m, const int32_t friendnumber); | ||
589 | |||
590 | /* Send an unrequested avatar information to a friend. | ||
591 | * Sends our avatar format and hash to a friend; he/she can use this information to validate | ||
592 | * an avatar from the cache and may (or not) reply with an avatar data request. | ||
593 | * | ||
594 | * Notice: it is NOT necessary to send these notification after changing the avatar or | ||
595 | * connecting. The library already does this. | ||
596 | * | ||
597 | * returns 0 on success | ||
598 | * returns -1 on failure. | ||
599 | */ | ||
600 | int m_send_avatar_info(const Messenger *m, const int32_t friendnumber); | ||
601 | |||
602 | |||
603 | /* Request the avatar data from a friend. | ||
604 | * Ask a friend to send their avatar data. The friend may or may not answer this request and, | ||
605 | * if answered, the information will be provided in callback 'avatar_data'. | ||
606 | * | ||
607 | * returns 0 on sucess | ||
608 | * returns -1 on failure. | ||
609 | */ | ||
610 | int m_request_avatar_data(const Messenger *m, const int32_t friendnumber); | ||
611 | |||
612 | |||
613 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | 442 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. |
614 | * returns -1 on error. | 443 | * returns -1 on error. |
615 | */ | 444 | */ |
@@ -702,48 +531,6 @@ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Mess | |||
702 | void *userdata); | 531 | void *userdata); |
703 | 532 | ||
704 | 533 | ||
705 | /* Set the callback function for avatar information. | ||
706 | * This callback will be called when avatar information are received from friends. These events | ||
707 | * can arrive at anytime, but are usually received uppon connection and in reply of avatar | ||
708 | * information requests. | ||
709 | * | ||
710 | * Function format is: | ||
711 | * function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata) | ||
712 | * | ||
713 | * where 'format' is the avatar image format (see AVATAR_FORMAT) and 'hash' is the hash of | ||
714 | * the avatar data for caching purposes and it is exactly AVATAR_HASH_LENGTH long. If the | ||
715 | * image format is NONE, the hash is zeroed. | ||
716 | * | ||
717 | */ | ||
718 | void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *), | ||
719 | void *userdata); | ||
720 | |||
721 | |||
722 | /* Set the callback function for avatar data. | ||
723 | * This callback will be called when the complete avatar data was correctly received from a | ||
724 | * friend. This only happens in reply of a avatar data request (see tox_request_avatar_data); | ||
725 | * | ||
726 | * Function format is: | ||
727 | * function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata) | ||
728 | * | ||
729 | * where 'format' is the avatar image format (see AVATAR_FORMAT); 'hash' is the | ||
730 | * locally-calculated cryptographic hash of the avatar data and it is exactly | ||
731 | * AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length | ||
732 | * of such data. | ||
733 | * | ||
734 | * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is | ||
735 | * always validated locally with the function tox_avatar_hash and ensured to match the image | ||
736 | * data, so this value can be safely used to compare with cached avatars. | ||
737 | * | ||
738 | * WARNING: users MUST treat all avatar image data received from another peer as untrusted and | ||
739 | * potentially malicious. The library only ensures that the data which arrived is the same the | ||
740 | * other user sent, and does not interpret or validate any image data. | ||
741 | */ | ||
742 | void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, | ||
743 | uint32_t, void *), void *userdata); | ||
744 | |||
745 | |||
746 | |||
747 | /**********GROUP CHATS************/ | 534 | /**********GROUP CHATS************/ |
748 | 535 | ||
749 | /* Set the callback for group invites. | 536 | /* Set the callback for group invites. |