diff --git a/core/Messenger.c b/core/Messenger.c index 3ad9097cf..f1d8b35ee 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -38,6 +38,8 @@ typedef struct { USERSTATUS userstatus; uint8_t userstatus_sent; 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? */ } Friend; uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; @@ -129,6 +131,8 @@ int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length) friendlist[i].userstatus = USERSTATUS_NONE; memcpy(friendlist[i].info, data, length); friendlist[i].info_size = length; + friendlist[i].message_id = 0; + friendlist[i].receives_read_receipts = 1; /* default: YES */ ++numfriends; return i; @@ -152,6 +156,8 @@ int m_addfriend_norequest(uint8_t * client_id) friendlist[i].statusmessage = calloc(1, 1); friendlist[i].statusmessage_length = 1; friendlist[i].userstatus = USERSTATUS_NONE; + friendlist[i].message_id = 0; + friendlist[i].receives_read_receipts = 1; /* default: YES */ numfriends++; return i; } @@ -195,19 +201,31 @@ int m_friendstatus(int friendnumber) } /* send a text chat message to an online friend - return 1 if packet was successfully put into the send queue + return the message id if packet was successfully put into the send queue return 0 if it was not */ -int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length) +uint32_t m_sendmessage(int friendnumber, uint8_t *message, uint32_t length) { if (friendnumber < 0 || friendnumber >= numfriends) return 0; - if (length >= MAX_DATA_SIZE || friendlist[friendnumber].status != FRIEND_ONLINE) + uint32_t msgid = ++friendlist[friendnumber].message_id; + if (msgid == 0) + msgid = 1; /* otherwise, false error */ + return m_sendmessage_withid(friendnumber, msgid, message, length); +} + +uint32_t m_sendmessage_withid(int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) +{ + if (friendnumber < 0 || friendnumber >= numfriends) + return 0; + if (length >= (MAX_DATA_SIZE - sizeof(theid)) || friendlist[friendnumber].status != FRIEND_ONLINE) /* this does not mean the maximum message length is MAX_DATA_SIZE - 1, it is actually 17 bytes less. */ return 0; uint8_t temp[MAX_DATA_SIZE]; temp[0] = PACKET_ID_MESSAGE; - memcpy(temp + 1, message, length); - return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1); + theid = htonl(theid); + memcpy(temp + 1, &theid, sizeof(theid)); + memcpy(temp + 1 + sizeof(theid), message, length); + return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1 + sizeof(theid)); } /* send a name packet to friendnumber @@ -382,6 +400,16 @@ static void set_friend_userstatus(int friendnumber, USERSTATUS status) friendlist[friendnumber].userstatus = status; } +/* Sets whether we send read receipts for friendnumber. */ +void m_set_sends_receipts(int friendnumber, int yesno) +{ + if (yesno != 0 || yesno != 1) + return; + if (friendnumber >= numfriends || friendnumber < 0) + return; + friendlist[friendnumber].receives_read_receipts = yesno; +} + /* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); static uint8_t friend_request_isset = 0; */ /* set the function that will be executed when a friend request is received. */ @@ -424,6 +452,14 @@ void m_callback_userstatus(void (*function)(int, USERSTATUS)) friend_userstatuschange_isset = 1; } +static void (*read_receipt)(int, uint32_t); +static uint8_t read_receipt_isset = 0; +void m_callback_read_receipt(void (*function)(int, uint32_t)) +{ + read_receipt = function; + read_receipt_isset = 1; +} + #define PORT 33445 /* run this at startup */ int initMessenger(void) @@ -521,8 +557,25 @@ static void doFriends(void) break; } case PACKET_ID_MESSAGE: { + if (friendlist[i].receives_read_receipts) { + uint8_t *thepacket = malloc(5); + thepacket[0] = PACKET_ID_RECEIPT; + memcpy(thepacket + 1, temp + 1, 4); + write_cryptpacket(friendlist[i].crypt_connection_id, thepacket, 5); + free(thepacket); + } if (friend_message_isset) - (*friend_message)(i, temp + 1, len - 1); + (*friend_message)(i, temp + 5, len - 5); + break; + } + case PACKET_ID_RECEIPT: { + uint32_t msgid; + if (len < 1 + sizeof(msgid)) + break; + memcpy(&msgid, temp + 1, sizeof(msgid)); + msgid = ntohl(msgid); + if (read_receipt_isset) + (*read_receipt)(i, msgid); break; } } diff --git a/core/Messenger.h b/core/Messenger.h index aef652ff8..d2fa8945b 100644 --- a/core/Messenger.h +++ b/core/Messenger.h @@ -41,6 +41,7 @@ extern "C" { #define PACKET_ID_NICKNAME 48 #define PACKET_ID_STATUSMESSAGE 49 #define PACKET_ID_USERSTATUS 50 +#define PACKET_ID_RECEIPT 65 #define PACKET_ID_MESSAGE 64 /* status definitions */ @@ -112,9 +113,14 @@ int m_delfriend(int friendnumber); int m_friendstatus(int friendnumber); /* send a text chat message to an online friend - returns 1 if packet was successfully put into the send queue - return 0 if it was not */ -int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length); + returns the message id if packet was successfully put into the send queue + return 0 if it was not + you will want to retain the return value, it will be passed to your read receipt callback + if one is received. + m_sendmessage_withid will send a message with the id of your choosing, + however we can generate an id for you by calling plain m_sendmessage. */ +uint32_t m_sendmessage(int friendnumber, uint8_t *message, uint32_t length); +uint32_t m_sendmessage_withid(int friendnumber, uint32_t theid, uint8_t *message, uint32_t length); /* Set our nickname name must be a string of maximum MAX_NAME_LENGTH length. @@ -160,6 +166,10 @@ int m_copy_self_statusmessage(uint8_t *buf, uint32_t maxlen); USERSTATUS m_get_userstatus(int friendnumber); USERSTATUS m_get_self_userstatus(void); +/* Sets whether we send read receipts for friendnumber. + * This function is not lazy, and it will fail if yesno is not (0 or 1).*/ +void m_set_sends_receipts(int friendnumber, int yesno); + /* set the function that will be executed when a friend request is received. function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)); @@ -178,6 +188,15 @@ void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t)); you are not responsible for freeing newstatus */ void m_callback_statusmessage(void (*function)(int, uint8_t *, uint16_t)); +/* set the callback for read receipts + function(int friendnumber, uint32_t receipt) + if you are keeping a record of returns from m_sendmessage, + receipt might be one of those values, and that means the message + has been received on the other side. since core doesn't + track ids for you, receipt may not correspond to any message + in that case, you should discard it. */ +void m_callback_read_receipt(void (*function)(int, uint32_t)); + /* run this at startup returns 0 if no connection problems returns -1 if there are problems */ diff --git a/testing/toxic/chat.c b/testing/toxic/chat.c index 2563fa9cc..28c5de6ce 100644 --- a/testing/toxic/chat.c +++ b/testing/toxic/chat.c @@ -57,7 +57,6 @@ static void chat_onMessage(ToxWindow *self, int num, uint8_t *msg, uint16_t len) self->blink = true; beep(); - flash(); } static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len) @@ -121,7 +120,7 @@ static void chat_onKey(ToxWindow *self, int key) wattroff(ctx->history, COLOR_PAIR(1)); wprintw(ctx->history, "%s\n", ctx->line); } - if (m_sendmessage(ctx->friendnum, (uint8_t*) ctx->line, strlen(ctx->line)+1) < 0) { + if (m_sendmessage(ctx->friendnum, (uint8_t*) ctx->line, strlen(ctx->line)+1) == 0) { wattron(ctx->history, COLOR_PAIR(3)); wprintw(ctx->history, " * Failed to send message.\n"); wattroff(ctx->history, COLOR_PAIR(3)); diff --git a/testing/toxic/main.c b/testing/toxic/main.c index 59333004f..b2310c80d 100644 --- a/testing/toxic/main.c +++ b/testing/toxic/main.c @@ -22,6 +22,7 @@ extern int add_req(uint8_t *public_key); // XXX /* Holds status of chat windows */ char WINDOW_STATUS[MAX_WINDOW_SLOTS]; +#define TOXICVER "0.1.0" //Will be moved to a -D flag later static ToxWindow windows[MAX_WINDOW_SLOTS]; static ToxWindow* prompt; @@ -258,7 +259,7 @@ static void draw_bar() move(LINES - 1, 0); attron(COLOR_PAIR(4) | A_BOLD); - printw(" TOXIC 1.0 |"); + printw(" TOXIC " TOXICVER " |"); attroff(COLOR_PAIR(4) | A_BOLD); int i; diff --git a/testing/toxic/prompt.c b/testing/toxic/prompt.c index 01261ccef..661d881fd 100644 --- a/testing/toxic/prompt.c +++ b/testing/toxic/prompt.c @@ -62,6 +62,16 @@ static void execute(ToxWindow *self, char *u_cmd) if (!isspace(cmd[cmd_end])) break; cmd[cmd_end + 1] = '\0'; + +/* What is this supposed to do? + if (cmd[0] == '/') { + wprintw(self->window,"Warning: Run your command without the /, this may not work\n"); + int i; + for (i = 1; i < strlen(cmd); i++) { //This doesn't work when it doesn't end with a space and another word + cmd[i - 1] = cmd[i]; //Still working on why + } + } +*/ if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || !strcmp(cmd, "q")) { endwin(); @@ -287,7 +297,7 @@ static void execute(ToxWindow *self, char *u_cmd) } msg[0] = 0; msg++; - if (m_sendmessage(atoi(id), (uint8_t*) msg, strlen(msg)+1) < 0) + if (m_sendmessage(atoi(id), (uint8_t*) msg, strlen(msg)+1) == 0) wprintw(self->window, "Error occurred while sending message.\n"); else wprintw(self->window, "Message successfully sent.\n"); @@ -368,7 +378,7 @@ static void print_usage(ToxWindow *self) wprintw(self->window, " myid : Print your ID\n"); wprintw(self->window, " quit/exit : Exit program\n"); wprintw(self->window, " help : Print this message again\n"); - wprintw(self->window, " clear : Clear this window\n"); + wprintw(self->window, " clear : Clear this window\n"); wattron(self->window, A_BOLD); wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n");