From 616abc70303990fbf8096fc6ada5fac100a6c66a Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sun, 19 Apr 2020 20:52:41 -0400 Subject: init --- IrcTokens/Line.cs | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 IrcTokens/Line.cs (limited to 'IrcTokens/Line.cs') diff --git a/IrcTokens/Line.cs b/IrcTokens/Line.cs new file mode 100644 index 0000000..7592376 --- /dev/null +++ b/IrcTokens/Line.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IrcTokens +{ + /// + /// Tools to represent, parse, and format IRC lines + /// + public class Line + { + public Dictionary Tags { get; set; } + public string Source { get; set; } + public string Command { get; set; } + public List Params { get; set; } + + private Hostmask _hostmask; + private string _rawLine; + + public override string ToString() => + $"Line(tags={string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}, params={string.Join(",", Params)})"; + + public Hostmask Hostmask => + _hostmask ??= new Hostmask(Source); + + public Line() { } + + /// + /// Build new object parsed from a string. Analogous to irctokens.tokenise() + /// + /// irc line to parse + public Line(string line) + { + _rawLine = line; + string[] split; + + if (line.StartsWith('@')) + { + Tags = new Dictionary(); + + split = line.Split(" "); + var messageTags = split[0]; + line = string.Join(" ", split.Skip(1)); + + foreach (var part in messageTags.Substring(1).Split(';')) + { + if (part.Contains('=')) + { + split = part.Split('='); + Tags[split[0]] = Protocol.UnescapeTag(split[1]); + } + else + { + Tags[part] = string.Empty; + } + } + } + + string trailing; + if (line.Contains(" :")) + { + split = line.Split(" :"); + line = split[0]; + trailing = string.Join(" :", split.Skip(1)); + } + else + { + trailing = null; + } + + Params = line.Contains(' ') + ? line.Split(' ').Where(p => !string.IsNullOrWhiteSpace(p)).ToList() + : new List {line}; + + if (Params[0].StartsWith(':')) + { + Source = Params[0].Substring(1); + Params.RemoveAt(0); + } + + if (Params.Count > 0) + { + Command = Params[0].ToUpper(); + Params.RemoveAt(0); + } + + if (trailing != null) + { + Params.Add(trailing); + } + } + + /// + /// Format a as a standards-compliant IRC line + /// + /// formatted irc line + public string Format() + { + var outs = new List(); + + if (Tags != null && Tags.Any()) + { + var tags = Tags.Keys + .Select(key => string.IsNullOrWhiteSpace(Tags[key]) ? key : $"{key}={Protocol.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]; + Params.RemoveAt(Params.Count - 1); + + foreach (var p in Params) + { + if (p.Contains(' ')) + throw new ArgumentException("non-last parameters cannot have spaces"); + if (p.StartsWith(':')) + throw new ArgumentException("non-last parameters cannot start with colon"); + } + outs.AddRange(Params); + + if (last == null || string.IsNullOrWhiteSpace(last) || last.Contains(' ') || last.StartsWith(':')) + last = $":{last}"; + outs.Add(last); + } + + return string.Join(" ", outs); + } + } +} -- cgit 1.4.1