using SharpChat.Commands; using SharpChat.Config; using SharpChat.Events; using SharpChat.Packet; using System; using System.Collections.Generic; using System.Linq; namespace SharpChat.PacketHandlers { public class SendMessageHandler : IChatPacketHandler { private readonly CachedValue MaxMessageLength; private List Commands { get; } = new(); public SendMessageHandler(CachedValue maxMsgLength) { MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength)); } public void AddCommand(IChatCommand command) { Commands.Add(command ?? throw new ArgumentNullException(nameof(command))); } public void AddCommands(IEnumerable commands) { Commands.AddRange(commands ?? throw new ArgumentNullException(nameof(commands))); } public bool IsMatch(ChatPacketHandlerContext ctx) { return ctx.CheckPacketId("2"); } public void Handle(ChatPacketHandlerContext ctx) { string[] args = ctx.SplitText(3); ChatUser user = ctx.Connection.User; // No longer concats everything after index 1 with \t, no previous implementation did that either string messageText = args.ElementAtOrDefault(2); if(user == null || !user.Can(ChatUserPermissions.SendMessage) || string.IsNullOrWhiteSpace(messageText)) return; // Extra validation step, not necessary at all but enforces proper formatting in SCv1. if(!long.TryParse(args[1], out long mUserId) || user.UserId != mUserId) return; ChatChannel channel = user.CurrentChannel; if(channel == null || !user.InChannel(channel) || (user.IsSilenced && !user.Can(ChatUserPermissions.SilenceUser))) return; if(user.Status != ChatUserStatus.Online) { user.Status = ChatUserStatus.Online; channel.Send(new UserUpdatePacket(user)); } int maxMsgLength = MaxMessageLength; if(messageText.Length > maxMsgLength) messageText = messageText[..maxMsgLength]; messageText = messageText.Trim(); #if DEBUG Logger.Write($"<{ctx.Connection.Id} {user.Username}> {messageText}"); #endif IChatMessage message = null; if(messageText.StartsWith("/")) { ChatCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channel); IChatCommand command = null; foreach(IChatCommand cmd in Commands) if(cmd.IsMatch(context)) { command = cmd; break; } if(command != null) { if(command is ActionCommand actionCommand) message = actionCommand.ActionDispatch(context); else { command.Dispatch(context); return; } } } message ??= new ChatMessage { Target = channel, TargetName = channel.TargetName, DateTime = DateTimeOffset.UtcNow, Sender = user, Text = messageText, }; lock(ctx.Chat.EventsAccess) { ctx.Chat.Events.AddEvent(message); channel.Send(new ChatMessageAddPacket(message)); } } } }