about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Harris <ben@tilde.team>2020-05-14 02:10:04 -0400
committerBen Harris <ben@tilde.team>2020-05-14 02:10:04 -0400
commita0fbcf83c57d15bf4bbdd2f18a8b8d539e3e4a1a (patch)
tree2399e5b4f920a10917451069d808cfc4d2eb259b
parent023e29ab75f1f413f918346edaddafdf8b1df5ee (diff)
Implement lots of things
-rw-r--r--IrcStates/ChannelUser.cs22
-rw-r--r--IrcStates/Extensions.cs8
-rw-r--r--IrcStates/ISupport.cs10
-rw-r--r--IrcStates/ISupportPrefix.cs12
-rw-r--r--IrcStates/Server.cs206
-rw-r--r--IrcStates/Tests/Channel.cs12
6 files changed, 231 insertions, 39 deletions
diff --git a/IrcStates/ChannelUser.cs b/IrcStates/ChannelUser.cs
index 220a9c4..fab881c 100644
--- a/IrcStates/ChannelUser.cs
+++ b/IrcStates/ChannelUser.cs
@@ -4,11 +4,29 @@ namespace IrcStates
 {
     public class ChannelUser
     {
-        public List<string> Modes { get; set; }
-
         public ChannelUser()
         {
             Modes = new List<string>();
         }
+
+        public List<string> Modes { get; set; }
+
+        protected bool Equals(ChannelUser other)
+        {
+            return other != null && Equals(Modes, other.Modes);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return Equals((ChannelUser) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            return Modes != null ? Modes.GetHashCode() : 0;
+        }
     }
 }
diff --git a/IrcStates/Extensions.cs b/IrcStates/Extensions.cs
index dde0edb..e604928 100644
--- a/IrcStates/Extensions.cs
+++ b/IrcStates/Extensions.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Reflection;
@@ -28,5 +29,12 @@ namespace IrcStates
                 ? Delegate.CreateDelegate(getType(types.ToArray()), methodInfo)
                 : Delegate.CreateDelegate(getType(types.ToArray()), target, methodInfo);
         }
+
+        public static void Update<TKey, TValue>(this Dictionary<TKey, TValue> dict, Dictionary<TKey, TValue> other)
+        {
+            if (dict == null || other == null || !other.Any()) return;
+
+            foreach (var (key, value) in other) dict[key] = value;
+        }
     }
 }
diff --git a/IrcStates/ISupport.cs b/IrcStates/ISupport.cs
index 1e89b6d..2fc27dc 100644
--- a/IrcStates/ISupport.cs
+++ b/IrcStates/ISupport.cs
@@ -14,7 +14,10 @@ namespace IrcStates
             Raw         = new Dictionary<string, string>();
             Modes       = 3;
             CaseMapping = Casemap.CaseMapping.Rfc1459;
-            // TODO: add remaining defaults, change properties to normal members as needed
+            Prefix      = new ISupportPrefix("(ov)@+");
+            ChanModes   = new ISupportChanModes("b,k,l,imnpst");
+            StatusMsg   = new List<string>();
+            Whox        = false;
         }
 
         public Dictionary<string, string> Raw { get; set; }
@@ -35,7 +38,7 @@ namespace IrcStates
         public void Parse(IEnumerable<string> tokens)
         {
             if (tokens == null) return;
-            
+
             // remove first and last
             tokens = tokens.Skip(1).SkipLast(1);
 
@@ -71,8 +74,7 @@ namespace IrcStates
                         Watch = int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
                         break;
                     case "CASEMAPPING":
-                        if (Enum.TryParse(value, true, out Casemap.CaseMapping caseMapping))
-                            CaseMapping = caseMapping;
+                        if (Enum.TryParse(value, true, out Casemap.CaseMapping caseMapping)) CaseMapping = caseMapping;
                         break;
                     case "CHANTYPES":
                         ChanTypes = new List<string> {value};
diff --git a/IrcStates/ISupportPrefix.cs b/IrcStates/ISupportPrefix.cs
index b535212..fb5114b 100644
--- a/IrcStates/ISupportPrefix.cs
+++ b/IrcStates/ISupportPrefix.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 
 namespace IrcStates
 {
@@ -11,8 +12,10 @@ namespace IrcStates
             if (splitVal == null) throw new ArgumentNullException(nameof(splitVal));
 
             var split = splitVal.Substring(1).Split(')', 2);
-            Modes    = new List<string> {split[0]};
-            Prefixes = new List<string> {split[1]};
+            Modes = new List<string>();
+            Modes.AddRange(split[0].Select(c => c.ToString(CultureInfo.InvariantCulture)));
+            Prefixes = new List<string>();
+            Prefixes.AddRange(split[1].Select(c => c.ToString(CultureInfo.InvariantCulture)));
         }
 
         public List<string> Modes { get; set; }
@@ -22,9 +25,10 @@ namespace IrcStates
         {
             return FromMode(mode.ToString(CultureInfo.InvariantCulture));
         }
+
         public string FromMode(string mode)
         {
-            return Modes.Contains(mode) ? Modes[Modes.IndexOf(mode)] : null;
+            return Modes.Contains(mode) ? Prefixes[Modes.IndexOf(mode)] : null;
         }
 
         public string FromPrefix(char prefix)
@@ -34,7 +38,7 @@ namespace IrcStates
 
         public string FromPrefix(string prefix)
         {
-            return Prefixes.Contains(prefix) ? Prefixes[Prefixes.IndexOf(prefix)] : null;
+            return Prefixes.Contains(prefix) ? Modes[Prefixes.IndexOf(prefix)] : null;
         }
     }
 }
diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs
index ea7dd9e..d9022a0 100644
--- a/IrcStates/Server.cs
+++ b/IrcStates/Server.cs
@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
-using System.Runtime.Serialization;
 using IrcTokens;
 
 namespace IrcStates
@@ -210,32 +209,161 @@ namespace IrcStates
 
         private Emit HandleSetname(Line line)
         {
-            throw new NotImplementedException();
+            var emit          = new Emit();
+            var realname      = line.Params[0];
+            var nicknameLower = CaseFold(line.Hostmask.NickName);
+
+            if (nicknameLower == 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)
         {
-            throw new NotImplementedException();
+            var emit          = new Emit();
+            var away          = line.Params.FirstOrDefault();
+            var nicknameLower = CaseFold(line.Hostmask.NickName);
+
+            if (nicknameLower == 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)
         {
-            throw new NotImplementedException();
+            var emit          = new Emit();
+            var account       = line.Params[0].Trim('*');
+            var nicknameLower = CaseFold(line.Hostmask.NickName);
+
+            if (nicknameLower == 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)
         {
-            throw new NotImplementedException();
+            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();
+            emit.Subcommand = subcommand;
+            emit.Finished   = !multiline;
+            emit.Tokens     = tokensStr;
+
+            switch (subcommand)
+            {
+                case "LS":
+                    TempCaps = tokens;
+                    if (!multiline)
+                    {
+                        AvailableCaps = TempCaps;
+                        TempCaps.Clear();
+                    }
+
+                    break;
+                case "NEW":
+                    AvailableCaps.Update(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)
         {
-            throw new NotImplementedException();
+            SelfHostmask(new Hostmask(line.Params[1]));
+            Account = line.Params[2];
+            return new Emit();
         }
 
         private Emit HandleChghost(Line line)
         {
-            throw new NotImplementedException();
+            var emit          = new Emit();
+            var username      = line.Params[0];
+            var hostname      = line.Params[1];
+            var nicknameLower = CaseFold(line.Hostmask.NickName);
+
+            if (nicknameLower == 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)
@@ -280,22 +408,63 @@ namespace IrcStates
 
         private Emit HandleTopicTime(Line line)
         {
-            throw new NotImplementedException();
+            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)
         {
-            throw new NotImplementedException();
+            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)
         {
-            throw new NotImplementedException();
+            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)
         {
-            throw new NotImplementedException();
+            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)
@@ -324,10 +493,7 @@ namespace IrcStates
 
                 var hostmask  = new Hostmask(nick.Substring(modes.Length));
                 var nickLower = CaseFold(hostmask.NickName);
-                if (!Users.ContainsKey(nickLower))
-                {
-                    AddUser(hostmask.NickName, nickLower);
-                }
+                if (!Users.ContainsKey(nickLower)) AddUser(hostmask.NickName, nickLower);
 
                 var user = Users[nickLower];
                 users.Add(user);
@@ -339,12 +505,8 @@ namespace IrcStates
                 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;
@@ -375,9 +537,7 @@ namespace IrcStates
                 Users.Remove(nickLower);
                 emit.User = user;
                 foreach (var channel in user.Channels.Select(c => Channels[c]))
-                {
                     channel.Users.Remove(user.NickNameLower);
-                }
             }
 
             return emit;
@@ -385,7 +545,9 @@ namespace IrcStates
 
         private Emit HandleLoggedOut(Line line)
         {
-            throw new NotImplementedException();
+            Account = null;
+            SelfHostmask(new Hostmask(line.Params[1]));
+            return new Emit();
         }
 
         private Emit HandleKick(Line line)
diff --git a/IrcStates/Tests/Channel.cs b/IrcStates/Tests/Channel.cs
index fea4ddb..64a845c 100644
--- a/IrcStates/Tests/Channel.cs
+++ b/IrcStates/Tests/Channel.cs
@@ -169,11 +169,9 @@ namespace IrcStates.Tests
             var chanUser1 = channel.Users[user.NickNameLower];
             var chanUser2 = channel.Users[_server.NickNameLower];
 
-            CollectionAssert.AreEqual(
-                new Dictionary<string, ChannelUser>
-                {
-                    {user.NickNameLower, chanUser1}, {_server.NickNameLower, chanUser2}
-                }, channel.Users);
+            Assert.AreEqual(2, channel.Users.Count);
+            CollectionAssert.AreEqual(chanUser1.Modes, channel.Users[user.NickNameLower].Modes);
+            CollectionAssert.AreEqual(chanUser2.Modes, channel.Users[_server.NickNameLower].Modes);
             CollectionAssert.AreEqual(new List<string> {"o", "v"}, chanUser1.Modes);
             Assert.AreEqual(channel.NameLower, user.Channels.Single());
         }
@@ -181,12 +179,12 @@ namespace IrcStates.Tests
         [TestMethod]
         public void UserhostInNames()
         {
-            _server.Parse(new Line("353 * * #chan :nickname!user@host other@user2@host2"));
+            _server.Parse(new Line("353 * * #chan :nickname!user@host other!user2@host2"));
             Assert.AreEqual("user", _server.UserName);
             Assert.AreEqual("host", _server.HostName);
 
             var user = _server.Users["other"];
-            Assert.AreEqual("user2", user.HostName);
+            Assert.AreEqual("user2", user.UserName);
             Assert.AreEqual("host2", user.HostName);
         }