diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 692d3d0e..ee5213a7 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -268,6 +268,7 @@ int m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t length) m->friendlist[i].statusmessage = calloc(1, 1); m->friendlist[i].statusmessage_length = 1; m->friendlist[i].userstatus = USERSTATUS_NONE; + m->friendlist[i].is_typing = 0; memcpy(m->friendlist[i].info, data, length); m->friendlist[i].info_size = length; m->friendlist[i].message_id = 0; @@ -315,6 +316,7 @@ int m_addfriend_norequest(Messenger *m, uint8_t *client_id) m->friendlist[i].statusmessage = calloc(1, 1); m->friendlist[i].statusmessage_length = 1; m->friendlist[i].userstatus = USERSTATUS_NONE; + m->friendlist[i].is_typing = 0; m->friendlist[i].message_id = 0; m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ @@ -615,6 +617,29 @@ USERSTATUS m_get_self_userstatus(Messenger *m) return m->userstatus; } +int m_set_usertyping(Messenger *m, int friendnumber, uint8_t is_typing) +{ + if (is_typing != 0 || is_typing != 1) { + return -1; + } + + if (friend_not_valid(m, friendnumber)) + return -1; + + m->friendlist[friendnumber].user_istyping = is_typing; + m->friendlist[friendnumber].user_istyping_sent = 0; + + return 0; +} + +uint8_t m_get_istyping(Messenger *m, int friendnumber) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + return m->friendlist[friendnumber].is_typing; +} + static int send_statusmessage(Messenger *m, int friendnumber, uint8_t *status, uint16_t length) { return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length); @@ -626,6 +651,12 @@ static int send_userstatus(Messenger *m, int friendnumber, USERSTATUS status) return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &stat, sizeof(stat)); } +static int send_user_istyping(Messenger *m, int friendnumber, uint8_t is_typing) +{ + uint8_t typing = is_typing; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing)); +} + static int send_ping(Messenger *m, int friendnumber) { int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_PING, 0, 0); @@ -654,6 +685,11 @@ static void set_friend_userstatus(Messenger *m, int friendnumber, USERSTATUS sta m->friendlist[friendnumber].userstatus = status; } +static void set_friend_typing(Messenger *m, int friendnumber, uint8_t is_typing) +{ + m->friendlist[friendnumber].is_typing = is_typing; +} + /* Sets whether we send read receipts for friendnumber. */ void m_set_sends_receipts(Messenger *m, int friendnumber, int yesno) { @@ -707,6 +743,12 @@ void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USE m->friend_userstatuschange_userdata = userdata; } +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int, uint8_t, void *), void *userdata) +{ + m->friend_typingchange = function; + m->friend_typingchange_userdata = userdata; +} + void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, uint32_t, void *), void *userdata) { m->read_receipt = function; @@ -1821,6 +1863,11 @@ void do_friends(Messenger *m) if (send_userstatus(m, i, m->userstatus)) m->friendlist[i].userstatus_sent = 1; } + + if (m->friendlist[i].user_istyping_sent == 0) { + if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) + m->friendlist[i].user_istyping_sent = 1; + } if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { send_ping(m, i); @@ -1882,6 +1929,19 @@ void do_friends(Messenger *m) set_friend_userstatus(m, i, status); break; } + + case PACKET_ID_TYPING: { + if (data_length != 1) + break; + + uint8_t typing = data[0]; + + if (m->friend_typingchange) + m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); + + set_friend_typing(m, i, typing); + break; + } case PACKET_ID_MESSAGE: { uint8_t *message_id = data; diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index ccca8fba..952aa436 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -42,6 +42,7 @@ #define PACKET_ID_NICKNAME 48 #define PACKET_ID_STATUSMESSAGE 49 #define PACKET_ID_USERSTATUS 50 +#define PACKET_ID_TYPING 51 #define PACKET_ID_RECEIPT 65 #define PACKET_ID_MESSAGE 64 #define PACKET_ID_ACTION 63 @@ -145,6 +146,9 @@ typedef struct { uint8_t statusmessage_sent; USERSTATUS userstatus; uint8_t userstatus_sent; + uint8_t user_istyping; + uint8_t user_istyping_sent; + uint8_t is_typing; uint16_t info_size; // Length of the info. uint32_t message_id; // a semi-unique id used in read receipts. uint8_t receives_read_receipts; // shall we send read receipts to this person? @@ -204,6 +208,8 @@ typedef struct Messenger { void *friend_statusmessagechange_userdata; void (*friend_userstatuschange)(struct Messenger *m, int, USERSTATUS, void *); void *friend_userstatuschange_userdata; + void (*friend_typingchange)(struct Messenger *m, int, uint8_t, void *); + void *friend_typingchange_userdata; void (*read_receipt)(struct Messenger *m, int, uint32_t, void *); void *read_receipt_userdata; void (*friend_statuschange)(struct Messenger *m, int, uint8_t, void *); @@ -398,6 +404,21 @@ int m_copy_self_statusmessage(Messenger *m, uint8_t *buf, uint32_t maxlen); USERSTATUS m_get_userstatus(Messenger *m, int friendnumber); USERSTATUS m_get_self_userstatus(Messenger *m); +/* Set our typing status for a friend. + * You are responsible for turning it on or off. + * + * returns 0 on success. + * returns -1 on failure. + */ +int m_set_usertyping(Messenger *m, int friendnumber, uint8_t is_typing); + +/* Get the typing status of a friend. + * + * returns 0 if friend is not typing. + * returns -1 if friend is typing. + */ +uint8_t m_get_istyping(Messenger *m, int friendnumber); + /* Sets whether we send read receipts for friendnumber. * This function is not lazy, and it will fail if yesno is not (0 or 1). */ @@ -439,6 +460,11 @@ void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int, */ void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USERSTATUS, void *), void *userdata); +/* Set the callback for typing changes. + * Function(int friendnumber, uint8_t is_typing) + */ +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int, uint8_t, void *), void *userdata); + /* Set the callback for read receipts. * Function(int friendnumber, uint32_t receipt) * diff --git a/toxcore/tox.c b/toxcore/tox.c index f4690080..3f2c1e92 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -270,6 +270,29 @@ TOX_USERSTATUS tox_get_self_user_status(Tox *tox) return (TOX_USERSTATUS)m_get_self_userstatus(m); } +/* Set our typing status for a friend. + * You are responsible for turning it on or off. + * + * returns 0 on success. + * returns -1 on failure. + */ +int tox_set_user_is_typing(Tox *tox, int friendnumber, uint8_t is_typing) +{ + Messenger *m = tox; + return (int)m_set_usertyping(m, friendnumber, is_typing); +} + +/* Get the typing status of a friend. + * + * returns 0 if friend is not typing. + * returns -1 if friend is typing. + */ +int tox_get_is_typing(Tox *tox, int friendnumber) +{ + Messenger *m = tox; + return (int)m_get_istyping(m, friendnumber); +} + /* Sets whether we send read receipts for friendnumber. * This function is not lazy, and it will fail if yesno is not (0 or 1). @@ -370,6 +393,17 @@ void tox_callback_user_status(Tox *tox, void (*_function)(Tox *tox, int, TOX_USE m_callback_userstatus(m, function, userdata); } +/* Set the callback for typing changes. + * function (int friendnumber, uint8_t is_typing) + */ +void tox_callback_typing_change(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata) +{ + Messenger *m = tox; + typedef void (*function_type)(Messenger *, int, uint8_t, void *); + function_type function_new = (function_type)function; + m_callback_typingchange(m, function_new, userdata); +} + /* Set the callback for read receipts. * function(int friendnumber, uint32_t receipt) * diff --git a/toxcore/tox.h b/toxcore/tox.h index 447a1146..0a4e80f7 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -280,6 +280,21 @@ int tox_get_self_status_message(Tox *tox, uint8_t *buf, uint32_t maxlen); */ TOX_USERSTATUS tox_get_user_status(Tox *tox, int friendnumber); TOX_USERSTATUS tox_get_self_user_status(Tox *tox); + +/* Set our typing status for a friend. + * You are responsible for turning it on or off. + * + * returns 0 on success. + * returns -1 on failure. + */ +int tox_set_user_is_typing(Tox *tox, int friendnumber, uint8_t is_typing); + +/* Get the typing status of a friend. + * + * returns 0 if friend is not typing. + * returns -1 if friend is typing. + */ +int tox_get_is_typing(Tox *tox, int friendnumber); /* Sets whether we send read receipts for friendnumber. * This function is not lazy, and it will fail if yesno is not (0 or 1). @@ -335,6 +350,11 @@ void tox_callback_status_message(Tox *tox, void (*function)(Tox *tox, int, uint8 * function(int friendnumber, USERSTATUS kind) */ void tox_callback_user_status(Tox *tox, void (*function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata); + +/* Set the callback for typing changes. + * function (int friendnumber, uint8_t is_typing) + */ +void tox_callback_typing_change(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata); /* Set the callback for read receipts. * function(int friendnumber, uint32_t receipt)