using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using IrcTokens; namespace IrcStates { public class Server { public const string WhoType = "525"; // randomly generated private readonly StatefulDecoder _decoder; private Dictionary TempCaps; public Server(string name) { Name = name; Registered = false; Modes = new List(); Motd = new List(); _decoder = new StatefulDecoder(); Users = new Dictionary(); Channels = new Dictionary(); ISupport = new ISupport(); HasCap = false; TempCaps = new Dictionary(); AvailableCaps = new Dictionary(); AgreedCaps = new List(); } public string Name { get; set; } public string NickName { get; set; } public string NickNameLower { get; set; } public string UserName { get; set; } public string HostName { get; set; } public string RealName { get; set; } public string Account { get; set; } public string Away { get; set; } public bool Registered { get; set; } public List Modes { get; set; } public List Motd { get; set; } public Dictionary Users { get; set; } public Dictionary Channels { get; set; } public Dictionary AvailableCaps { get; set; } public List AgreedCaps { get; set; } public ISupport ISupport { get; set; } public bool HasCap { get; set; } public override string ToString() { return $"Server(name={Name})"; } public string CaseFold(string str) { return Casemap.CaseFold(ISupport.CaseMapping, str); } public bool CaseFoldEquals(string s1, string s2) { return CaseFold(s1) == CaseFold(s2); } public bool IsMe(string nickname) { return CaseFold(nickname) == NickNameLower; } public bool HasUser(string nickname) { return Users.ContainsKey(CaseFold(nickname)); } private void AddUser(string nickname, string nicknameLower) { var user = CreateUser(nickname, nicknameLower); Users[nicknameLower] = user; } private User CreateUser(string nickname, string nicknameLower) { var user = new User(); user.SetNickName(nickname, nicknameLower); return user; } public bool IsChannel(string target) { return !string.IsNullOrEmpty(target) && ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture)); } public bool HasChannel(string name) { return Channels.ContainsKey(CaseFold(name)); } public Channel GetChannel(string name) { return HasChannel(name) ? Channels[name] : null; } public List<(Line, Emit)> Recv(byte[] data) { if (data == null) return null; var lines = _decoder.Push(data, data.Length); if (lines == null) throw new ServerDisconnectedException(); return lines.Select(l => (l, Parse(l))).ToList(); } public Emit Parse(Line line) { if (line == null) return null; switch (line.Command) { case Numeric.RPL_WELCOME: return HandleWelcome(line); case Numeric.RPL_ISUPPORT: return HandleISupport(line); case Numeric.RPL_MOTDSTART: case Numeric.RPL_MOTD: return HandleMotd(line); case Commands.Nick: return HandleNick(line); case Commands.Join: return HandleJoin(line); case Commands.Part: return HandlePart(line); case Commands.Kick: return HandleKick(line); case Commands.Quit: return HandleQuit(line); case Commands.Error: return HandleError(line); case Numeric.RPL_NAMREPLY: return HandleNames(line); case Numeric.RPL_CREATIONTIME: return HandleCreationTime(line); case Commands.Topic: return HandleTopic(line); case Numeric.RPL_TOPIC: return HandleTopicNumeric(line); case Numeric.RPL_TOPICWHOTIME: return HandleTopicTime(line); case Commands.Mode: return HandleMode(line); case Numeric.RPL_CHANNELMODEIS: return HandleChannelModeIs(line); case Numeric.RPL_UMODEIS: return HandleUModeIs(line); case Commands.Privmsg: case Commands.Notice: case Commands.Tagmsg: return HandleMessage(line); case Numeric.RPL_VISIBLEHOST: return HandleVisibleHost(line); case Numeric.RPL_WHOREPLY: return HandleWhoReply(line); case Numeric.RPL_WHOSPCRPL: return HandleWhox(line); case Numeric.RPL_WHOISUSER: return HandleWhoIsUser(line); case Commands.Chghost: return HandleChghost(line); case Commands.Setname: return HandleSetname(line); case Commands.Away: return HandleAway(line); case Commands.Account: return HandleAccount(line); case Commands.Cap: return HandleCap(line); case Numeric.RPL_LOGGEDIN: return HandleLoggedIn(line); case Numeric.RPL_LOGGEDOUT: return HandleLoggedOut(line); } return new Emit(); } private Emit HandleSetname(Line line) { throw new NotImplementedException(); } private Emit HandleAway(Line line) { throw new NotImplementedException(); } private Emit HandleAccount(Line line) { throw new NotImplementedException(); } private Emit HandleCap(Line line) { throw new NotImplementedException(); } private Emit HandleLoggedIn(Line line) { throw new NotImplementedException(); } private Emit HandleChghost(Line line) { throw new NotImplementedException(); } private Emit HandleWhoIsUser(Line line) { throw new NotImplementedException(); } private Emit HandleWhox(Line line) { throw new NotImplementedException(); } private Emit HandleWhoReply(Line line) { throw new NotImplementedException(); } private Emit HandleVisibleHost(Line line) { throw new NotImplementedException(); } private Emit HandleMessage(Line line) { throw new NotImplementedException(); } private Emit HandleUModeIs(Line line) { throw new NotImplementedException(); } private Emit HandleChannelModeIs(Line line) { throw new NotImplementedException(); } private Emit HandleMode(Line line) { throw new NotImplementedException(); } private Emit HandleTopicTime(Line line) { throw new NotImplementedException(); } private Emit HandleTopicNumeric(Line line) { throw new NotImplementedException(); } private Emit HandleTopic(Line line) { throw new NotImplementedException(); } private Emit HandleCreationTime(Line line) { throw new NotImplementedException(); } private Emit HandleNames(Line line) { throw new NotImplementedException(); } private Emit HandleError(Line line) { throw new NotImplementedException(); } private Emit HandleQuit(Line line) { throw new NotImplementedException(); } private Emit HandleLoggedOut(Line line) { throw new NotImplementedException(); } private Emit HandleKick(Line line) { throw new NotImplementedException(); } private Emit HandlePart(Line line) { throw new NotImplementedException(); } private Emit HandleJoin(Line line) { throw new NotImplementedException(); } private Emit HandleNick(Line line) { var nick = line.Params[0]; var nickLower = CaseFold(line.Hostmask.NickName); var emit = new Emit(); if (Users.ContainsKey(nickLower)) { var user = Users[nick]; emit.User = user; var oldNickLower = user.NickNameLower; var newNickLower = CaseFold(nick); user.SetNickName(nick, newNickLower); Users[newNickLower] = user; foreach (var channelLower in user.Channels) { var channel = Channels[channelLower]; var channelUser = channel.Users[oldNickLower]; channel.Users.Remove(oldNickLower); channel.Users[newNickLower] = channelUser; } } if (nickLower == NickNameLower) { emit.Self = true; NickName = nick; NickNameLower = CaseFold(nick); } return emit; } private Emit HandleMotd(Line line) { if (line.Command == Numeric.RPL_MOTDSTART) { Motd.Clear(); } var emit = new Emit {Text = line.Params[1]}; Motd.Add(line.Params[1]); return emit; } private Emit HandleISupport(Line line) { ISupport = new ISupport(); ISupport.Parse(line.Params.Skip(1).SkipLast(1)); return new Emit(); } private Emit HandleWelcome(Line line) { NickName = line.Params[0]; NickNameLower = CaseFold(line.Params[0]); Registered = true; return new Emit(); } } }