Add xmldocs, and handle null bytes
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
a03daca3d4
commit
a1e1922e62
|
@ -45,9 +45,8 @@ namespace StatesSample
|
||||||
{
|
{
|
||||||
while (_encoder.PendingBytes.Any())
|
while (_encoder.PendingBytes.Any())
|
||||||
{
|
{
|
||||||
var bytesSent = _socket.Send(_encoder.PendingBytes);
|
foreach (var line in _encoder.Pop(_socket.Send(_encoder.PendingBytes)))
|
||||||
var sentLines = _encoder.Pop(bytesSent);
|
Console.WriteLine($"> {line.Format()}");
|
||||||
foreach (var line in sentLines) Console.WriteLine($"> {line.Format()}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytesReceived = _socket.Receive(_bytes);
|
var bytesReceived = _socket.Receive(_bytes);
|
||||||
|
|
|
@ -13,15 +13,15 @@ namespace IRCStates
|
||||||
Modes = new Dictionary<string, string>();
|
Modes = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; private set; }
|
||||||
public string NameLower { get; set; }
|
public string NameLower { get; private set; }
|
||||||
public Dictionary<string, ChannelUser> Users { get; set; }
|
public Dictionary<string, ChannelUser> Users { get; private set; }
|
||||||
public string Topic { get; set; }
|
public string Topic { get; set; }
|
||||||
public string TopicSetter { get; set; }
|
public string TopicSetter { get; set; }
|
||||||
public DateTime TopicTime { get; set; }
|
public DateTime TopicTime { get; set; }
|
||||||
public DateTime Created { get; set; }
|
public DateTime Created { get; set; }
|
||||||
public Dictionary<string, List<string>> ListModes { get; set; }
|
public Dictionary<string, List<string>> ListModes { get; private set; }
|
||||||
public Dictionary<string, string> Modes { get; set; }
|
public Dictionary<string, string> Modes { get; private set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,9 +9,9 @@ namespace IRCStates
|
||||||
Modes = new List<string>();
|
Modes = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> Modes { get; set; }
|
public List<string> Modes { get; }
|
||||||
|
|
||||||
protected bool Equals(ChannelUser other)
|
private bool Equals(ChannelUser other)
|
||||||
{
|
{
|
||||||
return other != null && Equals(Modes, other.Modes);
|
return other != null && Equals(Modes, other.Modes);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ namespace IRCStates
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
if (obj.GetType() != GetType()) return false;
|
return obj.GetType() == GetType() && Equals((ChannelUser) obj);
|
||||||
return Equals((ChannelUser) obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
|
|
@ -5,6 +5,13 @@ namespace IRCStates
|
||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Update the dictionary with <see cref="other"/>'s keys and values
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dict"></param>
|
||||||
|
/// <param name="other"></param>
|
||||||
|
/// <typeparam name="TKey"></typeparam>
|
||||||
|
/// <typeparam name="TValue"></typeparam>
|
||||||
public static void UpdateWith<TKey, TValue>(this Dictionary<TKey, TValue> dict, Dictionary<TKey, TValue> other)
|
public static void UpdateWith<TKey, TValue>(this Dictionary<TKey, TValue> dict, Dictionary<TKey, TValue> other)
|
||||||
{
|
{
|
||||||
if (dict == null || other == null || !other.Any()) return;
|
if (dict == null || other == null || !other.Any()) return;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<RepositoryUrl>https://tildegit.org/ben/ircsharp/src/branch/master/IRCStates</RepositoryUrl>
|
<RepositoryUrl>https://tildegit.org/ben/ircsharp/src/branch/master/IRCStates</RepositoryUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageTags>irc</PackageTags>
|
<PackageTags>irc</PackageTags>
|
||||||
|
<PackageVersion>1.0.1</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -21,21 +21,25 @@ namespace IRCStates
|
||||||
Whox = false;
|
Whox = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> Raw { get; set; }
|
public Dictionary<string, string> Raw { get; }
|
||||||
public string Network { get; set; }
|
public string Network { get; private set; }
|
||||||
public ISupportChanModes ChanModes { get; set; }
|
public ISupportChanModes ChanModes { get; private set; }
|
||||||
public ISupportPrefix Prefix { get; set; }
|
public ISupportPrefix Prefix { get; private set; }
|
||||||
public int? Modes { get; set; }
|
public int? Modes { get; private set; }
|
||||||
public Casemap.CaseMapping CaseMapping { get; set; }
|
public Casemap.CaseMapping CaseMapping { get; private set; }
|
||||||
public List<string> ChanTypes { get; set; }
|
public List<string> ChanTypes { get; private set; }
|
||||||
public List<string> StatusMsg { get; set; }
|
public List<string> StatusMsg { get; private set; }
|
||||||
public string CallerId { get; set; }
|
public string CallerId { get; private set; }
|
||||||
public string Excepts { get; set; }
|
public string Excepts { get; private set; }
|
||||||
public string Invex { get; set; }
|
public string Invex { get; private set; }
|
||||||
public int? Monitor { get; set; }
|
public int? Monitor { get; private set; }
|
||||||
public int? Watch { get; set; }
|
public int? Watch { get; private set; }
|
||||||
public bool Whox { get; set; }
|
public bool Whox { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parse the ISupport values from the line's parameters
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tokens"></param>
|
||||||
public void Parse(IEnumerable<string> tokens)
|
public void Parse(IEnumerable<string> tokens)
|
||||||
{
|
{
|
||||||
if (tokens == null) return;
|
if (tokens == null) return;
|
||||||
|
|
|
@ -6,6 +6,10 @@ namespace IRCStates
|
||||||
{
|
{
|
||||||
public class ISupportChanModes
|
public class ISupportChanModes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Split the chanmodes and add to our known <see cref="ListModes"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="splitVal"></param>
|
||||||
public ISupportChanModes(string splitVal)
|
public ISupportChanModes(string splitVal)
|
||||||
{
|
{
|
||||||
if (splitVal == null) return;
|
if (splitVal == null) return;
|
||||||
|
@ -25,9 +29,9 @@ namespace IRCStates
|
||||||
SettingDModes.AddRange(split[3].Select(c => c.ToString(CultureInfo.InvariantCulture)));
|
SettingDModes.AddRange(split[3].Select(c => c.ToString(CultureInfo.InvariantCulture)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> ListModes { get; set; }
|
public List<string> ListModes { get; }
|
||||||
public List<string> SettingBModes { get; set; }
|
public List<string> SettingBModes { get; }
|
||||||
public List<string> SettingCModes { get; set; }
|
public List<string> SettingCModes { get; }
|
||||||
public List<string> SettingDModes { get; set; }
|
public List<string> SettingDModes { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@ namespace IRCStates
|
||||||
{
|
{
|
||||||
public class ISupportPrefix
|
public class ISupportPrefix
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Split the prefix value and add them to our known <see cref="Modes"/> and <see cref="Prefixes"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="splitVal"></param>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
public ISupportPrefix(string splitVal)
|
public ISupportPrefix(string splitVal)
|
||||||
{
|
{
|
||||||
if (splitVal == null) throw new ArgumentNullException(nameof(splitVal));
|
if (splitVal == null) throw new ArgumentNullException(nameof(splitVal));
|
||||||
|
@ -18,8 +23,8 @@ namespace IRCStates
|
||||||
Prefixes.AddRange(split[1].Select(c => c.ToString(CultureInfo.InvariantCulture)));
|
Prefixes.AddRange(split[1].Select(c => c.ToString(CultureInfo.InvariantCulture)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> Modes { get; set; }
|
public List<string> Modes { get; }
|
||||||
public List<string> Prefixes { get; set; }
|
public List<string> Prefixes { get; }
|
||||||
|
|
||||||
public string FromMode(char mode)
|
public string FromMode(char mode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace IRCStates
|
namespace IRCStates
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Known numeric response codes
|
||||||
|
/// </summary>
|
||||||
public static class Numeric
|
public static class Numeric
|
||||||
{
|
{
|
||||||
#pragma warning disable CA1707 // Identifiers should not contain underscores
|
#pragma warning disable CA1707 // Identifiers should not contain underscores
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace IRCStates
|
||||||
public const string WhoType = "525"; // randomly generated
|
public const string WhoType = "525"; // randomly generated
|
||||||
private readonly StatefulDecoder _decoder;
|
private readonly StatefulDecoder _decoder;
|
||||||
|
|
||||||
private readonly Dictionary<string, string> TempCaps;
|
private readonly Dictionary<string, string> _tempCaps;
|
||||||
|
|
||||||
public Server(string name)
|
public Server(string name)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ namespace IRCStates
|
||||||
Channels = new Dictionary<string, Channel>();
|
Channels = new Dictionary<string, Channel>();
|
||||||
ISupport = new ISupport();
|
ISupport = new ISupport();
|
||||||
HasCap = false;
|
HasCap = false;
|
||||||
TempCaps = new Dictionary<string, string>();
|
_tempCaps = new Dictionary<string, string>();
|
||||||
AvailableCaps = new Dictionary<string, string>();
|
AvailableCaps = new Dictionary<string, string>();
|
||||||
AgreedCaps = new List<string>();
|
AgreedCaps = new List<string>();
|
||||||
}
|
}
|
||||||
|
@ -54,56 +54,107 @@ namespace IRCStates
|
||||||
return $"Server(name={Name})";
|
return $"Server(name={Name})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use <see cref="ISupport"/>'s case mapping to convert to lowercase
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public string CaseFold(string str)
|
public string CaseFold(string str)
|
||||||
{
|
{
|
||||||
return Casemap.CaseFold(ISupport.CaseMapping, str);
|
return Casemap.CaseFold(ISupport.CaseMapping, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CaseFoldEquals(string s1, string s2)
|
/// <summary>
|
||||||
{
|
/// Is the current nickname this client?
|
||||||
return CaseFold(s1) == CaseFold(s2);
|
/// </summary>
|
||||||
}
|
/// <param name="nickname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private bool IsMe(string nickname)
|
private bool IsMe(string nickname)
|
||||||
{
|
{
|
||||||
return CaseFold(nickname) == NickNameLower;
|
return CaseFold(nickname) == NickNameLower;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check for a user - not case sensitive
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nickname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private bool HasUser(string nickname)
|
private bool HasUser(string nickname)
|
||||||
{
|
{
|
||||||
return Users.ContainsKey(CaseFold(nickname));
|
return Users.ContainsKey(CaseFold(nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
private User AddUser(string nickname, string nicknameLower)
|
/// <summary>
|
||||||
|
/// Get existing user by case-insensitive nickname
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nickname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private User GetUser(string nickname)
|
||||||
{
|
{
|
||||||
var user = CreateUser(nickname, nicknameLower);
|
return HasUser(nickname) ? Users[CaseFold(nickname)] : null;
|
||||||
Users[nicknameLower] = user;
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create and add user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nickname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private User AddUser(string nickname)
|
||||||
|
{
|
||||||
|
var user = CreateUser(nickname);
|
||||||
|
Users[CaseFold(nickname)] = user;
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private User CreateUser(string nickname, string nicknameLower)
|
/// <summary>
|
||||||
|
/// Build a new <see cref="User"/> and update correct case-mapped nick
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nickname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private User CreateUser(string nickname)
|
||||||
{
|
{
|
||||||
var user = new User();
|
var user = new User();
|
||||||
user.SetNickName(nickname, nicknameLower);
|
user.SetNickName(nickname, CaseFold(nickname));
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the channel a valid ISupport type?
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private bool IsChannel(string target)
|
private bool IsChannel(string target)
|
||||||
{
|
{
|
||||||
return !string.IsNullOrEmpty(target) &&
|
return !string.IsNullOrEmpty(target) &&
|
||||||
ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture));
|
ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the channel known to this client?
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public bool HasChannel(string name)
|
public bool HasChannel(string name)
|
||||||
{
|
{
|
||||||
return Channels.ContainsKey(CaseFold(name));
|
return IsChannel(name) && Channels.ContainsKey(CaseFold(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the channel if it's known to us
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Channel GetChannel(string name)
|
private Channel GetChannel(string name)
|
||||||
{
|
{
|
||||||
return HasChannel(name) ? Channels[name] : null;
|
return HasChannel(name) ? Channels[CaseFold(name)] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a <see cref="User"/> to a <see cref="Channel"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <returns>the <see cref="ChannelUser"/> that was added</returns>
|
||||||
private ChannelUser UserJoin(Channel channel, User user)
|
private ChannelUser UserJoin(Channel channel, User user)
|
||||||
{
|
{
|
||||||
var channelUser = new ChannelUser();
|
var channelUser = new ChannelUser();
|
||||||
|
@ -112,6 +163,11 @@ namespace IRCStates
|
||||||
return channelUser;
|
return channelUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set own <see cref="NickName"/>, <see cref="UserName"/>, and <see cref="HostName"/>
|
||||||
|
/// from a given <see cref="Hostmask"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostmask"></param>
|
||||||
private void SelfHostmask(Hostmask hostmask)
|
private void SelfHostmask(Hostmask hostmask)
|
||||||
{
|
{
|
||||||
NickName = hostmask.NickName;
|
NickName = hostmask.NickName;
|
||||||
|
@ -119,6 +175,19 @@ namespace IRCStates
|
||||||
if (hostmask.HostName != null) HostName = hostmask.HostName;
|
if (hostmask.HostName != null) HostName = hostmask.HostName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SelfHostmask(string raw)
|
||||||
|
{
|
||||||
|
SelfHostmask(new Hostmask(raw));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a user from a channel. Used to handle PART and KICK
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <param name="nickName"></param>
|
||||||
|
/// <param name="channelName"></param>
|
||||||
|
/// <param name="reasonIndex"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private (Emit, User) UserPart(Line line, string nickName, string channelName, int reasonIndex)
|
private (Emit, User) UserPart(Line line, string nickName, string channelName, int reasonIndex)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -128,7 +197,7 @@ namespace IRCStates
|
||||||
User user = null;
|
User user = null;
|
||||||
if (HasChannel(channelName))
|
if (HasChannel(channelName))
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(channelName);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
var nickLower = CaseFold(nickName);
|
var nickLower = CaseFold(nickName);
|
||||||
if (HasUser(nickLower))
|
if (HasUser(nickLower))
|
||||||
|
@ -153,6 +222,12 @@ namespace IRCStates
|
||||||
return (emit, user);
|
return (emit, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update modes on a <see cref="Channel"/> given modes and parameters
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="modes"></param>
|
||||||
|
/// <param name="parameters"></param>
|
||||||
private void SetChannelModes(Channel channel, IEnumerable<(bool, string)> modes, IList<string> parameters)
|
private void SetChannelModes(Channel channel, IEnumerable<(bool, string)> modes, IList<string> parameters)
|
||||||
{
|
{
|
||||||
foreach (var (add, c) in modes)
|
foreach (var (add, c) in modes)
|
||||||
|
@ -197,6 +272,13 @@ namespace IRCStates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle incoming bytes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns>parsed lines and emits</returns>
|
||||||
|
/// <exception cref="ServerDisconnectedException"></exception>
|
||||||
public IEnumerable<(Line, Emit)> Receive(byte[] data, int length)
|
public IEnumerable<(Line, Emit)> Receive(byte[] data, int length)
|
||||||
{
|
{
|
||||||
if (data == null) return null;
|
if (data == null) return null;
|
||||||
|
@ -204,9 +286,14 @@ namespace IRCStates
|
||||||
var lines = _decoder.Push(data, length);
|
var lines = _decoder.Push(data, length);
|
||||||
if (lines == null) throw new ServerDisconnectedException();
|
if (lines == null) throw new ServerDisconnectedException();
|
||||||
|
|
||||||
return lines.Select(l => (l, Parse(l))).ToList();
|
return lines.Select(l => (l, Parse(l)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate a <see cref="Line"/> to the correct handler
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public Emit Parse(Line line)
|
public Emit Parse(Line line)
|
||||||
{
|
{
|
||||||
if (line == null) return null;
|
if (line == null) return null;
|
||||||
|
@ -256,6 +343,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles SETNAME command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleSetname(Line line)
|
private Emit HandleSetname(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -278,6 +370,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles AWAY command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleAway(Line line)
|
private Emit HandleAway(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -300,6 +397,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles ACCOUNT command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleAccount(Line line)
|
private Emit HandleAccount(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -322,6 +424,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles CAP command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleCap(Line line)
|
private Emit HandleCap(Line line)
|
||||||
{
|
{
|
||||||
HasCap = true;
|
HasCap = true;
|
||||||
|
@ -343,11 +450,11 @@ namespace IRCStates
|
||||||
switch (subcommand)
|
switch (subcommand)
|
||||||
{
|
{
|
||||||
case "LS":
|
case "LS":
|
||||||
TempCaps.UpdateWith(tokens);
|
_tempCaps.UpdateWith(tokens);
|
||||||
if (!multiline)
|
if (!multiline)
|
||||||
{
|
{
|
||||||
AvailableCaps.UpdateWith(TempCaps);
|
AvailableCaps.UpdateWith(_tempCaps);
|
||||||
TempCaps.Clear();
|
_tempCaps.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -380,6 +487,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_LOGGEDIN numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleLoggedIn(Line line)
|
private Emit HandleLoggedIn(Line line)
|
||||||
{
|
{
|
||||||
SelfHostmask(new Hostmask(line.Params[1]));
|
SelfHostmask(new Hostmask(line.Params[1]));
|
||||||
|
@ -387,6 +499,11 @@ namespace IRCStates
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles CHGHOST command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleChghost(Line line)
|
private Emit HandleChghost(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -412,6 +529,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_WHOISUSER numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleWhoIsUser(Line line)
|
private Emit HandleWhoIsUser(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -440,6 +562,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_WHOSPCRPL numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleWhox(Line line)
|
private Emit HandleWhox(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -474,6 +601,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_WHOREPLY numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleWhoReply(Line line)
|
private Emit HandleWhoReply(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit {Target = line.Params[1]};
|
var emit = new Emit {Target = line.Params[1]};
|
||||||
|
@ -502,6 +634,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_VISIBLEHOST numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleVisibleHost(Line line)
|
private Emit HandleVisibleHost(Line line)
|
||||||
{
|
{
|
||||||
var split = line.Params[1].Split('@', 2);
|
var split = line.Params[1].Split('@', 2);
|
||||||
|
@ -519,22 +656,25 @@ namespace IRCStates
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles PRIVMSG, NOTICE, and TAGMSG commands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleMessage(Line line)
|
private Emit HandleMessage(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var message = line.Params.Count > 1 ? line.Params[1] : null;
|
var message = line.Params.Count > 1 ? line.Params[1] : null;
|
||||||
if (message != null) emit.Text = message;
|
if (message != null) emit.Text = message;
|
||||||
|
|
||||||
var nickLower = CaseFold(line.Hostmask.NickName);
|
var nick = CaseFold(line.Hostmask.NickName);
|
||||||
if (IsMe(nickLower))
|
if (IsMe(nick))
|
||||||
{
|
{
|
||||||
emit.SelfSource = true;
|
emit.SelfSource = true;
|
||||||
SelfHostmask(line.Hostmask);
|
SelfHostmask(line.Hostmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = HasUser(nickLower)
|
var user = GetUser(nick) ?? AddUser(nick);
|
||||||
? Users[nickLower]
|
|
||||||
: AddUser(line.Hostmask.NickName, nickLower);
|
|
||||||
emit.User = user;
|
emit.User = user;
|
||||||
|
|
||||||
if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName;
|
if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName;
|
||||||
|
@ -559,12 +699,17 @@ namespace IRCStates
|
||||||
emit.Target = line.Params[0];
|
emit.Target = line.Params[0];
|
||||||
|
|
||||||
if (IsChannel(target) && HasChannel(target))
|
if (IsChannel(target) && HasChannel(target))
|
||||||
emit.Channel = Channels[CaseFold(target)];
|
emit.Channel = GetChannel(target);
|
||||||
else if (IsMe(target)) emit.SelfTarget = true;
|
else if (IsMe(target)) emit.SelfTarget = true;
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_UMODEIS numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleUModeIs(Line line)
|
private Emit HandleUModeIs(Line line)
|
||||||
{
|
{
|
||||||
foreach (var c in line.Params[1]
|
foreach (var c in line.Params[1]
|
||||||
|
@ -576,12 +721,17 @@ namespace IRCStates
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_CHANNELMODEIS numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleChannelModeIs(Line line)
|
private Emit HandleChannelModeIs(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
if (HasChannel(line.Params[1]))
|
if (HasChannel(line.Params[1]))
|
||||||
{
|
{
|
||||||
var channel = Channels[CaseFold(line.Params[1])];
|
var channel = GetChannel(line.Params[1]);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
var modes = line.Params[2]
|
var modes = line.Params[2]
|
||||||
.TrimStart('+')
|
.TrimStart('+')
|
||||||
|
@ -593,6 +743,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles MODE command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleMode(Line line)
|
private Emit HandleMode(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
@ -635,13 +790,17 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_TOPICWHOTIME numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleTopicTime(Line line)
|
private Emit HandleTopicTime(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var channelLower = CaseFold(line.Params[1]);
|
if (HasChannel(line.Params[1]))
|
||||||
if (Channels.ContainsKey(channelLower))
|
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(line.Params[1]);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
channel.TopicSetter = line.Params[2];
|
channel.TopicSetter = line.Params[2];
|
||||||
channel.TopicTime = DateTimeOffset
|
channel.TopicTime = DateTimeOffset
|
||||||
|
@ -651,27 +810,35 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_TOPIC numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleTopicNumeric(Line line)
|
private Emit HandleTopicNumeric(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var channelLower = CaseFold(line.Params[1]);
|
if (HasChannel(line.Params[1]))
|
||||||
if (Channels.ContainsKey(channelLower))
|
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(line.Params[1]);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
Channels[channelLower].Topic = line.Params[2];
|
channel.Topic = line.Params[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles TOPIC command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleTopic(Line line)
|
private Emit HandleTopic(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var channelLower = CaseFold(line.Params[0]);
|
if (HasChannel(line.Params[0]))
|
||||||
if (Channels.ContainsKey(channelLower))
|
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(line.Params[0]);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
channel.Topic = line.Params[1];
|
channel.Topic = line.Params[1];
|
||||||
channel.TopicSetter = line.Hostmask.ToString();
|
channel.TopicSetter = line.Hostmask.ToString();
|
||||||
|
@ -681,13 +848,17 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_CREATIONTIME numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleCreationTime(Line line)
|
private Emit HandleCreationTime(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var channelLower = CaseFold(line.Params[1]);
|
if (HasChannel(line.Params[1]))
|
||||||
if (Channels.ContainsKey(channelLower))
|
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(line.Params[1]);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
channel.Created = DateTimeOffset
|
channel.Created = DateTimeOffset
|
||||||
.FromUnixTimeSeconds(int.Parse(line.Params[2], CultureInfo.InvariantCulture)).DateTime;
|
.FromUnixTimeSeconds(int.Parse(line.Params[2], CultureInfo.InvariantCulture)).DateTime;
|
||||||
|
@ -696,13 +867,17 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_NAMREPLY numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleNames(Line line)
|
private Emit HandleNames(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var channelLower = CaseFold(line.Params[2]);
|
if (!HasChannel(line.Params[2])) return emit;
|
||||||
|
|
||||||
if (!Channels.ContainsKey(channelLower)) return emit;
|
var channel = GetChannel(line.Params[2]);
|
||||||
var channel = Channels[channelLower];
|
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
var nicknames = line.Params[3].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
var nicknames = line.Params[3].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
var users = new List<User>();
|
var users = new List<User>();
|
||||||
|
@ -721,17 +896,15 @@ namespace IRCStates
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostmask = new Hostmask(nick.Substring(modes.Length));
|
var hostmask = new Hostmask(nick.Substring(modes.Length));
|
||||||
var nickLower = CaseFold(hostmask.NickName);
|
var user = GetUser(hostmask.NickName) ?? AddUser(hostmask.NickName);
|
||||||
if (!Users.ContainsKey(nickLower)) AddUser(hostmask.NickName, nickLower);
|
|
||||||
|
|
||||||
var user = Users[nickLower];
|
|
||||||
users.Add(user);
|
users.Add(user);
|
||||||
var channelUser = UserJoin(channel, user);
|
var channelUser = UserJoin(channel, user);
|
||||||
|
|
||||||
if (hostmask.UserName != null) user.UserName = hostmask.UserName;
|
if (hostmask.UserName != null) user.UserName = hostmask.UserName;
|
||||||
if (hostmask.HostName != null) user.HostName = hostmask.HostName;
|
if (hostmask.HostName != null) user.HostName = hostmask.HostName;
|
||||||
|
|
||||||
if (IsMe(nickLower)) SelfHostmask(hostmask);
|
if (IsMe(hostmask.NickName)) SelfHostmask(hostmask);
|
||||||
|
|
||||||
foreach (var mode in modes.Select(c => c.ToString(CultureInfo.InvariantCulture)))
|
foreach (var mode in modes.Select(c => c.ToString(CultureInfo.InvariantCulture)))
|
||||||
if (!channelUser.Modes.Contains(mode))
|
if (!channelUser.Modes.Contains(mode))
|
||||||
|
@ -741,6 +914,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles ERROR command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleError(Line line)
|
private Emit HandleError(Line line)
|
||||||
{
|
{
|
||||||
Users.Clear();
|
Users.Clear();
|
||||||
|
@ -748,22 +926,27 @@ namespace IRCStates
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles QUIT command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleQuit(Line line)
|
private Emit HandleQuit(Line line)
|
||||||
{
|
{
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
var nickLower = CaseFold(line.Hostmask.NickName);
|
var nick = line.Hostmask.NickName;
|
||||||
if (line.Params.Any()) emit.Text = line.Params[0];
|
if (line.Params.Any()) emit.Text = line.Params[0];
|
||||||
|
|
||||||
if (IsMe(nickLower) || line.Source == null)
|
if (IsMe(nick) || line.Source == null)
|
||||||
{
|
{
|
||||||
emit.Self = true;
|
emit.Self = true;
|
||||||
Users.Clear();
|
Users.Clear();
|
||||||
Channels.Clear();
|
Channels.Clear();
|
||||||
}
|
}
|
||||||
else if (Users.ContainsKey(nickLower))
|
else if (HasUser(nick))
|
||||||
{
|
{
|
||||||
var user = Users[nickLower];
|
var user = GetUser(nick);
|
||||||
Users.Remove(nickLower);
|
Users.Remove(user.NickNameLower);
|
||||||
emit.User = user;
|
emit.User = user;
|
||||||
foreach (var channel in user.Channels.Select(c => Channels[c]))
|
foreach (var channel in user.Channels.Select(c => Channels[c]))
|
||||||
channel.Users.Remove(user.NickNameLower);
|
channel.Users.Remove(user.NickNameLower);
|
||||||
|
@ -772,13 +955,23 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_LOGGEDOUT numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleLoggedOut(Line line)
|
private Emit HandleLoggedOut(Line line)
|
||||||
{
|
{
|
||||||
Account = null;
|
Account = null;
|
||||||
SelfHostmask(new Hostmask(line.Params[1]));
|
SelfHostmask(line.Params[1]);
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles KICK command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleKick(Line line)
|
private Emit HandleKick(Line line)
|
||||||
{
|
{
|
||||||
var (emit, kicked) = UserPart(line, line.Params[1], line.Params[0], 2);
|
var (emit, kicked) = UserPart(line, line.Params[1], line.Params[0], 2);
|
||||||
|
@ -787,30 +980,37 @@ namespace IRCStates
|
||||||
emit.UserTarget = kicked;
|
emit.UserTarget = kicked;
|
||||||
if (IsMe(kicked.NickName)) emit.Self = true;
|
if (IsMe(kicked.NickName)) emit.Self = true;
|
||||||
|
|
||||||
var kickerLower = CaseFold(line.Hostmask.NickName);
|
var kicker = line.Hostmask.NickName;
|
||||||
if (IsMe(kickerLower)) emit.SelfSource = true;
|
if (IsMe(kicker)) emit.SelfSource = true;
|
||||||
|
|
||||||
emit.UserSource = Users.ContainsKey(kickerLower)
|
emit.UserSource = GetUser(kicker) ?? CreateUser(kicker);
|
||||||
? Users[kickerLower]
|
|
||||||
: CreateUser(line.Hostmask.NickName, kickerLower);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles PART command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandlePart(Line line)
|
private Emit HandlePart(Line line)
|
||||||
{
|
{
|
||||||
var (emit, user) = UserPart(line, line.Hostmask.NickName, line.Params[0], 1);
|
var (emit, user) = UserPart(line, line.Hostmask.NickName, line.Params[0], 1);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
emit.User = user;
|
emit.User = user;
|
||||||
if (IsMe(user.NickName)) emit.Self = true;
|
emit.Self = IsMe(user.NickName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles JOIN command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleJoin(Line line)
|
private Emit HandleJoin(Line line)
|
||||||
{
|
{
|
||||||
var extended = line.Params.Count == 3;
|
var extended = line.Params.Count == 3;
|
||||||
|
@ -818,18 +1018,18 @@ namespace IRCStates
|
||||||
var realname = extended ? line.Params[2] : null;
|
var realname = extended ? line.Params[2] : null;
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
|
||||||
var channelLower = CaseFold(line.Params[0]);
|
var channelName = line.Params[0];
|
||||||
var nickLower = CaseFold(line.Hostmask.NickName);
|
var nick = line.Hostmask.NickName;
|
||||||
|
|
||||||
// handle own join
|
// handle own join
|
||||||
if (IsMe(nickLower))
|
if (IsMe(nick))
|
||||||
{
|
{
|
||||||
emit.Self = true;
|
emit.Self = true;
|
||||||
if (!HasChannel(channelLower))
|
if (!HasChannel(channelName))
|
||||||
{
|
{
|
||||||
var channel = new Channel();
|
var channel = new Channel();
|
||||||
channel.SetName(line.Params[0], channelLower);
|
channel.SetName(channelName, CaseFold(channelName));
|
||||||
Channels[channelLower] = channel;
|
Channels[CaseFold(channelName)] = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelfHostmask(line.Hostmask);
|
SelfHostmask(line.Hostmask);
|
||||||
|
@ -840,14 +1040,14 @@ namespace IRCStates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasChannel(channelLower))
|
if (HasChannel(channelName))
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(channelName);
|
||||||
emit.Channel = channel;
|
emit.Channel = channel;
|
||||||
|
|
||||||
if (!HasUser(nickLower)) AddUser(line.Hostmask.NickName, nickLower);
|
if (!HasUser(nick)) AddUser(nick);
|
||||||
|
|
||||||
var user = Users[nickLower];
|
var user = GetUser(nick);
|
||||||
emit.User = user;
|
emit.User = user;
|
||||||
if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName;
|
if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName;
|
||||||
if (line.Hostmask.HostName != null) user.HostName = line.Hostmask.HostName;
|
if (line.Hostmask.HostName != null) user.HostName = line.Hostmask.HostName;
|
||||||
|
@ -863,43 +1063,53 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles NICK command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleNick(Line line)
|
private Emit HandleNick(Line line)
|
||||||
{
|
{
|
||||||
var nick = line.Params[0];
|
var newNick = line.Params[0];
|
||||||
var nickLower = CaseFold(line.Hostmask.NickName);
|
var oldNick = line.Hostmask.NickName;
|
||||||
|
|
||||||
var emit = new Emit();
|
var emit = new Emit();
|
||||||
|
|
||||||
if (Users.ContainsKey(nickLower))
|
if (HasUser(oldNick))
|
||||||
{
|
{
|
||||||
var user = Users[nickLower];
|
var user = GetUser(oldNick);
|
||||||
Users.Remove(nickLower);
|
|
||||||
emit.User = user;
|
|
||||||
|
|
||||||
var oldNickLower = user.NickNameLower;
|
var oldNickLower = user.NickNameLower;
|
||||||
var newNickLower = CaseFold(nick);
|
var newNickLower = CaseFold(newNick);
|
||||||
user.SetNickName(nick, newNickLower);
|
|
||||||
|
emit.User = user;
|
||||||
|
Users.Remove(oldNickLower);
|
||||||
Users[newNickLower] = user;
|
Users[newNickLower] = user;
|
||||||
|
user.SetNickName(newNick, newNickLower);
|
||||||
|
|
||||||
foreach (var channelLower in user.Channels)
|
foreach (var channelLower in user.Channels)
|
||||||
{
|
{
|
||||||
var channel = Channels[channelLower];
|
var channel = GetChannel(channelLower);
|
||||||
var channelUser = channel.Users[oldNickLower];
|
var channelUser = channel.Users[oldNickLower];
|
||||||
channel.Users.Remove(oldNickLower);
|
channel.Users.Remove(oldNickLower);
|
||||||
channel.Users[newNickLower] = channelUser;
|
channel.Users[newNickLower] = channelUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsMe(nickLower))
|
if (IsMe(oldNick))
|
||||||
{
|
{
|
||||||
emit.Self = true;
|
emit.Self = true;
|
||||||
NickName = nick;
|
NickName = newNick;
|
||||||
NickNameLower = CaseFold(nick);
|
NickNameLower = CaseFold(newNick);
|
||||||
}
|
}
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_MOTDSTART and RPL_MOTD numerics
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleMotd(Line line)
|
private Emit HandleMotd(Line line)
|
||||||
{
|
{
|
||||||
if (line.Command == Numeric.RPL_MOTDSTART) Motd.Clear();
|
if (line.Command == Numeric.RPL_MOTDSTART) Motd.Clear();
|
||||||
|
@ -909,6 +1119,11 @@ namespace IRCStates
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_ISUPPORT numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleISupport(Line line)
|
private Emit HandleISupport(Line line)
|
||||||
{
|
{
|
||||||
ISupport = new ISupport();
|
ISupport = new ISupport();
|
||||||
|
@ -916,7 +1131,11 @@ namespace IRCStates
|
||||||
return new Emit();
|
return new Emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles RPL_WELCOME numeric
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private Emit HandleWelcome(Line line)
|
private Emit HandleWelcome(Line line)
|
||||||
{
|
{
|
||||||
NickName = line.Params[0];
|
NickName = line.Params[0];
|
||||||
|
|
|
@ -9,15 +9,15 @@ namespace IRCStates
|
||||||
Channels = new HashSet<string>();
|
Channels = new HashSet<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string NickName { get; set; }
|
public string NickName { get; private set; }
|
||||||
public string NickNameLower { get; set; }
|
public string NickNameLower { get; private set; }
|
||||||
|
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; }
|
||||||
public string HostName { get; set; }
|
public string HostName { get; set; }
|
||||||
public string RealName { get; set; }
|
public string RealName { get; set; }
|
||||||
public string Account { get; set; }
|
public string Account { get; set; }
|
||||||
public string Away { get; set; }
|
public string Away { get; set; }
|
||||||
public HashSet<string> Channels { get; set; }
|
public HashSet<string> Channels { get; private set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<RepositoryUrl>https://tildegit.org/ben/ircsharp/src/branch/master/IRCTokens</RepositoryUrl>
|
<RepositoryUrl>https://tildegit.org/ben/ircsharp/src/branch/master/IRCTokens</RepositoryUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageTags>irc</PackageTags>
|
<PackageTags>irc</PackageTags>
|
||||||
|
<PackageVersion>1.0.1</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -59,6 +59,15 @@ namespace IRCTokens
|
||||||
|
|
||||||
_buffer = _buffer == null ? Array.Empty<byte>() : _buffer.Concat(data.Take(bytesReceived)).ToArray();
|
_buffer = _buffer == null ? Array.Empty<byte>() : _buffer.Concat(data.Take(bytesReceived)).ToArray();
|
||||||
|
|
||||||
|
// truncate message at NUL if found
|
||||||
|
if (_buffer.Contains((byte) 0))
|
||||||
|
{
|
||||||
|
_buffer = _buffer
|
||||||
|
.Take(Array.IndexOf(_buffer, (byte) 0))
|
||||||
|
.Concat(new []{(byte) '\n'})
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
var listLines = _buffer.Split((byte) '\n').Select(l => l.Trim((byte) '\r')).ToList();
|
var listLines = _buffer.Split((byte) '\n').Select(l => l.Trim((byte) '\r')).ToList();
|
||||||
_buffer = listLines.LastOrDefault() ?? Array.Empty<byte>();
|
_buffer = listLines.LastOrDefault() ?? Array.Empty<byte>();
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace IRCTokens.Tests
|
||||||
public class Format
|
public class Format
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTags()
|
public void Tags()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello")
|
var line = new Line("PRIVMSG", "#channel", "hello")
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMissingTag()
|
public void MissingTag()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello").Format();
|
var line = new Line("PRIVMSG", "#channel", "hello").Format();
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestNullTag()
|
public void NullTag()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary<string, string> {{"a", null}}}
|
var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary<string, string> {{"a", null}}}
|
||||||
.Format();
|
.Format();
|
||||||
|
@ -36,7 +36,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEmptyTag()
|
public void EmptyTag()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary<string, string> {{"a", ""}}}
|
var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary<string, string> {{"a", ""}}}
|
||||||
.Format();
|
.Format();
|
||||||
|
@ -45,7 +45,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSource()
|
public void Source()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello") {Source = "nick!user@host"}.Format();
|
var line = new Line("PRIVMSG", "#channel", "hello") {Source = "nick!user@host"}.Format();
|
||||||
|
|
||||||
|
@ -53,21 +53,21 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestCommandLowercase()
|
public void CommandLowercase()
|
||||||
{
|
{
|
||||||
var line = new Line {Command = "privmsg"}.Format();
|
var line = new Line {Command = "privmsg"}.Format();
|
||||||
Assert.AreEqual("privmsg", line);
|
Assert.AreEqual("privmsg", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestCommandUppercase()
|
public void CommandUppercase()
|
||||||
{
|
{
|
||||||
var line = new Line {Command = "PRIVMSG"}.Format();
|
var line = new Line {Command = "PRIVMSG"}.Format();
|
||||||
Assert.AreEqual("PRIVMSG", line);
|
Assert.AreEqual("PRIVMSG", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTrailingSpace()
|
public void TrailingSpace()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "hello world").Format();
|
var line = new Line("PRIVMSG", "#channel", "hello world").Format();
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTrailingNoSpace()
|
public void TrailingNoSpace()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", "helloworld").Format();
|
var line = new Line("PRIVMSG", "#channel", "helloworld").Format();
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTrailingDoubleColon()
|
public void TrailingDoubleColon()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG", "#channel", ":helloworld").Format();
|
var line = new Line("PRIVMSG", "#channel", ":helloworld").Format();
|
||||||
|
|
||||||
|
@ -91,13 +91,13 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestInvalidNonLastSpace()
|
public void InvalidNonLastSpace()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentException>(() => { new Line("USER", "user", "0 *", "real name").Format(); });
|
Assert.ThrowsException<ArgumentException>(() => { new Line("USER", "user", "0 *", "real name").Format(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestInvalidNonLastColon()
|
public void InvalidNonLastColon()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentException>(() => { new Line("PRIVMSG", ":#channel", "hello").Format(); });
|
Assert.ThrowsException<ArgumentException>(() => { new Line("PRIVMSG", ":#channel", "hello").Format(); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace IRCTokens.Tests
|
||||||
public class Hostmask
|
public class Hostmask
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestHostmask()
|
public void FullHostmask()
|
||||||
{
|
{
|
||||||
var hostmask = new IRCTokens.Hostmask("nick!user@host");
|
var hostmask = new IRCTokens.Hostmask("nick!user@host");
|
||||||
Assert.AreEqual("nick", hostmask.NickName);
|
Assert.AreEqual("nick", hostmask.NickName);
|
||||||
|
@ -15,7 +15,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestNoHostName()
|
public void NoHostName()
|
||||||
{
|
{
|
||||||
var hostmask = new IRCTokens.Hostmask("nick!user");
|
var hostmask = new IRCTokens.Hostmask("nick!user");
|
||||||
Assert.AreEqual("nick", hostmask.NickName);
|
Assert.AreEqual("nick", hostmask.NickName);
|
||||||
|
@ -24,7 +24,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestNoUserName()
|
public void NoUserName()
|
||||||
{
|
{
|
||||||
var hostmask = new IRCTokens.Hostmask("nick@host");
|
var hostmask = new IRCTokens.Hostmask("nick@host");
|
||||||
Assert.AreEqual("nick", hostmask.NickName);
|
Assert.AreEqual("nick", hostmask.NickName);
|
||||||
|
@ -33,7 +33,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestOnlyNickName()
|
public void OnlyNickName()
|
||||||
{
|
{
|
||||||
var hostmask = new IRCTokens.Hostmask("nick");
|
var hostmask = new IRCTokens.Hostmask("nick");
|
||||||
Assert.AreEqual("nick", hostmask.NickName);
|
Assert.AreEqual("nick", hostmask.NickName);
|
||||||
|
@ -42,7 +42,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestHostmaskFromLine()
|
public void HostmaskFromLine()
|
||||||
{
|
{
|
||||||
var line = new Line(":nick!user@host PRIVMSG #channel hello");
|
var line = new Line(":nick!user@host PRIVMSG #channel hello");
|
||||||
var hostmask = new IRCTokens.Hostmask("nick!user@host");
|
var hostmask = new IRCTokens.Hostmask("nick!user@host");
|
||||||
|
@ -53,7 +53,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEmptyHostmaskFromLine()
|
public void EmptyHostmaskFromLine()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel hello");
|
var line = new Line("PRIVMSG #channel hello");
|
||||||
Assert.IsNull(line.Hostmask.HostName);
|
Assert.IsNull(line.Hostmask.HostName);
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSplit()
|
public void Split()
|
||||||
{
|
{
|
||||||
foreach (var test in LoadYaml<SplitModel>("Tests/Data/msg-split.yaml").Tests)
|
foreach (var test in LoadYaml<SplitModel>("Tests/Data/msg-split.yaml").Tests)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestJoin()
|
public void Join()
|
||||||
{
|
{
|
||||||
foreach (var test in LoadYaml<JoinModel>("Tests/Data/msg-join.yaml").Tests)
|
foreach (var test in LoadYaml<JoinModel>("Tests/Data/msg-join.yaml").Tests)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,13 +10,13 @@ namespace IRCTokens.Tests
|
||||||
private IRCTokens.StatefulDecoder _decoder;
|
private IRCTokens.StatefulDecoder _decoder;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void TestInitialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_decoder = new IRCTokens.StatefulDecoder();
|
_decoder = new IRCTokens.StatefulDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestPartial()
|
public void Partial()
|
||||||
{
|
{
|
||||||
var lines = _decoder.Push("PRIVMSG ");
|
var lines = _decoder.Push("PRIVMSG ");
|
||||||
Assert.AreEqual(0, lines.Count);
|
Assert.AreEqual(0, lines.Count);
|
||||||
|
@ -29,7 +29,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMultiple()
|
public void Multiple()
|
||||||
{
|
{
|
||||||
var lines = _decoder.Push("PRIVMSG #channel1 hello\r\nPRIVMSG #channel2 hello\r\n");
|
var lines = _decoder.Push("PRIVMSG #channel1 hello\r\nPRIVMSG #channel2 hello\r\n");
|
||||||
Assert.AreEqual(2, lines.Count);
|
Assert.AreEqual(2, lines.Count);
|
||||||
|
@ -41,7 +41,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEncoding()
|
public void EncodingIso8859()
|
||||||
{
|
{
|
||||||
var iso8859 = Encoding.GetEncoding("iso-8859-1");
|
var iso8859 = Encoding.GetEncoding("iso-8859-1");
|
||||||
_decoder = new IRCTokens.StatefulDecoder {Encoding = iso8859};
|
_decoder = new IRCTokens.StatefulDecoder {Encoding = iso8859};
|
||||||
|
@ -52,7 +52,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEncodingFallback()
|
public void EncodingFallback()
|
||||||
{
|
{
|
||||||
var latin1 = Encoding.GetEncoding("iso-8859-1");
|
var latin1 = Encoding.GetEncoding("iso-8859-1");
|
||||||
_decoder = new IRCTokens.StatefulDecoder {Encoding = null, Fallback = latin1};
|
_decoder = new IRCTokens.StatefulDecoder {Encoding = null, Fallback = latin1};
|
||||||
|
@ -63,14 +63,14 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEmpty()
|
public void Empty()
|
||||||
{
|
{
|
||||||
var lines = _decoder.Push(string.Empty);
|
var lines = _decoder.Push(string.Empty);
|
||||||
Assert.AreEqual(0, lines.Count);
|
Assert.AreEqual(0, lines.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestBufferUnfinished()
|
public void BufferUnfinished()
|
||||||
{
|
{
|
||||||
_decoder.Push("PRIVMSG #channel hello");
|
_decoder.Push("PRIVMSG #channel hello");
|
||||||
var lines = _decoder.Push(string.Empty);
|
var lines = _decoder.Push(string.Empty);
|
||||||
|
@ -78,7 +78,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestClear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_decoder.Push("PRIVMSG ");
|
_decoder.Push("PRIVMSG ");
|
||||||
_decoder.Clear();
|
_decoder.Clear();
|
||||||
|
|
|
@ -9,13 +9,13 @@ namespace IRCTokens.Tests
|
||||||
private IRCTokens.StatefulEncoder _encoder;
|
private IRCTokens.StatefulEncoder _encoder;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void TestInitialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_encoder = new IRCTokens.StatefulEncoder();
|
_encoder = new IRCTokens.StatefulEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestPush()
|
public void Push()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel hello");
|
var line = new Line("PRIVMSG #channel hello");
|
||||||
_encoder.Push(line);
|
_encoder.Push(line);
|
||||||
|
@ -23,7 +23,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestPopPartial()
|
public void PopPartial()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel hello");
|
var line = new Line("PRIVMSG #channel hello");
|
||||||
_encoder.Push(line);
|
_encoder.Push(line);
|
||||||
|
@ -43,7 +43,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestPopNoneReturned()
|
public void PopNoneReturned()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel hello");
|
var line = new Line("PRIVMSG #channel hello");
|
||||||
_encoder.Push(line);
|
_encoder.Push(line);
|
||||||
|
@ -52,7 +52,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestPopMultipleLines()
|
public void PopMultipleLines()
|
||||||
{
|
{
|
||||||
var line1 = new Line("PRIVMSG #channel1 hello");
|
var line1 = new Line("PRIVMSG #channel1 hello");
|
||||||
_encoder.Push(line1);
|
_encoder.Push(line1);
|
||||||
|
@ -65,7 +65,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestClear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_encoder.Push(new Line("PRIVMSG #channel hello"));
|
_encoder.Push(new Line("PRIVMSG #channel hello"));
|
||||||
_encoder.Clear();
|
_encoder.Clear();
|
||||||
|
@ -73,7 +73,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestEncoding()
|
public void EncodingIso8859()
|
||||||
{
|
{
|
||||||
var iso8859 = Encoding.GetEncoding("iso-8859-1");
|
var iso8859 = Encoding.GetEncoding("iso-8859-1");
|
||||||
_encoder = new IRCTokens.StatefulEncoder {Encoding = iso8859};
|
_encoder = new IRCTokens.StatefulEncoder {Encoding = iso8859};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
namespace IRCTokens.Tests
|
namespace IRCTokens.Tests
|
||||||
|
@ -7,98 +9,98 @@ namespace IRCTokens.Tests
|
||||||
public class Tokenization
|
public class Tokenization
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsMissing()
|
public void TagsMissing()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel");
|
var line = new Line("PRIVMSG #channel");
|
||||||
Assert.IsNull(line.Tags);
|
Assert.IsNull(line.Tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsMissingValue()
|
public void TagsMissingValue()
|
||||||
{
|
{
|
||||||
var line = new Line("@id= PRIVMSG #channel");
|
var line = new Line("@id= PRIVMSG #channel");
|
||||||
Assert.AreEqual(string.Empty, line.Tags["id"]);
|
Assert.AreEqual(string.Empty, line.Tags["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsMissingEqual()
|
public void TagsMissingEqual()
|
||||||
{
|
{
|
||||||
var line = new Line("@id PRIVMSG #channel");
|
var line = new Line("@id PRIVMSG #channel");
|
||||||
Assert.AreEqual(string.Empty, line.Tags["id"]);
|
Assert.AreEqual(string.Empty, line.Tags["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsUnescape()
|
public void TagsUnescape()
|
||||||
{
|
{
|
||||||
var line = new Line(@"@id=1\\\:\r\n\s2 PRIVMSG #channel");
|
var line = new Line(@"@id=1\\\:\r\n\s2 PRIVMSG #channel");
|
||||||
Assert.AreEqual("1\\;\r\n 2", line.Tags["id"]);
|
Assert.AreEqual("1\\;\r\n 2", line.Tags["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsOverlap()
|
public void TagsOverlap()
|
||||||
{
|
{
|
||||||
var line = new Line(@"@id=1\\\s\\s PRIVMSG #channel");
|
var line = new Line(@"@id=1\\\s\\s PRIVMSG #channel");
|
||||||
Assert.AreEqual("1\\ \\s", line.Tags["id"]);
|
Assert.AreEqual("1\\ \\s", line.Tags["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestTagsLoneEndSlash()
|
public void TagsLoneEndSlash()
|
||||||
{
|
{
|
||||||
var line = new Line("@id=1\\ PRIVMSG #channel");
|
var line = new Line("@id=1\\ PRIVMSG #channel");
|
||||||
Assert.AreEqual("1", line.Tags["id"]);
|
Assert.AreEqual("1", line.Tags["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSourceWithoutTags()
|
public void SourceWithoutTags()
|
||||||
{
|
{
|
||||||
var line = new Line(":nick!user@host PRIVMSG #channel");
|
var line = new Line(":nick!user@host PRIVMSG #channel");
|
||||||
Assert.AreEqual("nick!user@host", line.Source);
|
Assert.AreEqual("nick!user@host", line.Source);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSourceWithTags()
|
public void SourceWithTags()
|
||||||
{
|
{
|
||||||
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel");
|
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel");
|
||||||
Assert.AreEqual("nick!user@host", line.Source);
|
Assert.AreEqual("nick!user@host", line.Source);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSourceMissingWithoutTags()
|
public void SourceMissingWithoutTags()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel");
|
var line = new Line("PRIVMSG #channel");
|
||||||
Assert.IsNull(line.Source);
|
Assert.IsNull(line.Source);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSourceMissingWithTags()
|
public void SourceMissingWithTags()
|
||||||
{
|
{
|
||||||
var line = new Line("@id=123 PRIVMSG #channel");
|
var line = new Line("@id=123 PRIVMSG #channel");
|
||||||
Assert.IsNull(line.Source);
|
Assert.IsNull(line.Source);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestCommand()
|
public void Command()
|
||||||
{
|
{
|
||||||
var line = new Line("privmsg #channel");
|
var line = new Line("privmsg #channel");
|
||||||
Assert.AreEqual("PRIVMSG", line.Command);
|
Assert.AreEqual("PRIVMSG", line.Command);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestParamsTrailing()
|
public void ParamsTrailing()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG #channel :hello world");
|
var line = new Line("PRIVMSG #channel :hello world");
|
||||||
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
|
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestParamsOnlyTrailing()
|
public void ParamsOnlyTrailing()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG :hello world");
|
var line = new Line("PRIVMSG :hello world");
|
||||||
CollectionAssert.AreEqual(new List<string> {"hello world"}, line.Params);
|
CollectionAssert.AreEqual(new List<string> {"hello world"}, line.Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestParamsMissing()
|
public void ParamsMissing()
|
||||||
{
|
{
|
||||||
var line = new Line("PRIVMSG");
|
var line = new Line("PRIVMSG");
|
||||||
Assert.AreEqual("PRIVMSG", line.Command);
|
Assert.AreEqual("PRIVMSG", line.Command);
|
||||||
|
@ -106,7 +108,7 @@ namespace IRCTokens.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestAllTokens()
|
public void AllTokens()
|
||||||
{
|
{
|
||||||
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world");
|
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world");
|
||||||
CollectionAssert.AreEqual(new Dictionary<string, string> {{"id", "123"}}, line.Tags);
|
CollectionAssert.AreEqual(new Dictionary<string, string> {{"id", "123"}}, line.Tags);
|
||||||
|
@ -114,5 +116,18 @@ namespace IRCTokens.Tests
|
||||||
Assert.AreEqual("PRIVMSG", line.Command);
|
Assert.AreEqual("PRIVMSG", line.Command);
|
||||||
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
|
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NulByte()
|
||||||
|
{
|
||||||
|
var decoder = new IRCTokens.StatefulDecoder();
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(":nick!user@host PRIVMSG #channel :hello")
|
||||||
|
.Concat(Encoding.UTF8.GetBytes("\0"))
|
||||||
|
.Concat(Encoding.UTF8.GetBytes("world"))
|
||||||
|
.ToArray();
|
||||||
|
var line = decoder.Push(bytes, bytes.Length).First();
|
||||||
|
|
||||||
|
CollectionAssert.AreEqual(new List<string> {"#channel", "hello"}, line.Params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue