126 lines
4.5 KiB
C#
126 lines
4.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace ChatSharp
|
|
{
|
|
/// <summary>
|
|
/// Represents a raw IRC message. This is a low-level construct - PrivateMessage is used
|
|
/// to represent messages sent from users.
|
|
/// </summary>
|
|
public class IrcMessage
|
|
{
|
|
/// <summary>
|
|
/// The unparsed message.
|
|
/// </summary>
|
|
public string RawMessage { get; private set; }
|
|
/// <summary>
|
|
/// The message prefix.
|
|
/// </summary>
|
|
public string Prefix { get; private set; }
|
|
/// <summary>
|
|
/// The message command.
|
|
/// </summary>
|
|
public string Command { get; private set; }
|
|
/// <summary>
|
|
/// Additional parameters supplied with the message.
|
|
/// </summary>
|
|
public string[] Parameters { get; private set; }
|
|
/// <summary>
|
|
/// The message tags.
|
|
/// </summary>
|
|
public KeyValuePair<string, string>[] Tags { get; private set; }
|
|
/// <summary>
|
|
/// The message timestamp in ISO 8601 format.
|
|
/// </summary>
|
|
public Timestamp Timestamp { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Initializes and decodes an IRC message, given the raw message from the server.
|
|
/// </summary>
|
|
public IrcMessage(string rawMessage)
|
|
{
|
|
RawMessage = rawMessage;
|
|
Tags = System.Array.Empty<KeyValuePair<string, string>>();
|
|
|
|
if (rawMessage.StartsWith("@"))
|
|
{
|
|
var rawTags = rawMessage[1..rawMessage.IndexOf(' ')];
|
|
rawMessage = rawMessage[(rawMessage.IndexOf(' ') + 1)..];
|
|
|
|
// Parse tags as key value pairs
|
|
var tags = new List<KeyValuePair<string, string>>();
|
|
foreach (string rawTag in rawTags.Split(';'))
|
|
{
|
|
var replacedTag = rawTag.Replace(@"\:", ";");
|
|
// The spec declares `@a=` as a tag with an empty value, while `@b;` as a tag with a null value
|
|
KeyValuePair<string, string> tag = new(replacedTag, null);
|
|
|
|
if (replacedTag.Contains("="))
|
|
{
|
|
string key = replacedTag.Substring(0, replacedTag.IndexOf("="));
|
|
string value = replacedTag[(replacedTag.IndexOf("=") + 1)..];
|
|
tag = new KeyValuePair<string, string>(key, value);
|
|
}
|
|
|
|
tags.Add(tag);
|
|
}
|
|
|
|
Tags = tags.ToArray();
|
|
}
|
|
|
|
if (rawMessage.StartsWith(":"))
|
|
{
|
|
Prefix = rawMessage[1..rawMessage.IndexOf(' ')];
|
|
rawMessage = rawMessage[(rawMessage.IndexOf(' ') + 1)..];
|
|
}
|
|
|
|
if (rawMessage.Contains(' '))
|
|
{
|
|
Command = rawMessage.Remove(rawMessage.IndexOf(' '));
|
|
rawMessage = rawMessage[(rawMessage.IndexOf(' ') + 1)..];
|
|
// Parse parameters
|
|
var parameters = new List<string>();
|
|
while (!string.IsNullOrEmpty(rawMessage))
|
|
{
|
|
if (rawMessage.StartsWith(":"))
|
|
{
|
|
parameters.Add(rawMessage[1..]);
|
|
break;
|
|
}
|
|
if (!rawMessage.Contains(' '))
|
|
{
|
|
parameters.Add(rawMessage);
|
|
rawMessage = string.Empty;
|
|
break;
|
|
}
|
|
parameters.Add(rawMessage.Remove(rawMessage.IndexOf(' ')));
|
|
rawMessage = rawMessage[(rawMessage.IndexOf(' ') + 1)..];
|
|
}
|
|
Parameters = parameters.ToArray();
|
|
}
|
|
else
|
|
{
|
|
// Violates RFC 1459, but we'll parse it anyway
|
|
Command = rawMessage;
|
|
Parameters = System.Array.Empty<string>();
|
|
}
|
|
|
|
// Parse server-time message tag.
|
|
// Fallback to server-info if both znc.in/server-info and the former exists.
|
|
//
|
|
// znc.in/server-time tag
|
|
if (Tags.Any(tag => tag.Key == "t"))
|
|
{
|
|
var tag = Tags.SingleOrDefault(x => x.Key == "t");
|
|
Timestamp = new Timestamp(tag.Value, true);
|
|
}
|
|
// server-time tag
|
|
else if (Tags.Any(tag => tag.Key == "time"))
|
|
{
|
|
var tag = Tags.SingleOrDefault(x => x.Key == "time");
|
|
Timestamp = new Timestamp(tag.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|