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.cs220
1 files changed, 204 insertions, 16 deletions
diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs
index a552890..ea7dd9e 100644
--- a/IrcStates/Server.cs
+++ b/IrcStates/Server.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
+using System.Runtime.Serialization;
 using IrcTokens;
 
 namespace IrcStates
@@ -103,6 +104,55 @@ namespace IrcStates
             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 (nickLower == NickNameLower)
+                {
+                    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);
+        }
+
         public List<(Line, Emit)> Recv(byte[] data)
         {
             if (data == null) return null;
@@ -250,17 +300,87 @@ namespace IrcStates
 
         private Emit HandleNames(Line line)
         {
-            throw new NotImplementedException();
+            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 (nickLower == NickNameLower) 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)
         {
-            throw new NotImplementedException();
+            Users.Clear();
+            Channels.Clear();
+            return new Emit();
         }
 
         private Emit HandleQuit(Line line)
         {
-            throw new NotImplementedException();
+            var emit                         = new Emit();
+            var nickLower                    = CaseFold(line.Hostmask.NickName);
+            if (line.Params.Any()) emit.Text = line.Params[0];
+
+            if (nickLower == NickNameLower || 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)
@@ -270,29 +390,100 @@ namespace IrcStates
 
         private Emit HandleKick(Line line)
         {
-            throw new NotImplementedException();
+            var (emit, kicked) = UserPart(line, line.Params[1], line.Params[0], 2);
+            if (kicked != null)
+            {
+                emit.UserTarget = kicked;
+                if (kicked.NickNameLower == NickNameLower) emit.Self = true;
+
+                var kickerLower                                   = CaseFold(line.Hostmask.NickName);
+                if (kickerLower == NickNameLower) emit.SelfSource = true;
+
+                emit.UserSource = Users.ContainsKey(kickerLower)
+                    ? Users[kickerLower]
+                    : CreateUser(line.Hostmask.NickName, kickerLower);
+            }
+
+            return emit;
         }
 
         private Emit HandlePart(Line line)
         {
-            throw new NotImplementedException();
+            var (emit, user) = UserPart(line, line.Hostmask.NickName, line.Params[0], 1);
+            if (user != null)
+            {
+                emit.User = user;
+                if (user.NickNameLower == NickNameLower) emit.Self = true;
+            }
+
+            return emit;
         }
 
+
         private Emit HandleJoin(Line line)
         {
-            throw new NotImplementedException();
+            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 (nickLower == NickNameLower)
+            {
+                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 nick      = line.Params[0];
             var nickLower = CaseFold(line.Hostmask.NickName);
 
             var emit = new Emit();
 
             if (Users.ContainsKey(nickLower))
             {
-                var user = Users[nick];
+                var user = Users[nickLower];
+                Users.Remove(nickLower);
                 emit.User = user;
 
                 var oldNickLower = user.NickNameLower;
@@ -301,7 +492,7 @@ namespace IrcStates
                 Users[newNickLower] = user;
                 foreach (var channelLower in user.Channels)
                 {
-                    var channel = Channels[channelLower];
+                    var channel     = Channels[channelLower];
                     var channelUser = channel.Users[oldNickLower];
                     channel.Users.Remove(oldNickLower);
                     channel.Users[newNickLower] = channelUser;
@@ -310,8 +501,8 @@ namespace IrcStates
 
             if (nickLower == NickNameLower)
             {
-                emit.Self = true;
-                NickName = nick;
+                emit.Self     = true;
+                NickName      = nick;
                 NickNameLower = CaseFold(nick);
             }
 
@@ -320,10 +511,7 @@ namespace IrcStates
 
         private Emit HandleMotd(Line line)
         {
-            if (line.Command == Numeric.RPL_MOTDSTART)
-            {
-                Motd.Clear();
-            }
+            if (line.Command == Numeric.RPL_MOTDSTART) Motd.Clear();
 
             var emit = new Emit {Text = line.Params[1]};
             Motd.Add(line.Params[1]);
@@ -333,7 +521,7 @@ namespace IrcStates
         private Emit HandleISupport(Line line)
         {
             ISupport = new ISupport();
-            ISupport.Parse(line.Params.Skip(1).SkipLast(1));
+            ISupport.Parse(line.Params);
             return new Emit();
         }