From 05c05868c606e72ff27c3f909aabc7f85b57adf5 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Sun, 22 Mar 2015 00:56:14 -0400 Subject: [PATCH] implement group private messaging --- doc/toxic.conf.5 | 9 +++-- doc/toxic.conf.5.asc | 3 ++ misc/toxic.conf.example | 5 ++- src/execute.c | 22 ++++++++---- src/groupchat.c | 78 ++++++++++++++++++++++++++++++++++------- src/help.c | 7 ++-- src/line_info.c | 12 ++++++- src/line_info.h | 2 ++ src/settings.c | 24 ++++++++----- src/settings.h | 2 ++ 10 files changed, 129 insertions(+), 35 deletions(-) diff --git a/doc/toxic.conf.5 b/doc/toxic.conf.5 index 7adb194..6b4ad6b 100644 --- a/doc/toxic.conf.5 +++ b/doc/toxic.conf.5 @@ -2,12 +2,12 @@ .\" Title: toxic.conf .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2015-02-19 +.\" Date: 2015-02-26 .\" Manual: Toxic Manual .\" Source: toxic __VERSION__ .\" Language: English .\" -.TH "TOXIC\&.CONF" "5" "2015\-02\-19" "toxic __VERSION__" "Toxic Manual" +.TH "TOXIC\&.CONF" "5" "2015\-02\-26" "toxic __VERSION__" "Toxic Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -138,6 +138,11 @@ Indicator for alert messages\&. Indicator for normal messages\&. .RE .PP +\fBline_special\fR +.RS 4 +Indicator for special messages\&. +.RE +.PP \fBmplex_away\fR .RS 4 Set user status when attaching and detaching from GNU screen or tmux\&. true or false diff --git a/doc/toxic.conf.5.asc b/doc/toxic.conf.5.asc index bfeb4fe..b276023 100644 --- a/doc/toxic.conf.5.asc +++ b/doc/toxic.conf.5.asc @@ -88,6 +88,9 @@ OPTIONS *line_normal*;; Indicator for normal messages. + *line_special*;; + Indicator for special messages. + *mplex_away*;; Set user status when attaching and detaching from GNU screen or tmux. true or false diff --git a/misc/toxic.conf.example b/misc/toxic.conf.example index a4bf7fd..f4c0d9d 100644 --- a/misc/toxic.conf.example +++ b/misc/toxic.conf.example @@ -44,6 +44,9 @@ ui = { // Indicator for normal messages. line_normal="---"; + // Indicator for special messages (currently only used for private group messages) + line_special=">>>"; + // true to change status based on screen/tmux attach/detach, false to disable mplex_away=true; @@ -57,7 +60,7 @@ audio = { // preferred audio output device; numbers correspond to /lsdev out output_device=0; - + // default VAD treshold; float (recommended values are around 40) VAD_treshold=40.0; }; diff --git a/src/execute.c b/src/execute.c index 0596904..dd24f28 100644 --- a/src/execute.c +++ b/src/execute.c @@ -94,8 +94,8 @@ static struct cmd_func group_commands[] = { { NULL, NULL }, }; -#define SPECIAL_COMMANDS 9 -static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { +#define NUM_SPECIAL_COMMANDS 9 +static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { "/ban", "/deop", "/group", @@ -117,7 +117,7 @@ static bool is_special_command(const char *input) int i; - for (i = 0; i < SPECIAL_COMMANDS; ++i) { + for (i = 0; i < NUM_SPECIAL_COMMANDS; ++i) { if (strncmp(input, special_commands[i], s) == 0) return true; } @@ -127,7 +127,9 @@ static bool is_special_command(const char *input) /* Parses commands in the special_commands array which take exactly one argument that may contain spaces. * Unlike parse_command, this function does not split the input string at spaces. - * Returns number of arguments on success, returns -1 on failure + * + * Returns number of arguments on success + * Returns -1 on failure */ static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) { @@ -146,7 +148,9 @@ static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, } /* Parses input command and puts args (split by spaces) into args array. - * Returns number of arguments on success, -1 on failure. + * + * Returns number of arguments on success + * Returns -1 on failure. */ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) { @@ -194,7 +198,11 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a return num_args; } -/* Matches command to respective function. Returns 0 on match, 1 on no match */ +/* Matches command to respective function. + * + * Returns 0 on match, + * Returns -1 on no match + */ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands, char (*args)[MAX_STR_SIZE]) { @@ -207,7 +215,7 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c } } - return 1; + return -1; } void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) diff --git a/src/groupchat.c b/src/groupchat.c index f5b5ae3..f97fb97 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -70,9 +70,9 @@ extern struct user_settings *user_settings; extern struct Winthread Winthread; #ifdef AUDIO -#define AC_NUM_GROUP_COMMANDS 27 +#define AC_NUM_GROUP_COMMANDS 28 #else -#define AC_NUM_GROUP_COMMANDS 23 +#define AC_NUM_GROUP_COMMANDS 24 #endif /* AUDIO */ /* groupchat command names used for tab completion. */ @@ -100,6 +100,7 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = { { "/status" }, { "/topic" }, { "/unignore" }, + { "/whisper" }, #ifdef AUDIO @@ -345,7 +346,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p } static void groupchat_onGroupPrivateMessage(ToxWindow *self, Tox *m, int groupnum, uint32_t peernum, - const char *action, uint16_t len) + const char *msg, uint16_t len) { if (self->num != groupnum) return; @@ -358,8 +359,8 @@ static void groupchat_onGroupPrivateMessage(ToxWindow *self, Tox *m, int groupnu char timefrmt[TIME_STR_SIZE]; get_time_str(timefrmt, sizeof(timefrmt)); - line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, RED, "%s", action); - write_to_log(action, nick, ctx->log, false); + line_info_add(self, timefrmt, nick, NULL, IN_PRVT_MSG, 0, MAGENTA, "%s", msg); + write_to_log(msg, nick, ctx->log, false); sound_notify(self, silent, NT_WNDALERT_1, NULL); } @@ -627,9 +628,13 @@ static void send_group_message(ToxWindow *self, Tox *m, int groupnum, const char { ChatContext *ctx = self->chatwin; + if (msg == NULL) { + wprintw(ctx->history, "Invalid syntax.\n"); + return; + } + if (tox_group_message_send(m, self->num, (uint8_t *) msg, strlen(msg)) == -1) { - const char *errmsg = " * Failed to send message."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "%s", errmsg); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message"); return; } @@ -644,7 +649,7 @@ static void send_group_message(ToxWindow *self, Tox *m, int groupnum, const char write_to_log(msg, selfname, ctx->log, false); } -static void send_group_action(ToxWindow *self, Tox *m, int groupnum, char *action) +static void send_group_action(ToxWindow *self, Tox *m, int groupnum, const char *action) { ChatContext *ctx = self->chatwin; @@ -654,8 +659,7 @@ static void send_group_action(ToxWindow *self, Tox *m, int groupnum, char *actio } if (tox_group_action_send(m, groupnum, (uint8_t *) action, strlen(action)) == -1) { - const char *errmsg = " * Failed to send action."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "%s", errmsg); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action"); return; } @@ -670,6 +674,54 @@ static void send_group_action(ToxWindow *self, Tox *m, int groupnum, char *actio write_to_log(action, selfname, ctx->log, true); } +static void send_group_prvt_message(ToxWindow *self, Tox *m, int groupnum, const char *data) +{ + ChatContext *ctx = self->chatwin; + + if (data == NULL) { + wprintw(ctx->history, "Invalid syntax.\n"); + return; + } + + size_t i; + int peernum = -1, len = 0; + const char *msg = NULL; + + for (i = 0; i < groupchats[groupnum].num_peers; ++i) { + if (memcmp((char *) &groupchats[groupnum].peer_names[i * TOX_MAX_NAME_LENGTH], data, + groupchats[groupnum].peer_name_lengths[i]) == 0) { + len = strlen(data) - groupchats[groupnum].peer_name_lengths[i] - 1; + + if (len <= 0) + return; + + msg = data + groupchats[groupnum].peer_name_lengths[i] + 1; + peernum = i; + break; + } + } + + if (peernum == -1) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name"); + return; + } + + if (tox_group_private_message_send(m, groupnum, peernum, (uint8_t *) msg, len) == -1) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send private message"); + return; + } + + char selfname[TOX_MAX_NAME_LENGTH]; + uint16_t slen = tox_group_get_self_name(m, groupnum, (uint8_t *) selfname); + selfname[slen] = '\0'; + + char timefrmt[TIME_STR_SIZE]; + get_time_str(timefrmt, sizeof(timefrmt)); + + line_info_add(self, timefrmt, selfname, NULL, OUT_PRVT_MSG, 0, 0, "%s", msg); + write_to_log(msg, selfname, ctx->log, false); +} + static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) { ChatContext *ctx = self->chatwin; @@ -742,7 +794,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) add_line_to_hist(ctx); if (line[0] == '/') { - if (strncmp(line, "/close", 6) == 0) { + if (strncmp(line, "/close", strlen("/close")) == 0) { int offset = 6; if (line[offset] != '\0') @@ -750,8 +802,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) exit_groupchat(self, m, self->num, line + offset, ctx->len - offset); return; - } else if (strncmp(line, "/me ", 4) == 0) { + } else if (strncmp(line, "/me ", strlen("/me ")) == 0) { send_group_action(self, m, self->num, line + 4); + } else if (strncmp(line, "/whisper ", strlen("/whisper ")) == 0) { + send_group_prvt_message(self, m, self->num, line + 9); } else { execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE); } diff --git a/src/help.c b/src/help.c index f817c5e..afb43d1 100644 --- a/src/help.c +++ b/src/help.c @@ -246,7 +246,8 @@ static void help_draw_group(ToxWindow *self) wprintw(win, " /ignore : Ignore peer\n"); wprintw(win, " /rejoin : Rejoin the group (only works if not connected)\n"); wprintw(win, " /topic : Set group topic (show current topic if no msg)\n"); - wprintw(win, " /unignore : Unignore peer \n\n"); + wprintw(win, " /unignore : Unignore peer \n"); + wprintw(win, " /whisper : Send private message to nick\n\n"); #ifdef AUDIO wattron(win, A_BOLD); @@ -313,9 +314,9 @@ void help_onKey(ToxWindow *self, wint_t key) case 'r': #ifdef AUDIO - help_init_window(self, 14, 80); + help_init_window(self, 15, 80); #else - help_init_window(self, 10, 80); + help_init_window(self, 11, 80); #endif self->help->type = HELP_GROUP; break; diff --git a/src/line_info.c b/src/line_info.c index 06b05e4..460ad78 100644 --- a/src/line_info.c +++ b/src/line_info.c @@ -164,6 +164,11 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons len += strlen(user_settings->line_normal) + 3; break; + case IN_PRVT_MSG: + case OUT_PRVT_MSG: + len += strlen(user_settings->line_special) + 3; + break; + case CONNECTION: len += strlen(user_settings->line_join) + 2; break; @@ -301,6 +306,8 @@ void line_info_print(ToxWindow *self) case OUT_MSG: case OUT_MSG_READ: case IN_MSG: + case IN_PRVT_MSG: + case OUT_PRVT_MSG: wattron(win, COLOR_PAIR(BLUE)); wprintw(win, "%s ", line->timestr); wattroff(win, COLOR_PAIR(BLUE)); @@ -313,7 +320,10 @@ void line_info_print(ToxWindow *self) nameclr = CYAN; wattron(win, COLOR_PAIR(nameclr)); - wprintw(win, "%s %s: ", user_settings->line_normal, line->name1); + wprintw(win, "%s %s: ",(type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ? + user_settings->line_normal : + user_settings->line_special, + line->name1); wattroff(win, COLOR_PAIR(nameclr)); if (line->msg[0] == '>') diff --git a/src/line_info.h b/src/line_info.h index 0e5c9a1..0d65cb9 100644 --- a/src/line_info.h +++ b/src/line_info.h @@ -39,6 +39,8 @@ enum { IN_ACTION, OUT_ACTION, OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */ + IN_PRVT_MSG, /* PRVT should only be used for groups */ + OUT_PRVT_MSG, PROMPT, CONNECTION, DISCONNECTION, diff --git a/src/settings.c b/src/settings.c index 3775e5b..9df7c60 100644 --- a/src/settings.c +++ b/src/settings.c @@ -62,6 +62,7 @@ static struct ui_strings { const char* line_quit; const char* line_alert; const char* line_normal; + const char* line_special; const char* mplex_away; const char* mplex_away_note; @@ -82,11 +83,12 @@ static struct ui_strings { "line_quit", "line_alert", "line_normal", + "line_special", "mplex_away", "mplex_away_note", }; -static void ui_defaults(struct user_settings* settings) +static void ui_defaults(struct user_settings* settings) { settings->timestamps = TIMESTAMPS_ON; snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT); @@ -104,6 +106,7 @@ static void ui_defaults(struct user_settings* settings) snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT); snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL); + snprintf(settings->line_special, LINE_HINT_MAX + 1, "%s", LINE_SPECIAL); settings->mplex_away = MPLEX_ON; snprintf (settings->mplex_away_note, @@ -225,11 +228,11 @@ static int key_parse(const char** bind){ int len = strlen(*bind); if (len > 5) { - if(strncasecmp(*bind, "ctrl+", 5) == 0) + if(strncasecmp(*bind, "ctrl+", 5) == 0) return toupper(bind[0][5]) - 'A' + 1; } - if (strncasecmp(*bind, "tab", 3) == 0) + if (strncasecmp(*bind, "tab", 3) == 0) return T_KEY_TAB; if (strncasecmp(*bind, "page", 4) == 0) @@ -321,6 +324,9 @@ int settings_load(struct user_settings *s, const char *patharg) if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) { snprintf(s->line_normal, sizeof(s->line_normal), "%s", str); } + if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) { + snprintf(s->line_special, sizeof(s->line_special), "%s", str); + } config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away); @@ -346,7 +352,7 @@ int settings_load(struct user_settings *s, const char *patharg) snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str); int len = strlen(s->chatlogs_path); - if (len >= sizeof(s->chatlogs_path) - 2) + if (len >= sizeof(s->chatlogs_path) - 2) s->chatlogs_path[0] = '\0'; else if (s->chatlogs_path[len - 1] != '/') strcat(&s->chatlogs_path[len - 1], "/"); @@ -356,7 +362,7 @@ int settings_load(struct user_settings *s, const char *patharg) snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str); int len = strlen(str); - if (len >= sizeof(s->avatar_path)) + if (len >= sizeof(s->avatar_path)) s->avatar_path[0] = '\0'; } } @@ -423,25 +429,25 @@ int settings_load(struct user_settings *s, const char *patharg) if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) || !set_sound(call_outgoing, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) || !set_sound(generic_message, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) || !set_sound(transfer_pending, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) || !set_sound(transfer_completed, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) diff --git a/src/settings.h b/src/settings.h index 5403f0e..2e02a01 100644 --- a/src/settings.h +++ b/src/settings.h @@ -49,6 +49,7 @@ struct user_settings { char line_quit[LINE_HINT_MAX + 1]; char line_alert[LINE_HINT_MAX + 1]; char line_normal[LINE_HINT_MAX + 1]; + char line_special[LINE_HINT_MAX + 1]; char download_path[PATH_MAX]; char chatlogs_path[PATH_MAX]; @@ -104,6 +105,7 @@ enum { #define LINE_QUIT "<--" #define LINE_ALERT "-!-" #define LINE_NORMAL "---" +#define LINE_SPECIAL ">>>" #define TIMESTAMP_DEFAULT "%H:%M:%S" #define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]" #define MPLEX_AWAY_NOTE "Detached from screen"