From 21f1e95fb8e935134a969bc3d729964d8d2aadfa Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 14 May 2020 23:06:10 -0400 Subject: rename Irc to IRC --- IrcStates/Server.cs | 941 ---------------------------------------------------- 1 file changed, 941 deletions(-) delete mode 100644 IrcStates/Server.cs (limited to 'IrcStates/Server.cs') diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs deleted file mode 100644 index 2e80b75..0000000 --- a/IrcStates/Server.cs +++ /dev/null @@ -1,941 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -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); - } - - private bool CaseFoldEquals(string s1, string s2) - { - return CaseFold(s1) == CaseFold(s2); - } - - private bool IsMe(string nickname) - { - return CaseFold(nickname) == NickNameLower; - } - - private bool HasUser(string nickname) - { - return Users.ContainsKey(CaseFold(nickname)); - } - - private User AddUser(string nickname, string nicknameLower) - { - var user = CreateUser(nickname, nicknameLower); - Users[nicknameLower] = user; - return user; - } - - private User CreateUser(string nickname, string nicknameLower) - { - var user = new User(); - user.SetNickName(nickname, nicknameLower); - return user; - } - - private 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)); - } - - private Channel GetChannel(string name) - { - return HasChannel(name) ? Channels[name] : null; - } - - private ChannelUser UserJoin(Channel channel, User user) - { - var channelUser = new ChannelUser(); - user.Channels.Add(CaseFold(channel.Name)); - channel.Users[user.NickNameLower] = channelUser; - return channelUser; - } - - private void SelfHostmask(Hostmask hostmask) - { - NickName = hostmask.NickName; - if (hostmask.UserName != null) UserName = hostmask.UserName; - if (hostmask.HostName != null) HostName = hostmask.HostName; - } - - private (Emit, User) UserPart(Line line, string nickName, string channelName, int reasonIndex) - { - var emit = new Emit(); - var channelLower = CaseFold(channelName); - if (line.Params.Count >= reasonIndex + 1) emit.Text = line.Params[reasonIndex]; - - User user = null; - if (HasChannel(channelName)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - var nickLower = CaseFold(nickName); - if (HasUser(nickLower)) - { - user = Users[nickLower]; - user.Channels.Remove(channelLower); - channel.Users.Remove(nickLower); - if (!user.Channels.Any()) Users.Remove(nickLower); - } - - if (IsMe(nickName)) - { - Channels.Remove(channelLower); - foreach (var userToRemove in channel.Users.Keys.Select(u => Users[u])) - { - userToRemove.Channels.Remove(channelLower); - if (!userToRemove.Channels.Any()) Users.Remove(userToRemove.NickNameLower); - } - } - } - - return (emit, user); - } - - private void SetChannelModes(Channel channel, IEnumerable<(bool, string)> modes, IList parameters) - { - foreach (var (add, c) in modes) - { - var listMode = ISupport.ChanModes.ListModes.Contains(c); - if (ISupport.Prefix.Modes.Contains(c)) - { - var nicknameLower = CaseFold(parameters.First()); - parameters.RemoveAt(0); - if (!HasUser(nicknameLower)) continue; - - var channelUser = channel.Users[nicknameLower]; - if (add) - { - if (!channelUser.Modes.Contains(c)) - { - channelUser.Modes.Add(c); - } - } - else if (channelUser.Modes.Contains(c)) - { - channelUser.Modes.Remove(c); - } - } - else if (add && (listMode || - ISupport.ChanModes.SettingBModes.Contains(c) || - ISupport.ChanModes.SettingCModes.Contains(c))) - { - channel.AddMode(c, parameters.First(), listMode); - parameters.RemoveAt(0); - } - else if (!add && (listMode || ISupport.ChanModes.SettingBModes.Contains(c))) - { - channel.RemoveMode(c, parameters.First()); - parameters.RemoveAt(0); - } - else if (add) - { - channel.AddMode(c, null, false); - } - else - { - channel.RemoveMode(c, null); - } - } - } - - public IEnumerable<(Line, Emit)> Receive(byte[] data, int length) - { - if (data == null) return null; - - var lines = _decoder.Push(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; - - var emit = line.Command switch - { - Numeric.RPL_WELCOME => HandleWelcome(line), - Numeric.RPL_ISUPPORT => HandleISupport(line), - Numeric.RPL_MOTDSTART => HandleMotd(line), - Numeric.RPL_MOTD => HandleMotd(line), - Commands.Nick => HandleNick(line), - Commands.Join => HandleJoin(line), - Commands.Part => HandlePart(line), - Commands.Kick => HandleKick(line), - Commands.Quit => HandleQuit(line), - Commands.Error => HandleError(line), - Numeric.RPL_NAMREPLY => HandleNames(line), - Numeric.RPL_CREATIONTIME => HandleCreationTime(line), - Commands.Topic => HandleTopic(line), - Numeric.RPL_TOPIC => HandleTopicNumeric(line), - Numeric.RPL_TOPICWHOTIME => HandleTopicTime(line), - Commands.Mode => HandleMode(line), - Numeric.RPL_CHANNELMODEIS => HandleChannelModeIs(line), - Numeric.RPL_UMODEIS => HandleUModeIs(line), - Commands.Privmsg => HandleMessage(line), - Commands.Notice => HandleMessage(line), - Commands.Tagmsg => HandleMessage(line), - Numeric.RPL_VISIBLEHOST => HandleVisibleHost(line), - Numeric.RPL_WHOREPLY => HandleWhoReply(line), - Numeric.RPL_WHOSPCRPL => HandleWhox(line), - Numeric.RPL_WHOISUSER => HandleWhoIsUser(line), - Commands.Chghost => HandleChghost(line), - Commands.Setname => HandleSetname(line), - Commands.Away => HandleAway(line), - Commands.Account => HandleAccount(line), - Commands.Cap => HandleCap(line), - Numeric.RPL_LOGGEDIN => HandleLoggedIn(line), - Numeric.RPL_LOGGEDOUT => HandleLoggedOut(line), - _ => null - }; - - if (emit != null) - emit.Command = line.Command; - else - emit = new Emit(); - - return emit; - } - - private Emit HandleSetname(Line line) - { - var emit = new Emit(); - var realname = line.Params[0]; - var nicknameLower = CaseFold(line.Hostmask.NickName); - - if (IsMe(nicknameLower)) - { - emit.Self = true; - RealName = realname; - } - - if (Users.ContainsKey(nicknameLower)) - { - var user = Users[nicknameLower]; - emit.User = user; - user.RealName = realname; - } - - return emit; - } - - private Emit HandleAway(Line line) - { - var emit = new Emit(); - var away = line.Params.FirstOrDefault(); - var nicknameLower = CaseFold(line.Hostmask.NickName); - - if (IsMe(nicknameLower)) - { - emit.Self = true; - Away = away; - } - - if (Users.ContainsKey(nicknameLower)) - { - var user = Users[nicknameLower]; - emit.User = user; - user.Away = away; - } - - return emit; - } - - private Emit HandleAccount(Line line) - { - var emit = new Emit(); - var account = line.Params[0].Trim('*'); - var nicknameLower = CaseFold(line.Hostmask.NickName); - - if (IsMe(nicknameLower)) - { - emit.Self = true; - Account = account; - } - - if (Users.ContainsKey(nicknameLower)) - { - var user = Users[nicknameLower]; - emit.User = user; - user.Account = account; - } - - return emit; - } - - private Emit HandleCap(Line line) - { - HasCap = true; - var subcommand = line.Params[1].ToUpperInvariant(); - var multiline = line.Params[2] == "*"; - var caps = line.Params[multiline ? 3 : 2]; - - var tokens = new Dictionary(); - var tokensStr = new List(); - foreach (var cap in caps.Split(' ', StringSplitOptions.RemoveEmptyEntries)) - { - tokensStr.Add(cap); - var kv = cap.Split('=', 2); - tokens[kv[0]] = kv.Length > 1 ? kv[1] : string.Empty; - } - - var emit = new Emit {Subcommand = subcommand, Finished = !multiline, Tokens = tokensStr}; - - switch (subcommand) - { - case "LS": - TempCaps.UpdateWith(tokens); - if (!multiline) - { - AvailableCaps.UpdateWith(TempCaps); - TempCaps.Clear(); - } - - break; - case "NEW": - AvailableCaps.UpdateWith(tokens); - break; - case "DEL": - foreach (var key in tokens.Keys.Where(key => AvailableCaps.ContainsKey(key))) - { - AvailableCaps.Remove(key); - if (AgreedCaps.Contains(key)) AgreedCaps.Remove(key); - } - - break; - case "ACK": - foreach (var key in tokens.Keys) - if (key.StartsWith('-')) - { - var k = key.Substring(1); - if (AgreedCaps.Contains(k)) AgreedCaps.Remove(k); - } - else if (!AgreedCaps.Contains(key) && AvailableCaps.ContainsKey(key)) - { - AgreedCaps.Add(key); - } - - break; - } - - return emit; - } - - private Emit HandleLoggedIn(Line line) - { - SelfHostmask(new Hostmask(line.Params[1])); - Account = line.Params[2]; - return new Emit(); - } - - private Emit HandleChghost(Line line) - { - var emit = new Emit(); - var username = line.Params[0]; - var hostname = line.Params[1]; - var nicknameLower = CaseFold(line.Hostmask.NickName); - - if (IsMe(nicknameLower)) - { - emit.Self = true; - UserName = username; - HostName = hostname; - } - - if (Users.ContainsKey(nicknameLower)) - { - var user = Users[nicknameLower]; - emit.User = user; - user.UserName = username; - user.HostName = hostname; - } - - return emit; - } - - private Emit HandleWhoIsUser(Line line) - { - var emit = new Emit(); - var nickname = line.Params[1]; - var username = line.Params[2]; - var hostname = line.Params[3]; - var realname = line.Params[5]; - - if (IsMe(nickname)) - { - emit.Self = true; - UserName = username; - HostName = hostname; - RealName = realname; - } - - if (HasUser(nickname)) - { - var user = Users[CaseFold(nickname)]; - emit.User = user; - user.UserName = username; - user.HostName = hostname; - user.RealName = realname; - } - - return emit; - } - - private Emit HandleWhox(Line line) - { - var emit = new Emit(); - if (line.Params[1] == WhoType && line.Params.Count == 8) - { - var nickname = line.Params[5]; - var username = line.Params[2]; - var hostname = line.Params[4]; - var realname = line.Params[7]; - var account = line.Params[6] == "0" ? null : line.Params[6]; - - if (IsMe(nickname)) - { - emit.Self = true; - UserName = username; - HostName = hostname; - RealName = realname; - Account = account; - } - - if (HasUser(nickname)) - { - var user = Users[CaseFold(nickname)]; - emit.User = user; - user.UserName = username; - user.HostName = hostname; - user.RealName = realname; - user.Account = account; - } - } - - return emit; - } - - private Emit HandleWhoReply(Line line) - { - var emit = new Emit {Target = line.Params[1]}; - var nickname = line.Params[5]; - var username = line.Params[2]; - var hostname = line.Params[3]; - var realname = line.Params[7].Split(' ', 2)[1]; - - if (IsMe(nickname)) - { - emit.Self = true; - UserName = username; - HostName = hostname; - RealName = realname; - } - - if (HasUser(nickname)) - { - var user = Users[CaseFold(nickname)]; - emit.User = user; - user.UserName = username; - user.HostName = hostname; - user.RealName = realname; - } - - return emit; - } - - private Emit HandleVisibleHost(Line line) - { - var split = line.Params[1].Split('@', 2); - switch (split.Length) - { - case 1: - HostName = split[0]; - break; - case 2: - HostName = split[1]; - UserName = split[0]; - break; - } - - return new Emit(); - } - - private Emit HandleMessage(Line line) - { - var emit = new Emit(); - var message = line.Params.Count > 1 ? line.Params[1] : null; - if (message != null) emit.Text = message; - - var nickLower = CaseFold(line.Hostmask.NickName); - if (IsMe(nickLower)) - { - emit.SelfSource = true; - SelfHostmask(line.Hostmask); - } - - var user = HasUser(nickLower) - ? Users[nickLower] - : AddUser(line.Hostmask.NickName, nickLower); - emit.User = user; - - if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName; - if (line.Hostmask.HostName != null) user.HostName = line.Hostmask.HostName; - - var target = line.Params[0]; - var statusMsg = new List(); - while (target.Length > 0) - { - var t = target[0].ToString(CultureInfo.InvariantCulture); - if (ISupport.StatusMsg.Contains(t)) - { - statusMsg.Add(t); - target = target.Substring(1); - } - else - break; - } - - emit.Target = line.Params[0]; - - if (IsChannel(target) && HasChannel(target)) - { - emit.Channel = Channels[CaseFold(target)]; - } - else if (IsMe(target)) - { - emit.SelfTarget = true; - } - - return emit; - } - - private Emit HandleUModeIs(Line line) - { - foreach (var c in line.Params[1] - .TrimStart('+') - .Select(m => m.ToString(CultureInfo.InvariantCulture)) - .Where(m => !Modes.Contains(m))) - { - Modes.Add(c); - } - - return new Emit(); - } - - private Emit HandleChannelModeIs(Line line) - { - var emit = new Emit(); - if (HasChannel(line.Params[1])) - { - var channel = Channels[CaseFold(line.Params[1])]; - emit.Channel = channel; - var modes = line.Params[2] - .TrimStart('+') - .Select(p => (true, p.ToString(CultureInfo.InvariantCulture))); - var parameters = line.Params.Skip(3).ToList(); - SetChannelModes(channel, modes, parameters); - } - - return emit; - } - - private Emit HandleMode(Line line) - { - var emit = new Emit(); - var target = line.Params[0]; - var modeString = line.Params[1]; - var parameters = line.Params.Skip(2).ToList(); - - var modifier = '+'; - var modes = new List<(bool, string)>(); - var tokens = new List(); - - foreach (var c in modeString) - { - if (new[] {'+', '-'}.Contains(c)) - { - modifier = c; - } - else - { - modes.Add((modifier == '+', c.ToString(CultureInfo.InvariantCulture))); - tokens.Add($"{modifier}{c}"); - } - } - - emit.Tokens = tokens; - - if (IsMe(target)) - { - emit.SelfTarget = true; - foreach (var (add, c) in modes) - { - if (add && !Modes.Contains(c)) - Modes.Add(c); - else if (Modes.Contains(c)) Modes.Remove(c); - } - } - else if (HasChannel(target)) - { - var channel = GetChannel(CaseFold(target)); - emit.Channel = channel; - SetChannelModes(channel, modes, parameters); - } - - return emit; - } - - private Emit HandleTopicTime(Line line) - { - var emit = new Emit(); - var channelLower = CaseFold(line.Params[1]); - if (Channels.ContainsKey(channelLower)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - channel.TopicSetter = line.Params[2]; - channel.TopicTime = DateTimeOffset - .FromUnixTimeSeconds(int.Parse(line.Params[3], CultureInfo.InvariantCulture)).DateTime; - } - - return emit; - } - - private Emit HandleTopicNumeric(Line line) - { - var emit = new Emit(); - var channelLower = CaseFold(line.Params[1]); - if (Channels.ContainsKey(channelLower)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - Channels[channelLower].Topic = line.Params[2]; - } - - return emit; - } - - private Emit HandleTopic(Line line) - { - var emit = new Emit(); - var channelLower = CaseFold(line.Params[0]); - if (Channels.ContainsKey(channelLower)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - channel.Topic = line.Params[1]; - channel.TopicSetter = line.Hostmask.ToString(); - channel.TopicTime = DateTime.UtcNow; - } - - return emit; - } - - private Emit HandleCreationTime(Line line) - { - var emit = new Emit(); - var channelLower = CaseFold(line.Params[1]); - if (Channels.ContainsKey(channelLower)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - channel.Created = DateTimeOffset - .FromUnixTimeSeconds(int.Parse(line.Params[2], CultureInfo.InvariantCulture)).DateTime; - } - - return emit; - } - - private Emit HandleNames(Line line) - { - var emit = new Emit(); - var channelLower = CaseFold(line.Params[2]); - - if (!Channels.ContainsKey(channelLower)) return emit; - var channel = Channels[channelLower]; - emit.Channel = channel; - var nicknames = line.Params[3].Split(' ', StringSplitOptions.RemoveEmptyEntries); - var users = new List(); - emit.Users = users; - - foreach (var nick in nicknames) - { - var modes = ""; - foreach (var c in nick) - { - var mode = ISupport.Prefix.FromPrefix(c); - if (mode != null) - modes += mode; - else - break; - } - - var hostmask = new Hostmask(nick.Substring(modes.Length)); - var nickLower = CaseFold(hostmask.NickName); - if (!Users.ContainsKey(nickLower)) AddUser(hostmask.NickName, nickLower); - - var user = Users[nickLower]; - users.Add(user); - var channelUser = UserJoin(channel, user); - - if (hostmask.UserName != null) user.UserName = hostmask.UserName; - if (hostmask.HostName != null) user.HostName = hostmask.HostName; - - if (IsMe(nickLower)) SelfHostmask(hostmask); - - foreach (var mode in modes.Select(c => c.ToString(CultureInfo.InvariantCulture))) - if (!channelUser.Modes.Contains(mode)) - channelUser.Modes.Add(mode); - } - - return emit; - } - - private Emit HandleError(Line line) - { - Users.Clear(); - Channels.Clear(); - return new Emit(); - } - - private Emit HandleQuit(Line line) - { - var emit = new Emit(); - var nickLower = CaseFold(line.Hostmask.NickName); - if (line.Params.Any()) emit.Text = line.Params[0]; - - if (IsMe(nickLower) || line.Source == null) - { - emit.Self = true; - Users.Clear(); - Channels.Clear(); - } - else if (Users.ContainsKey(nickLower)) - { - var user = Users[nickLower]; - Users.Remove(nickLower); - emit.User = user; - foreach (var channel in user.Channels.Select(c => Channels[c])) - channel.Users.Remove(user.NickNameLower); - } - - return emit; - } - - private Emit HandleLoggedOut(Line line) - { - Account = null; - SelfHostmask(new Hostmask(line.Params[1])); - return new Emit(); - } - - private Emit HandleKick(Line line) - { - var (emit, kicked) = UserPart(line, line.Params[1], line.Params[0], 2); - if (kicked != null) - { - emit.UserTarget = kicked; - if (IsMe(kicked.NickName)) emit.Self = true; - - var kickerLower = CaseFold(line.Hostmask.NickName); - if (IsMe(kickerLower)) emit.SelfSource = true; - - emit.UserSource = Users.ContainsKey(kickerLower) - ? Users[kickerLower] - : CreateUser(line.Hostmask.NickName, kickerLower); - } - - return emit; - } - - private Emit HandlePart(Line line) - { - var (emit, user) = UserPart(line, line.Hostmask.NickName, line.Params[0], 1); - if (user != null) - { - emit.User = user; - if (IsMe(user.NickName)) emit.Self = true; - } - - return emit; - } - - - private Emit HandleJoin(Line line) - { - var extended = line.Params.Count == 3; - var account = extended ? line.Params[1].Trim('*') : null; - var realname = extended ? line.Params[2] : null; - var emit = new Emit(); - - var channelLower = CaseFold(line.Params[0]); - var nickLower = CaseFold(line.Hostmask.NickName); - - // handle own join - if (IsMe(nickLower)) - { - emit.Self = true; - if (!HasChannel(channelLower)) - { - var channel = new Channel(); - channel.SetName(line.Params[0], channelLower); - Channels[channelLower] = channel; - } - - SelfHostmask(line.Hostmask); - if (extended) - { - Account = account; - RealName = realname; - } - } - - if (HasChannel(channelLower)) - { - var channel = Channels[channelLower]; - emit.Channel = channel; - - if (!HasUser(nickLower)) AddUser(line.Hostmask.NickName, nickLower); - - var user = Users[nickLower]; - emit.User = user; - if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName; - if (line.Hostmask.HostName != null) user.HostName = line.Hostmask.HostName; - if (extended) - { - user.Account = account; - user.RealName = realname; - } - - UserJoin(channel, user); - } - - return emit; - } - - - 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[nickLower]; - Users.Remove(nickLower); - 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 (IsMe(nickLower)) - { - 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); - return new Emit(); - } - - - private Emit HandleWelcome(Line line) - { - NickName = line.Params[0]; - NickNameLower = CaseFold(line.Params[0]); - Registered = true; - return new Emit(); - } - } -} -- cgit 1.4.1