diff --git a/Content.Server/Chat/Managers/ChatSanitizationManager.cs b/Content.Server/Chat/Managers/ChatSanitizationManager.cs index b0d28eae75c..0c78e45f86e 100644 --- a/Content.Server/Chat/Managers/ChatSanitizationManager.cs +++ b/Content.Server/Chat/Managers/ChatSanitizationManager.cs @@ -35,7 +35,7 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager { ":D", "chatsan-smiles-widely" }, { "D:", "chatsan-frowns-deeply" }, { ":O", "chatsan-surprised" }, - { ":3", "chatsan-smiles" }, //nope + { ":3", "chatsan-smiles" }, { ":S", "chatsan-uncertain" }, { ":>", "chatsan-grins" }, { ":<", "chatsan-pouts" }, diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index a14bbd14d54..4c88e8cc5a4 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -756,8 +756,9 @@ private bool CanSendInGame(string message, IConsoleShell? shell = null, ICommonS // ReSharper disable once InconsistentNaming private string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false, bool capitalizeTheWordI = true) { - var newMessage = message.Trim(); - newMessage = SanitizeMessageReplaceWords(newMessage); + var newMessage = SanitizeMessageReplaceWords(message.Trim()); + + GetRadioKeycodePrefix(source, newMessage, out newMessage, out var prefix); // Sanitize it first as it might change the word order _sanitizer.TrySanitizeEmoteShorthands(newMessage, source, out newMessage, out emoteStr); @@ -769,7 +770,7 @@ private string SanitizeInGameICMessage(EntityUid source, string message, out str if (punctuate) newMessage = SanitizeMessagePeriod(newMessage); - return newMessage; + return prefix + newMessage; } private string SanitizeInGameOOCMessage(string message) diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index e5944ec30ae..414c26d6c7a 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -85,6 +85,35 @@ public SpeechVerbPrototype GetSpeechVerb(EntityUid source, string message, Speec return current ?? _prototypeManager.Index(speech.SpeechVerb); } + /// + /// Splits the input message into a radio prefix part and the rest to preserve it during sanitization. + /// + /// + /// This is primarily for the chat emote sanitizer, which can match against ":b" as an emote, which is a valid radio keycode. + /// + public void GetRadioKeycodePrefix(EntityUid source, + string input, + out string output, + out string prefix) + { + prefix = string.Empty; + output = input; + + // If the string is less than 2, then it's probably supposed to be an emote. + // No one is sending empty radio messages! + if (input.Length <= 2) + return; + + if (!(input.StartsWith(RadioChannelPrefix) || input.StartsWith(RadioChannelAltPrefix))) + return; + + if (!_keyCodes.TryGetValue(input[1], out _)) + return; + + prefix = input[..2]; + output = input[2..]; + } + /// /// Attempts to resolve radio prefixes in chat messages (e.g., remove a leading ":e" and resolve the requested /// channel. Returns true if a radio message was attempted, even if the channel is invalid.