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"