Skip to content

Commit

Permalink
feat: Add word block list to config
Browse files Browse the repository at this point in the history
A list of blocked words can now be added to the config file. Any message
that contains a word on the list will not be able to send, and will
cause an error message to be displayed.
  • Loading branch information
JFreegman committed Dec 29, 2024
1 parent 5e17fc4 commit 70b0041
Show file tree
Hide file tree
Showing 23 changed files with 239 additions and 56 deletions.
9 changes: 7 additions & 2 deletions doc/toxic.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 2024-02-09
.\" Date: 2024-12-23
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2024\-02\-09" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2024\-12\-23" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
Expand Down Expand Up @@ -368,6 +368,11 @@ The colour of the conferences\(cqs tab window name\&. (black, white, gray, brown
.RE
.RE
.PP
\fBblocked_words\fR
.RS 4
A list of case\-insensitive words that cannot be sent in messages\&. String value\&. Must be enclosed in double quotes and must be ⇐ 256 characters\&.
.RE
.PP
\fBsounds\fR
.RS 4
Configuration related to notification sounds\&. Special value "silent" can be used to disable a specific notification\&.
Expand Down
3 changes: 3 additions & 0 deletions doc/toxic.conf.5.asc
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ OPTIONS
*tab_name_colour*;;
The colour of the conferences's tab window name. (black, white, gray, brown, red, green, blue, cyan, yellow, magenta, orange, pink)

*blocked_words*::
A list of case-insensitive words that cannot be sent in messages. String value. Must be enclosed in double quotes and must be <= 256 characters.

*sounds*::
Configuration related to notification sounds.
Special value "silent" can be used to disable a specific notification. +
Expand Down
9 changes: 9 additions & 0 deletions misc/toxic.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ conferences = {
// };
};

// A list of case-insensitive words that cannot be sent in messages. If you attempt to send
// a message that contains a word in this list to a group, friend, etc., the message will not
// send and an error will be displayed. Words must be enclosed in double quotes and must not
// be longer than 256 characters.
blocked_words = [
// "hunter2",
// "certainly!"
];

// To disable a sound set the path to "silent"
sounds = {
error="__DATADIR__/sounds/ToxicError.wav";
Expand Down
1 change: 1 addition & 0 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,5 @@ void invoke_autoruns(ToxWindow *self, const char *autorun_path)

closedir(d);
}

#endif /* PYTHON */
6 changes: 6 additions & 0 deletions src/audio_call.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ void callback_recv_invite(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_recv_ringing(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand All @@ -466,6 +467,7 @@ void callback_recv_ringing(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_recv_starting(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand All @@ -484,6 +486,7 @@ void callback_recv_starting(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_call_started(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand All @@ -502,6 +505,7 @@ void callback_call_started(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_call_canceled(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand All @@ -519,6 +523,7 @@ void callback_call_canceled(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_call_rejected(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand All @@ -536,6 +541,7 @@ void callback_call_rejected(Toxic *toxic, uint32_t friend_number)
}
}
}

void callback_call_ended(Toxic *toxic, uint32_t friend_number)
{
if (friend_number >= CallControl.max_calls) {
Expand Down
5 changes: 3 additions & 2 deletions src/audio_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void get_al_device_names(void)

if (stringed_device_list != NULL) {
audio_state->default_al_device_name[type] = alcGetString(NULL,
type == input ? ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER : ALC_DEFAULT_DEVICE_SPECIFIER);
type == input ? ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER : ALC_DEFAULT_DEVICE_SPECIFIER);

for (; *stringed_device_list != '\0'
&& audio_state->num_al_devices[type] < MAX_OPENAL_DEVICES; ++audio_state->num_al_devices[type]) {
Expand Down Expand Up @@ -341,7 +341,7 @@ static DeviceError open_al_device(DeviceType type, FrameInfo frame_info)
{
audio_state->al_device[type] = type == input
? alcCaptureOpenDevice(audio_state->current_al_device_name[type],
frame_info.sample_rate, sound_mode(frame_info.stereo), frame_info.samples_per_frame * 2)
frame_info.sample_rate, sound_mode(frame_info.stereo), frame_info.samples_per_frame * 2)
: alcOpenDevice(audio_state->current_al_device_name[type]);

if (audio_state->al_device[type] == NULL) {
Expand Down Expand Up @@ -754,6 +754,7 @@ static void *poll_input(void *arg)

pthread_exit(NULL);
}

#endif

float get_input_volume(void)
Expand Down
31 changes: 18 additions & 13 deletions src/chat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1394,16 +1394,19 @@ static bool chat_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr)
input_ret = true;
rm_trailing_spaces_buf(ctx);

if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
wstrsubst(ctx->line, L'¶', L'\n');

wstrsubst(ctx->line, L'¶', L'\n');
char line[MAX_STR_SIZE];

char line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
}

if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
}
const bool contains_blocked_word = string_contains_blocked_word(line, &toxic->client_data);

if (line[0] != '\0' && !contains_blocked_word) {
add_line_to_hist(ctx);

if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
Expand All @@ -1414,7 +1417,7 @@ static bool chat_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr)
} else {
execute(ctx->history, self, toxic, line, CHAT_COMMAND_MODE);
}
} else if (line[0]) {
} else {
char selfname[TOX_MAX_NAME_LENGTH + 1];
tox_self_get_name(tox, (uint8_t *) selfname);

Expand All @@ -1423,14 +1426,16 @@ static bool chat_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr)

const int id = line_info_add(self, c_config, true, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
}
}

wclear(ctx->linewin);
wmove(self->window, y2, 0);
reset_buf(ctx);
if (!contains_blocked_word) {
wclear(ctx->linewin);
wmove(self->window, y2, 0);
reset_buf(ctx);
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, "* Message contains blocked word");
}
}

if (ctx->len <= 0 && ctx->self_is_typing) {
Expand Down
31 changes: 18 additions & 13 deletions src/conference.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,16 +1042,19 @@ static bool conference_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr
input_ret = true;
rm_trailing_spaces_buf(ctx);

if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
wstrsubst(ctx->line, L'¶', L'\n');

wstrsubst(ctx->line, L'¶', L'\n');
char line[MAX_STR_SIZE];

char line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
}

if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
}
const bool contains_blocked_word = string_contains_blocked_word(line, &toxic->client_data);

if (line[0] != '\0' && !contains_blocked_word) {
add_line_to_hist(ctx);

if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
Expand All @@ -1062,20 +1065,22 @@ static bool conference_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr
} else {
execute(ctx->history, self, toxic, line, CONFERENCE_COMMAND_MODE);
}
} else if (line[0]) {
} else {
Tox_Err_Conference_Send_Message err;

if (!tox_conference_send_message(tox, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
}
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
}
}

wclear(ctx->linewin);
wmove(self->window, y2, 0);
reset_buf(ctx);
if (!contains_blocked_word) {
wclear(ctx->linewin);
wmove(self->window, y2, 0);
reset_buf(ctx);
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, "* Message contains blocked word");
}
}

