From 399b92c8e7cbca8d6e30184b0ccc8813bf0ad228 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Sun, 15 Sep 2013 16:38:38 -0400 Subject: [PATCH] added groupchats --- src/chat.c | 47 ++++----- src/chat.h | 4 + src/friendlist.c | 7 +- src/groupchat.c | 233 ++++++++++++++++++++++++++++++++++++++++++++ src/groupchat.h | 6 ++ src/main.c | 2 + src/prompt.c | 179 +++++++++++++++++++++++++++------- src/toxic_windows.h | 29 +++++- src/windows.c | 21 +++- 9 files changed, 452 insertions(+), 76 deletions(-) create mode 100644 src/groupchat.c create mode 100644 src/groupchat.h diff --git a/src/chat.c b/src/chat.c index 18f683b..1267a17 100644 --- a/src/chat.c +++ b/src/chat.c @@ -18,18 +18,9 @@ #include "friendlist.h" #include "chat.h" -#define CURS_Y_OFFSET 3 - extern char *DATA_FILE; extern int store_data(Tox *m, char *path); -typedef struct { - wchar_t line[MAX_STR_SIZE]; - size_t pos; - WINDOW *history; - WINDOW *linewin; -} ChatContext; - struct tm *get_time(void) { struct tm *timeinfo; @@ -41,11 +32,10 @@ struct tm *get_time(void) static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint16_t len) { - if (self->friendnum != num) + if (self->num != num) return; ChatContext *ctx = (ChatContext *) self->chatwin; - struct tm *timeinfo = get_time(); uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'}; @@ -65,7 +55,7 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint1 void chat_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t status) { - if (self->friendnum != num) + if (self->num != num) return; StatusBar *statusbar = (StatusBar *) self->stb; @@ -74,7 +64,7 @@ void chat_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t status) static void chat_onAction(ToxWindow *self, Tox *m, int num, uint8_t *action, uint16_t len) { - if (self->friendnum != num) + if (self->num != num) return; ChatContext *ctx = (ChatContext *) self->chatwin; @@ -97,7 +87,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int num, uint8_t *action, uin static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len) { - if (self->friendnum != num) + if (self->num != num) return; snprintf(self->name, sizeof(self->name), "%s", nick); @@ -105,7 +95,7 @@ static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t static void chat_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USERSTATUS status) { - if (self->friendnum != num) + if (self->num != num) return; StatusBar *statusbar = (StatusBar *) self->stb; @@ -114,7 +104,7 @@ static void chat_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USERSTATUS static void chat_onStatusMessageChange(ToxWindow *self, int num, uint8_t *status, uint16_t len) { - if (self->friendnum != num) + if (self->num != num) return; StatusBar *statusbar = (StatusBar *) self->stb; @@ -133,7 +123,7 @@ int string_is_empty(char *string) } /* convert wide characters to null terminated string */ -static uint8_t *wcs_to_char(wchar_t *string) +uint8_t *wcs_to_char(wchar_t *string) { size_t len = 0; char *ret = NULL; @@ -162,7 +152,7 @@ static uint8_t *wcs_to_char(wchar_t *string) } /* convert a wide char to null terminated string */ -static char *wc_to_char(wchar_t ch) +char *wc_to_char(wchar_t ch) { int len = 0; static char ret[MB_LEN_MAX + 1]; @@ -239,7 +229,7 @@ static void execute(ToxWindow *self, ChatContext *ctx, StatusBar *statusbar, Tox wattroff(ctx->history, COLOR_PAIR(YELLOW)); if (!statusbar->is_online - || tox_sendaction(m, self->friendnum, action, strlen(action) + 1) == 0) { + || tox_sendaction(m, self->num, action, strlen(action) + 1) == 0) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, " * Failed to send action\n"); wattroff(ctx->history, COLOR_PAIR(RED)); @@ -393,7 +383,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) if (line[0] == '/') { if (close_win = !strncmp(line, "/close", strlen("/close"))) { - int f_num = self->friendnum; + int f_num = self->num; delwin(ctx->linewin); delwin(statusbar->topline); del_window(self); @@ -415,7 +405,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) wprintw(ctx->history, "%s\n", line); if (!statusbar->is_online - || tox_sendmessage(m, self->friendnum, line, strlen(line) + 1) == 0) { + || tox_sendmessage(m, self->num, line, strlen(line) + 1) == 0) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, " * Failed to send message.\n"); wattroff(ctx->history, COLOR_PAIR(RED)); @@ -438,7 +428,6 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) static void chat_onDraw(ToxWindow *self, Tox *m) { curs_set(1); - int x, y; getmaxyx(self->window, y, x); @@ -487,9 +476,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m) /* Reset statusbar->statusmsg on window resize */ if (x != self->x) { uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; - tox_copy_statusmessage(m, self->friendnum, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); + tox_copy_statusmessage(m, self->num, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); - statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->friendnum); + statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->num); } self->x = x; @@ -520,13 +509,13 @@ static void chat_onInit(ToxWindow *self, Tox *m) /* Init statusbar info */ StatusBar *statusbar = (StatusBar *) self->stb; - statusbar->status = tox_get_userstatus(m, self->friendnum); - statusbar->is_online = tox_get_friend_connectionstatus(m, self->friendnum) == 1; + statusbar->status = tox_get_userstatus(m, self->num); + statusbar->is_online = tox_get_friend_connectionstatus(m, self->num) == 1; uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; - tox_copy_statusmessage(m, self->friendnum, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); + tox_copy_statusmessage(m, self->num, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); - statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->friendnum); + statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->num); /* Init subwindows */ ChatContext *ctx = (ChatContext *) self->chatwin; @@ -571,7 +560,7 @@ ToxWindow new_chat(Tox *m, ToxWindow *prompt, int friendnum) } ret.prompt = prompt; - ret.friendnum = friendnum; + ret.num = friendnum; return ret; } diff --git a/src/chat.h b/src/chat.h index 25e64b7..10405ec 100644 --- a/src/chat.h +++ b/src/chat.h @@ -1,6 +1,10 @@ #ifndef CHAT_H_6489PZ13 #define CHAT_H_6489PZ13 +struct tm *get_time(void); +char *wc_to_char(wchar_t ch); +uint8_t *wcs_to_char(wchar_t *string); +int string_is_empty(char *string); ToxWindow new_chat(Tox *m, ToxWindow *prompt, int friendnum); #endif /* end of include guard: CHAT_H_6489PZ13 */ diff --git a/src/friendlist.c b/src/friendlist.c index 9be6c30..8f01eb9 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -49,10 +49,7 @@ void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t sta if (num < 0 || num >= num_friends) return; - if (status == 1) - friends[num].online = true; - else - friends[num].online = false; + friends[num].online = status == 1 ? true : false; } void friendlist_onNickChange(ToxWindow *self, int num, uint8_t *str, uint16_t len) @@ -227,7 +224,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; tox_copy_statusmessage(m, friends[i].num, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); snprintf(friends[i].statusmsg, sizeof(friends[i].statusmsg), "%s", statusmsg); - friends[i].statusmsg_len = tox_get_statusmessage_size(m, self->friendnum); + friends[i].statusmsg_len = tox_get_statusmessage_size(m, self->num); } self->x = x; diff --git a/src/groupchat.c b/src/groupchat.c new file mode 100644 index 0000000..d1db257 --- /dev/null +++ b/src/groupchat.c @@ -0,0 +1,233 @@ +/* + * Toxic -- Tox Curses Client + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "toxic_windows.h" +#include "chat.h" + +static GroupChat groupchats[MAX_GROUPCHAT_NUM]; +static int group_chat_index = 0; + +ToxWindow new_groupchat(Tox *m, ToxWindow *prompt, int groupnum); + +extern char *DATA_FILE; +extern int store_data(Tox *m, char *path); + +int get_num_groupchats(void) +{ + int count = 0; + int i; + + for (i = 0; i < group_chat_index; ++i) { + if (groupchats[i].active) + ++count; + } + + return count; +} + +int init_groupchat_win(ToxWindow *prompt, Tox *m) +{ + int i; + + for (i = 0; i <= group_chat_index; ++i) { + if (!groupchats[i].active) { + groupchats[i].active = true; + groupchats[i].chatwin = add_window(m, new_groupchat(m, prompt, i)); + set_active_window(groupchats[i].chatwin); + + if (i == group_chat_index) + ++group_chat_index; + + return 0; + } + } + + return -1; +} + +static void close_groupchatwin(Tox *m, int groupnum) +{ + tox_del_groupchat(m, groupnum); + memset(&(groupchats[groupnum]), 0, sizeof(GroupChat)); + + int i; + + for (i = group_chat_index; i > 0; --i) { + if (groupchats[i-1].active) + break; + } + + group_chat_index = i; +} + +static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, uint8_t *msg, uint16_t len) +{ + if (self->num != groupnum) + return; + + ChatContext *ctx = (ChatContext *) self->chatwin; + struct tm *timeinfo = get_time(); + + // uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'}; + // tox_getname(m, num, nick); + + wattron(ctx->history, COLOR_PAIR(CYAN)); + wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + wattroff(ctx->history, COLOR_PAIR(CYAN)); + wattron(ctx->history, COLOR_PAIR(4)); + wprintw(ctx->history, "Toxicle: "); + wattroff(ctx->history, COLOR_PAIR(4)); + wprintw(ctx->history, "%s\n", msg); + + self->blink = true; + beep(); +} + +static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key) +{ + ChatContext *ctx = (ChatContext *) self->chatwin; + struct tm *timeinfo = get_time(); + + int x, y, y2, x2; + getyx(self->window, y, x); + getmaxyx(self->window, y2, x2); + + /* Add printable chars to buffer and print on input space */ +#if HAVE_WIDECHAR + if (iswprint(key)) { +#else + if (isprint(key)) { +#endif + if (ctx->pos < (MAX_STR_SIZE-1)) { + mvwaddstr(self->window, y, x, wc_to_char(key)); + ctx->line[ctx->pos++] = key; + ctx->line[ctx->pos] = L'\0'; + } + } + + /* BACKSPACE key: Remove one character from line */ + else if (key == 0x107 || key == 0x8 || key == 0x7f) { + if (ctx->pos > 0) { + ctx->line[--ctx->pos] = L'\0'; + + if (x == 0) + mvwdelch(self->window, y - 1, x2 - 1); + else + mvwdelch(self->window, y, x - 1); + } + } + + /* RETURN key: Execute command or print line */ + else if (key == '\n') { + uint8_t *line = wcs_to_char(ctx->line); + wclear(ctx->linewin); + wmove(self->window, y2 - CURS_Y_OFFSET, 0); + wclrtobot(self->window); + bool close_win = false; + + if (line[0] == '/') { + if (close_win = !strncmp(line, "/close", strlen("/close"))) { + set_active_window(0); + int group_num = groupchats[self->num].chatwin; + delwin(ctx->linewin); + del_window(self); + close_groupchatwin(m, group_num); + } //else + //execute(self, ctx, statusbar, m, line); + } else { + /* make sure the string has at least non-space character */ + if (!string_is_empty(line)) { + uint8_t selfname[TOX_MAX_NAME_LENGTH]; + tox_getselfname(m, selfname, TOX_MAX_NAME_LENGTH); + + wattron(ctx->history, COLOR_PAIR(CYAN)); + wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + wattroff(ctx->history, COLOR_PAIR(CYAN)); + wattron(ctx->history, COLOR_PAIR(GREEN)); + wprintw(ctx->history, "%s: ", selfname); + wattroff(ctx->history, COLOR_PAIR(GREEN)); + wprintw(ctx->history, "%s\n", line); + + if (tox_group_message_send(m, self->num, line, strlen(line) + 1) == -1) { + wattron(ctx->history, COLOR_PAIR(RED)); + wprintw(ctx->history, " * Failed to send message.\n"); + wattroff(ctx->history, COLOR_PAIR(RED)); + } + } + } + + if (close_win) + free(ctx); + else { + ctx->line[0] = L'\0'; + ctx->pos = 0; + } + + free(line); + } +} + +static void groupchat_onDraw(ToxWindow *self, Tox *m) +{ + curs_set(1); + int x, y; + getmaxyx(self->window, y, x); + ChatContext *ctx = (ChatContext *) self->chatwin; + mvwhline(ctx->linewin, 0, 0, '_', x); + wrefresh(self->window); +} + +static void groupchat_onInit(ToxWindow *self, Tox *m) +{ + int x, y; + ChatContext *ctx = (ChatContext *) self->chatwin; + getmaxyx(self->window, y, x); + ctx->history = subwin(self->window, y-4, x, 0, 0); + scrollok(ctx->history, 1); + ctx->linewin = subwin(self->window, 2, x, y-4, 0); + // print_help(ctx); + wmove(self->window, y - CURS_Y_OFFSET, 0); +} + +ToxWindow new_groupchat(Tox *m, ToxWindow *prompt, int groupnum) +{ + ToxWindow ret; + memset(&ret, 0, sizeof(ret)); + + ret.onKey = &groupchat_onKey; + ret.onDraw = &groupchat_onDraw; + ret.onInit = &groupchat_onInit; + ret.onGroupMessage = &groupchat_onGroupMessage; + // ret.onNickChange = &groupchat_onNickChange; + // ret.onStatusChange = &groupchat_onStatusChange; + // ret.onAction = &groupchat_onAction; + + snprintf(ret.name, sizeof(ret.name), "Room #%d", groupnum); + + ChatContext *chatwin = calloc(1, sizeof(ChatContext)); + + if (chatwin != NULL) + ret.chatwin = chatwin; + else { + endwin(); + fprintf(stderr, "calloc() failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + ret.prompt = prompt; + ret.num = groupnum; + + return ret; +} diff --git a/src/groupchat.h b/src/groupchat.h new file mode 100644 index 0000000..851e4e4 --- /dev/null +++ b/src/groupchat.h @@ -0,0 +1,6 @@ +/* + * Toxic -- Tox Curses Client + */ + +int init_groupchat_win(ToxWindow *prompt, Tox *m); +int get_num_groupchats(void); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 262b154..26fdb31 100644 --- a/src/main.c +++ b/src/main.c @@ -102,6 +102,8 @@ static Tox *init_tox() tox_callback_userstatus(m, on_statuschange, NULL); tox_callback_statusmessage(m, on_statusmessagechange, NULL); tox_callback_action(m, on_action, NULL); + tox_callback_group_invite(m, on_groupinvite, NULL); + tox_callback_group_message(m, on_groupmessage, NULL); #ifdef __linux__ tox_setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy")); #elif defined(_WIN32) diff --git a/src/prompt.c b/src/prompt.c index ed411a2..78705c9 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -11,11 +11,15 @@ #include #include "prompt.h" +#include "groupchat.h" extern char *DATA_FILE; -uint8_t pending_requests[MAX_STR_SIZE][TOX_CLIENT_ID_SIZE]; // XXX -uint8_t num_requests = 0; // XXX +uint8_t pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE]; +uint8_t num_frnd_requests = 0; + +uint8_t pending_grp_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE]; +uint8_t num_grp_requests = 0; static char prompt_buf[MAX_STR_SIZE] = {'\0'}; static int prompt_buf_pos = 0; @@ -25,7 +29,10 @@ void cmd_accept(ToxWindow *, Tox *m, int, char **); void cmd_add(ToxWindow *, Tox *m, int, char **); void cmd_clear(ToxWindow *, Tox *m, int, char **); void cmd_connect(ToxWindow *, Tox *m, int, char **); +void cmd_groupchat(ToxWindow *, Tox *m, int, char **); void cmd_help(ToxWindow *, Tox *m, int, char **); +void cmd_invite(ToxWindow *, Tox *m, int, char **); +void cmd_join(ToxWindow *, Tox *m, int, char **); void cmd_msg(ToxWindow *, Tox *m, int, char **); void cmd_myid(ToxWindow *, Tox *m, int, char **); void cmd_nick(ToxWindow *, Tox *m, int, char **); @@ -33,7 +40,7 @@ void cmd_quit(ToxWindow *, Tox *m, int, char **); void cmd_status(ToxWindow *, Tox *m, int, char **); void cmd_note(ToxWindow *, Tox *m, int, char **); -#define NUM_COMMANDS 13 +#define NUM_COMMANDS 16 static struct { char *name; @@ -44,7 +51,10 @@ static struct { { "clear", cmd_clear }, { "connect", cmd_connect }, { "exit", cmd_quit }, + { "groupchat", cmd_groupchat }, { "help", cmd_help }, + { "invite", cmd_invite }, + { "join", cmd_join }, { "msg", cmd_msg }, { "myid", cmd_myid }, { "nick", cmd_nick }, @@ -82,30 +92,18 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected) statusbar->is_online = is_connected; } -void prompt_onFriendRequest(ToxWindow *prompt, uint8_t *key, uint8_t *data, uint16_t length) +/* Adds friend request to pending friend requests. */ +int add_friend_req(uint8_t *public_key) { - int n = add_req(key); - wprintw(prompt->window, "\nFriend request from:\n"); - - int i; - - for (i = 0; i < KEY_SIZE_BYTES; ++i) { - wprintw(prompt->window, "%02x", key[i] & 0xff); - } - - wprintw(prompt->window, "\n\nWith the message: %s\n\n", data); - wprintw(prompt->window, "Type \"accept %d\" to accept it.\n", n); - - prompt->blink = true; - beep(); + memcpy(pending_frnd_requests[num_frnd_requests++], public_key, TOX_CLIENT_ID_SIZE); + return num_frnd_requests - 1; } -// XXX: -int add_req(uint8_t *public_key) +/* Adds group chat invite to pending group chat requests */ +int add_group_req(uint8_t *group_pub_key) { - memcpy(pending_requests[num_requests], public_key, TOX_CLIENT_ID_SIZE); - ++num_requests; - return num_requests - 1; + memcpy(pending_grp_requests[num_grp_requests++], group_pub_key, TOX_CLIENT_ID_SIZE); + return num_grp_requests - 1; } // XXX: FIX @@ -132,27 +130,25 @@ unsigned char *hex_string_to_bin(char hex_string[]) /* command functions */ void cmd_accept(ToxWindow *self, Tox *m, int argc, char **argv) { - int num; - /* check arguments */ if (argc != 1) { wprintw(self->window, "Invalid syntax.\n"); return; } - num = atoi(argv[1]); + int num = atoi(argv[1]); - if (num < 0 || num >= num_requests) { - wprintw(self->window, "No pending request with that number.\n"); + if (num < 0 || num >= num_frnd_requests) { + wprintw(self->window, "No pending friend request with that number.\n"); return; } - num = tox_addfriend_norequest(m, pending_requests[num]); + num = tox_addfriend_norequest(m, pending_frnd_requests[num]); if (num == -1) wprintw(self->window, "Failed to add friend.\n"); else { - wprintw(self->window, "Friend accepted as: %d.\n", num); + wprintw(self->window, "Friend accepted.\n"); on_friendadded(m, num); } } @@ -274,7 +270,7 @@ void cmd_connect(ToxWindow *self, Tox *m, int argc, char **argv) char *port = argv[2]; char *key = argv[3]; - if (!ip || !port || !key) { + if (ip == NULL || port == NULL || key == NULL) { wprintw(self->window, "Invalid syntax.\n"); return; } @@ -302,6 +298,31 @@ void cmd_quit(ToxWindow *self, Tox *m, int argc, char **argv) exit_toxic(m); } +void cmd_groupchat(ToxWindow *self, Tox *m, int argc, char **argv) +{ + int ngc = get_num_groupchats(); + + if (ngc < 0 || ngc >= MAX_GROUPCHAT_NUM) { + wprintw(self->window, "\nMaximum number of group chats has been reached.\n"); + return; + } + + int groupnum = tox_add_groupchat(m); + + if (groupnum == -1) { + wprintw(self->window, "Group chat failed to initialize.\n"); + return; + } + + if (init_groupchat_win(self, m) == -1) { + wprintw(self->window, "Group chat failed to initialize.\n"); + tox_del_groupchat(m, groupnum); + return; + } + + wprintw(self->window, "Group chat created as %d.\n", groupnum); +} + void cmd_help(ToxWindow *self, Tox *m, int argc, char **argv) { wclear(self->window); @@ -328,6 +349,55 @@ void cmd_help(ToxWindow *self, Tox *m, int argc, char **argv) wattroff(self->window, COLOR_PAIR(CYAN)); } +void cmd_invite(ToxWindow *self, Tox *m, int argc, char **argv) +{ + if (argc != 2) { + wprintw(self->window, "Invalid syntax.\n"); + return; + } + + if (argv[1] == NULL || argv[2] == NULL) { + wprintw(self->window, "Invalid syntax.\n"); + return; + } + + int friendnum = atoi(argv[1]); + int groupnum = atoi(argv[2]); + int n = tox_invite_friend(m, friendnum, groupnum); + + if (n == -1) { + wprintw(self->window, "Failed to invite friend.\n"); + return; + } + + wprintw(self->window, "Invited friend %d to group chat %d.\n", friendnum, groupnum); +} + +void cmd_join(ToxWindow *self, Tox *m, int argc, char **argv) +{ + if (argc != 1) { + wprintw(self->window, "Invalid syntax.\n"); + return; + } + + if (argv[1] == NULL) { + wprintw(self->window, "Invalid syntax.\n"); + return; + } + + int num = atoi(argv[1]); + + if (num < 0 || num >= num_grp_requests) { + wprintw(self->window, "No pending group chat invites with that number.\n"); + return; + } + + num = tox_join_groupchat(m, num, pending_grp_requests[num]); + + if (num == -1 || init_groupchat_win(self, m) == -1) + wprintw(self->window, "Group chat failed to initialize.\n"); +} + void cmd_msg(ToxWindow *self, Tox *m, int argc, char **argv) { /* check arguments */ @@ -405,11 +475,6 @@ void cmd_nick(ToxWindow *self, Tox *m, int argc, char **argv) void cmd_status(ToxWindow *self, Tox *m, int argc, char **argv) { - if (argc < 1 || argc > 2) { - wprintw(self->window, "Wrong number of arguments.\n"); - return; - } - uint8_t *msg = NULL; if (argc == 2) { @@ -425,6 +490,9 @@ void cmd_status(ToxWindow *self, Tox *m, int argc, char **argv) wprintw(self->window, "Messages must be enclosed in quotes.\n"); return; } + } else if (argc < 1 || argc > 2) { + wprintw(self->window, "Wrong number of arguments.\n"); + return; } char *status = argv[1]; @@ -671,6 +739,42 @@ static void prompt_onInit(ToxWindow *self, Tox *m) wclrtoeol(self->window); } +void prompt_onFriendRequest(ToxWindow *self, uint8_t *key, uint8_t *data, uint16_t length) +{ + int n = add_friend_req(key); + wprintw(self->window, "\nFriend request from:\n"); + + int i; + + for (i = 0; i < KEY_SIZE_BYTES; ++i) { + wprintw(self->window, "%02x", key[i] & 0xff); + } + + wprintw(self->window, "\n\nWith the message: %s\n\n", data); + wprintw(self->window, "Type \"accept %d\" to accept it.\n", n); + + self->blink = true; + beep(); +} + +void prompt_onGroupInvite(ToxWindow *self, Tox *m, int friendnumber, uint8_t *group_pub_key) +{ + int ngc = get_num_groupchats(); + if (ngc < 0 || ngc >= MAX_GROUPCHAT_NUM) { + wprintw(self->window, "\nGroup chat invite from: %d\n", friendnumber); + wprintw(self->window, "\nMaximum number of group chats has been reached. Discarding invite.\n"); + return; + } + + int n = add_group_req(group_pub_key); + + wprintw(self->window, "\nGroup chat invite from: %d\n", friendnumber); + wprintw(self->window, "Type \"join %d\" to join the chat.\n", n); + + self->blink = true; + beep(); +} + void prompt_init_statusbar(ToxWindow *self, Tox *m) { int x, y; @@ -698,10 +802,13 @@ ToxWindow new_prompt() { ToxWindow ret; memset(&ret, 0, sizeof(ret)); + ret.onKey = &prompt_onKey; ret.onDraw = &prompt_onDraw; ret.onInit = &prompt_onInit; ret.onFriendRequest = &prompt_onFriendRequest; + ret.onGroupInvite = &prompt_onGroupInvite; + strcpy(ret.name, "prompt"); StatusBar *stb = calloc(1, sizeof(StatusBar)); diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 11d346e..5768e67 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -1,9 +1,14 @@ /* * Toxic -- Tox Curses Client */ + #ifndef _windows_h #define _windows_h +#ifndef TOXICVER +#define TOXICVER "NOVER" /* Use the -D flag to set this */ +#endif + #include #include #include @@ -14,6 +19,7 @@ #define MAX_WINDOWS_NUM 32 #define MAX_FRIENDS_NUM 100 +#define MAX_GROUPCHAT_NUM 32 #define MAX_STR_SIZE 256 #define KEY_SIZE_BYTES 32 #define TOXIC_MAX_NAME_LENGTH 30 /* Not to be confused with TOX_MAX_NAME_LENGTH */ @@ -21,10 +27,7 @@ #define UNKNOWN_NAME "Unknown" #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 - -#ifndef TOXICVER -#define TOXICVER "NOVER" //Use the -D flag to set this -#endif +#define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */ /* Curses foreground colours (background is black) */ #define WHITE 0 @@ -49,9 +52,11 @@ struct ToxWindow_ { void(*onStatusChange)(ToxWindow *, Tox *, int, TOX_USERSTATUS); void(*onStatusMessageChange)(ToxWindow *, int, uint8_t *, uint16_t); void(*onAction)(ToxWindow *, Tox *, int, uint8_t *, uint16_t); + void(*onGroupMessage)(ToxWindow *, Tox *, int, uint8_t *, uint16_t); + void(*onGroupInvite)(ToxWindow *, Tox *, int, uint8_t *); char name[TOX_MAX_NAME_LENGTH]; - int friendnum; + int num; int x; void *chatwin; @@ -72,6 +77,18 @@ typedef struct { bool is_online; } StatusBar; +typedef struct { + wchar_t line[MAX_STR_SIZE]; + size_t pos; + WINDOW *history; + WINDOW *linewin; +} ChatContext; + +typedef struct { + int chatwin; + bool active; +} GroupChat; + void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata); void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata); void on_message(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); @@ -80,6 +97,8 @@ void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, v void on_statuschange(Tox *m, int friendnumber, TOX_USERSTATUS status, void *userdata); void on_statusmessagechange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); void on_friendadded(Tox *m, int friendnumber); +void on_groupmessage(Tox *m, int groupnumber, uint8_t *message, uint16_t length, void *userdata); +void on_groupinvite(Tox *m, int friendnumber, uint8_t *group_pub_key, void *userdata); ToxWindow *init_windows(); void draw_active_window(Tox *m); int add_window(Tox *m, ToxWindow w); diff --git a/src/windows.c b/src/windows.c index f61768b..60d5d7c 100644 --- a/src/windows.c +++ b/src/windows.c @@ -124,6 +124,26 @@ void on_friendadded(Tox *m, int friendnumber) if (store_data(m, DATA_FILE)) wprintw(prompt->window, "\nCould not store Tox data\n"); } + +void on_groupmessage(Tox *m, int groupnumber, uint8_t *message, uint16_t length, void *userdata) +{ + int i; + + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + if (windows[i].onGroupMessage != NULL) + windows[i].onGroupMessage(&windows[i], m, groupnumber, message, length); + } +} + +void on_groupinvite(Tox *m, int friendnumber, uint8_t *group_pub_key, void *userdata) +{ + int i; + + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + if (windows[i].onGroupInvite != NULL) + windows[i].onGroupInvite(&windows[i], m, friendnumber, group_pub_key); + } +} /* CALLBACKS END */ int add_window(Tox *m, ToxWindow w) @@ -261,7 +281,6 @@ void prepare_window(WINDOW *w) void draw_active_window(Tox *m) { - ToxWindow *a = active_window; wint_t ch = 0;