1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-26 15:13:27 +01:00

implement read receipts

This commit is contained in:
Jfreegman 2014-09-07 02:43:53 -04:00
parent 3c2c1f15ce
commit 5b9bd603ea
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
10 changed files with 141 additions and 35 deletions

View File

@ -240,7 +240,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *acti
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action); line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true); write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1) if (self->active_box != -1)
@ -288,6 +288,12 @@ static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char
statusbar->statusmsg_len = strlen(statusbar->statusmsg); statusbar->statusmsg_len = strlen(statusbar->statusmsg);
} }
static void chat_onReadReceipt(ToxWindow *self, Tox *m, int32_t num, uint32_t receipt)
{
struct chat_queue *q = self->chatwin->cqueue;
cqueue_remove(self, q, receipt);
}
static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
uint64_t filesize, const char *pathname, uint16_t path_len) uint64_t filesize, const char *pathname, uint16_t path_len)
{ {
@ -831,9 +837,9 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, selfname, NULL, ACTION, 0, 0, "%s", action); line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
write_to_log(action, selfname, ctx->log, true); write_to_log(action, selfname, ctx->log, true);
cqueue_add(ctx->cqueue, action, strlen(action), QACTION, ctx->hst->line_end->id); cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, ctx->hst->line_end->id + 1);
} }
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
@ -915,7 +921,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line); line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
write_to_log(line, selfname, ctx->log, false); write_to_log(line, selfname, ctx->log, false);
cqueue_add(ctx->cqueue, line, strlen(line), QMESSAGE, ctx->hst->line_end->id); cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
} }
wclear(ctx->linewin); wclear(ctx->linewin);
@ -1120,6 +1126,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.onFileSendRequest = &chat_onFileSendRequest; ret.onFileSendRequest = &chat_onFileSendRequest;
ret.onFileControl = &chat_onFileControl; ret.onFileControl = &chat_onFileControl;
ret.onFileData = &chat_onFileData; ret.onFileData = &chat_onFileData;
ret.onReadReceipt = &chat_onReadReceipt;
#ifdef _AUDIO #ifdef _AUDIO
ret.onInvite = &chat_onInvite; ret.onInvite = &chat_onInvite;

View File

@ -197,7 +197,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action); line_info_add(self, timefrmt, nick, NULL, GROUP_ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true); write_to_log(action, nick, ctx->log, true);
} }

View File

