From ec7f1727e5869a19b36c1c69cc60cee2fd070102 Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Tue, 4 Oct 2016 16:34:42 +0100 Subject: [PATCH] Allow setting multiple chat trigger characters (PR #449, bug 4341, bug 5668) Special characters only, minus a couple of potentially-problematic characters. Technically this is a breaking change - but anyone using multi-char triggers is probably crazy anyway and has been driven off by now. --- configs/core.cfg | 4 +-- core/ChatTriggers.cpp | 66 +++++++++++++++++++++++++++++-------------- core/ChatTriggers.h | 13 ++++++--- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/configs/core.cfg b/configs/core.cfg index c04ffbe8..19b726f1 100644 --- a/configs/core.cfg +++ b/configs/core.cfg @@ -30,12 +30,12 @@ "ServerLang" "en" /** - * String to use as the public chat trigger. Set an empty string to disable. + * List of characters to use for public chat triggers. Set an empty list to disable. */ "PublicChatTrigger" "!" /** - * String to use as the silent chat trigger. Set an empty string to disable. + * List of characters to use for silent chat triggers. Set an empty list to disable. */ "SilentChatTrigger" "/" diff --git a/core/ChatTriggers.cpp b/core/ChatTriggers.cpp index 4f50ade4..3c1dc111 100644 --- a/core/ChatTriggers.cpp +++ b/core/ChatTriggers.cpp @@ -8,7 +8,7 @@ * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more @@ -38,12 +38,13 @@ #include "logic_bridge.h" #include "sourcemod.h" #include "provider.h" +#include #include ChatTriggers g_ChatTriggers; bool g_bSupressSilentFails = false; -ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false), +ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false), m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL) { m_PubTrigger = "!"; @@ -61,20 +62,43 @@ ChatTriggers::~ChatTriggers() m_ArgSBackup = NULL; } -ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, - const char *value, +void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value) +{ + ke::AutoPtr filtered(new char[strlen(value) + 1]); + + const char *src = value; + char *dest = filtered.get(); + char c; + while ((c = *src++) != '\0') { + if (c <= ' ' || c == '"' || c == '\'' || (c >= '0' && c <= '9') || c == ';' || (c >= 'A' && c <= 'Z') || c == '\\' || (c >= 'a' && c <= 'z') || c >= 0x7F) { + logger->LogError("Ignoring %s chat trigger character '%c', not in valid set: %s", (type == ChatTrigger_Private ? "silent" : "public"), c, "!#$%&()*+,-./:<=>?@[]^_`{|}~"); + continue; + } + *dest++ = c; + } + *dest = '\0'; + + if (type == ChatTrigger_Private) { + m_PrivTrigger = filtered.get(); + } else { + m_PubTrigger = filtered.get(); + } +} + +ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, + const char *value, ConfigSource source, - char *error, + char *error, size_t maxlength) { if (strcmp(key, "PublicChatTrigger") == 0) { - m_PubTrigger = value; + SetChatTrigger(ChatTrigger_Public, value); return ConfigResult_Accept; } else if (strcmp(key, "SilentChatTrigger") == 0) { - m_PrivTrigger = value; + SetChatTrigger(ChatTrigger_Private, value); return ConfigResult_Accept; } else if (strcmp(key, "SilentFailSuppress") == 0) @@ -156,7 +180,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command) if (!args) return false; - /* Save these off for post hook as the command data returned from the engine in older engine versions + /* Save these off for post hook as the command data returned from the engine in older engine versions * can be NULL, despite the data still being there and valid. */ m_Arg0Backup = command->Arg(0); size_t len = strlen(args); @@ -182,7 +206,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command) if ( #if SOURCE_ENGINE == SE_EPISODEONE - !m_bIsINS && + !m_bIsINS && #endif client != 0 && args[0] == '"' && args[len-1] == '"') { @@ -250,17 +274,17 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command) bool is_trigger = false; bool is_silent = false; - /* Check for either trigger */ - if (m_PubTrigger.length() && strncmp(m_ArgSBackup, m_PubTrigger.chars(), m_PubTrigger.length()) == 0) - { - is_trigger = true; - args = &m_ArgSBackup[m_PubTrigger.length()]; - } - else if (m_PrivTrigger.length() && strncmp(m_ArgSBackup, m_PrivTrigger.chars(), m_PrivTrigger.length()) == 0) - { + // Prefer the silent trigger in case of clashes. + if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) { is_trigger = true; is_silent = true; - args = &m_ArgSBackup[m_PrivTrigger.length()]; + } else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) { + is_trigger = true; + } + + if (is_trigger) { + // Bump the args past the chat trigger - we only support single-character triggers now. + args = &m_ArgSBackup[1]; } /** @@ -318,8 +342,8 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args) char cmd_buf[64]; size_t cmd_len = 0; const char *inptr = args; - while (*inptr != '\0' - && !textparsers->IsWhitespace(inptr) + while (*inptr != '\0' + && !textparsers->IsWhitespace(inptr) && *inptr != '"' && cmd_len < sizeof(cmd_buf) - 1) { @@ -342,7 +366,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args) return false; } - /* Now, prepend. Don't worry about the buffers. This will + /* Now, prepend. Don't worry about the buffers. This will * work because the sizes are limited from earlier. */ char new_buf[80]; diff --git a/core/ChatTriggers.h b/core/ChatTriggers.h index c968b773..db49d4e4 100644 --- a/core/ChatTriggers.h +++ b/core/ChatTriggers.h @@ -8,7 +8,7 @@ * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more @@ -50,10 +50,10 @@ public: //SMGlobalClass void OnSourceModAllInitialized_Post(); void OnSourceModGameInitialized(); void OnSourceModShutdown(); - ConfigResult OnSourceModConfigChanged(const char *key, - const char *value, + ConfigResult OnSourceModConfigChanged(const char *key, + const char *value, ConfigSource source, - char *error, + char *error, size_t maxlength); private: //ConCommand bool OnSayCommand_Pre(int client, const ICommandArgs *args); @@ -64,6 +64,11 @@ public: bool IsChatTrigger(); bool WasFloodedMessage(); private: + enum ChatTriggerType { + ChatTrigger_Public, + ChatTrigger_Private, + }; + void SetChatTrigger(ChatTriggerType type, const char *value); bool PreProcessTrigger(edict_t *pEdict, const char *args); bool ClientIsFlooding(int client); cell_t CallOnClientSayCommand(int client);