about summary refs log tree commit diff
path: root/IrcStates/Server.cs
diff options
context:
space:
mode:
Diffstat (limited to 'IrcStates/Server.cs')
-rw-r--r--IrcStates/Server.cs941
1 files changed, 0 insertions, 941 deletions
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<string, string> TempCaps;
-
-        public Server(string name)
-        {
-            Name          = name;
-            Registered    = false;
-            Modes         = new List<string>();
-            Motd          = new List<string>();
-            _decoder      = new StatefulDecoder();
-            Users         = new Dictionary<string, User>();
-            Channels      = new Dictionary<string, Channel>();
-            ISupport      = new ISupport();
-            HasCap        = false;
-            TempCaps      = new Dictionary<string, string>();
-            AvailableCaps = new Dictionary<string, string>();
-            AgreedCaps    = new List<string>();
-        }
-
-        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<string> Modes { get; set; }
-        public List<string> Motd { get; set; }
-        public Dictionary<string, User> Users { get; set; }
-        public Dictionary<string, Channel> Channels { get; set; }
-        public Dictionary<string, string> AvailableCaps { get; set; }
-        public List<string> 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<string> 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<string, string>();
-            var tokensStr = new List<string>();
-            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<string>();
-            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<string>();
-
-            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<User>();
-            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();
-        }
-    }
-}