@ -153,7 +153,16 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint
/* for type-specific formatting in print function */ /* for type-specific formatting in print function */
switch (type) { switch (type) {
case ACTION: case OUT_ACTION:
case IN_ACTION:
case GROUP_ACTION:
len += 5;
break;
case OUT_MSG:
len += 4;
break;
case CONNECTION: case CONNECTION:
len += 3; len += 3;
break; break;
@ -277,6 +286,7 @@ void line_info_print(ToxWindow *self)
switch (type) { switch (type) {
case OUT_MSG: case OUT_MSG:
case OUT_MSG_READ:
case IN_MSG: case IN_MSG:
wattron(win, COLOR_PAIR(BLUE)); wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s", line->timestamp); wprintw(win, "%s", line->timestamp);
@ -296,22 +306,39 @@ void line_info_print(ToxWindow *self)
if (line->msg[0] == '>') if (line->msg[0] == '>')
wattron(win, COLOR_PAIR(GREEN)); wattron(win, COLOR_PAIR(GREEN));
wprintw(win, "%s\n", line->msg); wprintw(win, "%s", line->msg);
if (line->msg[0] == '>') if (line->msg[0] == '>')
wattroff(win, COLOR_PAIR(GREEN)); wattroff(win, COLOR_PAIR(GREEN));
if (type == OUT_MSG) { /* sent message with no recieve receipt */
wattron(win, COLOR_PAIR(RED));
wprintw(win, " x", line->msg);
wattroff(win, COLOR_PAIR(RED));
}
wprintw(win, "\n", line->msg);
break; break;
case ACTION: case GROUP_ACTION:
case OUT_ACTION_READ:
case OUT_ACTION:
case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE)); wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s", line->timestamp); wprintw(win, "%s", line->timestamp);
wattroff(win, COLOR_PAIR(BLUE)); wattroff(win, COLOR_PAIR(BLUE));
wattron(win, COLOR_PAIR(YELLOW)); wattron(win, COLOR_PAIR(YELLOW));
wprintw(win, "* %s %s\n", line->name1, line->msg); wprintw(win, "* %s %s", line->name1, line->msg);
wattroff(win, COLOR_PAIR(YELLOW)); wattroff(win, COLOR_PAIR(YELLOW));
if (type == OUT_ACTION) { /* sent action with no recieve receipt */
wattron(win, COLOR_PAIR(RED));
wprintw(win, " x", line->msg);
wattroff(win, COLOR_PAIR(RED));
}
wprintw(win, "\n", line->msg);
break; break;
case SYS_MSG: case SYS_MSG:
@ -390,6 +417,7 @@ void line_info_print(ToxWindow *self)
line_info_print(self); line_info_print(self);
} }
/* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, char *msg) void line_info_set(ToxWindow *self, uint32_t id, char *msg)
{ {
struct line_info *line = self->chatwin->hst->line_end; struct line_info *line = self->chatwin->hst->line_end;

View File

@ -34,8 +34,12 @@ enum {
SYS_MSG, SYS_MSG,
IN_MSG, IN_MSG,
OUT_MSG, OUT_MSG,
OUT_MSG_READ, /* for sent messages that have received a read reply. don't set this with line_info_add */
IN_ACTION,
OUT_ACTION,
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
GROUP_ACTION,
PROMPT, PROMPT,
ACTION,
CONNECTION, CONNECTION,
NAME_CHANGE, NAME_CHANGE,
} LINE_TYPE; } LINE_TYPE;
@ -49,7 +53,7 @@ struct line_info {
uint8_t bold; uint8_t bold;
uint8_t colour; uint8_t colour;
uint32_t id; uint32_t id;
uint16_t len; /* combined len of all strings */ uint16_t len; /* combined len of entire line */
uint8_t newlines; uint8_t newlines;
struct line_info *prev; struct line_info *prev;

View File

@ -25,6 +25,8 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "message_queue.h" #include "message_queue.h"
#include "misc_tools.h"
#include "line_info.h"
void cqueue_cleanup(struct chat_queue *q) void cqueue_cleanup(struct chat_queue *q)
{ {
@ -41,7 +43,7 @@ void cqueue_cleanup(struct chat_queue *q)
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id) void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id)
{ {
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); struct cqueue_msg *new_m = calloc(1, sizeof(struct cqueue_msg));
if (new_m == NULL) if (new_m == NULL)
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY); exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
@ -50,38 +52,90 @@ void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, ui
new_m->len = len; new_m->len = len;
new_m->type = type; new_m->type = type;
new_m->line_id = line_id; new_m->line_id = line_id;
new_m->next = NULL;
if (q->root == NULL) if (q->root == NULL) {
new_m->prev = NULL;
q->root = new_m; q->root = new_m;
else } else {
new_m->prev = q->end;
q->end->next = new_m; q->end->next = new_m;
}
q->end = new_m; q->end = new_m;
} }
static void cqueue_remove(struct chat_queue *q) /* update line to show receipt was received after queue removal */
static void cqueue_mark_read(ToxWindow *self, uint32_t id, uint8_t type)
{ {
struct cqueue_msg *new_root = q->root->next; struct line_info *line = self->chatwin->hst->line_end;
free(q->root);
q->root = new_root; while (line) {
if (line->id == id) {
line->type = type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
line->len -= 2; /* removes " x" */
return;
}
line = line->prev;
}
} }
void cqueue_try_send(Tox *m, struct chat_queue *q) /* removes the message with the same receipt number from queue and updates line to show the message was received*/
void cqueue_remove(ToxWindow *self, struct chat_queue *q, uint32_t receipt)
{ {
struct cqueue_msg *q_msg = q->root;
while (q_msg) {
struct cqueue_msg *next = q_msg->next;
if (q_msg->receipt == receipt) {
uint32_t line_id = q_msg->line_id;
uint8_t type = q_msg->type;
if (q_msg->prev == NULL) {
if (next)
next->prev = NULL;
free(q->root);
q->root = next;
} else {
q_msg->prev->next = next;
free(q_msg);
}
cqueue_mark_read(self, line_id, type);
return;
}
q_msg = next;
}
}
#define CQUEUE_TRY_SEND_INTERVAL 5
/* Tries to send oldest message in queue. If fails, tries again in CQUEUE_TRY_SEND_INTERVAL seconds */
void cqueue_try_send(ToxWindow *self, Tox *m)
{
struct chat_queue *q = self->chatwin->cqueue;
if (q->root == NULL) if (q->root == NULL)
return; return;
struct cqueue_msg *q_msg = q->root; struct cqueue_msg *q_msg = q->root;
uint32_t receipt; uint64_t curtime = get_unix_time();
if (q_msg->type == QMESSAGE) /* allow some time for a laggy read receipt before resending
TODO: timeout should be removed when receipts are fixed in core) */
if (q_msg->receipt != 0 && !timed_out(q_msg->last_send_try, curtime, CQUEUE_TRY_SEND_INTERVAL))
return;
uint32_t receipt = 0;
if (q_msg->type == OUT_MSG)
receipt = tox_send_message(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len); receipt = tox_send_message(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len);
else else
receipt = tox_send_action(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len); receipt = tox_send_action(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len);
if (receipt == 0) q->root->last_send_try = curtime;
return; q->root->receipt = receipt;
cqueue_remove(q);
} }

