Remove avatar stuff from Messenger.

The new api sees avatars as a different type of file transfer.
This commit is contained in:
irungentoo 2015-02-24 19:39:19 -05:00
parent ca21569a9d
commit 8fa8e9dcd7
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
2 changed files with 0 additions and 699 deletions

View File

@ -39,7 +39,6 @@
static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status);
static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
uint32_t length, uint8_t congestion_control); uint32_t length, uint8_t congestion_control);
static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, uint8_t op);
// friend_not_valid determines if the friendnumber passed is valid in the Messenger object // friend_not_valid determines if the friendnumber passed is valid in the Messenger object
static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) 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
id_copy(m->friendlist[i].real_pk, real_pk); id_copy(m->friendlist[i].real_pk, real_pk);
m->friendlist[i].statusmessage_length = 0; m->friendlist[i].statusmessage_length = 0;
m->friendlist[i].userstatus = USERSTATUS_NONE; m->friendlist[i].userstatus = USERSTATUS_NONE;
m->friendlist[i].avatar_info_sent = 0;
m->friendlist[i].avatar_recv_data = NULL;
m->friendlist[i].avatar_send_data.bytes_sent = 0;
m->friendlist[i].avatar_send_data.last_reset = 0;
m->friendlist[i].is_typing = 0; m->friendlist[i].is_typing = 0;
m->friendlist[i].message_id = 0; m->friendlist[i].message_id = 0;
friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, 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)
if (m->friendlist[friendnumber].status == FRIEND_ONLINE) if (m->friendlist[friendnumber].status == FRIEND_ONLINE)
remove_online_friend(m, friendnumber); remove_online_friend(m, friendnumber);
free(m->friendlist[friendnumber].avatar_recv_data);
clear_receipts(m, friendnumber); clear_receipts(m, friendnumber);
remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk);
friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); 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)
return 0; return 0;
} }
int m_unset_avatar(Messenger *m)
{
if (m->avatar_data != NULL)
free(m->avatar_data);
m->avatar_data = NULL;
m->avatar_data_length = 0;
m->avatar_format = AVATAR_FORMAT_NONE;
memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH);
uint32_t i;
for (i = 0; i < m->numfriends; ++i)
m->friendlist[i].avatar_info_sent = 0;
return 0;
}
int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length)
{
if (format == AVATAR_FORMAT_NONE) {
m_unset_avatar(m);
return 0;
}
if (length > AVATAR_MAX_DATA_LENGTH || length == 0)
return -1;
if (data == NULL)
return -1;
uint8_t *tmp = realloc(m->avatar_data, length);
if (tmp == NULL)
return -1;
m->avatar_format = format;
m->avatar_data = tmp;
m->avatar_data_length = length;
memcpy(m->avatar_data, data, length);
m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length);
uint32_t i;
for (i = 0; i < m->numfriends; ++i)
m->friendlist[i].avatar_info_sent = 0;
return 0;
}
int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
uint8_t *hash)
{
if (format)
*format = m->avatar_format;
if (length)
*length = m->avatar_data_length;
if (hash)
memcpy(hash, m->avatar_hash, AVATAR_HASH_LENGTH);
if (buf != NULL && maxlen > 0) {
if (m->avatar_data_length <= maxlen)
memcpy(buf, m->avatar_data, m->avatar_data_length);
else
return -1;
}
return 0;
}
int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen)
{
if (hash == NULL)
return -1;
return crypto_hash_sha256(hash, data, datalen);
}
int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen)
{
return m_hash(hash, data, datalen);
}
int m_request_avatar_info(const Messenger *m, const int32_t friendnumber)
{
if (friend_not_valid(m, friendnumber))
return -1;
if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO_REQ, 0, 0, 0))
return 0;
else
return -1;
}
int m_send_avatar_info(const Messenger *m, const int32_t friendnumber)
{
if (friend_not_valid(m, friendnumber))
return -1;
uint8_t data[sizeof(uint8_t) + AVATAR_HASH_LENGTH];
data[0] = m->avatar_format;
memcpy(data + 1, m->avatar_hash, AVATAR_HASH_LENGTH);
if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO, data, sizeof(data), 0))
return 0;
else
return -1;
}
int m_request_avatar_data(const Messenger *m, const int32_t friendnumber)
{
if (friend_not_valid(m, friendnumber))
return -1;
AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
if (avrd == NULL) {
avrd = calloc(sizeof(AVATAR_RECEIVEDATA), 1);
if (avrd == NULL)
return -1;
avrd->started = 0;
m->friendlist[friendnumber].avatar_recv_data = avrd;
}
if (avrd->started) {
LOGGER_DEBUG("Resetting already started data request. "
"friendnumber == %u", friendnumber);
}
avrd->started = 0;
avrd->bytes_received = 0;
avrd->total_length = 0;
avrd->format = AVATAR_FORMAT_NONE;
return send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_REQ);
}
/* return the size of friendnumber's user status. /* return the size of friendnumber's user status.
* Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
*/ */
@ -1021,20 +872,6 @@ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Mess
m->friend_connectionstatuschange_internal_userdata = userdata; m->friend_connectionstatuschange_internal_userdata = userdata;
} }
void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *),
void *userdata)
{
m->avatar_info_recv = function;
m->avatar_info_recv_userdata = userdata;
}
void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *,
uint32_t, void *), void *userdata)
{
m->avatar_data_recv = function;
m->avatar_data_recv_userdata = userdata;
}
static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber) static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber)
{ {
int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp;
@ -1646,9 +1483,6 @@ Messenger *new_messenger(Messenger_Options *options)
m->net = new_networking(ip, TOX_PORT_DEFAULT); m->net = new_networking(ip, TOX_PORT_DEFAULT);
} }
m->avatar_format = AVATAR_FORMAT_NONE;
m->avatar_data = NULL;
if (m->net == NULL) { if (m->net == NULL) {
free(m); free(m);
return NULL; return NULL;
@ -1714,11 +1548,9 @@ void kill_messenger(Messenger *m)
kill_networking(m->net); kill_networking(m->net);
for (i = 0; i < m->numfriends; ++i) { for (i = 0; i < m->numfriends; ++i) {
free(m->friendlist[i].avatar_recv_data);
clear_receipts(m, i); clear_receipts(m, i);
} }
free(m->avatar_data);
free(m->friendlist); free(m->friendlist);
free(m); free(m);
} }
@ -1752,293 +1584,16 @@ static int handle_status(void *object, int i, uint8_t status)
m->friendlist[i].userstatus_sent = 0; m->friendlist[i].userstatus_sent = 0;
m->friendlist[i].statusmessage_sent = 0; m->friendlist[i].statusmessage_sent = 0;
m->friendlist[i].user_istyping_sent = 0; m->friendlist[i].user_istyping_sent = 0;
m->friendlist[i].avatar_info_sent = 0;
m->friendlist[i].ping_lastrecv = temp_time; m->friendlist[i].ping_lastrecv = temp_time;
} else { /* Went offline. */ } else { /* Went offline. */
if (m->friendlist[i].status == FRIEND_ONLINE) { if (m->friendlist[i].status == FRIEND_ONLINE) {
set_friend_status(m, i, FRIEND_CONFIRMED); set_friend_status(m, i, FRIEND_CONFIRMED);
} }
/* Clear avatar transfer state */
if (m->friendlist[i].avatar_recv_data) {
free(m->friendlist[i].avatar_recv_data);
m->friendlist[i].avatar_recv_data = NULL;
}
} }
return 0; return 0;
} }
/* Sends an avatar data control packet to the peer. Usually to return status
* values or request data.
*/
static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber,
uint8_t op)
{
int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_CONTROL,
&op, sizeof(op), 0);
LOGGER_DEBUG("friendnumber = %u, op = %u, ret = %d",
friendnumber, op, ret);
return ret ? 0 : -1;
}
static int handle_avatar_data_control(Messenger *m, uint32_t friendnumber,
uint8_t *data, uint32_t data_length)
{
if (data_length != 1) {
LOGGER_DEBUG("Error: PACKET_ID_AVATAR_DATA_CONTROL with bad "
"data_length = %u, friendnumber = %u",
data_length, friendnumber);
send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR);
return -1; /* Error */
}
LOGGER_DEBUG("friendnumber = %u, op = %u", friendnumber, data[0]);
switch (data[0]) {
case AVATAR_DATACONTROL_REQ: {
/* Check data transfer limits for this friend */
AVATAR_SENDDATA *const avsd = &(m->friendlist[friendnumber].avatar_send_data);
if (avsd->bytes_sent >= AVATAR_DATA_TRANSFER_LIMIT) {
/* User reached data limit. Check timeout */
uint64_t now = unix_time();
if (avsd->last_reset > 0
&& (avsd->last_reset + AVATAR_DATA_TRANSFER_TIMEOUT < now)) {
avsd->bytes_sent = 0;
avsd->last_reset = now;
} else {
/* Friend still rate-limitted. Send an error and stops. */
LOGGER_DEBUG("Avatar data transfer limit reached. "
"friendnumber = %u", friendnumber);
send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR);
return 0;
}
}
/* Start the transmission with a DATA_START message. Format:
* uint8_t format
* uint8_t hash[AVATAR_HASH_LENGTH]
* uint32_t total_length
*/
LOGGER_DEBUG("Sending start msg to friend number %u. "
"m->avatar_format = %u, m->avatar_data_length = %u",
friendnumber, m->avatar_format, m->avatar_data_length);
uint8_t start_data[1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)];
uint32_t avatar_len = htonl(m->avatar_data_length);
start_data[0] = m->avatar_format;
memcpy(start_data + 1, m->avatar_hash, AVATAR_HASH_LENGTH);
memcpy(start_data + 1 + AVATAR_HASH_LENGTH, &avatar_len, sizeof(uint32_t));
avsd->bytes_sent += sizeof(start_data); /* For rate limit */
int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_START,
start_data, sizeof(start_data), 0);
if (!ret) {
/* Something went wrong, try to signal the error so the friend
* can clear up the state. */
send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR);
return 0;
}
/* User have no avatar data, nothing more to do. */
if (m->avatar_format == AVATAR_FORMAT_NONE)
return 0;
/* Send the actual avatar data. */
uint32_t offset = 0;
while (offset < m->avatar_data_length) {
uint32_t chunk_len = m->avatar_data_length - offset;
if (chunk_len > AVATAR_DATA_MAX_CHUNK_SIZE)
chunk_len = AVATAR_DATA_MAX_CHUNK_SIZE;
uint8_t chunk[AVATAR_DATA_MAX_CHUNK_SIZE];
memcpy(chunk, m->avatar_data + offset, chunk_len);
offset += chunk_len;
avsd->bytes_sent += chunk_len; /* For rate limit */
int ret = write_cryptpacket_id(m, friendnumber,
PACKET_ID_AVATAR_DATA_PUSH,
chunk, chunk_len, 0);
if (!ret) {
LOGGER_DEBUG("write_cryptpacket_id failed. ret = %d, "
"friendnumber = %u, offset = %u",
ret, friendnumber, offset);
send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR);
return -1;
}
}
return 0;
}
case AVATAR_DATACONTROL_ERROR: {
if (m->friendlist[friendnumber].avatar_recv_data) {
/* We were receiving the data, sender detected an error
(eg. changing avatar) and asked us to stop. */
free(m->friendlist[friendnumber].avatar_recv_data);
m->friendlist[friendnumber].avatar_recv_data = NULL;
}
return 0;
}
}
return -1;
}
static int handle_avatar_data_start(Messenger *m, uint32_t friendnumber,
uint8_t *data, uint32_t data_length)
{
LOGGER_DEBUG("data_length = %u, friendnumber = %u", data_length, friendnumber);
if (data_length != 1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)) {
LOGGER_DEBUG("Invalid msg length = %u, friendnumber = %u",
data_length, friendnumber);
return -1;
}
AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
if (avrd == NULL) {
LOGGER_DEBUG("Received an unrequested DATA_START, friendnumber = %u",
friendnumber);
return -1;
}
if (avrd->started) {
/* Already receiving data from this friend. Must be an error
* or an malicious request, because we zeroed the started bit
* when we requested the data. */
LOGGER_DEBUG("Received an unrequested duplicated DATA_START, "
"friendnumber = %u", friendnumber);
return -1;
}
/* Copy data from message to our control structure */
avrd->started = 1;
avrd->format = data[0];
memcpy(avrd->hash, data + 1, AVATAR_HASH_LENGTH);
uint32_t tmp_len;
memcpy(&tmp_len, data + 1 + AVATAR_HASH_LENGTH, sizeof(uint32_t));
avrd->total_length = ntohl(tmp_len);
avrd->bytes_received = 0;
LOGGER_DEBUG("friendnumber = %u, avrd->format = %u, "
"avrd->total_length = %u, avrd->bytes_received = %u",
friendnumber, avrd->format, avrd->total_length,
avrd->bytes_received);
if (avrd->total_length > AVATAR_MAX_DATA_LENGTH) {
/* Invalid data length. Stops. */
LOGGER_DEBUG("Error: total_length > MAX_AVATAR_DATA_LENGTH, "
"friendnumber = %u", friendnumber);
free(avrd);
avrd = NULL;
m->friendlist[friendnumber].avatar_recv_data = NULL;
return 0;
}
if (avrd->format == AVATAR_FORMAT_NONE || avrd->total_length == 0) {
/* No real data to receive. Run callback function and finish. */
LOGGER_DEBUG("format == NONE, friendnumber = %u", friendnumber);
if (m->avatar_data_recv) {
memset(avrd->hash, 0, AVATAR_HASH_LENGTH);
(m->avatar_data_recv)(m, friendnumber, avrd->format, avrd->hash,
NULL, 0, m->avatar_data_recv_userdata);
}
free(avrd);
avrd = NULL;
m->friendlist[friendnumber].avatar_recv_data = NULL;
return 0;
}
/* Waits for more data to be received */
return 0;
}
static int handle_avatar_data_push(Messenger *m, uint32_t friendnumber,
uint8_t *data, uint32_t data_length)
{
LOGGER_DEBUG("friendnumber = %u, data_length = %u", friendnumber, data_length);
AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data;
if (avrd == NULL) {
/* No active transfer. It must be an error or a malicious request,
* because we set the avatar_recv_data on the first DATA_START. */
LOGGER_DEBUG("Error: avrd == NULL, friendnumber = %u", friendnumber);
return -1; /* Error */
}
if (avrd->started == 0) {
/* Receiving data for a non-started request. Must be an error
* or an malicious request. */
LOGGER_DEBUG("Received an data push for a yet non started data "
"request. friendnumber = %u", friendnumber);
return -1; /* Error */
}
uint32_t new_length = avrd->bytes_received + data_length;
if (new_length > avrd->total_length
|| new_length >= AVATAR_MAX_DATA_LENGTH) {
/* Invalid data length due to error or malice. Stops. */
LOGGER_DEBUG("Invalid data length. friendnumber = %u, "
"new_length = %u, avrd->total_length = %u",
friendnumber, new_length, avrd->total_length);
free(avrd);
m->friendlist[friendnumber].avatar_recv_data = NULL;
return 0;
}
memcpy(avrd->data + avrd->bytes_received, data, data_length);
avrd->bytes_received += data_length;
if (avrd->bytes_received == avrd->total_length) {
LOGGER_DEBUG("All data received. friendnumber = %u", friendnumber);
/* All data was received. Check if the hashes match. It the
* requester's responsability to do this. The sender may have done
* anything with its avatar data between the DATA_START and now.
*/
uint8_t cur_hash[AVATAR_HASH_LENGTH];
m_avatar_hash(cur_hash, avrd->data, avrd->bytes_received);
if (memcmp(cur_hash, avrd->hash, AVATAR_HASH_LENGTH) == 0) {
/* Avatar successfuly received! */
if (m->avatar_data_recv) {
(m->avatar_data_recv)(m, friendnumber, avrd->format, cur_hash,
avrd->data, avrd->bytes_received, m->avatar_data_recv_userdata);
}
} else {
LOGGER_DEBUG("Avatar hash error. friendnumber = %u", friendnumber);
}
free(avrd);
m->friendlist[friendnumber].avatar_recv_data = NULL;
return 0;
}
/* Waits for more data to be received */
return 0;
}
static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
{ {
if (len == 0) if (len == 0)
@ -2178,42 +1733,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
break; break;
} }
case PACKET_ID_AVATAR_INFO_REQ: {
/* Send our avatar information */
m_send_avatar_info(m, i);
break;
}
case PACKET_ID_AVATAR_INFO: {
if (m->avatar_info_recv) {
/*
* A malicious user may send an incomplete avatar info message.
* Check if it have the correct size for the format:
* [1 uint8_t: avatar format] [32 uint8_t: hash]
*/
if (data_length == AVATAR_HASH_LENGTH + 1) {
(m->avatar_info_recv)(m, i, data[0], data + 1, m->avatar_info_recv_userdata);
}
}
break;
}
case PACKET_ID_AVATAR_DATA_CONTROL: {
handle_avatar_data_control(m, i, data, data_length);
break;
}
case PACKET_ID_AVATAR_DATA_START: {
handle_avatar_data_start(m, i, data, data_length);
break;
}
case PACKET_ID_AVATAR_DATA_PUSH: {
handle_avatar_data_push(m, i, data, data_length);
break;
}
case PACKET_ID_INVITE_GROUPCHAT: { case PACKET_ID_INVITE_GROUPCHAT: {
if (data_length == 0) if (data_length == 0)
break; break;
@ -2362,11 +1881,6 @@ void do_friends(Messenger *m)
m->friendlist[i].userstatus_sent = 1; m->friendlist[i].userstatus_sent = 1;
} }
if (m->friendlist[i].avatar_info_sent == 0) {
if (m_send_avatar_info(m, i) == 0)
m->friendlist[i].avatar_info_sent = 1;
}
if (m->friendlist[i].user_istyping_sent == 0) { if (m->friendlist[i].user_istyping_sent == 0) {
if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) if (send_user_istyping(m, i, m->friendlist[i].user_istyping))
m->friendlist[i].user_istyping_sent = 1; m->friendlist[i].user_istyping_sent = 1;

View File

@ -33,8 +33,6 @@
#define MAX_NAME_LENGTH 128 #define MAX_NAME_LENGTH 128
/* TODO: this must depend on other variable. */ /* TODO: this must depend on other variable. */
#define MAX_STATUSMESSAGE_LENGTH 1007 #define MAX_STATUSMESSAGE_LENGTH 1007
#define AVATAR_MAX_DATA_LENGTH 16384
#define AVATAR_HASH_LENGTH crypto_hash_sha256_BYTES
#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t))
@ -47,11 +45,6 @@
#define PACKET_ID_STATUSMESSAGE 49 #define PACKET_ID_STATUSMESSAGE 49
#define PACKET_ID_USERSTATUS 50 #define PACKET_ID_USERSTATUS 50
#define PACKET_ID_TYPING 51 #define PACKET_ID_TYPING 51
#define PACKET_ID_AVATAR_INFO_REQ 52
#define PACKET_ID_AVATAR_INFO 53
#define PACKET_ID_AVATAR_DATA_CONTROL 54
#define PACKET_ID_AVATAR_DATA_START 55
#define PACKET_ID_AVATAR_DATA_PUSH 56
#define PACKET_ID_MESSAGE 64 #define PACKET_ID_MESSAGE 64
#define PACKET_ID_ACTION 65 #define PACKET_ID_ACTION 65
#define PACKET_ID_MSI 69 #define PACKET_ID_MSI 69
@ -112,14 +105,6 @@ enum {
/* Interval between the sending of tcp relay information */ /* Interval between the sending of tcp relay information */
#define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60)
/* Must be < MAX_CRYPTO_DATA_SIZE */
#define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1)
/* Per-friend data limit for avatar data requests */
#define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH)
#define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */
enum { enum {
CONNECTION_NONE, CONNECTION_NONE,
CONNECTION_TCP, CONNECTION_TCP,
@ -138,42 +123,6 @@ typedef enum {
} }
USERSTATUS; USERSTATUS;
/* AVATAR_FORMAT -
* Data formats for user avatar images
*/
typedef enum {
AVATAR_FORMAT_NONE = 0,
AVATAR_FORMAT_PNG
}
AVATAR_FORMAT;
/* AVATAR_DATACONTROL
* To control avatar data requests (PACKET_ID_AVATAR_DATA_CONTROL)
*/
typedef enum {
AVATAR_DATACONTROL_REQ,
AVATAR_DATACONTROL_ERROR
}
AVATAR_DATACONTROL;
typedef struct {
uint8_t started;
AVATAR_FORMAT format;
uint8_t hash[AVATAR_HASH_LENGTH];
uint32_t total_length;
uint32_t bytes_received;
uint8_t data[AVATAR_MAX_DATA_LENGTH];
}
AVATAR_RECEIVEDATA;
typedef struct {
/* Fields only used to limit the network usage from a given friend */
uint32_t bytes_sent; /* Total bytes send to this user */
uint64_t last_reset; /* Time the data counter was last reset */
}
AVATAR_SENDDATA;
struct File_Transfers { struct File_Transfers {
uint64_t size; uint64_t size;
uint64_t transferred; uint64_t transferred;
@ -217,7 +166,6 @@ typedef struct {
uint8_t statusmessage_sent; uint8_t statusmessage_sent;
USERSTATUS userstatus; USERSTATUS userstatus;
uint8_t userstatus_sent; uint8_t userstatus_sent;
uint8_t avatar_info_sent;
uint8_t user_istyping; uint8_t user_istyping;
uint8_t user_istyping_sent; uint8_t user_istyping_sent;
uint8_t is_typing; uint8_t is_typing;
@ -230,9 +178,6 @@ typedef struct {
struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
AVATAR_SENDDATA avatar_send_data;
AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend.
struct { struct {
int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object); int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object);
void *object; void *object;
@ -269,11 +214,6 @@ struct Messenger {
USERSTATUS userstatus; USERSTATUS userstatus;
AVATAR_FORMAT avatar_format;
uint8_t *avatar_data;
uint32_t avatar_data_length;
uint8_t avatar_hash[AVATAR_HASH_LENGTH];
Friend *friendlist; Friend *friendlist;
uint32_t numfriends; uint32_t numfriends;
@ -305,10 +245,6 @@ struct Messenger {
void *friend_connectionstatuschange_userdata; void *friend_connectionstatuschange_userdata;
void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *);
void *friend_connectionstatuschange_internal_userdata; void *friend_connectionstatuschange_internal_userdata;
void *avatar_info_recv_userdata;
void (*avatar_info_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, void *);
void *avatar_data_recv_userdata;
void (*avatar_data_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *);
void *group_chat_object; /* Set by new_groupchats()*/ void *group_chat_object; /* Set by new_groupchats()*/
void (*group_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t); 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);
uint8_t m_get_self_userstatus(const Messenger *m); uint8_t m_get_self_userstatus(const Messenger *m);
/* Set the user avatar image data.
* This should be made before connecting, so we will not announce that the user have no avatar
* before setting and announcing a new one, forcing the peers to re-download it.
*
* Notice that the library treats the image as raw data and does not interpret it by any way.
*
* Arguments:
* format - Avatar image format or NONE for user with no avatar (see AVATAR_FORMAT);
* data - pointer to the avatar data (may be NULL it the format is NONE);
* length - length of image data. Must be <= MAX_AVATAR_DATA_LENGTH.
*
* returns 0 on success
* returns -1 on failure.
*/
int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length);
/* Unsets the user avatar.
returns 0 on success (currently always returns 0) */
int m_unset_avatar(Messenger *m);
/* Get avatar data from the current user.
* Copies the current user avatar data to the destination buffer and sets the image format
* accordingly.
*
* If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and
* 'length' is set to zero.
*
* If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored.
*
* Arguments:
* format - destination pointer to the avatar image format (see AVATAR_FORMAT);
* buf - destination buffer to the image data. Must have at least 'maxlen' bytes;
* length - destination pointer to the image data length;
* maxlen - length of the destination buffer 'buf';
* hash - destination pointer to the avatar hash (it must be exactly AVATAR_HASH_LENGTH bytes long).
*
* returns 0 on success;
* returns -1 on failure.
*
*/
int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen,
uint8_t *hash);
/* Generates a cryptographic hash of the given data.
* This function may be used by clients for any purpose, but is provided primarily for
* validating cached avatars.
* This function is a wrapper to internal message-digest functions.
*
* Arguments:
* hash - destination buffer for the hash data, it must be exactly crypto_hash_sha256_BYTES bytes long.
* data - data to be hashed;
* datalen - length of the data;
*
* returns 0 on success
* returns -1 on failure.
*/
int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen);
/* Generates a cryptographic hash of the given avatar data.
* This function is a wrapper to m_hash and specifically provided
* to generate hashes from user avatars that may be memcmp()ed with the values returned by the
* other avatar functions. It is specially important to validate cached avatars.
*
* Arguments:
* hash - destination buffer for the hash data, it must be exactly AVATAR_HASH_LENGTH bytes long.
* data - avatar image data;
* datalen - length of the avatar image data; it must be <= MAX_AVATAR_DATA_LENGTH.
*
* returns 0 on success
* returns -1 on failure.
*/
int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen);
/* Request avatar information from a friend.
* Asks a friend to provide their avatar information (image format and hash). The friend may
* or may not answer this request and, if answered, the information will be provided through
* the callback 'avatar_info'.
*
* returns 0 on success
* returns -1 on failure.
*/
int m_request_avatar_info(const Messenger *m, const int32_t friendnumber);
/* Send an unrequested avatar information to a friend.
* Sends our avatar format and hash to a friend; he/she can use this information to validate
* an avatar from the cache and may (or not) reply with an avatar data request.
*
* Notice: it is NOT necessary to send these notification after changing the avatar or
* connecting. The library already does this.
*
* returns 0 on success
* returns -1 on failure.
*/
int m_send_avatar_info(const Messenger *m, const int32_t friendnumber);
/* Request the avatar data from a friend.
* Ask a friend to send their avatar data. The friend may or may not answer this request and,
* if answered, the information will be provided in callback 'avatar_data'.
*
* returns 0 on sucess
* returns -1 on failure.
*/
int m_request_avatar_data(const Messenger *m, const int32_t friendnumber);
/* returns timestamp of last time friendnumber was seen online, or 0 if never seen. /* returns timestamp of last time friendnumber was seen online, or 0 if never seen.
* returns -1 on error. * returns -1 on error.
*/ */
@ -702,48 +531,6 @@ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Mess
void *userdata); void *userdata);
/* Set the callback function for avatar information.
* This callback will be called when avatar information are received from friends. These events
* can arrive at anytime, but are usually received uppon connection and in reply of avatar
* information requests.
*
* Function format is:
* function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata)
*
* where 'format' is the avatar image format (see AVATAR_FORMAT) and 'hash' is the hash of
* the avatar data for caching purposes and it is exactly AVATAR_HASH_LENGTH long. If the
* image format is NONE, the hash is zeroed.
*
*/
void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *),
void *userdata);
/* Set the callback function for avatar data.
* This callback will be called when the complete avatar data was correctly received from a
* friend. This only happens in reply of a avatar data request (see tox_request_avatar_data);
*
* Function format is:
* function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)
*
* where 'format' is the avatar image format (see AVATAR_FORMAT); 'hash' is the
* locally-calculated cryptographic hash of the avatar data and it is exactly
* AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length
* of such data.
*
* If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is
* always validated locally with the function tox_avatar_hash and ensured to match the image
* data, so this value can be safely used to compare with cached avatars.
*
* WARNING: users MUST treat all avatar image data received from another peer as untrusted and
* potentially malicious. The library only ensures that the data which arrived is the same the
* other user sent, and does not interpret or validate any image data.
*/
void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *,
uint32_t, void *), void *userdata);
/**********GROUP CHATS************/ /**********GROUP CHATS************/
/* Set the callback for group invites. /* Set the callback for group invites.