about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Harris <ben@tilde.team>2020-05-13 23:34:33 -0400
committerBen Harris <ben@tilde.team>2020-05-13 23:34:33 -0400
commit023e29ab75f1f413f918346edaddafdf8b1df5ee (patch)
tree9e8c6956c0c0ecac9639b1c727fe94cb253d71f7
parentb93174070a0964f254781686ed2390855127ad7a (diff)
implement some stuff
-rw-r--r--IrcStates/Channel.cs7
-rw-r--r--IrcStates/ChannelUser.cs5
-rw-r--r--IrcStates/ISupport.cs4
-rw-r--r--IrcStates/ISupportPrefix.cs10
-rw-r--r--IrcStates/Server.cs220
-rw-r--r--IrcStates/Tests/Casemap.cs2
-rw-r--r--IrcStates/Tests/Channel.cs24
-rw-r--r--IrcStates/Tests/User.cs7
-rw-r--r--IrcStates/User.cs5
9 files changed, 267 insertions, 17 deletions
diff --git a/IrcStates/Channel.cs b/IrcStates/Channel.cs
index b502f2a..16b4654 100644
--- a/IrcStates/Channel.cs
+++ b/IrcStates/Channel.cs
@@ -6,6 +6,13 @@ namespace IrcStates
 {
     public class Channel
     {
+        public Channel()
+        {
+            Users     = new Dictionary<string, ChannelUser>();
+            ListModes = new Dictionary<string, List<string>>();
+            Modes     = new Dictionary<string, string>();
+        }
+
         public string Name { get; set; }
         public string NameLower { get; set; }
         public Dictionary<string, ChannelUser> Users { get; set; }
diff --git a/IrcStates/ChannelUser.cs b/IrcStates/ChannelUser.cs
index 14f4280..220a9c4 100644
--- a/IrcStates/ChannelUser.cs
+++ b/IrcStates/ChannelUser.cs
@@ -5,5 +5,10 @@ namespace IrcStates
     public class ChannelUser
     {
         public List<string> Modes { get; set; }
+
+        public ChannelUser()
+        {
+            Modes = new List<string>();
+        }
     }
 }
diff --git a/IrcStates/ISupport.cs b/IrcStates/ISupport.cs
index afb633d..1e89b6d 100644
--- a/IrcStates/ISupport.cs
+++ b/IrcStates/ISupport.cs
@@ -3,6 +3,7 @@
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 
 namespace IrcStates
 {
@@ -35,6 +36,9 @@ namespace IrcStates
         {
             if (tokens == null) return;
             
+            // remove first and last
+            tokens = tokens.Skip(1).SkipLast(1);
+
             foreach (var token in tokens)
             {
                 var split = token.Split('=', 2);
diff --git a/IrcStates/ISupportPrefix.cs b/IrcStates/ISupportPrefix.cs
index b319e04..b535212 100644
--- a/IrcStates/ISupportPrefix.cs
+++ b/IrcStates/ISupportPrefix.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 
 namespace IrcStates
 {
@@ -17,11 +18,20 @@ namespace IrcStates
         public List<string> Modes { get; set; }
         public List<string> Prefixes { get; set; }
 
+        public string FromMode(char mode)
+        {
+            return FromMode(mode.ToString(CultureInfo.InvariantCulture));
+        }
         public string FromMode(string mode)
         {
             return Modes.Contains(mode) ? Modes[Modes.IndexOf(mode)] : null;
         }
 
+        public string FromPrefix(char prefix)
+        {
+            return FromPrefix(prefix.ToString(CultureInfo.InvariantCulture));
+        }
+
         public string FromPrefix(string prefix)
         {
             return Prefixes.Contains(prefix) ? Prefixes[Prefixes.IndexOf(prefix)] : null;
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();
         }
 
diff --git a/IrcStates/Tests/Casemap.cs b/IrcStates/Tests/Casemap.cs
index eccc828..6022593 100644
--- a/IrcStates/Tests/Casemap.cs
+++ b/IrcStates/Tests/Casemap.cs
@@ -51,7 +51,7 @@ namespace IrcStates.Tests
             Assert.IsTrue(server.Users.ContainsKey("newnickname"));
             Assert.AreEqual("NewNickname", user.NickName);
             Assert.AreEqual("newnickname", user.NickNameLower);
-            Assert.AreEqual("NewNickName", server.NickName);
+            Assert.AreEqual("NewNickname", server.NickName);
             Assert.AreEqual("newnickname", server.NickNameLower);
         }
     }
diff --git a/IrcStates/Tests/Channel.cs b/IrcStates/Tests/Channel.cs
index d793920..fea4ddb 100644
--- a/IrcStates/Tests/Channel.cs
+++ b/IrcStates/Tests/Channel.cs
@@ -101,6 +101,30 @@ namespace IrcStates.Tests
         }
 
         [TestMethod]
+        public void QuitSelf()
+        {
+            _server.Parse(new Line("QUIT :i'm outta here"));
+            Assert.IsFalse(_server.Users.Any());
+            Assert.IsFalse(_server.Channels.Any());
+        }
+
+        [TestMethod]
+        public void QuitSelfWithSource()
+        {
+            _server.Parse(new Line(":nickname QUIT :i'm outta here"));
+            Assert.IsFalse(_server.Users.Any());
+            Assert.IsFalse(_server.Channels.Any());
+        }
+
+        [TestMethod]
+        public void QuitOther()
+        {
+            _server.Parse(new Line(":other JOIN #chan"));
+            _server.Parse(new Line(":other QUIT :see ya"));
+            Assert.IsFalse(_server.Users.ContainsKey("other"));
+        }
+
+        [TestMethod]
         public void TopicText()
         {
             _server.Parse(new Line("332 * #chan :test"));
diff --git a/IrcStates/Tests/User.cs b/IrcStates/Tests/User.cs
index 4c78255..5857cfc 100644
--- a/IrcStates/Tests/User.cs
+++ b/IrcStates/Tests/User.cs
@@ -16,6 +16,13 @@ namespace IrcStates.Tests
         }
 
         [TestMethod]
+        public void Welcome()
+        {
+            Assert.AreEqual("test", _server.Name);
+            Assert.AreEqual("nickname", _server.NickName);
+        }
+
+        [TestMethod]
         public void NicknameChange()
         {
             _server.Parse(new Line(":nickname NICK nickname2"));
diff --git a/IrcStates/User.cs b/IrcStates/User.cs
index b9a9570..7df331b 100644
--- a/IrcStates/User.cs
+++ b/IrcStates/User.cs
@@ -4,6 +4,11 @@ namespace IrcStates
 {
     public class User
     {
+        public User()
+        {
+            Channels = new HashSet<string>();
+        }
+
         public string NickName { get; set; }
         public string NickNameLower { get; set; }