View File

@ -20,17 +20,14 @@
* *
*/ */
enum {
QMESSAGE,
QACTION,
} MESSAGE_TYPE;
struct cqueue_msg { struct cqueue_msg {
char message[MAX_STR_SIZE]; char message[MAX_STR_SIZE];
int len; int len;
int line_id; int line_id;
uint8_t type; uint8_t type;
uint32_t receipt; uint32_t receipt;
uint64_t last_send_try;
struct cqueue_msg *prev;
struct cqueue_msg *next; struct cqueue_msg *next;
}; };
@ -42,5 +39,9 @@ struct chat_queue {
void cqueue_cleanup(struct chat_queue *q); void cqueue_cleanup(struct chat_queue *q);
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id); void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id);
void cqueue_check(Tox *m);
void cqueue_try_send(Tox *m, struct chat_queue *q); /* Tries to send oldest message in queue once every CQUEUE_TRY_SEND_INTERVAL seconds */
void cqueue_try_send(ToxWindow *self, Tox *m);
/* removes the message with the same receipt number from queue and updates line to show the message was received*/
void cqueue_remove(ToxWindow *self, struct chat_queue *q, uint32_t receipt);

View File

@ -285,6 +285,7 @@ static Tox *init_tox(void)
tox_callback_file_send_request(m, on_file_sendrequest, NULL); tox_callback_file_send_request(m, on_file_sendrequest, NULL);
tox_callback_file_control(m, on_file_control, NULL); tox_callback_file_control(m, on_file_control, NULL);
tox_callback_file_data(m, on_file_data, NULL); tox_callback_file_data(m, on_file_data, NULL);
tox_callback_read_receipt(m, on_read_receipt, NULL);
#ifdef __linux__ #ifdef __linux__
tox_set_name(m, (uint8_t *) "Cool dude", strlen("Cool dude")); tox_set_name(m, (uint8_t *) "Cool dude", strlen("Cool dude"));
@ -587,11 +588,11 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i); ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1) if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1)
cqueue_try_send(m, toxwin->chatwin->cqueue); cqueue_try_send(toxwin, m);
} }
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
usleep(100000); /* 0.1 second */ usleep(50000);
} }
} }

View File

@ -108,5 +108,6 @@ void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t
const uint8_t *data, uint16_t length, void *userdata); const uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata); void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata); void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
void on_read_receipt(Tox *m, int32_t, uint32_t, void *userdata);
#endif /* #define _toxic_h */ #endif /* #define _toxic_h */

View File

@ -219,6 +219,15 @@ void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_
} }
} }
void on_read_receipt(Tox *m, int32_t friendnumber, uint32_t receipt, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onReadReceipt != NULL)
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
}
}
/* CALLBACKS END */ /* CALLBACKS END */
int add_window(Tox *m, ToxWindow w) int add_window(Tox *m, ToxWindow w)

View File

@ -119,6 +119,7 @@ struct ToxWindow {
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t); void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t);
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t); void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t); void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
void(*onReadReceipt)(ToxWindow *, Tox *, int32_t, uint32_t);
#ifdef _AUDIO #ifdef _AUDIO