return input_ret;
Expand Down
25 changes: 15 additions & 10 deletions src/groupchats.c
Original file line number Diff line number Diff line change
Expand Up @@ -1986,16 +1986,19 @@ static bool groupchat_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr)
input_ret = true;
rm_trailing_spaces_buf(ctx);

if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
wstrsubst(ctx->line, L'¶', L'\n');

wstrsubst(ctx->line, L'¶', L'\n');
char line[MAX_STR_SIZE];

char line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
}

if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(line, 0, sizeof(line));
}
const bool contains_blocked_word = string_contains_blocked_word(line, &toxic->client_data);

if (line[0] != '\0' && !contains_blocked_word) {
add_line_to_hist(ctx);

if (line[0] == '/') {
if (strncmp(line, "/close", strlen("/close")) == 0) {
Expand Down Expand Up @@ -2023,15 +2026,17 @@ static bool groupchat_onKey(ToxWindow *self, Toxic *toxic, wint_t key, bool ltr)
} else {
execute(ctx->history, self, toxic, line, GROUPCHAT_COMMAND_MODE);
}
} else if (line[0]) {
send_group_message(self, toxic, self->num, line, TOX_MESSAGE_TYPE_NORMAL);
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
send_group_message(self, toxic, self->num, line, TOX_MESSAGE_TYPE_NORMAL);
}
}

if (!contains_blocked_word) {
wclear(ctx->linewin);
wmove(self->window, y2, 0);
reset_buf(ctx);
} else {
line_info_add(self, c_config, false, NULL, NULL, SYS_MSG, 0, RED, "* Message contains blocked word");
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,12 @@ int main(int argc, char **argv)
init_queue_add(init_q, "Failed to load conference config settings: error %d", cs_ret);
}

const int bl_ret = settings_load_blocked_words(&toxic->client_data, run_opts);

if (bl_ret != 0) {
init_queue_add(init_q, "Failed to load blocked words list: error %d", bl_ret);
}

set_active_window_by_type(windows, WINDOW_TYPE_PROMPT);

if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
Expand Down
17 changes: 16 additions & 1 deletion src/misc_tools.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
* under the GNU General Public License 3.0.
*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for strcasestr() */
#endif

#include <assert.h>
#include <arpa/inet.h>
#include <ctype.h>
Expand Down Expand Up @@ -679,7 +683,7 @@ void free_ptr_array(void **arr)

void **tmp = arr;

while (*arr) {
while (*arr != NULL) {
free(*arr);
++arr;
}
Expand Down Expand Up @@ -789,3 +793,14 @@ size_t format_time_str(char *s, size_t max, const char *format, const struct tm
return strftime(s, max, format, tm);
#pragma GCC diagnostic pop
}

bool string_contains_blocked_word(const char *line, const Client_Data *client_data)
{
for (size_t i = 0; i < client_data->num_blocked_words; ++i) {
if (strcasestr(line, client_data->blocked_words[i]) != NULL) {
return true;
}
}

return false;
}
6 changes: 6 additions & 0 deletions src/misc_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,14 @@ int colour_string_to_int(const char *colour);
*/
size_t format_time_str(char *s, size_t max, const char *format, const struct tm *tm);

/*
* Returns true if `line` contains a word that's in the client's blocked words list.
*/
bool string_contains_blocked_word(const char *line, const Client_Data *client_data);

#ifdef __cplusplus
} /* extern "C" */

#endif /* __cplusplus */

#endif /* MISC_TOOLS_H */
2 changes: 2 additions & 0 deletions src/notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ static struct _ActiveNotifications {
time_t n_timeout;
#endif /* BOX_NOTIFY */
} actives[ACTIVE_NOTIFS_MAX];

/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
Expand Down Expand Up @@ -582,6 +583,7 @@ void stop_sound(int id)
clear_actives_index(id);
}
}

#endif /* SOUND_NOTIFY */

static int m_play_sound(const Client_Config *c_config, Notification notif, uint64_t flags)
Expand Down
Loading

0 comments on commit 70b0041

Please sign in to comment.