diff options
author | Ben Harris <ben@tilde.team> | 2020-05-14 23:06:10 -0400 |
---|---|---|
committer | Ben Harris <ben@tilde.team> | 2020-05-14 23:17:47 -0400 |
commit | 21f1e95fb8e935134a969bc3d729964d8d2aadfa (patch) | |
tree | db2be27e9b5ac48e19f92b56cbad68ab59f7099e /IrcTokens/Line.cs | |
parent | 304df7805b9925c2edd992fd4177eef80197f807 (diff) |
rename Irc to IRC
Diffstat (limited to 'IrcTokens/Line.cs')
-rw-r--r-- | IrcTokens/Line.cs | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/IrcTokens/Line.cs b/IrcTokens/Line.cs deleted file mode 100644 index 36899bf..0000000 --- a/IrcTokens/Line.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace IrcTokens -{ - /// <summary> - /// Tools to represent, parse, and format IRC lines - /// </summary> - public class Line : IEquatable<Line> - { - private static readonly string[] TagUnescaped = {"\\", " ", ";", "\r", "\n"}; - - private static readonly string[] TagEscaped = {"\\\\", "\\s", "\\:", "\\r", "\\n"}; - - private Hostmask _hostmask; - - public Line() - { - } - - public Line(string command, params string[] parameters) - { - Command = command; - Params = parameters.ToList(); - } - - /// <summary> - /// Build new <see cref="Line" /> object parsed from - /// <param name="line">a string</param> - /// . Analogous to irctokens.tokenise() - /// </summary> - /// <param name="line">irc line to parse</param> - public Line(string line) - { - if (string.IsNullOrWhiteSpace(line)) throw new ArgumentNullException(nameof(line)); - - string[] split; - - if (line.StartsWith('@')) - { - Tags = new Dictionary<string, string>(); - - split = line.Split(" ", 2); - var messageTags = split[0]; - line = split[1]; - - foreach (var part in messageTags.Substring(1).Split(';')) - if (part.Contains('=', StringComparison.Ordinal)) - { - split = part.Split('=', 2); - Tags[split[0]] = UnescapeTag(split[1]); - } - else - { - Tags[part] = string.Empty; - } - } - - string trailing; - if (line.Contains(" :", StringComparison.Ordinal)) - { - split = line.Split(" :", 2); - line = split[0]; - trailing = split[1]; - } - else - { - trailing = null; - } - - Params = line.Contains(' ', StringComparison.Ordinal) - ? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList() - : new List<string> {line}; - - if (Params[0].StartsWith(':')) - { - Source = Params[0].Substring(1); - Params.RemoveAt(0); - } - - if (Params.Count > 0) - { - Command = Params[0].ToUpper(CultureInfo.InvariantCulture); - Params.RemoveAt(0); - } - - if (trailing != null) Params.Add(trailing); - } - - public Dictionary<string, string> Tags { get; set; } - public string Source { get; set; } - public string Command { get; set; } - public List<string> Params { get; set; } - - public Hostmask Hostmask => - _hostmask ??= new Hostmask(Source); - - public bool Equals(Line other) - { - if (other == null) return false; - - return Format() == other.Format(); - } - - /// <summary> - /// Unescape ircv3 tag - /// </summary> - /// <param name="val">escaped string</param> - /// <returns>unescaped string</returns> - private static string UnescapeTag(string val) - { - var unescaped = new StringBuilder(); - - var graphemeIterator = StringInfo.GetTextElementEnumerator(val); - graphemeIterator.Reset(); - - while (graphemeIterator.MoveNext()) - { - var current = graphemeIterator.GetTextElement(); - - if (current == @"\") - try - { - graphemeIterator.MoveNext(); - var next = graphemeIterator.GetTextElement(); - var pair = current + next; - unescaped.Append(TagEscaped.Contains(pair) - ? TagUnescaped[Array.IndexOf(TagEscaped, pair)] - : next); - } - catch (InvalidOperationException) - { - // ignored - } - else - unescaped.Append(current); - } - - return unescaped.ToString(); - } - - /// <summary> - /// Escape strings for use in ircv3 tags - /// </summary> - /// <param name="val">string to escape</param> - /// <returns>escaped string</returns> - private static string EscapeTag(string val) - { - for (var i = 0; i < TagUnescaped.Length; ++i) - val = val?.Replace(TagUnescaped[i], TagEscaped[i], StringComparison.Ordinal); - - return val; - } - - public override string ToString() - { - var vars = new List<string>(); - - if (Command != null) vars.Add($"command={Command}"); - - if (Source != null) vars.Add($"source={Source}"); - - if (Params != null && Params.Any()) vars.Add($"params=[{string.Join(",", Params)}]"); - - if (Tags != null && Tags.Any()) - vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]"); - - return $"Line({string.Join(", ", vars)})"; - } - - public override int GetHashCode() - { - return Format().GetHashCode(StringComparison.Ordinal); - } - - public override bool Equals(object obj) - { - return Equals(obj as Line); - } - - /// <summary> - /// Format a <see cref="Line" /> as a standards-compliant IRC line - /// </summary> - /// <returns>formatted irc line</returns> - public string Format() - { - var outs = new List<string>(); - - if (Tags != null && Tags.Any()) - { - var tags = Tags.Keys - .OrderBy(k => k) - .Select(key => - string.IsNullOrWhiteSpace(Tags[key]) ? key : $"{key}={EscapeTag(Tags[key])}") - .ToList(); - - outs.Add($"@{string.Join(";", tags)}"); - } - - if (Source != null) outs.Add($":{Source}"); - - outs.Add(Command); - - if (Params != null && Params.Any()) - { - var last = Params[^1]; - var withoutLast = Params.SkipLast(1).ToList(); - - foreach (var p in withoutLast) - { - if (p.Contains(' ', StringComparison.Ordinal)) - throw new ArgumentException(@"non-last parameters cannot have spaces", p); - - if (p.StartsWith(':')) - throw new ArgumentException(@"non-last parameters cannot start with colon", p); - } - - outs.AddRange(withoutLast); - - if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || - last.StartsWith(':')) - last = $":{last}"; - - outs.Add(last); - } - - return string.Join(" ", outs); - } - } -} |