.net 6, tidy up some warnings
This commit is contained in:
parent
d83294c7bc
commit
b82b8c259a
|
@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatSharp", "ChatSharp\Chat
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatSharp.Tests", "ChatSharpTests\ChatSharp.Tests.csproj", "{24D593EC-CA81-41DC-9FE7-A434DDDE229D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{9F4A4C6C-8C21-471C-96FC-A932EF12002A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -29,6 +31,14 @@ Global
|
|||
{24D593EC-CA81-41DC-9FE7-A434DDDE229D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{24D593EC-CA81-41DC-9FE7-A434DDDE229D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{24D593EC-CA81-41DC-9FE7-A434DDDE229D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9F4A4C6C-8C21-471C-96FC-A932EF12002A}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of capabilities supported by the library, along with the enabled and disabled
|
||||
/// capabilities after negotiating with the server.
|
||||
/// A list of capabilities supported by the library, along with the enabled and disabled
|
||||
/// capabilities after negotiating with the server.
|
||||
/// </summary>
|
||||
public class CapabilityPool : IEnumerable<IrcCapability>
|
||||
{
|
||||
private List<IrcCapability> Capabilities { get; set; }
|
||||
|
||||
internal CapabilityPool()
|
||||
{
|
||||
Capabilities = new List<IrcCapability>();
|
||||
Capabilities = new();
|
||||
}
|
||||
|
||||
private List<IrcCapability> Capabilities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IrcCapability with the specified name.
|
||||
/// Gets the IrcCapability with the specified name.
|
||||
/// </summary>
|
||||
public IrcCapability this[string name]
|
||||
{
|
||||
|
@ -30,17 +31,48 @@ namespace ChatSharp
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of enabled capabilities after negotiating capabilities with the server.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<string> Enabled
|
||||
{
|
||||
get { return Capabilities.Where(cap => cap.IsEnabled).Select(x => x.Name); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of disabled capabilities after negotiating capabilities with the server.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<string> Disabled
|
||||
{
|
||||
get { return Capabilities.Where(cap => cap.IsEnabled).Select(x => x.Name); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the capabilities in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcCapability> GetEnumerator()
|
||||
{
|
||||
return Capabilities.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal void Add(string name)
|
||||
{
|
||||
if (Capabilities.Any(cap => cap.Name == name))
|
||||
return;
|
||||
|
||||
Capabilities.Add(new IrcCapability(name));
|
||||
Capabilities.Add(new(name));
|
||||
}
|
||||
|
||||
internal void AddRange(IEnumerable<string> range)
|
||||
{
|
||||
foreach (string item in range)
|
||||
foreach (var item in range)
|
||||
Add(item);
|
||||
}
|
||||
|
||||
|
@ -50,7 +82,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the specified capability.
|
||||
/// Enables the specified capability.
|
||||
/// </summary>
|
||||
internal void Enable(string name)
|
||||
{
|
||||
|
@ -61,7 +93,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the specified capability.
|
||||
/// Disables the specified capability.
|
||||
/// </summary>
|
||||
internal void Disable(string name)
|
||||
{
|
||||
|
@ -72,37 +104,13 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified capability is enabled.
|
||||
/// Checks if the specified capability is enabled.
|
||||
/// </summary>
|
||||
internal bool IsEnabled(string name)
|
||||
{
|
||||
return Capabilities.Any(cap => cap.Name == name && cap.IsEnabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of enabled capabilities after negotiating capabilities with the server.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<string> Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return Capabilities.Where(cap => cap.IsEnabled).Select(x => x.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of disabled capabilities after negotiating capabilities with the server.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<string> Disabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return Capabilities.Where(cap => cap.IsEnabled).Select(x => x.Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool Contains(string name)
|
||||
{
|
||||
return Capabilities.Any(cap => cap.Name == name);
|
||||
|
@ -123,18 +131,5 @@ namespace ChatSharp
|
|||
Add(name);
|
||||
return this[name];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the capabilities in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcCapability> GetEnumerator()
|
||||
{
|
||||
return Capabilities.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,13 +6,13 @@ using System.Linq;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of IRC channels a user is present in.
|
||||
/// A collection of IRC channels a user is present in.
|
||||
/// </summary>
|
||||
public class ChannelCollection : IEnumerable<IrcChannel>
|
||||
{
|
||||
internal ChannelCollection()
|
||||
{
|
||||
Channels = new List<IrcChannel>();
|
||||
Channels = new();
|
||||
}
|
||||
|
||||
internal ChannelCollection(IrcClient client) : this()
|
||||
|
@ -20,8 +20,44 @@ namespace ChatSharp
|
|||
Client = client;
|
||||
}
|
||||
|
||||
private IrcClient Client { get; set; }
|
||||
private List<IrcChannel> Channels { get; set; }
|
||||
private IrcClient Client { get; }
|
||||
private List<IrcChannel> Channels { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel at the given index.
|
||||
/// </summary>
|
||||
public IrcChannel this[int index] => Channels[index];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel by the given channel name, including channel prefix (i.e. '#')
|
||||
/// </summary>
|
||||
public IrcChannel this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
var channel =
|
||||
Channels.FirstOrDefault(c => string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (channel == null)
|
||||
throw new KeyNotFoundException();
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an for the channels in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcChannel> GetEnumerator()
|
||||
{
|
||||
return Channels.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an for the channels in this collection.
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal void Add(IrcChannel channel)
|
||||
{
|
||||
|
@ -36,7 +72,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join the specified channel. Only applicable for your own user.
|
||||
/// Join the specified channel. Only applicable for your own user.
|
||||
/// </summary>
|
||||
public void Join(string name)
|
||||
{
|
||||
|
@ -47,61 +83,20 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the channel by the given name, including channel prefix (i.e. '#'), is in this collection.
|
||||
/// Returns true if the channel by the given name, including channel prefix (i.e. '#'), is in this collection.
|
||||
/// </summary>
|
||||
public bool Contains(string name)
|
||||
{
|
||||
return Channels.Any(c => c.Name == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel at the given index.
|
||||
/// </summary>
|
||||
public IrcChannel this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Channels[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel by the given channel name, including channel prefix (i.e. '#')
|
||||
/// </summary>
|
||||
public IrcChannel this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
var channel = Channels.FirstOrDefault(c => string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (channel == null)
|
||||
throw new KeyNotFoundException();
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
internal IrcChannel GetOrAdd(string name)
|
||||
{
|
||||
if (this.Contains(name))
|
||||
if (Contains(name))
|
||||
return this[name];
|
||||
var channel = new IrcChannel(Client, name);
|
||||
this.Add(channel);
|
||||
Add(channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an for the channels in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcChannel> GetEnumerator()
|
||||
{
|
||||
return Channels.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an for the channels in this collection.
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net5.0</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://tildegit.org/ben/chatsharp</RepositoryUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageProjectUrl>https://tildegit.org/ben/chatsharp</PackageProjectUrl>
|
||||
<Description>c# irc library</Description>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://tildegit.org/ben/chatsharp</RepositoryUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageProjectUrl>https://tildegit.org/ben/chatsharp</PackageProjectUrl>
|
||||
<Description>c# irc library</Description>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,8 +1,8 @@
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Customize the behavior of the ChatSharp client, including enabling or disabling
|
||||
/// "helper" features.
|
||||
/// Customize the behavior of the ChatSharp client, including enabling or disabling
|
||||
/// "helper" features.
|
||||
/// </summary>
|
||||
public class ClientSettings
|
||||
{
|
||||
|
@ -16,29 +16,33 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// If true, the client will WHOIS itself upon joining, which will populate the hostname in
|
||||
/// IrcClient.User. This will allow you, for example, to use IrcUser.Match(...) on yourself
|
||||
/// to see if you match any masks.
|
||||
/// If true, the client will WHOIS itself upon joining, which will populate the hostname in
|
||||
/// IrcClient.User. This will allow you, for example, to use IrcUser.Match(...) on yourself
|
||||
/// to see if you match any masks.
|
||||
/// </summary>
|
||||
public bool WhoIsOnConnect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the client will MODE any channel it joins, populating IrcChannel.Mode. If false,
|
||||
/// IrcChannel.Mode will be null until the mode is explicitly requested.
|
||||
/// If true, the client will MODE any channel it joins, populating IrcChannel.Mode. If false,
|
||||
/// IrcChannel.Mode will be null until the mode is explicitly requested.
|
||||
/// </summary>
|
||||
public bool ModeOnJoin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the library will generate a random nick with alphanumerical characters if it
|
||||
/// encounters a NICK error.
|
||||
/// If true, the library will generate a random nick with alphanumerical characters if it
|
||||
/// encounters a NICK error.
|
||||
/// </summary>
|
||||
public bool GenerateRandomNickIfRefused { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the library will WHOIS everyone in a channel upon joining. This procedure can
|
||||
/// take several minutes on larger channels.
|
||||
/// If true, the library will WHOIS everyone in a channel upon joining. This procedure can
|
||||
/// take several minutes on larger channels.
|
||||
/// </summary>
|
||||
public bool WhoIsOnJoin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The delay, in seconds, between each WHOIS when WhoIsOnJoin is true.
|
||||
/// The delay, in seconds, between each WHOIS when WhoIsOnJoin is true.
|
||||
/// </summary>
|
||||
public int JoinWhoIsDelay { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,18 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic event args for events regarding channels.
|
||||
/// Generic event args for events regarding channels.
|
||||
/// </summary>
|
||||
public class ChannelEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel this event regards.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
|
||||
internal ChannelEventArgs(IrcChannel channel)
|
||||
{
|
||||
Channel = channel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The channel this event regards.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,28 +3,30 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Details of a channel topic event.
|
||||
/// Details of a channel topic event.
|
||||
/// </summary>
|
||||
public class ChannelTopicEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel whose topic has changed.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
/// <summary>
|
||||
/// The new topic
|
||||
/// </summary>
|
||||
public string Topic { get; set; }
|
||||
/// <summary>
|
||||
/// The original topic.
|
||||
/// </summary>
|
||||
public string OldTopic { get; set; }
|
||||
|
||||
internal ChannelTopicEventArgs(IrcChannel channel, string oldTopic, string topic)
|
||||
{
|
||||
Channel = channel;
|
||||
Topic = topic;
|
||||
OldTopic = oldTopic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The channel whose topic has changed.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new topic
|
||||
/// </summary>
|
||||
public string Topic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original topic.
|
||||
/// </summary>
|
||||
public string OldTopic { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,23 +3,24 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic event args for events regarding users in channels.
|
||||
/// Generic event args for events regarding users in channels.
|
||||
/// </summary>
|
||||
public class ChannelUserEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel this event regards.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
/// <summary>
|
||||
/// The user this event regards.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
internal ChannelUserEventArgs(IrcChannel channel, IrcUser user)
|
||||
{
|
||||
Channel = channel;
|
||||
User = user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The channel this event regards.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user this event regards.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,43 +3,45 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes an invalid nick event.
|
||||
/// Describes an invalid nick event.
|
||||
/// </summary>
|
||||
public class ErronousNickEventArgs : EventArgs
|
||||
public class ErroneousNickEventArgs : EventArgs
|
||||
{
|
||||
private static Random random;
|
||||
private static string GenerateRandomNick()
|
||||
{
|
||||
const string nickCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static Random _random;
|
||||
|
||||
if (random == null)
|
||||
random = new Random();
|
||||
var nick = new char[8];
|
||||
for (int i = 0; i < nick.Length; i++)
|
||||
nick[i] = nickCharacters[random.Next(nickCharacters.Length)];
|
||||
return new string(nick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The nick that was not accepted by the server.
|
||||
/// </summary>
|
||||
/// <value>The invalid nick.</value>
|
||||
public string InvalidNick { get; set; }
|
||||
/// <summary>
|
||||
/// The nick ChatSharp intends to use instead.
|
||||
/// </summary>
|
||||
/// <value>The new nick.</value>
|
||||
public string NewNick { get; set; }
|
||||
/// <summary>
|
||||
/// Set to true to instruct ChatSharp NOT to send a valid nick.
|
||||
/// </summary>
|
||||
public bool DoNotHandle { get; set; }
|
||||
|
||||
internal ErronousNickEventArgs(string invalidNick)
|
||||
internal ErroneousNickEventArgs(string invalidNick)
|
||||
{
|
||||
InvalidNick = invalidNick;
|
||||
NewNick = GenerateRandomNick();
|
||||
DoNotHandle = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The nick that was not accepted by the server.
|
||||
/// </summary>
|
||||
/// <value>The invalid nick.</value>
|
||||
public string InvalidNick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The nick ChatSharp intends to use instead.
|
||||
/// </summary>
|
||||
/// <value>The new nick.</value>
|
||||
public string NewNick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to instruct ChatSharp NOT to send a valid nick.
|
||||
/// </summary>
|
||||
public bool DoNotHandle { get; set; }
|
||||
|
||||
private static string GenerateRandomNick()
|
||||
{
|
||||
const string nickCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
_random ??= new();
|
||||
var nick = new char[8];
|
||||
for (var i = 0; i < nick.Length; i++)
|
||||
nick[i] = nickCharacters[_random.Next(nickCharacters.Length)];
|
||||
return new(nick);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,18 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a Error occurs.
|
||||
/// Raised when a Error occurs.
|
||||
/// </summary>
|
||||
public class ErrorEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The error that has occured.
|
||||
/// </summary>
|
||||
public Exception Error { get; set; }
|
||||
|
||||
internal ErrorEventArgs(Exception error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error that has occured.
|
||||
/// </summary>
|
||||
public Exception Error { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,18 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a IRC Error reply occurs. See rfc1459 6.1 for details.
|
||||
/// Raised when a IRC Error reply occurs. See rfc1459 6.1 for details.
|
||||
/// </summary>
|
||||
public class ErrorReplyEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRC error reply that has occured.
|
||||
/// </summary>
|
||||
public IrcMessage Message { get; set; }
|
||||
|
||||
internal ErrorReplyEventArgs(IrcMessage message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The IRC error reply that has occured.
|
||||
/// </summary>
|
||||
public IrcMessage Message { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,30 +3,32 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event describing an IRC notice.
|
||||
/// Event describing an IRC notice.
|
||||
/// </summary>
|
||||
public class IrcNoticeEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRC message that describes this NOTICE.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
public IrcMessage Message { get; set; }
|
||||
/// <summary>
|
||||
/// The text of the notice.
|
||||
/// </summary>
|
||||
public string Notice { get { return Message.Parameters[1]; } }
|
||||
/// <summary>
|
||||
/// The source of the notice (often a user).
|
||||
/// </summary>
|
||||
/// <value>The source.</value>
|
||||
public string Source { get { return Message.Prefix; } }
|
||||
|
||||
internal IrcNoticeEventArgs(IrcMessage message)
|
||||
{
|
||||
if (message.Parameters.Length != 2)
|
||||
throw new IrcProtocolException("NOTICE was delivered in incorrect format");
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The IRC message that describes this NOTICE.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
public IrcMessage Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The text of the notice.
|
||||
/// </summary>
|
||||
public string Notice => Message.Parameters[1];
|
||||
|
||||
/// <summary>
|
||||
/// The source of the notice (often a user).
|
||||
/// </summary>
|
||||
/// <value>The source.</value>
|
||||
public string Source => Message.Prefix;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace ChatSharp
|
||||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a user (possibly yourself) is kicked from a channel.
|
||||
/// Raised when a user (possibly yourself) is kicked from a channel.
|
||||
/// </summary>
|
||||
public class KickEventArgs : EventArgs
|
||||
{
|
||||
|
@ -16,21 +16,23 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The channel the user was kicked from.
|
||||
/// The channel the user was kicked from.
|
||||
/// </summary>
|
||||
public IrcChannel Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user who issued the kick.
|
||||
/// The user who issued the kick.
|
||||
/// </summary>
|
||||
public IrcUser Kicker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that was kicked.
|
||||
/// The user that was kicked.
|
||||
/// </summary>
|
||||
public IrcUser Kicked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The reason provided for the kick (may be null).
|
||||
/// The reason provided for the kick (may be null).
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,29 +3,31 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a change to a channel or user mode.
|
||||
/// Describes a change to a channel or user mode.
|
||||
/// </summary>
|
||||
public class ModeChangeEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The target of this change (a channel or user).
|
||||
/// </summary>
|
||||
/// <value>The target.</value>
|
||||
public string Target { get; set; }
|
||||
/// <summary>
|
||||
/// The user who issued the change.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
/// <summary>
|
||||
/// The mode change string.
|
||||
/// </summary>
|
||||
public string Change { get; set; }
|
||||
|
||||
internal ModeChangeEventArgs(string target, IrcUser user, string change)
|
||||
{
|
||||
Target = target;
|
||||
User = user;
|
||||
Change = change;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The target of this change (a channel or user).
|
||||
/// </summary>
|
||||
/// <value>The target.</value>
|
||||
public string Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user who issued the change.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The mode change string.
|
||||
/// </summary>
|
||||
public string Change { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,20 +3,22 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a user has changed their nick.
|
||||
/// Raised when a user has changed their nick.
|
||||
/// </summary>
|
||||
public class NickChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The user whose nick changed.
|
||||
/// The user whose nick changed.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original nick.
|
||||
/// The original nick.
|
||||
/// </summary>
|
||||
public string OldNick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new nick.
|
||||
/// The new nick.
|
||||
/// </summary>
|
||||
public string NewNick { get; set; }
|
||||
}
|
||||
|
|
|
@ -3,25 +3,26 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a private message we have received.
|
||||
/// The term "private message" is misleading - this describes both messages sent user-to-user,
|
||||
/// and messages sent to a channel.
|
||||
/// Describes a private message we have received.
|
||||
/// The term "private message" is misleading - this describes both messages sent user-to-user,
|
||||
/// and messages sent to a channel.
|
||||
/// </summary>
|
||||
public class PrivateMessageEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRC message received.
|
||||
/// </summary>
|
||||
public IrcMessage IrcMessage { get; set; }
|
||||
/// <summary>
|
||||
/// The private message received.
|
||||
/// </summary>
|
||||
public PrivateMessage PrivateMessage { get; set; }
|
||||
|
||||
internal PrivateMessageEventArgs(IrcClient client, IrcMessage ircMessage, ServerInfo serverInfo)
|
||||
{
|
||||
IrcMessage = ircMessage;
|
||||
PrivateMessage = new PrivateMessage(client, IrcMessage, serverInfo);
|
||||
PrivateMessage = new(client, IrcMessage, serverInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The IRC message received.
|
||||
/// </summary>
|
||||
public IrcMessage IrcMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The private message received.
|
||||
/// </summary>
|
||||
public PrivateMessage PrivateMessage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,23 +3,24 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a raw IRC message we have sent or received.
|
||||
/// Describes a raw IRC message we have sent or received.
|
||||
/// </summary>
|
||||
public class RawMessageEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The text of the raw IRC message.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
/// <summary>
|
||||
/// True if this message is going from ChatSharp to the server.
|
||||
/// </summary>
|
||||
public bool Outgoing { get; set; }
|
||||
|
||||
internal RawMessageEventArgs(string message, bool outgoing)
|
||||
{
|
||||
Message = message;
|
||||
Outgoing = outgoing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The text of the raw IRC message.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this message is going from ChatSharp to the server.
|
||||
/// </summary>
|
||||
public bool Outgoing { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,18 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when we have received the MOTD from the server.
|
||||
/// Raised when we have received the MOTD from the server.
|
||||
/// </summary>
|
||||
public class ServerMOTDEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The message of the day.
|
||||
/// </summary>
|
||||
public string MOTD { get; set; }
|
||||
|
||||
internal ServerMOTDEventArgs(string motd)
|
||||
{
|
||||
MOTD = motd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The message of the day.
|
||||
/// </summary>
|
||||
public string MOTD { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,18 +4,18 @@ using System.Net.Sockets;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a SocketError occurs.
|
||||
/// Raised when a SocketError occurs.
|
||||
/// </summary>
|
||||
public class SocketErrorEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The error that has occured.
|
||||
/// </summary>
|
||||
public SocketError SocketError { get; set; }
|
||||
|
||||
internal SocketErrorEventArgs(SocketError socketError)
|
||||
{
|
||||
SocketError = socketError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error that has occured.
|
||||
/// </summary>
|
||||
public SocketError SocketError { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,18 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the features the server supports.
|
||||
/// Describes the features the server supports.
|
||||
/// </summary>
|
||||
public class SupportsEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The server's supported featureset.
|
||||
/// </summary>
|
||||
public ServerInfo ServerInfo { get; set; }
|
||||
|
||||
internal SupportsEventArgs(ServerInfo serverInfo)
|
||||
{
|
||||
ServerInfo = serverInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The server's supported featureset.
|
||||
/// </summary>
|
||||
public ServerInfo ServerInfo { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,18 @@
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic event args that represent an event regarding a user.
|
||||
/// Generic event args that represent an event regarding a user.
|
||||
/// </summary>
|
||||
public class UserEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The user this regards.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
internal UserEventArgs(IrcUser user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user this regards.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
}
|
||||
}
|
|
@ -3,19 +3,19 @@
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the response to a WHO (WHOX protocol) query. Note that ChatSharp may generate WHO
|
||||
/// queries that the user did not ask for.
|
||||
/// Describes the response to a WHO (WHOX protocol) query. Note that ChatSharp may generate WHO
|
||||
/// queries that the user did not ask for.
|
||||
/// </summary>
|
||||
public class WhoxReceivedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The WHOIS response from the server.
|
||||
/// </summary>
|
||||
public ExtendedWho[] WhoxResponse { get; set; }
|
||||
|
||||
internal WhoxReceivedEventArgs(ExtendedWho[] whoxResponse)
|
||||
{
|
||||
WhoxResponse = whoxResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The WHOIS response from the server.
|
||||
/// </summary>
|
||||
public ExtendedWho[] WhoxResponse { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,19 @@ using System;
|
|||
namespace ChatSharp.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the response to a WHOIS query. Note that ChatSharp may generate WHOIS
|
||||
/// queries that the consumer did not ask for.
|
||||
/// Describes the response to a WHOIS query. Note that ChatSharp may generate WHOIS
|
||||
/// queries that the consumer did not ask for.
|
||||
/// </summary>
|
||||
public class WhoIsReceivedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The WHOIS response from the server.
|
||||
/// </summary>
|
||||
public WhoIs WhoIsResponse { get; set; }
|
||||
|
||||
internal WhoIsReceivedEventArgs(WhoIs whoIsResponse)
|
||||
{
|
||||
WhoIsResponse = whoIsResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The WHOIS response from the server.
|
||||
/// </summary>
|
||||
public WhoIs WhoIsResponse { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace ChatSharp.Handlers
|
|||
client.IsNegotiatingCapabilities = true;
|
||||
// Parse server capabilities
|
||||
var serverCapsString = message.Parameters[2] == "*" ? message.Parameters[3] : message.Parameters[2];
|
||||
serverCaps.AddRange(serverCapsString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
serverCaps.AddRange(serverCapsString.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
|
||||
// CAP 3.2 multiline support. Send CAP requests on the last CAP LS line.
|
||||
// The last CAP LS line doesn't have * set as Parameters[2]
|
||||
|
@ -30,18 +30,22 @@ namespace ChatSharp.Handlers
|
|||
// Check if we have to request any capability to be enabled.
|
||||
// If not, end the capability negotiation.
|
||||
if (requestedCaps.Count > 0)
|
||||
{
|
||||
client.SendRawMessage("CAP REQ :{0}", string.Join(" ", requestedCaps));
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SendRawMessage("CAP END");
|
||||
client.IsNegotiatingCapabilities = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case "ACK":
|
||||
// Get the accepted capabilities
|
||||
var acceptedCaps = message.Parameters[2].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string acceptedCap in acceptedCaps)
|
||||
var acceptedCaps =
|
||||
message.Parameters[2].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var acceptedCap in acceptedCaps)
|
||||
{
|
||||
client.Capabilities.Enable(acceptedCap);
|
||||
// Begin SASL authentication
|
||||
|
@ -54,7 +58,8 @@ namespace ChatSharp.Handlers
|
|||
|
||||
// Check if the enabled capabilities count is the same as the ones
|
||||
// acknowledged by the server.
|
||||
if (client.IsNegotiatingCapabilities && client.Capabilities.Enabled.Count() == acceptedCaps.Count() && !client.IsAuthenticatingSasl)
|
||||
if (client.IsNegotiatingCapabilities &&
|
||||
client.Capabilities.Enabled.Count() == acceptedCaps.Count() && !client.IsAuthenticatingSasl)
|
||||
{
|
||||
client.SendRawMessage("CAP END");
|
||||
client.IsNegotiatingCapabilities = false;
|
||||
|
@ -63,13 +68,15 @@ namespace ChatSharp.Handlers
|
|||
break;
|
||||
case "NAK":
|
||||
// Get the rejected capabilities
|
||||
var rejectedCaps = message.Parameters[2].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string acceptedCap in rejectedCaps)
|
||||
var rejectedCaps =
|
||||
message.Parameters[2].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var acceptedCap in rejectedCaps)
|
||||
client.Capabilities.Disable(acceptedCap);
|
||||
|
||||
// Check if the disabled capabilities count is the same as the ones
|
||||
// rejected by the server.
|
||||
if (client.IsNegotiatingCapabilities && client.Capabilities.Disabled.Count() == rejectedCaps.Count())
|
||||
if (client.IsNegotiatingCapabilities &&
|
||||
client.Capabilities.Disabled.Count() == rejectedCaps.Count())
|
||||
{
|
||||
client.SendRawMessage("CAP END");
|
||||
client.IsNegotiatingCapabilities = false;
|
||||
|
@ -78,16 +85,14 @@ namespace ChatSharp.Handlers
|
|||
break;
|
||||
case "LIST":
|
||||
var activeCapsString = message.Parameters[2] == "*" ? message.Parameters[3] : message.Parameters[2];
|
||||
var activeCaps = activeCapsString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var activeCaps = activeCapsString.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// Check which cap we have that isn't active but the server lists
|
||||
// as active.
|
||||
foreach (string cap in activeCaps)
|
||||
{
|
||||
foreach (var cap in activeCaps)
|
||||
if (client.Capabilities.Contains(cap))
|
||||
if (!client.Capabilities[cap].IsEnabled)
|
||||
client.Capabilities.Enable(cap);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NEW":
|
||||
|
@ -95,12 +100,14 @@ namespace ChatSharp.Handlers
|
|||
var wantCaps = new List<string>();
|
||||
|
||||
// Check which new capabilities we support and send a REQ for them
|
||||
wantCaps.AddRange(newCaps.Where(cap => client.Capabilities.Contains(cap) && !client.Capabilities[cap].IsEnabled));
|
||||
wantCaps.AddRange(newCaps.Where(cap =>
|
||||
client.Capabilities.Contains(cap) && !client.Capabilities[cap].IsEnabled));
|
||||
|
||||
client.SendRawMessage(string.Format("CAP REQ :{0}", string.Join(" ", wantCaps)));
|
||||
break;
|
||||
case "DEL":
|
||||
var disabledCaps = message.Parameters[2].Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
var disabledCaps = message.Parameters[2].Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToList();
|
||||
|
||||
// Disable each recently server-disabled capability
|
||||
disabledCaps.ForEach(
|
||||
|
@ -111,9 +118,7 @@ namespace ChatSharp.Handlers
|
|||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
using ChatSharp.Events;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
@ -20,13 +19,13 @@ namespace ChatSharp.Handlers
|
|||
|
||||
// account-notify capability
|
||||
if (client.Capabilities.IsEnabled("account-notify"))
|
||||
client.Who(user.Nick, WhoxFlag.None, WhoxField.Nick | WhoxField.AccountName, (whoQuery) =>
|
||||
client.Who(user.Nick, WhoxFlag.None, WhoxField.Nick | WhoxField.AccountName, whoQuery =>
|
||||
{
|
||||
if (whoQuery.Count == 1)
|
||||
user.Account = whoQuery[0].User.Account;
|
||||
});
|
||||
|
||||
client.OnUserJoinedChannel(new ChannelUserEventArgs(channel, user));
|
||||
client.OnUserJoinedChannel(new(channel, user));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +34,7 @@ namespace ChatSharp.Handlers
|
|||
var channel = client.Channels.GetOrAdd(message.Parameters[1]);
|
||||
var old = channel._Topic;
|
||||
channel._Topic = message.Parameters[2];
|
||||
client.OnChannelTopicReceived(new ChannelTopicEventArgs(channel, old, channel._Topic));
|
||||
client.OnChannelTopicReceived(new(channel, old, channel._Topic));
|
||||
}
|
||||
|
||||
public static void HandleGetEmptyTopic(IrcClient client, IrcMessage message)
|
||||
|
@ -43,7 +42,7 @@ namespace ChatSharp.Handlers
|
|||
var channel = client.Channels.GetOrAdd(message.Parameters[1]);
|
||||
var old = channel._Topic;
|
||||
channel._Topic = message.Parameters[2];
|
||||
client.OnChannelTopicReceived(new ChannelTopicEventArgs(channel, old, channel._Topic));
|
||||
client.OnChannelTopicReceived(new(channel, old, channel._Topic));
|
||||
}
|
||||
|
||||
public static void HandlePart(IrcClient client, IrcMessage message)
|
||||
|
@ -59,7 +58,7 @@ namespace ChatSharp.Handlers
|
|||
if (user.ChannelModes.ContainsKey(channel))
|
||||
user.ChannelModes.Remove(channel);
|
||||
|
||||
client.OnUserPartedChannel(new ChannelUserEventArgs(channel, user));
|
||||
client.OnUserPartedChannel(new(channel, user));
|
||||
}
|
||||
|
||||
public static void HandleUserListPart(IrcClient client, IrcMessage message)
|
||||
|
@ -74,9 +73,9 @@ namespace ChatSharp.Handlers
|
|||
continue;
|
||||
|
||||
// Parse hostmask
|
||||
var nick = hostmask.Substring(0, hostmask.IndexOf("!"));
|
||||
var ident = hostmask[(nick.Length + 1)..hostmask.LastIndexOf("@")];
|
||||
var hostname = hostmask[(hostmask.LastIndexOf("@") + 1)..];
|
||||
var nick = hostmask.Substring(0, hostmask.IndexOf("!", StringComparison.Ordinal));
|
||||
var ident = hostmask[(nick.Length + 1)..hostmask.LastIndexOf("@", StringComparison.Ordinal)];
|
||||
var hostname = hostmask[(hostmask.LastIndexOf("@", StringComparison.Ordinal) + 1)..];
|
||||
|
||||
// Get user modes
|
||||
var modes = client.ServerInfo.GetModesForNick(nick);
|
||||
|
@ -128,19 +127,21 @@ namespace ChatSharp.Handlers
|
|||
public static void HandleUserListEnd(IrcClient client, IrcMessage message)
|
||||
{
|
||||
var channel = client.Channels[message.Parameters[1]];
|
||||
client.OnChannelListReceived(new ChannelEventArgs(channel));
|
||||
client.OnChannelListReceived(new(channel));
|
||||
if (client.Settings.ModeOnJoin)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetMode(channel.Name, c => { /* no-op */ });
|
||||
client.GetMode(channel.Name, _ =>
|
||||
{
|
||||
/* no-op */
|
||||
});
|
||||
}
|
||||
catch { /* who cares */ }
|
||||
}
|
||||
if (client.Settings.WhoIsOnJoin)
|
||||
{
|
||||
Task.Factory.StartNew(() => WhoIsChannel(channel, client, 0));
|
||||
}
|
||||
catch
|
||||
{
|
||||
/* who cares */
|
||||
}
|
||||
|
||||
if (client.Settings.WhoIsOnJoin) Task.Factory.StartNew(() => WhoIsChannel(channel, client, 0));
|
||||
}
|
||||
|
||||
private static void WhoIsChannel(IrcChannel channel, IrcClient client, int index)
|
||||
|
@ -148,13 +149,13 @@ namespace ChatSharp.Handlers
|
|||
// Note: joins and parts that happen during this will cause strange behavior here
|
||||
Thread.Sleep(client.Settings.JoinWhoIsDelay * 1000);
|
||||
var user = channel.Users[index];
|
||||
client.WhoIs(user.Nick, (whois) =>
|
||||
{
|
||||
user.User = whois.User.User;
|
||||
user.Hostname = whois.User.Hostname;
|
||||
user.RealName = whois.User.RealName;
|
||||
Task.Factory.StartNew(() => WhoIsChannel(channel, client, index + 1));
|
||||
});
|
||||
client.WhoIs(user.Nick, whois =>
|
||||
{
|
||||
user.User = whois.User.User;
|
||||
user.Hostname = whois.User.Hostname;
|
||||
user.RealName = whois.User.RealName;
|
||||
Task.Factory.StartNew(() => WhoIsChannel(channel, client, index + 1));
|
||||
});
|
||||
}
|
||||
|
||||
public static void HandleKick(IrcClient client, IrcMessage message)
|
||||
|
@ -163,8 +164,8 @@ namespace ChatSharp.Handlers
|
|||
var kicked = channel.Users[message.Parameters[1]];
|
||||
if (kicked.Channels.Contains(channel))
|
||||
kicked.Channels.Remove(channel);
|
||||
client.OnUserKicked(new KickEventArgs(channel, new IrcUser(message.Prefix),
|
||||
client.OnUserKicked(new(channel, new(message.Prefix),
|
||||
kicked, message.Parameters[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
namespace ChatSharp.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC error replies handler. See rfc1459 6.1.
|
||||
/// IRC error replies handler. See rfc1459 6.1.
|
||||
/// </summary>
|
||||
internal static class ErrorHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC Error replies handler. See rfc1459 6.1.
|
||||
/// IRC Error replies handler. See rfc1459 6.1.
|
||||
/// </summary>
|
||||
public static void HandleError(IrcClient client, IrcMessage message)
|
||||
{
|
||||
client.OnErrorReply(new Events.ErrorReplyEventArgs(message));
|
||||
client.OnErrorReply(new(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace ChatSharp.Handlers
|
|||
var parameters = parameterString[parameterString.IndexOf(' ')..].Split(' ');
|
||||
var request = client.RequestManager.PeekOperation("GETMODE b " + parameters[1]);
|
||||
var list = (MaskCollection)request.State;
|
||||
list.Add(new Mask(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
list.Add(new(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
IrcClient.DateTimeFromIrcTime(int.Parse(parameters[4]))));
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace ChatSharp.Handlers
|
|||
var parameters = parameterString[(parameterString.IndexOf(' ') + 1)..].Split(' ');
|
||||
var request = client.RequestManager.PeekOperation("GETMODE e " + parameters[1]);
|
||||
var list = (MaskCollection)request.State;
|
||||
list.Add(new Mask(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
list.Add(new(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
IrcClient.DateTimeFromIrcTime(int.Parse(parameters[4]))));
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace ChatSharp.Handlers
|
|||
var parameters = parameterString[(parameterString.IndexOf(' ') + 1)..].Split(' ');
|
||||
var request = client.RequestManager.PeekOperation("GETMODE I " + parameters[1]);
|
||||
var list = (MaskCollection)request.State;
|
||||
list.Add(new Mask(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
list.Add(new(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
IrcClient.DateTimeFromIrcTime(int.Parse(parameters[4]))));
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ namespace ChatSharp.Handlers
|
|||
var parameters = parameterString[(parameterString.IndexOf(' ') + 1)..].Split(' ');
|
||||
var request = client.RequestManager.PeekOperation("GETMODE q " + parameters[1]);
|
||||
var list = (MaskCollection)request.State;
|
||||
list.Add(new Mask(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
list.Add(new(parameters[2], client.Users.GetOrAdd(parameters[3]),
|
||||
IrcClient.DateTimeFromIrcTime(int.Parse(parameters[4]))));
|
||||
}
|
||||
|
||||
|
@ -66,4 +66,4 @@ namespace ChatSharp.Handlers
|
|||
request.Callback?.Invoke(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
using ChatSharp.Events;
|
||||
using System;
|
||||
|
||||
namespace ChatSharp.Handlers
|
||||
|
@ -18,21 +17,21 @@ namespace ChatSharp.Handlers
|
|||
throw new IrcProtocolException("372 MOTD message is incorrectly formatted.");
|
||||
var part = message.Parameters[1][2..];
|
||||
MOTD += part + Environment.NewLine;
|
||||
client.OnMOTDPartReceived(new ServerMOTDEventArgs(part));
|
||||
client.OnMOTDPartReceived(new(part));
|
||||
}
|
||||
|
||||
public static void HandleEndOfMOTD(IrcClient client, IrcMessage message)
|
||||
{
|
||||
client.OnMOTDReceived(new ServerMOTDEventArgs(MOTD));
|
||||
client.OnConnectionComplete(new EventArgs());
|
||||
client.OnMOTDReceived(new(MOTD));
|
||||
client.OnConnectionComplete(new());
|
||||
// Verify our identity
|
||||
VerifyOurIdentity(client);
|
||||
}
|
||||
|
||||
public static void HandleMOTDNotFound(IrcClient client, IrcMessage message)
|
||||
{
|
||||
client.OnMOTDReceived(new ServerMOTDEventArgs(MOTD));
|
||||
client.OnConnectionComplete(new EventArgs());
|
||||
client.OnMOTDReceived(new(MOTD));
|
||||
client.OnConnectionComplete(new());
|
||||
|
||||
VerifyOurIdentity(client);
|
||||
}
|
||||
|
@ -40,15 +39,13 @@ namespace ChatSharp.Handlers
|
|||
private static void VerifyOurIdentity(IrcClient client)
|
||||
{
|
||||
if (client.Settings.WhoIsOnConnect)
|
||||
{
|
||||
client.WhoIs(client.User.Nick, whois =>
|
||||
{
|
||||
client.User.Nick = whois.User.Nick;
|
||||
client.User.User = whois.User.User;
|
||||
client.User.Hostname = whois.User.Hostname;
|
||||
client.User.RealName = whois.User.RealName;
|
||||
});
|
||||
}
|
||||
{
|
||||
client.User.Nick = whois.User.Nick;
|
||||
client.User.User = whois.User.User;
|
||||
client.User.Hostname = whois.User.Hostname;
|
||||
client.User.RealName = whois.User.RealName;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using ChatSharp.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ChatSharp.Events;
|
||||
|
||||
namespace ChatSharp.Handlers
|
||||
{
|
||||
|
@ -66,13 +65,17 @@ namespace ChatSharp.Handlers
|
|||
client.SetHandler("005", ServerHandlers.HandleISupport);
|
||||
|
||||
// Error replies rfc1459 6.1
|
||||
client.SetHandler("401", ErrorHandlers.HandleError);//ERR_NOSUCHNICK "<nickname> :No such nick/channel"
|
||||
client.SetHandler("402", ErrorHandlers.HandleError);//ERR_NOSUCHSERVER "<server name> :No such server"
|
||||
client.SetHandler("403", ErrorHandlers.HandleError);//ERR_NOSUCHCHANNEL "<channel name> :No such channel"
|
||||
client.SetHandler("404", ErrorHandlers.HandleError);//ERR_CANNOTSENDTOCHAN "<channel name> :Cannot send to channel"
|
||||
client.SetHandler("405", ErrorHandlers.HandleError);//ERR_TOOMANYCHANNELS "<channel name> :You have joined too many \ channels"
|
||||
client.SetHandler("406", ErrorHandlers.HandleError);//ERR_WASNOSUCHNICK "<nickname> :There was no such nickname"
|
||||
client.SetHandler("407", ErrorHandlers.HandleError);//ERR_TOOMANYTARGETS "<target> :Duplicate recipients. No message \
|
||||
client.SetHandler("401", ErrorHandlers.HandleError); //ERR_NOSUCHNICK "<nickname> :No such nick/channel"
|
||||
client.SetHandler("402", ErrorHandlers.HandleError); //ERR_NOSUCHSERVER "<server name> :No such server"
|
||||
client.SetHandler("403", ErrorHandlers.HandleError); //ERR_NOSUCHCHANNEL "<channel name> :No such channel"
|
||||
client.SetHandler("404",
|
||||
ErrorHandlers.HandleError); //ERR_CANNOTSENDTOCHAN "<channel name> :Cannot send to channel"
|
||||
client.SetHandler("405",
|
||||
ErrorHandlers.HandleError); //ERR_TOOMANYCHANNELS "<channel name> :You have joined too many \ channels"
|
||||
client.SetHandler("406",
|
||||
ErrorHandlers.HandleError); //ERR_WASNOSUCHNICK "<nickname> :There was no such nickname"
|
||||
client.SetHandler("407",
|
||||
ErrorHandlers.HandleError); //ERR_TOOMANYTARGETS "<target> :Duplicate recipients. No message \
|
||||
|
||||
// Capability handlers
|
||||
client.SetHandler("CAP", CapabilityHandlers.HandleCapability);
|
||||
|
@ -92,7 +95,7 @@ namespace ChatSharp.Handlers
|
|||
var oldNick = user.Nick;
|
||||
user.Nick = message.Parameters[0];
|
||||
|
||||
client.OnNickChanged(new NickChangedEventArgs
|
||||
client.OnNickChanged(new()
|
||||
{
|
||||
User = user,
|
||||
OldNick = oldNick,
|
||||
|
@ -106,7 +109,7 @@ namespace ChatSharp.Handlers
|
|||
if (client.User.Nick != user.Nick)
|
||||
{
|
||||
client.Users.Remove(user);
|
||||
client.OnUserQuit(new UserEventArgs(user));
|
||||
client.OnUserQuit(new(user));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +121,7 @@ namespace ChatSharp.Handlers
|
|||
|
||||
public static void HandleNotice(IrcClient client, IrcMessage message)
|
||||
{
|
||||
client.OnNoticeReceived(new IrcNoticeEventArgs(message));
|
||||
client.OnNoticeReceived(new(message));
|
||||
}
|
||||
|
||||
public static void HandlePrivmsg(IrcClient client, IrcMessage message)
|
||||
|
@ -133,7 +136,7 @@ namespace ChatSharp.Handlers
|
|||
|
||||
public static void HandleErronousNick(IrcClient client, IrcMessage message)
|
||||
{
|
||||
var eventArgs = new ErronousNickEventArgs(client.User.Nick);
|
||||
var eventArgs = new ErroneousNickEventArgs(client.User.Nick);
|
||||
if (message.Command == "433") // Nick in use
|
||||
client.OnNickInUse(eventArgs);
|
||||
// else ... TODO
|
||||
|
@ -143,8 +146,8 @@ namespace ChatSharp.Handlers
|
|||
|
||||
public static void HandleMode(IrcClient client, IrcMessage message)
|
||||
{
|
||||
string target, mode = null;
|
||||
int i = 2;
|
||||
string target, mode;
|
||||
var i = 2;
|
||||
if (message.Command == "MODE")
|
||||
{
|
||||
target = message.Parameters[0];
|
||||
|
@ -156,50 +159,51 @@ namespace ChatSharp.Handlers
|
|||
mode = message.Parameters[2];
|
||||
i++;
|
||||
}
|
||||
|
||||
// Handle change
|
||||
bool add = true;
|
||||
var add = true;
|
||||
if (target.StartsWith("#"))
|
||||
{
|
||||
var channel = client.Channels[target];
|
||||
try
|
||||
{
|
||||
foreach (char c in mode)
|
||||
foreach (var c in mode)
|
||||
{
|
||||
if (c == '+')
|
||||
{
|
||||
add = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '-')
|
||||
{
|
||||
add = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (channel.Mode == null)
|
||||
channel.Mode = string.Empty;
|
||||
// TODO: Support the ones here that aren't done properly
|
||||
if (client.ServerInfo.SupportedChannelModes.ParameterizedSettings.Contains(c))
|
||||
{
|
||||
client.OnModeChanged(new ModeChangeEventArgs(channel.Name, new IrcUser(message.Prefix),
|
||||
client.OnModeChanged(new(channel.Name, new(message.Prefix),
|
||||
(add ? "+" : "-") + c + " " + message.Parameters[i++]));
|
||||
}
|
||||
else if (client.ServerInfo.SupportedChannelModes.ChannelLists.Contains(c))
|
||||
{
|
||||
client.OnModeChanged(new ModeChangeEventArgs(channel.Name, new IrcUser(message.Prefix),
|
||||
client.OnModeChanged(new(channel.Name, new(message.Prefix),
|
||||
(add ? "+" : "-") + c + " " + message.Parameters[i++]));
|
||||
}
|
||||
else if (client.ServerInfo.SupportedChannelModes.ChannelUserModes.Contains(c))
|
||||
{
|
||||
if (!channel.UsersByMode.ContainsKey(c))
|
||||
{
|
||||
channel.UsersByMode.Add(c,
|
||||
new UserPoolView(channel.Users.Where(u =>
|
||||
new(channel.Users.Where(u =>
|
||||
{
|
||||
if (!u.ChannelModes.ContainsKey(channel))
|
||||
u.ChannelModes.Add(channel, new List<char?>());
|
||||
u.ChannelModes.Add(channel, new());
|
||||
return u.ChannelModes[channel].Contains(c);
|
||||
})));
|
||||
}
|
||||
var user = new IrcUser(message.Parameters[i]);
|
||||
if (add)
|
||||
{
|
||||
|
@ -212,9 +216,11 @@ namespace ChatSharp.Handlers
|
|||
if (channel.UsersByMode[c].Contains(user.Nick))
|
||||
user.ChannelModes[channel] = null;
|
||||
}
|
||||
client.OnModeChanged(new ModeChangeEventArgs(channel.Name, new IrcUser(message.Prefix),
|
||||
|
||||
client.OnModeChanged(new(channel.Name, new(message.Prefix),
|
||||
(add ? "+" : "-") + c + " " + message.Parameters[i++]));
|
||||
}
|
||||
|
||||
if (client.ServerInfo.SupportedChannelModes.Settings.Contains(c))
|
||||
{
|
||||
if (add)
|
||||
|
@ -223,13 +229,19 @@ namespace ChatSharp.Handlers
|
|||
channel.Mode += c.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.Mode = channel.Mode.Replace(c.ToString(), string.Empty);
|
||||
client.OnModeChanged(new ModeChangeEventArgs(channel.Name, new IrcUser(message.Prefix),
|
||||
}
|
||||
|
||||
client.OnModeChanged(new(channel.Name, new(message.Prefix),
|
||||
(add ? "+" : "-") + c));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (message.Command == "324")
|
||||
{
|
||||
var operation = client.RequestManager.DequeueOperation("MODE " + channel.Name);
|
||||
|
@ -239,17 +251,17 @@ namespace ChatSharp.Handlers
|
|||
else
|
||||
{
|
||||
// TODO: Handle user modes other than ourselves?
|
||||
foreach (char c in mode)
|
||||
{
|
||||
foreach (var c in mode)
|
||||
if (add)
|
||||
{
|
||||
if (!client.User.Mode.Contains(c))
|
||||
client.User.Mode += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.User.Mode = client.User.Mode.Replace(c.ToString(), string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ namespace ChatSharp.Handlers
|
|||
public static void HandleAuthentication(IrcClient client, IrcMessage message)
|
||||
{
|
||||
if (client.IsAuthenticatingSasl)
|
||||
{
|
||||
if (message.Parameters[0] == "+")
|
||||
{
|
||||
// Based off irc-framework implementation
|
||||
|
@ -22,6 +21,7 @@ namespace ChatSharp.Handlers
|
|||
b64Bytes = b64Bytes.Skip(400).ToArray();
|
||||
client.SendRawMessage(string.Format("AUTHENTICATE {0}", Encoding.UTF8.GetString(chunk)));
|
||||
}
|
||||
|
||||
if (b64Bytes.Length > 0)
|
||||
client.SendRawMessage(string.Format("AUTHENTICATE {0}", Encoding.UTF8.GetString(b64Bytes)));
|
||||
else
|
||||
|
@ -29,7 +29,6 @@ namespace ChatSharp.Handlers
|
|||
|
||||
client.IsAuthenticatingSasl = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleError(IrcClient client, IrcMessage message)
|
||||
|
@ -41,4 +40,4 @@ namespace ChatSharp.Handlers
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using ChatSharp.Events;
|
||||
|
||||
namespace ChatSharp.Handlers
|
||||
{
|
||||
internal static class ServerHandlers
|
||||
|
@ -7,7 +5,7 @@ namespace ChatSharp.Handlers
|
|||
public static void HandleISupport(IrcClient client, IrcMessage message)
|
||||
{
|
||||
if (client.ServerInfo == null)
|
||||
client.ServerInfo = new ServerInfo();
|
||||
client.ServerInfo = new();
|
||||
foreach (var item in message.Parameters)
|
||||
{
|
||||
string key, value;
|
||||
|
@ -21,10 +19,10 @@ namespace ChatSharp.Handlers
|
|||
key = item.Remove(item.IndexOf('='));
|
||||
value = item[(item.IndexOf('=') + 1)..];
|
||||
}
|
||||
|
||||
// TODO: Consider doing this differently
|
||||
// TODO: Allow users to specify other things to handle
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
switch (key.ToUpper())
|
||||
{
|
||||
case "PREFIX":
|
||||
|
@ -54,13 +52,14 @@ namespace ChatSharp.Handlers
|
|||
case "MAXLIST":
|
||||
var limits = value.Split(',');
|
||||
client.ServerInfo.ModeListLimits = new ServerInfo.ModeListLimit[limits.Length];
|
||||
for (int i = 0; i < limits.Length; i++)
|
||||
for (var i = 0; i < limits.Length; i++)
|
||||
{
|
||||
var limitedModes = limits[i].Remove(limits[i].IndexOf(':'));
|
||||
var limit = int.Parse(limits[i][(limits[i].IndexOf(':') + 1)..]);
|
||||
foreach (var mode in limitedModes)
|
||||
client.ServerInfo.ModeListLimits[i] = new ServerInfo.ModeListLimit(mode, limit);
|
||||
client.ServerInfo.ModeListLimits[i] = new(mode, limit);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NETWORK":
|
||||
client.ServerInfo.NetworkName = value;
|
||||
|
@ -84,18 +83,16 @@ namespace ChatSharp.Handlers
|
|||
client.ServerInfo.MaxAwayLength = int.Parse(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (key.ToUpper())
|
||||
{
|
||||
case "WHOX":
|
||||
client.ServerInfo.ExtendedWho = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
client.OnServerInfoReceived(new SupportsEventArgs(client.ServerInfo));
|
||||
|
||||
client.OnServerInfoReceived(new(client.ServerInfo));
|
||||
}
|
||||
|
||||
public static void HandleMyInfo(IrcClient client, IrcMessage message)
|
||||
|
@ -103,15 +100,11 @@ namespace ChatSharp.Handlers
|
|||
// 004 sendak.freenode.net ircd-seven-1.1.3 DOQRSZaghilopswz CFILMPQbcefgijklmnopqrstvz bkloveqjfI
|
||||
// TODO: Figure out how to properly handle this message
|
||||
if (client.ServerInfo == null)
|
||||
client.ServerInfo = new ServerInfo();
|
||||
client.ServerInfo = new();
|
||||
if (message.Parameters.Length >= 5)
|
||||
{
|
||||
foreach (var c in message.Parameters[4])
|
||||
{
|
||||
if (!client.ServerInfo.SupportedChannelModes.ChannelUserModes.Contains(c))
|
||||
client.ServerInfo.SupportedChannelModes.ChannelUserModes += c.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ namespace ChatSharp.Handlers
|
|||
{
|
||||
var whois = (WhoIs)client.RequestManager.PeekOperation("WHOIS " + message.Parameters[1]).State;
|
||||
var channels = message.Parameters[2].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < channels.Length; i++)
|
||||
for (var i = 0; i < channels.Length; i++)
|
||||
if (!channels[i].StartsWith("#"))
|
||||
channels[i] = channels[i][1..];
|
||||
whois.Channels = whois.Channels.Concat(channels).ToArray();
|
||||
|
@ -68,21 +68,20 @@ namespace ChatSharp.Handlers
|
|||
if (!client.Users.Contains(whois.User.Nick))
|
||||
client.Users.Add(whois.User);
|
||||
request.Callback?.Invoke(request);
|
||||
client.OnWhoIsReceived(new Events.WhoIsReceivedEventArgs(whois));
|
||||
client.OnWhoIsReceived(new(whois));
|
||||
}
|
||||
|
||||
public static void HandleWho(IrcClient client, IrcMessage message)
|
||||
{
|
||||
// A standard WHO request (numeric 352) is just like a WHOX request, except that it has less fields.
|
||||
foreach (var query in client.RequestManager.PendingOperations.Where(kvp => kvp.Key.StartsWith("WHO ")))
|
||||
{
|
||||
if (query.Key != string.Empty && query.Value != null)
|
||||
{
|
||||
var whoList = (List<ExtendedWho>)client.RequestManager.PeekOperation(query.Key).State;
|
||||
var who = new ExtendedWho
|
||||
{
|
||||
Channel = message.Parameters[1],
|
||||
User = new IrcUser
|
||||
User = new()
|
||||
{
|
||||
User = message.Parameters[2],
|
||||
Nick = message.Parameters[5]
|
||||
|
@ -95,29 +94,28 @@ namespace ChatSharp.Handlers
|
|||
var supposedRealName = message.Parameters[7];
|
||||
|
||||
// Parsing IRC spec craziness: the hops field is included in the real name field
|
||||
var hops = supposedRealName.Substring(0, supposedRealName.IndexOf(" "));
|
||||
var hops = supposedRealName[..supposedRealName.IndexOf(" ", StringComparison.Ordinal)];
|
||||
who.Hops = int.Parse(hops);
|
||||
|
||||
var realName = supposedRealName[(supposedRealName.IndexOf(" ") + 1)..];
|
||||
var realName = supposedRealName[(supposedRealName.IndexOf(" ", StringComparison.Ordinal) + 1)..];
|
||||
who.User.RealName = realName;
|
||||
|
||||
whoList.Add(who);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleWhox(IrcClient client, IrcMessage message)
|
||||
{
|
||||
int msgQueryType = int.Parse(message.Parameters[1]);
|
||||
var msgQueryType = int.Parse(message.Parameters[1]);
|
||||
var whoxQuery = new KeyValuePair<string, RequestOperation>();
|
||||
|
||||
foreach (var query in client.RequestManager.PendingOperations.Where(kvp => kvp.Key.StartsWith("WHO ")))
|
||||
{
|
||||
// Parse query to retrieve querytype
|
||||
string key = query.Key;
|
||||
string[] queryParts = key.Split(new[] { ' ' });
|
||||
var key = query.Key;
|
||||
var queryParts = key.Split(new[] { ' ' });
|
||||
|
||||
int queryType = int.Parse(queryParts[2]);
|
||||
var queryType = int.Parse(queryParts[2]);
|
||||
|
||||
// Check querytype against message querytype
|
||||
if (queryType == msgQueryType) whoxQuery = query;
|
||||
|
@ -128,12 +126,12 @@ namespace ChatSharp.Handlers
|
|||
var whoxList = (List<ExtendedWho>)client.RequestManager.PeekOperation(whoxQuery.Key).State;
|
||||
var whox = new ExtendedWho();
|
||||
|
||||
string key = whoxQuery.Key;
|
||||
string[] queryParts = key.Split(new[] { ' ' });
|
||||
var key = whoxQuery.Key;
|
||||
var queryParts = key.Split(new[] { ' ' });
|
||||
|
||||
// Handle what fields were included in the WHOX request
|
||||
WhoxField fields = (WhoxField)int.Parse(queryParts[3]);
|
||||
int fieldIdx = 1;
|
||||
var fields = (WhoxField)int.Parse(queryParts[3]);
|
||||
var fieldIdx = 1;
|
||||
do
|
||||
{
|
||||
if ((fields & WhoxField.QueryType) != 0)
|
||||
|
@ -213,8 +211,8 @@ namespace ChatSharp.Handlers
|
|||
whox.User.RealName = message.Parameters[fieldIdx];
|
||||
fieldIdx++;
|
||||
}
|
||||
}
|
||||
while (fieldIdx < message.Parameters.Length - 1);
|
||||
} while (fieldIdx < message.Parameters.Length - 1);
|
||||
|
||||
whoxList.Add(whox);
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +226,8 @@ namespace ChatSharp.Handlers
|
|||
{
|
||||
if (client.ServerInfo.ExtendedWho)
|
||||
{
|
||||
var query = client.RequestManager.PendingOperations.Where(kvp => kvp.Key.StartsWith("WHO " + message.Parameters[1])).FirstOrDefault();
|
||||
var query = client.RequestManager.PendingOperations
|
||||
.Where(kvp => kvp.Key.StartsWith("WHO " + message.Parameters[1])).FirstOrDefault();
|
||||
var request = client.RequestManager.DequeueOperation(query.Key);
|
||||
var whoxList = (List<ExtendedWho>)request.State;
|
||||
|
||||
|
@ -237,11 +236,12 @@ namespace ChatSharp.Handlers
|
|||
client.Users.Add(whox.User);
|
||||
|
||||
request.Callback?.Invoke(request);
|
||||
client.OnWhoxReceived(new Events.WhoxReceivedEventArgs(whoxList.ToArray()));
|
||||
client.OnWhoxReceived(new(whoxList.ToArray()));
|
||||
}
|
||||
else
|
||||
{
|
||||
var query = client.RequestManager.PendingOperations.Where(kvp => kvp.Key == "WHO " + message.Parameters[1]).FirstOrDefault();
|
||||
var query = client.RequestManager.PendingOperations
|
||||
.Where(kvp => kvp.Key == "WHO " + message.Parameters[1]).FirstOrDefault();
|
||||
var request = client.RequestManager.DequeueOperation(query.Key);
|
||||
var whoList = (List<ExtendedWho>)request.State;
|
||||
|
||||
|
@ -250,7 +250,7 @@ namespace ChatSharp.Handlers
|
|||
client.Users.Add(who.User);
|
||||
|
||||
request.Callback?.Invoke(request);
|
||||
client.OnWhoxReceived(new Events.WhoxReceivedEventArgs(whoList.ToArray()));
|
||||
client.OnWhoxReceived(new(whoList.ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,4 +277,4 @@ namespace ChatSharp.Handlers
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +1,12 @@
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A IRC capability.
|
||||
/// A IRC capability.
|
||||
/// </summary>
|
||||
public class IrcCapability
|
||||
{
|
||||
/// <summary>
|
||||
/// The capability identifier.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
/// <summary>
|
||||
/// The state of the capability after negotiating with the server.
|
||||
/// Disabled by default when the capability is created.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a capability given a name.
|
||||
/// Constructs a capability given a name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public IrcCapability(string name)
|
||||
|
@ -24,5 +14,16 @@
|
|||
Name = name;
|
||||
IsEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The capability identifier.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The state of the capability after negotiating with the server.
|
||||
/// Disabled by default when the capability is created.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; internal set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,22 +4,27 @@ using System.Linq;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// An IRC channel.
|
||||
/// An IRC channel.
|
||||
/// </summary>
|
||||
public class IrcChannel
|
||||
{
|
||||
private IrcClient Client { get; set; }
|
||||
|
||||
internal string _Topic;
|
||||
|
||||
internal IrcChannel(IrcClient client, string name)
|
||||
{
|
||||
Client = client;
|
||||
Name = name;
|
||||
Users = new(client.Users.Where(u => u.Channels.Contains(this)));
|
||||
}
|
||||
|
||||
private IrcClient Client { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The channel topic. Will send a TOPIC command if set.
|
||||
/// The channel topic. Will send a TOPIC command if set.
|
||||
/// </summary>
|
||||
public string Topic
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Topic;
|
||||
}
|
||||
get => _Topic;
|
||||
set
|
||||
{
|
||||
Client.SetTopic(Name, value);
|
||||
|
@ -28,32 +33,28 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name, including the prefix (i.e. #), of this channel.
|
||||
/// The name, including the prefix (i.e. #), of this channel.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The channel mode. May be null if we have not received the mode yet.
|
||||
/// The channel mode. May be null if we have not received the mode yet.
|
||||
/// </summary>
|
||||
public string Mode { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The users in this channel.
|
||||
/// The users in this channel.
|
||||
/// </summary>
|
||||
public UserPoolView Users { get; private set; }
|
||||
public UserPoolView Users { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Users in this channel, grouped by mode. Users with no special mode are grouped under null.
|
||||
/// Users in this channel, grouped by mode. Users with no special mode are grouped under null.
|
||||
/// </summary>
|
||||
public Dictionary<char?, UserPoolView> UsersByMode { get; set; }
|
||||
|
||||
internal IrcChannel(IrcClient client, string name)
|
||||
{
|
||||
Client = client;
|
||||
Name = name;
|
||||
Users = new UserPoolView(client.Users.Where(u => u.Channels.Contains(this)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invites a user to this channel.
|
||||
/// Invites a user to this channel.
|
||||
/// </summary>
|
||||
public void Invite(string nick)
|
||||
{
|
||||
|
@ -61,7 +62,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks a user from this channel.
|
||||
/// Kicks a user from this channel.
|
||||
/// </summary>
|
||||
public void Kick(string nick)
|
||||
{
|
||||
|
@ -69,7 +70,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks a user from this channel, giving a reason for the kick.
|
||||
/// Kicks a user from this channel, giving a reason for the kick.
|
||||
/// </summary>
|
||||
public void Kick(string nick, string reason)
|
||||
{
|
||||
|
@ -77,7 +78,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parts this channel.
|
||||
/// Parts this channel.
|
||||
/// </summary>
|
||||
public void Part()
|
||||
{
|
||||
|
@ -85,7 +86,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parts this channel, giving a reason for your departure.
|
||||
/// Parts this channel, giving a reason for your departure.
|
||||
/// </summary>
|
||||
public void Part(string reason)
|
||||
{
|
||||
|
@ -93,7 +94,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a PRIVMSG to this channel.
|
||||
/// Sends a PRIVMSG to this channel.
|
||||
/// </summary>
|
||||
public void SendMessage(string message)
|
||||
{
|
||||
|
@ -101,7 +102,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the channel mode.
|
||||
/// Set the channel mode.
|
||||
/// </summary>
|
||||
public void ChangeMode(string change)
|
||||
{
|
||||
|
@ -109,7 +110,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this channel is equal to another (compares names).
|
||||
/// True if this channel is equal to another (compares names).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Equals(IrcChannel other)
|
||||
|
@ -118,7 +119,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this channel is equal to another (compares names).
|
||||
/// True if this channel is equal to another (compares names).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object obj)
|
||||
|
@ -129,7 +130,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code of the channel's name.
|
||||
/// Returns the hash code of the channel's name.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
|
@ -137,4 +138,4 @@ namespace ChatSharp
|
|||
return Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace ChatSharp
|
|||
public partial class IrcClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Changes your nick.
|
||||
/// Changes your nick.
|
||||
/// </summary>
|
||||
public void Nick(string newNick)
|
||||
{
|
||||
|
@ -16,43 +16,49 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to one or more destinations (channels or users).
|
||||
/// Sends a message to one or more destinations (channels or users).
|
||||
/// </summary>
|
||||
public void SendMessage(string message, params string[] destinations)
|
||||
{
|
||||
const string illegalCharacters = "\r\n\0";
|
||||
if (destinations == null || !destinations.Any()) throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains)) throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
string to = string.Join(",", destinations);
|
||||
if (destinations == null || !destinations.Any())
|
||||
throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains))
|
||||
throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
var to = string.Join(",", destinations);
|
||||
SendRawMessage("PRIVMSG {0} :{1}{2}", to, PrivmsgPrefix, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a CTCP action (i.e. "* SirCmpwn waves hello") to one or more destinations.
|
||||
/// Sends a CTCP action (i.e. "* SirCmpwn waves hello") to one or more destinations.
|
||||
/// </summary>
|
||||
public void SendAction(string message, params string[] destinations)
|
||||
{
|
||||
const string illegalCharacters = "\r\n\0";
|
||||
if (destinations == null || !destinations.Any()) throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains)) throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
string to = string.Join(",", destinations);
|
||||
if (destinations == null || !destinations.Any())
|
||||
throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains))
|
||||
throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
var to = string.Join(",", destinations);
|
||||
SendRawMessage("PRIVMSG {0} :\x0001ACTION {1}{2}\x0001", to, PrivmsgPrefix, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a NOTICE to one or more destinations (channels or users).
|
||||
/// Sends a NOTICE to one or more destinations (channels or users).
|
||||
/// </summary>
|
||||
public void SendNotice(string message, params string[] destinations)
|
||||
{
|
||||
const string illegalCharacters = "\r\n\0";
|
||||
if (destinations == null || !destinations.Any()) throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains)) throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
string to = string.Join(",", destinations);
|
||||
if (destinations == null || !destinations.Any())
|
||||
throw new InvalidOperationException("Message must have at least one target.");
|
||||
if (illegalCharacters.Any(message.Contains))
|
||||
throw new ArgumentException("Illegal characters are present in message.", nameof(message));
|
||||
var to = string.Join(",", destinations);
|
||||
SendRawMessage("NOTICE {0} :{1}{2}", to, PrivmsgPrefix, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leaves the specified channel.
|
||||
/// Leaves the specified channel.
|
||||
/// </summary>
|
||||
public void PartChannel(string channel)
|
||||
{
|
||||
|
@ -62,7 +68,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leaves the specified channel, giving a reason for your departure.
|
||||
/// Leaves the specified channel, giving a reason for your departure.
|
||||
/// </summary>
|
||||
public void PartChannel(string channel, string reason)
|
||||
{
|
||||
|
@ -72,14 +78,14 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins the specified channel.
|
||||
/// Joins the specified channel.
|
||||
/// </summary>
|
||||
public void JoinChannel(string channel, string key = null)
|
||||
{
|
||||
if (Channels.Contains(channel))
|
||||
throw new InvalidOperationException("Client is already present in channel.");
|
||||
|
||||
string joinCmd = string.Format("JOIN {0}", channel);
|
||||
var joinCmd = string.Format("JOIN {0}", channel);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
joinCmd += string.Format(" {0}", key);
|
||||
|
||||
|
@ -89,21 +95,19 @@ namespace ChatSharp
|
|||
var flags = WhoxField.Nick | WhoxField.Hostname | WhoxField.AccountName | WhoxField.Username;
|
||||
|
||||
if (Capabilities.IsEnabled("account-notify"))
|
||||
Who(channel, WhoxFlag.None, flags, (whoList) =>
|
||||
Who(channel, WhoxFlag.None, flags, whoList =>
|
||||
{
|
||||
if (whoList.Count > 0)
|
||||
{
|
||||
foreach (var whoQuery in whoList)
|
||||
{
|
||||
var user = Users.GetOrAdd(whoQuery.User.Hostmask);
|
||||
user.Account = whoQuery.User.Account;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the topic for the specified channel.
|
||||
/// Sets the topic for the specified channel.
|
||||
/// </summary>
|
||||
public void SetTopic(string channel, string topic)
|
||||
{
|
||||
|
@ -113,7 +117,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the topic for the specified channel.
|
||||
/// Retrieves the topic for the specified channel.
|
||||
/// </summary>
|
||||
public void GetTopic(string channel)
|
||||
{
|
||||
|
@ -121,7 +125,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks the specified user from the specified channel.
|
||||
/// Kicks the specified user from the specified channel.
|
||||
/// </summary>
|
||||
public void KickUser(string channel, string user)
|
||||
{
|
||||
|
@ -129,7 +133,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks the specified user from the specified channel.
|
||||
/// Kicks the specified user from the specified channel.
|
||||
/// </summary>
|
||||
public void KickUser(string channel, string user, string reason)
|
||||
{
|
||||
|
@ -137,7 +141,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invites the specified user to the specified channel.
|
||||
/// Invites the specified user to the specified channel.
|
||||
/// </summary>
|
||||
public void InviteUser(string channel, string user)
|
||||
{
|
||||
|
@ -145,7 +149,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a WHOIS query asking for information on the given nick.
|
||||
/// Sends a WHOIS query asking for information on the given nick.
|
||||
/// </summary>
|
||||
public void WhoIs(string nick)
|
||||
{
|
||||
|
@ -153,22 +157,19 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a WHOIS query asking for information on the given nick, and a callback
|
||||
/// to run when we have received the response.
|
||||
/// Sends a WHOIS query asking for information on the given nick, and a callback
|
||||
/// to run when we have received the response.
|
||||
/// </summary>
|
||||
public void WhoIs(string nick, Action<WhoIs> callback)
|
||||
{
|
||||
var whois = new WhoIs();
|
||||
RequestManager.QueueOperation("WHOIS " + nick, new RequestOperation(whois, ro =>
|
||||
{
|
||||
callback?.Invoke((WhoIs)ro.State);
|
||||
}));
|
||||
RequestManager.QueueOperation("WHOIS " + nick, new(whois, ro => { callback?.Invoke((WhoIs)ro.State); }));
|
||||
SendRawMessage("WHOIS {0}", nick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an extended WHO query asking for specific information about a single user
|
||||
/// or the users in a channel, and runs a callback when we have received the response.
|
||||
/// Sends an extended WHO query asking for specific information about a single user
|
||||
/// or the users in a channel, and runs a callback when we have received the response.
|
||||
/// </summary>
|
||||
public void Who(string target, WhoxFlag flags, WhoxField fields, Action<List<ExtendedWho>> callback)
|
||||
{
|
||||
|
@ -177,38 +178,35 @@ namespace ChatSharp
|
|||
var whox = new List<ExtendedWho>();
|
||||
|
||||
// Generate random querytype for WHO query
|
||||
int queryType = RandomNumber.Next(0, 999);
|
||||
var queryType = RandomNumber.Next(0, 999);
|
||||
|
||||
// Add the querytype field if it wasn't defined
|
||||
var _fields = fields;
|
||||
if ((fields & WhoxField.QueryType) == 0)
|
||||
_fields |= WhoxField.QueryType;
|
||||
|
||||
string whoQuery = string.Format("WHO {0} {1}%{2},{3}", target, flags.AsString(), _fields.AsString(), queryType);
|
||||
string queryKey = string.Format("WHO {0} {1} {2:D}", target, queryType, _fields);
|
||||
var whoQuery = string.Format("WHO {0} {1}%{2},{3}", target, flags.AsString(), _fields.AsString(),
|
||||
queryType);
|
||||
var queryKey = string.Format("WHO {0} {1} {2:D}", target, queryType, _fields);
|
||||
|
||||
RequestManager.QueueOperation(queryKey, new RequestOperation(whox, ro =>
|
||||
{
|
||||
callback?.Invoke((List<ExtendedWho>)ro.State);
|
||||
}));
|
||||
RequestManager.QueueOperation(queryKey,
|
||||
new(whox, ro => { callback?.Invoke((List<ExtendedWho>)ro.State); }));
|
||||
SendRawMessage(whoQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
var whox = new List<ExtendedWho>();
|
||||
|
||||
string whoQuery = string.Format("WHO {0}", target);
|
||||
var whoQuery = string.Format("WHO {0}", target);
|
||||
|
||||
RequestManager.QueueOperation(whoQuery, new RequestOperation(whox, ro =>
|
||||
{
|
||||
callback?.Invoke((List<ExtendedWho>)ro.State);
|
||||
}));
|
||||
RequestManager.QueueOperation(whoQuery,
|
||||
new(whox, ro => { callback?.Invoke((List<ExtendedWho>)ro.State); }));
|
||||
SendRawMessage(whoQuery);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests the mode of a channel from the server.
|
||||
/// Requests the mode of a channel from the server.
|
||||
/// </summary>
|
||||
public void GetMode(string channel)
|
||||
{
|
||||
|
@ -216,20 +214,20 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests the mode of a channel from the server, and passes it to a callback later.
|
||||
/// Requests the mode of a channel from the server, and passes it to a callback later.
|
||||
/// </summary>
|
||||
public void GetMode(string channel, Action<IrcChannel> callback)
|
||||
{
|
||||
RequestManager.QueueOperation("MODE " + channel, new RequestOperation(channel, ro =>
|
||||
{
|
||||
var c = Channels[(string)ro.State];
|
||||
callback?.Invoke(c);
|
||||
}));
|
||||
RequestManager.QueueOperation("MODE " + channel, new(channel, ro =>
|
||||
{
|
||||
var c = Channels[(string)ro.State];
|
||||
callback?.Invoke(c);
|
||||
}));
|
||||
SendRawMessage("MODE {0}", channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mode of a target.
|
||||
/// Sets the mode of a target.
|
||||
/// </summary>
|
||||
public void ChangeMode(string target, string change)
|
||||
{
|
||||
|
@ -237,17 +235,17 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of masks from a channel by a mode. This can be used, for example,
|
||||
/// to get a list of bans.
|
||||
/// Gets a collection of masks from a channel by a mode. This can be used, for example,
|
||||
/// to get a list of bans.
|
||||
/// </summary>
|
||||
public void GetModeList(string channel, char mode, Action<MaskCollection> callback)
|
||||
{
|
||||
RequestManager.QueueOperation("GETMODE " + mode + " " + channel, new RequestOperation(new MaskCollection(), ro =>
|
||||
{
|
||||
var c = (MaskCollection)ro.State;
|
||||
callback?.Invoke(c);
|
||||
}));
|
||||
RequestManager.QueueOperation("GETMODE " + mode + " " + channel, new(new MaskCollection(), ro =>
|
||||
{
|
||||
var c = (MaskCollection)ro.State;
|
||||
callback?.Invoke(c);
|
||||
}));
|
||||
SendRawMessage("MODE {0} {1}", channel, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using ChatSharp.Events;
|
||||
using ChatSharp.Handlers;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,23 +6,174 @@ using System.Net.Security;
|
|||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Timers;
|
||||
using ChatSharp.Events;
|
||||
using ChatSharp.Handlers;
|
||||
using ErrorEventArgs = ChatSharp.Events.ErrorEventArgs;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// An IRC client.
|
||||
/// An IRC client.
|
||||
/// </summary>
|
||||
public sealed partial class IrcClient
|
||||
{
|
||||
/// <summary>
|
||||
/// A raw IRC message handler.
|
||||
/// A raw IRC message handler.
|
||||
/// </summary>
|
||||
public delegate void MessageHandler(IrcClient client, IrcMessage message);
|
||||
private Dictionary<string, MessageHandler> Handlers { get; set; }
|
||||
|
||||
private const int ReadBufferLength = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a custom handler for an IRC message. This applies to the low level IRC protocol,
|
||||
/// not for private messages.
|
||||
/// Creates a new IRC client, but will not connect until ConnectAsync is called.
|
||||
/// </summary>
|
||||
/// <param name="serverAddress">Server address including port in the form of "hostname:port".</param>
|
||||
/// <param name="user">The IRC user to connect as.</param>
|
||||
/// <param name="useSSL">Connect with SSL if true.</param>
|
||||
public IrcClient(string serverAddress, IrcUser user, bool useSSL = false)
|
||||
{
|
||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
||||
ServerAddress = serverAddress ?? throw new ArgumentNullException(nameof(serverAddress));
|
||||
Encoding = Encoding.UTF8;
|
||||
Settings = new();
|
||||
Handlers = new();
|
||||
MessageHandlers.RegisterDefaultHandlers(this);
|
||||
RequestManager = new();
|
||||
UseSSL = useSSL;
|
||||
WriteQueue = new();
|
||||
ServerInfo = new();
|
||||
PrivmsgPrefix = "";
|
||||
Channels = User.Channels = new(this);
|
||||
// Add self to user pool
|
||||
Users = new() { User };
|
||||
Capabilities = new();
|
||||
|
||||
// List of supported capabilities
|
||||
Capabilities.AddRange(new[]
|
||||
{
|
||||
"server-time", "multi-prefix", "cap-notify", "znc.in/server-time", "znc.in/server-time-iso",
|
||||
"account-notify", "chghost", "userhost-in-names", "sasl"
|
||||
});
|
||||
|
||||
IsNegotiatingCapabilities = false;
|
||||
IsAuthenticatingSasl = false;
|
||||
|
||||
RandomNumber = new();
|
||||
}
|
||||
|
||||
private Dictionary<string, MessageHandler> Handlers { get; }
|
||||
|
||||
internal static Random RandomNumber { get; private set; }
|
||||
|
||||
private byte[] ReadBuffer { get; set; }
|
||||
private int ReadBufferIndex { get; set; }
|
||||
private string ServerHostname { get; set; }
|
||||
private int ServerPort { get; set; }
|
||||
private Timer PingTimer { get; set; }
|
||||
private Socket Socket { get; set; }
|
||||
private ConcurrentQueue<string> WriteQueue { get; }
|
||||
private bool IsWriting { get; set; }
|
||||
|
||||
internal RequestManager RequestManager { get; set; }
|
||||
|
||||
internal string ServerNameFromPing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address this client is connected to, or will connect to. Setting this
|
||||
/// after the client is connected will not cause a reconnect.
|
||||
/// </summary>
|
||||
public string ServerAddress
|
||||
{
|
||||
get => ServerHostname + ":" + ServerPort;
|
||||
internal set
|
||||
{
|
||||
var parts = value.Split(':');
|
||||
if (parts.Length > 2 || parts.Length == 0)
|
||||
throw new FormatException("Server address is not in correct format ('hostname:port')");
|
||||
ServerHostname = parts[0];
|
||||
if (parts.Length > 1)
|
||||
ServerPort = int.Parse(parts[1]);
|
||||
else
|
||||
ServerPort = 6667;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The low level TCP stream for this client.
|
||||
/// </summary>
|
||||
public Stream NetworkStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, SSL will be used to connect.
|
||||
/// </summary>
|
||||
public bool UseSSL { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, invalid SSL certificates are ignored.
|
||||
/// </summary>
|
||||
public bool IgnoreInvalidSSL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The character encoding to use for the connection. Defaults to UTF-8.
|
||||
/// </summary>
|
||||
/// <value>The encoding.</value>
|
||||
public Encoding Encoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user this client is logged in as.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The channels this user is joined to.
|
||||
/// </summary>
|
||||
public ChannelCollection Channels { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Settings that control the behavior of ChatSharp.
|
||||
/// </summary>
|
||||
public ClientSettings Settings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Information about the server we are connected to. Servers may not send us this information,
|
||||
/// but it's required for ChatSharp to function, so by default this is a guess. Handle
|
||||
/// IrcClient.ServerInfoReceived if you'd like to know when it's populated with real information.
|
||||
/// </summary>
|
||||
public ServerInfo ServerInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A string to prepend to all PRIVMSGs sent. Many IRC bots prefix their messages with \u200B, to
|
||||
/// indicate to other bots that you are a bot.
|
||||
/// </summary>
|
||||
public string PrivmsgPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of users on this network that we are aware of.
|
||||
/// </summary>
|
||||
public UserPool Users { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of capabilities supported by the library, along with enabled and disabled capabilities
|
||||
/// after negotiating with the server.
|
||||
/// </summary>
|
||||
public CapabilityPool Capabilities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true when the client is negotiating IRC capabilities with the server.
|
||||
/// If set to False, capability negotiation is finished.
|
||||
/// </summary>
|
||||
public bool IsNegotiatingCapabilities { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to True when the client is authenticating with SASL.
|
||||
/// If set to False, SASL authentication is finished.
|
||||
/// </summary>
|
||||
public bool IsAuthenticatingSasl { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets a custom handler for an IRC message. This applies to the low level IRC protocol,
|
||||
/// not for private messages.
|
||||
/// </summary>
|
||||
public void SetHandler(string message, MessageHandler handler)
|
||||
{
|
||||
|
@ -43,165 +192,32 @@ namespace ChatSharp
|
|||
return new DateTime(1970, 1, 1).AddSeconds(time);
|
||||
}
|
||||
|
||||
internal static Random RandomNumber { get; private set; }
|
||||
|
||||
private const int ReadBufferLength = 1024;
|
||||
|
||||
private byte[] ReadBuffer { get; set; }
|
||||
private int ReadBufferIndex { get; set; }
|
||||
private string ServerHostname { get; set; }
|
||||
private int ServerPort { get; set; }
|
||||
private Timer PingTimer { get; set; }
|
||||
private Socket Socket { get; set; }
|
||||
private ConcurrentQueue<string> WriteQueue { get; set; }
|
||||
private bool IsWriting { get; set; }
|
||||
|
||||
internal RequestManager RequestManager { get; set; }
|
||||
|
||||
internal string ServerNameFromPing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address this client is connected to, or will connect to. Setting this
|
||||
/// after the client is connected will not cause a reconnect.
|
||||
/// </summary>
|
||||
public string ServerAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
return ServerHostname + ":" + ServerPort;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
string[] parts = value.Split(':');
|
||||
if (parts.Length > 2 || parts.Length == 0)
|
||||
throw new FormatException("Server address is not in correct format ('hostname:port')");
|
||||
ServerHostname = parts[0];
|
||||
if (parts.Length > 1)
|
||||
ServerPort = int.Parse(parts[1]);
|
||||
else
|
||||
ServerPort = 6667;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The low level TCP stream for this client.
|
||||
/// </summary>
|
||||
public Stream NetworkStream { get; set; }
|
||||
/// <summary>
|
||||
/// If true, SSL will be used to connect.
|
||||
/// </summary>
|
||||
public bool UseSSL { get; private set; }
|
||||
/// <summary>
|
||||
/// If true, invalid SSL certificates are ignored.
|
||||
/// </summary>
|
||||
public bool IgnoreInvalidSSL { get; set; }
|
||||
/// <summary>
|
||||
/// The character encoding to use for the connection. Defaults to UTF-8.
|
||||
/// </summary>
|
||||
/// <value>The encoding.</value>
|
||||
public Encoding Encoding { get; set; }
|
||||
/// <summary>
|
||||
/// The user this client is logged in as.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public IrcUser User { get; set; }
|
||||
/// <summary>
|
||||
/// The channels this user is joined to.
|
||||
/// </summary>
|
||||
public ChannelCollection Channels { get; private set; }
|
||||
/// <summary>
|
||||
/// Settings that control the behavior of ChatSharp.
|
||||
/// </summary>
|
||||
public ClientSettings Settings { get; set; }
|
||||
/// <summary>
|
||||
/// Information about the server we are connected to. Servers may not send us this information,
|
||||
/// but it's required for ChatSharp to function, so by default this is a guess. Handle
|
||||
/// IrcClient.ServerInfoReceived if you'd like to know when it's populated with real information.
|
||||
/// </summary>
|
||||
public ServerInfo ServerInfo { get; set; }
|
||||
/// <summary>
|
||||
/// A string to prepend to all PRIVMSGs sent. Many IRC bots prefix their messages with \u200B, to
|
||||
/// indicate to other bots that you are a bot.
|
||||
/// </summary>
|
||||
public string PrivmsgPrefix { get; set; }
|
||||
/// <summary>
|
||||
/// A list of users on this network that we are aware of.
|
||||
/// </summary>
|
||||
public UserPool Users { get; set; }
|
||||
/// <summary>
|
||||
/// A list of capabilities supported by the library, along with enabled and disabled capabilities
|
||||
/// after negotiating with the server.
|
||||
/// </summary>
|
||||
public CapabilityPool Capabilities { get; set; }
|
||||
/// <summary>
|
||||
/// Set to true when the client is negotiating IRC capabilities with the server.
|
||||
/// If set to False, capability negotiation is finished.
|
||||
/// </summary>
|
||||
public bool IsNegotiatingCapabilities { get; internal set; }
|
||||
/// <summary>
|
||||
/// Set to True when the client is authenticating with SASL.
|
||||
/// If set to False, SASL authentication is finished.
|
||||
/// </summary>
|
||||
public bool IsAuthenticatingSasl { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new IRC client, but will not connect until ConnectAsync is called.
|
||||
/// </summary>
|
||||
/// <param name="serverAddress">Server address including port in the form of "hostname:port".</param>
|
||||
/// <param name="user">The IRC user to connect as.</param>
|
||||
/// <param name="useSSL">Connect with SSL if true.</param>
|
||||
public IrcClient(string serverAddress, IrcUser user, bool useSSL = false)
|
||||
{
|
||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
||||
ServerAddress = serverAddress ?? throw new ArgumentNullException(nameof(serverAddress));
|
||||
Encoding = Encoding.UTF8;
|
||||
Settings = new ClientSettings();
|
||||
Handlers = new Dictionary<string, MessageHandler>();
|
||||
MessageHandlers.RegisterDefaultHandlers(this);
|
||||
RequestManager = new RequestManager();
|
||||
UseSSL = useSSL;
|
||||
WriteQueue = new ConcurrentQueue<string>();
|
||||
ServerInfo = new ServerInfo();
|
||||
PrivmsgPrefix = "";
|
||||
Channels = User.Channels = new ChannelCollection(this);
|
||||
// Add self to user pool
|
||||
Users = new UserPool { User };
|
||||
Capabilities = new CapabilityPool();
|
||||
|
||||
// List of supported capabilities
|
||||
Capabilities.AddRange(new string[] {
|
||||
"server-time", "multi-prefix", "cap-notify", "znc.in/server-time", "znc.in/server-time-iso",
|
||||
"account-notify", "chghost", "userhost-in-names", "sasl"
|
||||
});
|
||||
|
||||
IsNegotiatingCapabilities = false;
|
||||
IsAuthenticatingSasl = false;
|
||||
|
||||
RandomNumber = new Random();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the IRC server.
|
||||
/// Connects to the IRC server.
|
||||
/// </summary>
|
||||
public void ConnectAsync()
|
||||
{
|
||||
if (Socket != null && Socket.Connected) throw new InvalidOperationException("Socket is already connected to server.");
|
||||
Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
if (Socket != null && Socket.Connected)
|
||||
throw new InvalidOperationException("Socket is already connected to server.");
|
||||
Socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
ReadBuffer = new byte[ReadBufferLength];
|
||||
ReadBufferIndex = 0;
|
||||
PingTimer = new Timer(30000);
|
||||
PingTimer.Elapsed += (sender, e) =>
|
||||
PingTimer = new(30000);
|
||||
PingTimer.Elapsed += (_, _) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ServerNameFromPing))
|
||||
SendRawMessage("PING :{0}", ServerNameFromPing);
|
||||
};
|
||||
var checkQueue = new Timer(1000);
|
||||
checkQueue.Elapsed += (sender, e) =>
|
||||
checkQueue.Elapsed += (_, _) =>
|
||||
{
|
||||
string nextMessage;
|
||||
if (!WriteQueue.IsEmpty)
|
||||
{
|
||||
while (!WriteQueue.TryDequeue(out nextMessage)) ;
|
||||
string nextMessage;
|
||||
while (!WriteQueue.TryDequeue(out nextMessage))
|
||||
{
|
||||
}
|
||||
|
||||
SendRawMessage(nextMessage);
|
||||
}
|
||||
};
|
||||
|
@ -210,7 +226,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a QUIT message and disconnect.
|
||||
/// Send a QUIT message and disconnect.
|
||||
/// </summary>
|
||||
public void Quit()
|
||||
{
|
||||
|
@ -218,7 +234,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a QUIT message with a reason and disconnect.
|
||||
/// Send a QUIT message with a reason and disconnect.
|
||||
/// </summary>
|
||||
public void Quit(string reason)
|
||||
{
|
||||
|
@ -244,7 +260,7 @@ namespace ChatSharp
|
|||
if (UseSSL)
|
||||
{
|
||||
if (IgnoreInvalidSSL)
|
||||
NetworkStream = new SslStream(NetworkStream, false, (sender, certificate, chain, policyErrors) => true);
|
||||
NetworkStream = new SslStream(NetworkStream, false, (_, _, _, _) => true);
|
||||
else
|
||||
NetworkStream = new SslStream(NetworkStream);
|
||||
((SslStream)NetworkStream).AuthenticateAsClient(ServerHostname);
|
||||
|
@ -263,11 +279,11 @@ namespace ChatSharp
|
|||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
OnNetworkError(new SocketErrorEventArgs(e.SocketErrorCode));
|
||||
OnNetworkError(new(e.SocketErrorCode));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OnError(new Events.ErrorEventArgs(e));
|
||||
OnError(new(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +291,7 @@ namespace ChatSharp
|
|||
{
|
||||
if (NetworkStream == null)
|
||||
{
|
||||
OnNetworkError(new SocketErrorEventArgs(SocketError.NotConnected));
|
||||
OnNetworkError(new(SocketError.NotConnected));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -287,7 +303,7 @@ namespace ChatSharp
|
|||
catch (IOException e)
|
||||
{
|
||||
if (e.InnerException is SocketException socketException)
|
||||
OnNetworkError(new SocketErrorEventArgs(socketException.SocketErrorCode));
|
||||
OnNetworkError(new(socketException.SocketErrorCode));
|
||||
else
|
||||
throw;
|
||||
return;
|
||||
|
@ -296,41 +312,42 @@ namespace ChatSharp
|
|||
ReadBufferIndex = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
int messageLength = Array.IndexOf(ReadBuffer, (byte)'\n', 0, length);
|
||||
var messageLength = Array.IndexOf(ReadBuffer, (byte)'\n', 0, length);
|
||||
if (messageLength == -1) // Incomplete message
|
||||
{
|
||||
ReadBufferIndex = length;
|
||||
break;
|
||||
}
|
||||
|
||||
messageLength++;
|
||||
var message = Encoding.GetString(ReadBuffer, 0, messageLength - 2); // -2 to remove \r\n
|
||||
HandleMessage(message);
|
||||
Array.Copy(ReadBuffer, messageLength, ReadBuffer, 0, length - messageLength);
|
||||
length -= messageLength;
|
||||
}
|
||||
NetworkStream.BeginRead(ReadBuffer, ReadBufferIndex, ReadBuffer.Length - ReadBufferIndex, DataReceived, null);
|
||||
|
||||
NetworkStream.BeginRead(ReadBuffer, ReadBufferIndex, ReadBuffer.Length - ReadBufferIndex, DataReceived,
|
||||
null);
|
||||
}
|
||||
|
||||
private void HandleMessage(string rawMessage)
|
||||
{
|
||||
OnRawMessageReceived(new RawMessageEventArgs(rawMessage, false));
|
||||
OnRawMessageReceived(new(rawMessage, false));
|
||||
var message = new IrcMessage(rawMessage);
|
||||
if (Handlers.ContainsKey(message.Command.ToUpper()))
|
||||
Handlers[message.Command.ToUpper()](this, message);
|
||||
else
|
||||
{
|
||||
// TODO: Fire an event or something
|
||||
Handlers[message.Command.ToUpper()](this, message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a raw IRC message. Behaves like /quote in most IRC clients.
|
||||
/// Send a raw IRC message. Behaves like /quote in most IRC clients.
|
||||
/// </summary>
|
||||
public void SendRawMessage(string message, params object[] format)
|
||||
{
|
||||
if (NetworkStream == null)
|
||||
{
|
||||
OnNetworkError(new SocketErrorEventArgs(SocketError.NotConnected));
|
||||
OnNetworkError(new(SocketError.NotConnected));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -349,7 +366,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a raw IRC message. Behaves like /quote in most IRC clients.
|
||||
/// Send a raw IRC message. Behaves like /quote in most IRC clients.
|
||||
/// </summary>
|
||||
public void SendIrcMessage(IrcMessage message)
|
||||
{
|
||||
|
@ -360,7 +377,7 @@ namespace ChatSharp
|
|||
{
|
||||
if (NetworkStream == null)
|
||||
{
|
||||
OnNetworkError(new SocketErrorEventArgs(SocketError.NotConnected));
|
||||
OnNetworkError(new(SocketError.NotConnected));
|
||||
IsWriting = false;
|
||||
return;
|
||||
}
|
||||
|
@ -372,7 +389,7 @@ namespace ChatSharp
|
|||
catch (IOException e)
|
||||
{
|
||||
if (e.InnerException is SocketException socketException)
|
||||
OnNetworkError(new SocketErrorEventArgs(socketException.SocketErrorCode));
|
||||
OnNetworkError(new(socketException.SocketErrorCode));
|
||||
else
|
||||
throw;
|
||||
return;
|
||||
|
@ -382,208 +399,258 @@ namespace ChatSharp
|
|||
IsWriting = false;
|
||||
}
|
||||
|
||||
OnRawMessageSent(new RawMessageEventArgs((string)result.AsyncState, true));
|
||||
OnRawMessageSent(new((string)result.AsyncState, true));
|
||||
|
||||
string nextMessage;
|
||||
if (!WriteQueue.IsEmpty)
|
||||
{
|
||||
while (!WriteQueue.TryDequeue(out nextMessage)) ;
|
||||
while (!WriteQueue.TryDequeue(out nextMessage))
|
||||
{
|
||||
}
|
||||
|
||||
SendRawMessage(nextMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IRC Error Replies. rfc1459 6.1.
|
||||
/// IRC Error Replies. rfc1459 6.1.
|
||||
/// </summary>
|
||||
public event EventHandler<Events.ErrorReplyEventArgs> ErrorReply;
|
||||
internal void OnErrorReply(Events.ErrorReplyEventArgs e)
|
||||
public event EventHandler<ErrorReplyEventArgs> ErrorReply;
|
||||
|
||||
internal void OnErrorReply(ErrorReplyEventArgs e)
|
||||
{
|
||||
ErrorReply?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised for errors.
|
||||
/// Raised for errors.
|
||||
/// </summary>
|
||||
public event EventHandler<Events.ErrorEventArgs> Error;
|
||||
internal void OnError(Events.ErrorEventArgs e)
|
||||
public event EventHandler<ErrorEventArgs> Error;
|
||||
|
||||
internal void OnError(ErrorEventArgs e)
|
||||
{
|
||||
Error?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised for socket errors. ChatSharp does not automatically reconnect.
|
||||
/// Raised for socket errors. ChatSharp does not automatically reconnect.
|
||||
/// </summary>
|
||||
public event EventHandler<SocketErrorEventArgs> NetworkError;
|
||||
|
||||
internal void OnNetworkError(SocketErrorEventArgs e)
|
||||
{
|
||||
NetworkError?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a raw message is sent.
|
||||
/// Occurs when a raw message is sent.
|
||||
/// </summary>
|
||||
public event EventHandler<RawMessageEventArgs> RawMessageSent;
|
||||
|
||||
internal void OnRawMessageSent(RawMessageEventArgs e)
|
||||
{
|
||||
RawMessageSent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a raw message received.
|
||||
/// Occurs when a raw message received.
|
||||
/// </summary>
|
||||
public event EventHandler<RawMessageEventArgs> RawMessageReceived;
|
||||
|
||||
internal void OnRawMessageReceived(RawMessageEventArgs e)
|
||||
{
|
||||
RawMessageReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a notice received.
|
||||
/// Occurs when a notice received.
|
||||
/// </summary>
|
||||
public event EventHandler<IrcNoticeEventArgs> NoticeReceived;
|
||||
|
||||
internal void OnNoticeReceived(IrcNoticeEventArgs e)
|
||||
{
|
||||
NoticeReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the server has sent us part of the MOTD.
|
||||
/// Occurs when the server has sent us part of the MOTD.
|
||||
/// </summary>
|
||||
public event EventHandler<ServerMOTDEventArgs> MOTDPartReceived;
|
||||
|
||||
internal void OnMOTDPartReceived(ServerMOTDEventArgs e)
|
||||
{
|
||||
MOTDPartReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the entire server MOTD has been received.
|
||||
/// Occurs when the entire server MOTD has been received.
|
||||
/// </summary>
|
||||
public event EventHandler<ServerMOTDEventArgs> MOTDReceived;
|
||||
|
||||
internal void OnMOTDReceived(ServerMOTDEventArgs e)
|
||||
{
|
||||
MOTDReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a private message received. This can be a channel OR a user message.
|
||||
/// Occurs when a private message received. This can be a channel OR a user message.
|
||||
/// </summary>
|
||||
public event EventHandler<PrivateMessageEventArgs> PrivateMessageReceived;
|
||||
|
||||
internal void OnPrivateMessageReceived(PrivateMessageEventArgs e)
|
||||
{
|
||||
PrivateMessageReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a message is received in an IRC channel.
|
||||
/// Occurs when a message is received in an IRC channel.
|
||||
/// </summary>
|
||||
public event EventHandler<PrivateMessageEventArgs> ChannelMessageReceived;
|
||||
|
||||
internal void OnChannelMessageReceived(PrivateMessageEventArgs e)
|
||||
{
|
||||
ChannelMessageReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a message is received from a user.
|
||||
/// Occurs when a message is received from a user.
|
||||
/// </summary>
|
||||
public event EventHandler<PrivateMessageEventArgs> UserMessageReceived;
|
||||
|
||||
internal void OnUserMessageReceived(PrivateMessageEventArgs e)
|
||||
{
|
||||
UserMessageReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised if the nick you've chosen is in use. By default, ChatSharp will pick a
|
||||
/// random nick to use instead. Set ErronousNickEventArgs.DoNotHandle to prevent this.
|
||||
/// Raised if the nick you've chosen is in use. By default, ChatSharp will pick a
|
||||
/// random nick to use instead. Set ErronousNickEventArgs.DoNotHandle to prevent this.
|
||||
/// </summary>
|
||||
public event EventHandler<ErronousNickEventArgs> NickInUse;
|
||||
internal void OnNickInUse(ErronousNickEventArgs e)
|
||||
public event EventHandler<ErroneousNickEventArgs> NickInUse;
|
||||
|
||||
internal void OnNickInUse(ErroneousNickEventArgs e)
|
||||
{
|
||||
NickInUse?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user or channel mode is changed.
|
||||
/// Occurs when a user or channel mode is changed.
|
||||
/// </summary>
|
||||
public event EventHandler<ModeChangeEventArgs> ModeChanged;
|
||||
|
||||
internal void OnModeChanged(ModeChangeEventArgs e)
|
||||
{
|
||||
ModeChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user joins a channel.
|
||||
/// Occurs when a user joins a channel.
|
||||
/// </summary>
|
||||
public event EventHandler<ChannelUserEventArgs> UserJoinedChannel;
|
||||
|
||||
internal void OnUserJoinedChannel(ChannelUserEventArgs e)
|
||||
{
|
||||
UserJoinedChannel?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user parts a channel.
|
||||
/// Occurs when a user parts a channel.
|
||||
/// </summary>
|
||||
public event EventHandler<ChannelUserEventArgs> UserPartedChannel;
|
||||
|
||||
internal void OnUserPartedChannel(ChannelUserEventArgs e)
|
||||
{
|
||||
UserPartedChannel?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when we have received the list of users present in a channel.
|
||||
/// Occurs when we have received the list of users present in a channel.
|
||||
/// </summary>
|
||||
public event EventHandler<ChannelEventArgs> ChannelListReceived;
|
||||
|
||||
internal void OnChannelListReceived(ChannelEventArgs e)
|
||||
{
|
||||
ChannelListReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when we have received the topic of a channel.
|
||||
/// Occurs when we have received the topic of a channel.
|
||||
/// </summary>
|
||||
public event EventHandler<ChannelTopicEventArgs> ChannelTopicReceived;
|
||||
|
||||
internal void OnChannelTopicReceived(ChannelTopicEventArgs e)
|
||||
{
|
||||
ChannelTopicReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the IRC connection is established and it is safe to begin interacting with the server.
|
||||
/// Occurs when the IRC connection is established and it is safe to begin interacting with the server.
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> ConnectionComplete;
|
||||
|
||||
internal void OnConnectionComplete(EventArgs e)
|
||||
{
|
||||
ConnectionComplete?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when we receive server info (such as max nick length).
|
||||
/// Occurs when we receive server info (such as max nick length).
|
||||
/// </summary>
|
||||
public event EventHandler<SupportsEventArgs> ServerInfoReceived;
|
||||
|
||||
internal void OnServerInfoReceived(SupportsEventArgs e)
|
||||
{
|
||||
ServerInfoReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user is kicked.
|
||||
/// Occurs when a user is kicked.
|
||||
/// </summary>
|
||||
public event EventHandler<KickEventArgs> UserKicked;
|
||||
|
||||
internal void OnUserKicked(KickEventArgs e)
|
||||
{
|
||||
UserKicked?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a WHOIS response is received.
|
||||
/// Occurs when a WHOIS response is received.
|
||||
/// </summary>
|
||||
public event EventHandler<WhoIsReceivedEventArgs> WhoIsReceived;
|
||||
|
||||
internal void OnWhoIsReceived(WhoIsReceivedEventArgs e)
|
||||
{
|
||||
WhoIsReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user has changed their nick.
|
||||
/// Occurs when a user has changed their nick.
|
||||
/// </summary>
|
||||
public event EventHandler<NickChangedEventArgs> NickChanged;
|
||||
|
||||
internal void OnNickChanged(NickChangedEventArgs e)
|
||||
{
|
||||
NickChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a user has quit.
|
||||
/// Occurs when a user has quit.
|
||||
/// </summary>
|
||||
public event EventHandler<UserEventArgs> UserQuit;
|
||||
|
||||
internal void OnUserQuit(UserEventArgs e)
|
||||
{
|
||||
UserQuit?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a WHO (WHOX protocol) is received.
|
||||
/// Occurs when a WHO (WHOX protocol) is received.
|
||||
/// </summary>
|
||||
public event EventHandler<WhoxReceivedEventArgs> WhoxReceived;
|
||||
|
||||
internal void OnWhoxReceived(WhoxReceivedEventArgs e)
|
||||
{
|
||||
WhoxReceived?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +1,22 @@
|
|||
using System;
|
||||
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.
|
||||
/// 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.
|
||||
/// 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>>();
|
||||
Tags = Array.Empty<KeyValuePair<string, string>>();
|
||||
|
||||
if (rawMessage.StartsWith("@"))
|
||||
{
|
||||
|
@ -49,7 +25,7 @@ namespace ChatSharp
|
|||
|
||||
// Parse tags as key value pairs
|
||||
var tags = new List<KeyValuePair<string, string>>();
|
||||
foreach (string rawTag in rawTags.Split(';'))
|
||||
foreach (var 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
|
||||
|
@ -57,9 +33,9 @@ namespace ChatSharp
|
|||
|
||||
if (replacedTag.Contains("="))
|
||||
{
|
||||
string key = replacedTag.Substring(0, replacedTag.IndexOf("="));
|
||||
string value = replacedTag[(replacedTag.IndexOf("=") + 1)..];
|
||||
tag = new KeyValuePair<string, string>(key, value);
|
||||
var key = replacedTag.Substring(0, replacedTag.IndexOf("=", StringComparison.Ordinal));
|
||||
var value = replacedTag[(replacedTag.IndexOf("=", StringComparison.Ordinal) + 1)..];
|
||||
tag = new(key, value);
|
||||
}
|
||||
|
||||
tags.Add(tag);
|
||||
|
@ -87,22 +63,25 @@ namespace ChatSharp
|
|||
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>();
|
||||
Parameters = Array.Empty<string>();
|
||||
}
|
||||
|
||||
// Parse server-time message tag.
|
||||
|
@ -112,14 +91,44 @@ namespace ChatSharp
|
|||
if (Tags.Any(tag => tag.Key == "t"))
|
||||
{
|
||||
var tag = Tags.SingleOrDefault(x => x.Key == "t");
|
||||
Timestamp = new Timestamp(tag.Value, true);
|
||||
Timestamp = new(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);
|
||||
Timestamp = new(tag.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unparsed message.
|
||||
/// </summary>
|
||||
public string RawMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The message prefix.
|
||||
/// </summary>
|
||||
public string Prefix { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The message command.
|
||||
/// </summary>
|
||||
public string Command { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional parameters supplied with the message.
|
||||
/// </summary>
|
||||
public string[] Parameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The message tags.
|
||||
/// </summary>
|
||||
public KeyValuePair<string, string>[] Tags { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The message timestamp in ISO 8601 format.
|
||||
/// </summary>
|
||||
public Timestamp Timestamp { get; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when the server complains about IRC protocol errors.
|
||||
/// Raised when the server complains about IRC protocol errors.
|
||||
/// </summary>
|
||||
public class IrcProtocolException : Exception
|
||||
{
|
||||
|
@ -13,7 +13,6 @@ namespace ChatSharp
|
|||
|
||||
internal IrcProtocolException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,42 +4,40 @@ using System.Collections.Generic;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A user connected to IRC.
|
||||
/// A user connected to IRC.
|
||||
/// </summary>
|
||||
public class IrcUser : IEquatable<IrcUser>
|
||||
{
|
||||
internal IrcUser()
|
||||
{
|
||||
Channels = new ChannelCollection();
|
||||
ChannelModes = new Dictionary<IrcChannel, List<char?>>();
|
||||
Channels = new();
|
||||
ChannelModes = new();
|
||||
Account = "*";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an IrcUser given a hostmask or nick.
|
||||
/// Constructs an IrcUser given a hostmask or nick.
|
||||
/// </summary>
|
||||
public IrcUser(string host) : this()
|
||||
{
|
||||
if (!host.Contains("@") && !host.Contains("!"))
|
||||
{
|
||||
Nick = host;
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] mask = host.Split('@', '!');
|
||||
var mask = host.Split('@', '!');
|
||||
Nick = mask[0];
|
||||
User = mask[1];
|
||||
if (mask.Length <= 2)
|
||||
{
|
||||
Hostname = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Hostname = mask[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an IrcUser given a nick and user.
|
||||
/// Constructs an IrcUser given a nick and user.
|
||||
/// </summary>
|
||||
public IrcUser(string nick, string user) : this()
|
||||
{
|
||||
|
@ -50,7 +48,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an IRC user given a nick, user, and password.
|
||||
/// Constructs an IRC user given a nick, user, and password.
|
||||
/// </summary>
|
||||
public IrcUser(string nick, string user, string password) : this(nick, user)
|
||||
{
|
||||
|
@ -58,7 +56,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an IRC user given a nick, user, password, and real name.
|
||||
/// Constructs an IRC user given a nick, user, password, and real name.
|
||||
/// </summary>
|
||||
public IrcUser(string nick, string user, string password, string realName) : this(nick, user, password)
|
||||
{
|
||||
|
@ -66,59 +64,68 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user's nick.
|
||||
/// The user's nick.
|
||||
/// </summary>
|
||||
public string Nick { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's user (an IRC construct, a string that identifies your username).
|
||||
/// The user's user (an IRC construct, a string that identifies your username).
|
||||
/// </summary>
|
||||
public string User { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's password. Will not be set on anyone but your own user.
|
||||
/// The user's password. Will not be set on anyone but your own user.
|
||||
/// </summary>
|
||||
public string Password { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's mode.
|
||||
/// The user's mode.
|
||||
/// </summary>
|
||||
/// <value>The mode.</value>
|
||||
public string Mode { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's real name.
|
||||
/// The user's real name.
|
||||
/// </summary>
|
||||
/// <value>The name of the real.</value>
|
||||
public string RealName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's hostname.
|
||||
/// The user's hostname.
|
||||
/// </summary>
|
||||
public string Hostname { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Channels this user is present in. Note that this only includes channels you are
|
||||
/// also present in, even after a successful WHOIS.
|
||||
/// Channels this user is present in. Note that this only includes channels you are
|
||||
/// also present in, even after a successful WHOIS.
|
||||
/// </summary>
|
||||
/// <value>The channels.</value>
|
||||
public ChannelCollection Channels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's account. If 0 or *, the user is not logged in.
|
||||
/// Otherwise, the user is logged in with services.
|
||||
/// The user's account. If 0 or *, the user is not logged in.
|
||||
/// Otherwise, the user is logged in with services.
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
|
||||
internal Dictionary<IrcChannel, List<char?>> ChannelModes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This user's hostmask (nick!user@host).
|
||||
/// This user's hostmask (nick!user@host).
|
||||
/// </summary>
|
||||
public string Hostmask
|
||||
public string Hostmask => Nick + "!" + User + "@" + Hostname;
|
||||
|
||||
/// <summary>
|
||||
/// True if this user is equal to another (compares hostmasks).
|
||||
/// </summary>
|
||||
public bool Equals(IrcUser other)
|
||||
{
|
||||
get
|
||||
{
|
||||
return Nick + "!" + User + "@" + Hostname;
|
||||
}
|
||||
return other.Hostmask == Hostmask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the user matches the given mask. Can be used to check if a ban applies
|
||||
/// to this user, for example.
|
||||
/// Returns true if the user matches the given mask. Can be used to check if a ban applies
|
||||
/// to this user, for example.
|
||||
/// </summary>
|
||||
public bool Match(string mask)
|
||||
{
|
||||
|
@ -130,28 +137,33 @@ namespace ChatSharp
|
|||
if (Match(parts[0], Nick) && Match(parts[1], User) && Match(parts[2], Hostname))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given hostmask matches the given mask.
|
||||
/// Checks if the given hostmask matches the given mask.
|
||||
/// </summary>
|
||||
public static bool Match(string mask, string value)
|
||||
{
|
||||
if (value == null)
|
||||
value = string.Empty;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
for (; j < value.Length && i < mask.Length; j++)
|
||||
{
|
||||
if (mask[i] == '?')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else if (mask[i] == '*')
|
||||
{
|
||||
i++;
|
||||
if (i >= mask.Length)
|
||||
return true;
|
||||
while (++j < value.Length && value[j] != mask[i]) ;
|
||||
while (++j < value.Length && value[j] != mask[i])
|
||||
{
|
||||
}
|
||||
|
||||
if (j-- == value.Length)
|
||||
return false;
|
||||
}
|
||||
|
@ -161,20 +173,12 @@ namespace ChatSharp
|
|||
return false;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return i == mask.Length && j == value.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this user is equal to another (compares hostmasks).
|
||||
/// </summary>
|
||||
public bool Equals(IrcUser other)
|
||||
{
|
||||
return other.Hostmask == Hostmask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this user is equal to another (compares hostmasks).
|
||||
/// True if this user is equal to another (compares hostmasks).
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
|
@ -184,7 +188,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code of the user's hostmask.
|
||||
/// Returns the hash code of the user's hostmask.
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
|
@ -192,11 +196,11 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the user's hostmask.
|
||||
/// Returns the user's hostmask.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return Hostmask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ using System;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A mask that can be used to match against a user's hostmask in a channel list,
|
||||
/// such as banned users.
|
||||
/// A mask that can be used to match against a user's hostmask in a channel list,
|
||||
/// such as banned users.
|
||||
/// </summary>
|
||||
public class Mask
|
||||
{
|
||||
|
@ -16,17 +16,19 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user who created this mask.
|
||||
/// The user who created this mask.
|
||||
/// </summary>
|
||||
public IrcUser Creator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time this mask was added to the channel list.
|
||||
/// The time this mask was added to the channel list.
|
||||
/// </summary>
|
||||
/// <value>The creation time.</value>
|
||||
public DateTime CreationTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The mask string.
|
||||
/// The mask string.
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,83 +5,24 @@ using System.Linq;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of masks from a channel list.
|
||||
/// A collection of masks from a channel list.
|
||||
/// </summary>
|
||||
public class MaskCollection : IEnumerable<Mask>
|
||||
{
|
||||
internal MaskCollection()
|
||||
{
|
||||
Masks = new List<Mask>();
|
||||
Masks = new();
|
||||
}
|
||||
|
||||
private List<Mask> Masks { get; set; }
|
||||
private List<Mask> Masks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a mask to the collection. This only modifies the local mask list, changes are
|
||||
/// not flushed to the server.
|
||||
/// Returns the mask at the requested index.
|
||||
/// </summary>
|
||||
public void Add(Mask mask)
|
||||
{
|
||||
Masks.Add(mask);
|
||||
}
|
||||
public Mask this[int index] => Masks[index];
|
||||
|
||||
/// <summary>
|
||||
/// Removes a mask from the collection. This only modifies the local mask list, changes are
|
||||
/// not flushed to the server.
|
||||
/// </summary>
|
||||
public void Remove(Mask mask)
|
||||
{
|
||||
Masks.Remove(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this collection includes the given mask.
|
||||
/// </summary>
|
||||
public bool Contains(Mask mask)
|
||||
{
|
||||
return Masks.Contains(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this collection includes any masks that are equal to the given mask.
|
||||
/// </summary>
|
||||
public bool ContainsMask(Mask mask)
|
||||
{
|
||||
return Masks.Any(m => m.Value == mask.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the mask at the requested index.
|
||||
/// </summary>
|
||||
public Mask this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Masks[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if any mask matches the given user.
|
||||
/// </summary>
|
||||
public bool ContainsMatch(IrcUser user)
|
||||
{
|
||||
return Masks.Any(m => user.Match(m.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the mask that matches the given user.
|
||||
/// </summary>
|
||||
public Mask GetMatch(IrcUser user)
|
||||
{
|
||||
var match = Masks.FirstOrDefault(m => user.Match(m.Value));
|
||||
if (match == null)
|
||||
throw new KeyNotFoundException("No mask matches the specified user.");
|
||||
return match;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the masks in this collection.
|
||||
/// Enumerates over the masks in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<Mask> GetEnumerator()
|
||||
{
|
||||
|
@ -92,5 +33,58 @@ namespace ChatSharp
|
|||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a mask to the collection. This only modifies the local mask list, changes are
|
||||
/// not flushed to the server.
|
||||
/// </summary>
|
||||
public void Add(Mask mask)
|
||||
{
|
||||
Masks.Add(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a mask from the collection. This only modifies the local mask list, changes are
|
||||
/// not flushed to the server.
|
||||
/// </summary>
|
||||
public void Remove(Mask mask)
|
||||
{
|
||||
Masks.Remove(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this collection includes the given mask.
|
||||
/// </summary>
|
||||
public bool Contains(Mask mask)
|
||||
{
|
||||
return Masks.Contains(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this collection includes any masks that are equal to the given mask.
|
||||
/// </summary>
|
||||
public bool ContainsMask(Mask mask)
|
||||
{
|
||||
return Masks.Any(m => m.Value == mask.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if any mask matches the given user.
|
||||
/// </summary>
|
||||
public bool ContainsMatch(IrcUser user)
|
||||
{
|
||||
return Masks.Any(m => user.Match(m.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the mask that matches the given user.
|
||||
/// </summary>
|
||||
public Mask GetMatch(IrcUser user)
|
||||
{
|
||||
var match = Masks.FirstOrDefault(m => user.Match(m.Value));
|
||||
if (match == null)
|
||||
throw new KeyNotFoundException("No mask matches the specified user.");
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an IRC message sent from user-to-user or user-to-channel.
|
||||
/// Represents an IRC message sent from user-to-user or user-to-channel.
|
||||
/// </summary>
|
||||
public class PrivateMessage
|
||||
{
|
||||
|
@ -20,20 +20,23 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user that sent this message.
|
||||
/// The user that sent this message.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The message text.
|
||||
/// The message text.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source of the message (a nick or a channel name).
|
||||
/// The source of the message (a nick or a channel name).
|
||||
/// </summary>
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this message was posted to a channel.
|
||||
/// True if this message was posted to a channel.
|
||||
/// </summary>
|
||||
public bool IsChannelMessage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,10 @@ namespace ChatSharp
|
|||
{
|
||||
public RequestManager()
|
||||
{
|
||||
PendingOperations = new Dictionary<string, RequestOperation>();
|
||||
PendingOperations = new();
|
||||
}
|
||||
|
||||
internal Dictionary<string, RequestOperation> PendingOperations { get; private set; }
|
||||
internal Dictionary<string, RequestOperation> PendingOperations { get; }
|
||||
|
||||
public void QueueOperation(string key, RequestOperation operation)
|
||||
{
|
||||
|
@ -22,7 +22,8 @@ namespace ChatSharp
|
|||
|
||||
public RequestOperation PeekOperation(string key)
|
||||
{
|
||||
var realKey = PendingOperations.Keys.FirstOrDefault(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
|
||||
var realKey =
|
||||
PendingOperations.Keys.FirstOrDefault(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
|
||||
return PendingOperations[realKey];
|
||||
}
|
||||
|
||||
|
@ -36,13 +37,13 @@ namespace ChatSharp
|
|||
|
||||
internal class RequestOperation
|
||||
{
|
||||
public object State { get; set; }
|
||||
public Action<RequestOperation> Callback { get; set; }
|
||||
|
||||
public RequestOperation(object state, Action<RequestOperation> callback)
|
||||
{
|
||||
State = state;
|
||||
Callback = callback;
|
||||
}
|
||||
|
||||
public object State { get; set; }
|
||||
public Action<RequestOperation> Callback { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Information provided by the server about its featureset.
|
||||
/// Information provided by the server about its featureset.
|
||||
/// </summary>
|
||||
public class ServerInfo
|
||||
{
|
||||
|
@ -11,13 +11,94 @@ namespace ChatSharp
|
|||
{
|
||||
// Guess for some defaults
|
||||
Prefixes = new[] { "ovhaq", "@+%&~" };
|
||||
SupportedChannelModes = new ChannelModes();
|
||||
SupportedChannelModes = new();
|
||||
IsGuess = true;
|
||||
ExtendedWho = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mode for a given channel user list prefix.
|
||||
/// ChatSharp makes some assumptions about what the server supports in order to function properly.
|
||||
/// If it has not received a 005 message giving it accurate information, this value will be true.
|
||||
/// </summary>
|
||||
public bool IsGuess { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nick prefixes for special modes in channel user lists
|
||||
/// </summary>
|
||||
public string[] Prefixes { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supported channel prefixes (i.e. '#')
|
||||
/// </summary>
|
||||
public char[] ChannelTypes { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Channel modes supported by this server
|
||||
/// </summary>
|
||||
public ChannelModes SupportedChannelModes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of MODE changes possible with a single command
|
||||
/// </summary>
|
||||
public int? MaxModesPerCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of channels a user may join
|
||||
/// </summary>
|
||||
public int? MaxChannelsPerUser { get; set; } // TODO: Support more than just # channels
|
||||
|
||||
/// <summary>
|
||||
/// Maximum length of user nicks on this server
|
||||
/// </summary>
|
||||
public int? MaxNickLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The limits imposed on list modes, such as +b
|
||||
/// </summary>
|
||||
public ModeListLimit[] ModeListLimits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the network, as identified by the server
|
||||
/// </summary>
|
||||
public string NetworkName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to ban exception character if this server supports ban exceptions
|
||||
/// </summary>
|
||||
public char? SupportsBanExceptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to invite exception character if this server supports invite exceptions
|
||||
/// </summary>
|
||||
public char? SupportsInviteExceptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to maximum topic length for this server
|
||||
/// </summary>
|
||||
public int? MaxTopicLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to the maximum length of a KICK comment
|
||||
/// </summary>
|
||||
public int? MaxKickCommentLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to the maximum length of a channel name
|
||||
/// </summary>
|
||||
public int? MaxChannelNameLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to the maximum length of an away message
|
||||
/// </summary>
|
||||
public int? MaxAwayLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server supports WHOX (WHO extension)
|
||||
/// </summary>
|
||||
public bool ExtendedWho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mode for a given channel user list prefix.
|
||||
/// </summary>
|
||||
public char? GetModeForPrefix(char prefix)
|
||||
{
|
||||
|
@ -27,8 +108,8 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel modes for a given user nick.
|
||||
/// Returns an empty array if user has no modes.
|
||||
/// Gets the channel modes for a given user nick.
|
||||
/// Returns an empty array if user has no modes.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<char?> GetModesForNick(string nick)
|
||||
|
@ -37,8 +118,7 @@ namespace ChatSharp
|
|||
List<char?> modeList = new();
|
||||
List<char> nickPrefixes = new();
|
||||
|
||||
foreach (char prefix in supportedPrefixes)
|
||||
{
|
||||
foreach (var prefix in supportedPrefixes)
|
||||
if (nick.Contains(prefix))
|
||||
{
|
||||
_ = nick.Remove(nick.IndexOf(prefix));
|
||||
|
@ -50,79 +130,12 @@ namespace ChatSharp
|
|||
modeList.Add(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modeList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ChatSharp makes some assumptions about what the server supports in order to function properly.
|
||||
/// If it has not received a 005 message giving it accurate information, this value will be true.
|
||||
/// </summary>
|
||||
public bool IsGuess { get; internal set; }
|
||||
/// <summary>
|
||||
/// Nick prefixes for special modes in channel user lists
|
||||
/// </summary>
|
||||
public string[] Prefixes { get; internal set; }
|
||||
/// <summary>
|
||||
/// Supported channel prefixes (i.e. '#')
|
||||
/// </summary>
|
||||
public char[] ChannelTypes { get; internal set; }
|
||||
/// <summary>
|
||||
/// Channel modes supported by this server
|
||||
/// </summary>
|
||||
public ChannelModes SupportedChannelModes { get; set; }
|
||||
/// <summary>
|
||||
/// The maximum number of MODE changes possible with a single command
|
||||
/// </summary>
|
||||
public int? MaxModesPerCommand { get; set; }
|
||||
/// <summary>
|
||||
/// The maximum number of channels a user may join
|
||||
/// </summary>
|
||||
public int? MaxChannelsPerUser { get; set; } // TODO: Support more than just # channels
|
||||
/// <summary>
|
||||
/// Maximum length of user nicks on this server
|
||||
/// </summary>
|
||||
public int? MaxNickLength { get; set; }
|
||||
/// <summary>
|
||||
/// The limits imposed on list modes, such as +b
|
||||
/// </summary>
|
||||
public ModeListLimit[] ModeListLimits { get; set; }
|
||||
/// <summary>
|
||||
/// The name of the network, as identified by the server
|
||||
/// </summary>
|
||||
public string NetworkName { get; set; }
|
||||
/// <summary>
|
||||
/// Set to ban exception character if this server supports ban exceptions
|
||||
/// </summary>
|
||||
public char? SupportsBanExceptions { get; set; }
|
||||
/// <summary>
|
||||
/// Set to invite exception character if this server supports invite exceptions
|
||||
/// </summary>
|
||||
public char? SupportsInviteExceptions { get; set; }
|
||||
/// <summary>
|
||||
/// Set to maximum topic length for this server
|
||||
/// </summary>
|
||||
public int? MaxTopicLength { get; set; }
|
||||
/// <summary>
|
||||
/// Set to the maximum length of a KICK comment
|
||||
/// </summary>
|
||||
public int? MaxKickCommentLength { get; set; }
|
||||
/// <summary>
|
||||
/// Set to the maximum length of a channel name
|
||||
/// </summary>
|
||||
public int? MaxChannelNameLength { get; set; }
|
||||
/// <summary>
|
||||
/// Set to the maximum length of an away message
|
||||
/// </summary>
|
||||
public int? MaxAwayLength { get; set; }
|
||||
/// <summary>
|
||||
/// Server supports WHOX (WHO extension)
|
||||
/// </summary>
|
||||
public bool ExtendedWho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modes a server supports that are applicable to channels.
|
||||
/// Modes a server supports that are applicable to channels.
|
||||
/// </summary>
|
||||
public class ChannelModes
|
||||
{
|
||||
|
@ -137,29 +150,33 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modes that are used for lists (i.e. bans).
|
||||
/// Modes that are used for lists (i.e. bans).
|
||||
/// </summary>
|
||||
public string ChannelLists { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modes that can be set on a user of a channel (i.e. ops, voice, etc).
|
||||
/// Modes that can be set on a user of a channel (i.e. ops, voice, etc).
|
||||
/// </summary>
|
||||
public string ChannelUserModes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modes that take a parameter (i.e. +k).
|
||||
/// Modes that take a parameter (i.e. +k).
|
||||
/// </summary>
|
||||
public string ParameterizedSettings { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modes that take an optional parameter (i.e. +f).
|
||||
/// Modes that take an optional parameter (i.e. +f).
|
||||
/// </summary>
|
||||
public string OptionallyParameterizedSettings { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modes that change channel settings.
|
||||
/// Modes that change channel settings.
|
||||
/// </summary>
|
||||
public string Settings { get; internal set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limits imposed on channel lists, such as the maximum bans per channel.
|
||||
/// Limits imposed on channel lists, such as the maximum bans per channel.
|
||||
/// </summary>
|
||||
public class ModeListLimit
|
||||
{
|
||||
|
@ -170,13 +187,14 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The mode character this applies to (i.e. 'b')
|
||||
/// The mode character this applies to (i.e. 'b')
|
||||
/// </summary>
|
||||
public char Mode { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum entries for this list.
|
||||
/// The maximum entries for this list.
|
||||
/// </summary>
|
||||
public int Maximum { get; internal set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,31 +4,24 @@ using System.Globalization;
|
|||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a message timestamp received from a server.
|
||||
/// Represents a message timestamp received from a server.
|
||||
/// </summary>
|
||||
public class Timestamp
|
||||
{
|
||||
/// <summary>
|
||||
/// A date representation of the timestamp.
|
||||
/// </summary>
|
||||
public DateTime Date { get; internal set; }
|
||||
/// <summary>
|
||||
/// A unix epoch representation of the timestamp.
|
||||
/// </summary>
|
||||
public double UnixTimestamp { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and parses the timestamp received from the server.
|
||||
/// Initializes and parses the timestamp received from the server.
|
||||
/// </summary>
|
||||
/// <param name="date"></param>
|
||||
/// <param name="compatibility">Enable pre-ZNC 1.0 compatibility. In previous versions of the tag,
|
||||
/// servers sent a unix timestamp instead of a ISO 8601 string.</param>
|
||||
/// <param name="compatibility">
|
||||
/// Enable pre-ZNC 1.0 compatibility. In previous versions of the tag,
|
||||
/// servers sent a unix timestamp instead of a ISO 8601 string.
|
||||
/// </param>
|
||||
internal Timestamp(string date, bool compatibility = false)
|
||||
{
|
||||
if (!compatibility)
|
||||
{
|
||||
DateTime parsedDate;
|
||||
if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out parsedDate))
|
||||
if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind,
|
||||
out var parsedDate))
|
||||
throw new ArgumentException("The date string was provided in an invalid format.", date);
|
||||
|
||||
Date = parsedDate;
|
||||
|
@ -36,8 +29,7 @@ namespace ChatSharp
|
|||
}
|
||||
else
|
||||
{
|
||||
double parsedTimestamp;
|
||||
if (!double.TryParse(date, out parsedTimestamp))
|
||||
if (!double.TryParse(date, out var parsedTimestamp))
|
||||
throw new ArgumentException("The timestamp string was provided in an invalid format.", date);
|
||||
|
||||
UnixTimestamp = parsedTimestamp;
|
||||
|
@ -46,15 +38,25 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this timestamp is equal to another (compares unix timestamps).
|
||||
/// A date representation of the timestamp.
|
||||
/// </summary>
|
||||
public DateTime Date { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A unix epoch representation of the timestamp.
|
||||
/// </summary>
|
||||
public double UnixTimestamp { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this timestamp is equal to another (compares unix timestamps).
|
||||
/// </summary>
|
||||
public bool Equals(Timestamp other)
|
||||
{
|
||||
return other.UnixTimestamp == UnixTimestamp;
|
||||
return (int)other.UnixTimestamp == (int)UnixTimestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if this timestamp is equal to another (compares unix timestamps).
|
||||
/// True if this timestamp is equal to another (compares unix timestamps).
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
|
@ -64,7 +66,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a ISO 8601 string representation of the timestamp.
|
||||
/// Returns a ISO 8601 string representation of the timestamp.
|
||||
/// </summary>
|
||||
public string ToISOString()
|
||||
{
|
||||
|
@ -72,11 +74,11 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code of the unix timestamp.
|
||||
/// Returns the hash code of the unix timestamp.
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return UnixTimestamp.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A pool of users the client is aware of on the network. IrcUser objects in this
|
||||
/// pool are shared across the entire library (e.g. a PrivateMessage will reuse an
|
||||
/// IrcUser object from this poll).
|
||||
/// A pool of users the client is aware of on the network. IrcUser objects in this
|
||||
/// pool are shared across the entire library (e.g. a PrivateMessage will reuse an
|
||||
/// IrcUser object from this poll).
|
||||
/// </summary>
|
||||
public class UserPool : IEnumerable<IrcUser>
|
||||
{
|
||||
private List<IrcUser> Users { get; set; }
|
||||
|
||||
internal UserPool()
|
||||
{
|
||||
Users = new List<IrcUser>();
|
||||
Users = new();
|
||||
}
|
||||
|
||||
private List<IrcUser> Users { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IrcUser with the specified nick.
|
||||
/// Gets the IrcUser with the specified nick.
|
||||
/// </summary>
|
||||
public IrcUser this[string nick]
|
||||
{
|
||||
|
@ -31,6 +32,19 @@ namespace ChatSharp
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the users in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcUser> GetEnumerator()
|
||||
{
|
||||
return Users.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal void Add(IrcUser user)
|
||||
{
|
||||
if (Users.Any(u => u.Hostmask == user.Hostmask))
|
||||
|
@ -50,9 +64,9 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any user in the pool matches this mask. Note that not all users
|
||||
/// in the user pool will be fully populated, even if you set ClientSettings.WhoIsOnJoin
|
||||
/// to true (it takes time to whois everyone in your channels).
|
||||
/// Returns true if any user in the pool matches this mask. Note that not all users
|
||||
/// in the user pool will be fully populated, even if you set ClientSettings.WhoIsOnJoin
|
||||
/// to true (it takes time to whois everyone in your channels).
|
||||
/// </summary>
|
||||
public bool ContainsMask(string mask)
|
||||
{
|
||||
|
@ -60,7 +74,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any user in the pool has the specified nick.
|
||||
/// Returns true if any user in the pool has the specified nick.
|
||||
/// </summary>
|
||||
public bool Contains(string nick)
|
||||
{
|
||||
|
@ -68,7 +82,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given IrcUser is in the pool.
|
||||
/// Returns true if the given IrcUser is in the pool.
|
||||
/// </summary>
|
||||
public bool Contains(IrcUser user)
|
||||
{
|
||||
|
@ -87,6 +101,7 @@ namespace ChatSharp
|
|||
ret.Hostname = user.Hostname;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Add(user);
|
||||
return user;
|
||||
}
|
||||
|
@ -98,18 +113,5 @@ namespace ChatSharp
|
|||
return this[user.Nick];
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the users in this collection.
|
||||
/// </summary>
|
||||
public IEnumerator<IrcUser> GetEnumerator()
|
||||
{
|
||||
return Users.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A filtered view of the user pool.
|
||||
/// A filtered view of the user pool.
|
||||
/// </summary>
|
||||
public class UserPoolView : IEnumerable<IrcUser>
|
||||
{
|
||||
private IEnumerable<IrcUser> Users { get; set; }
|
||||
|
||||
internal UserPoolView(IEnumerable<IrcUser> users)
|
||||
{
|
||||
Users = users;
|
||||
}
|
||||
|
||||
private IEnumerable<IrcUser> Users { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IrcUser with the specified nick.
|
||||
/// Gets the IrcUser with the specified nick.
|
||||
/// </summary>
|
||||
public IrcUser this[string nick]
|
||||
{
|
||||
|
@ -29,18 +30,25 @@ namespace ChatSharp
|
|||
}
|
||||
}
|
||||
|
||||
internal IrcUser this[int index]
|
||||
internal IrcUser this[int index] => Users.ToList()[index];
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the users in this collection (with the filter applied).
|
||||
/// </summary>
|
||||
public IEnumerator<IrcUser> GetEnumerator()
|
||||
{
|
||||
get
|
||||
{
|
||||
return Users.ToList()[index];
|
||||
}
|
||||
return Users.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any user in the pool matches this mask. Note that not all users
|
||||
/// in the user pool will be fully populated, even if you set ClientSettings.WhoIsOnJoin
|
||||
/// to true (it takes time to whois everyone in your channels).
|
||||
/// Returns true if any user in the pool matches this mask. Note that not all users
|
||||
/// in the user pool will be fully populated, even if you set ClientSettings.WhoIsOnJoin
|
||||
/// to true (it takes time to whois everyone in your channels).
|
||||
/// </summary>
|
||||
public bool ContainsMask(string mask)
|
||||
{
|
||||
|
@ -48,7 +56,7 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any user in the pool has the specified nick.
|
||||
/// Returns true if any user in the pool has the specified nick.
|
||||
/// </summary>
|
||||
public bool Contains(string nick)
|
||||
{
|
||||
|
@ -56,25 +64,11 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given IrcUser is in the pool.
|
||||
/// Returns true if the given IrcUser is in the pool.
|
||||
/// </summary>
|
||||
public bool Contains(IrcUser user)
|
||||
{
|
||||
return Users.Any(u => u.Hostmask == user.Hostmask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the users in this collection (with the filter applied).
|
||||
/// </summary>
|
||||
public IEnumerator<IrcUser> GetEnumerator()
|
||||
{
|
||||
return Users.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +1,55 @@
|
|||
using System;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// The results of an IRC WHOIS query. Depending on the capabilities of the server you're connected to,
|
||||
/// some of these fields may be null.
|
||||
/// The results of an IRC WHOIS query. Depending on the capabilities of the server you're connected to,
|
||||
/// some of these fields may be null.
|
||||
/// </summary>
|
||||
public class WhoIs
|
||||
{
|
||||
internal WhoIs()
|
||||
{
|
||||
User = new IrcUser();
|
||||
User = new();
|
||||
SecondsIdle = -1;
|
||||
Channels = System.Array.Empty<string>();
|
||||
Channels = Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fully populated IrcUser, including hostname, real name, etc.
|
||||
/// A fully populated IrcUser, including hostname, real name, etc.
|
||||
/// </summary>
|
||||
public IrcUser User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of channels this user is joined to. Depending on the IRC network you connect to,
|
||||
/// this may omit channels that you are not present in.
|
||||
/// A list of channels this user is joined to. Depending on the IRC network you connect to,
|
||||
/// this may omit channels that you are not present in.
|
||||
/// </summary>
|
||||
public string[] Channels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the whois'd user is a network operator.
|
||||
/// If true, the whois'd user is a network operator.
|
||||
/// </summary>
|
||||
public bool IrcOp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Seconds since this user last interacted with IRC.
|
||||
/// Seconds since this user last interacted with IRC.
|
||||
/// </summary>
|
||||
public int SecondsIdle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The server this user is connected to.
|
||||
/// The server this user is connected to.
|
||||
/// </summary>
|
||||
public string Server { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional information about the server this user is connected to.
|
||||
/// Additional information about the server this user is connected to.
|
||||
/// </summary>
|
||||
/// <value>The server info.</value>
|
||||
public string ServerInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The nickserv account this user is logged into, if applicable.
|
||||
/// The nickserv account this user is logged into, if applicable.
|
||||
/// </summary>
|
||||
public string LoggedInAs { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace ChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// The results of an IRC WHO (WHOX protocol) query. Depending on what information you request,
|
||||
/// some of these fields may be null.
|
||||
/// The results of an IRC WHO (WHOX protocol) query. Depending on what information you request,
|
||||
/// some of these fields may be null.
|
||||
/// </summary>
|
||||
public class ExtendedWho
|
||||
{
|
||||
|
@ -11,7 +12,7 @@ namespace ChatSharp
|
|||
{
|
||||
QueryType = -1;
|
||||
Channel = "*";
|
||||
User = new IrcUser();
|
||||
User = new();
|
||||
IP = string.Empty;
|
||||
Server = string.Empty;
|
||||
Flags = string.Empty;
|
||||
|
@ -21,166 +22,199 @@ namespace ChatSharp
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of the query. Defaults to a randomly generated number so ChatSharp can keep
|
||||
/// track of WHOX queries it issues.
|
||||
/// Type of the query. Defaults to a randomly generated number so ChatSharp can keep
|
||||
/// track of WHOX queries it issues.
|
||||
/// </summary>
|
||||
public int QueryType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Channel name
|
||||
/// Channel name
|
||||
/// </summary>
|
||||
public string Channel { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// User
|
||||
/// User
|
||||
/// </summary>
|
||||
public IrcUser User { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Numeric IP address of the user (unresolved hostname)
|
||||
/// Numeric IP address of the user (unresolved hostname)
|
||||
/// </summary>
|
||||
public string IP { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server name
|
||||
/// Server name
|
||||
/// </summary>
|
||||
public string Server { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// User flags
|
||||
/// User flags
|
||||
/// </summary>
|
||||
public string Flags { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Distance, in hops
|
||||
/// Distance, in hops
|
||||
/// </summary>
|
||||
public int Hops { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time the user has been idle for
|
||||
/// Time the user has been idle for
|
||||
/// </summary>
|
||||
public int TimeIdle { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// OP level of the user in the channel
|
||||
/// OP level of the user in the channel
|
||||
/// </summary>
|
||||
public string OpLevel { get; internal set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Field matching flags for WHOX protocol.
|
||||
/// Field matching flags for WHOX protocol.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum WhoxFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not match any flag at all. By doing so, ircds defaults to 'nuhsr'
|
||||
/// (everything except the numeric IP).
|
||||
/// Do not match any flag at all. By doing so, ircds defaults to 'nuhsr'
|
||||
/// (everything except the numeric IP).
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Matches nick (in nick!user@host)
|
||||
/// Matches nick (in nick!user@host)
|
||||
/// </summary>
|
||||
Nick = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Matches username (in nick!user@host)
|
||||
/// Matches username (in nick!user@host)
|
||||
/// </summary>
|
||||
Username = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Matches hostname (in nick!user@host)
|
||||
/// Matches hostname (in nick!user@host)
|
||||
/// </summary>
|
||||
Hostname = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Matches numeric IPs
|
||||
/// Matches numeric IPs
|
||||
/// </summary>
|
||||
NumericIp = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Matches server name
|
||||
/// Matches server name
|
||||
/// </summary>
|
||||
ServerName = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Matches informational text
|
||||
/// Matches informational text
|
||||
/// </summary>
|
||||
Info = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Matches account name
|
||||
/// Matches account name
|
||||
/// </summary>
|
||||
AccountName = 64,
|
||||
|
||||
/// <summary>
|
||||
/// Matches visible and invisble users in a channel
|
||||
/// Matches visible and invisble users in a channel
|
||||
/// </summary>
|
||||
DelayedChanMembers = 128,
|
||||
|
||||
/// <summary>
|
||||
/// Matches IRC operators
|
||||
/// Matches IRC operators
|
||||
/// </summary>
|
||||
IrcOp = 256,
|
||||
|
||||
/// <summary>
|
||||
/// Special purpose flag, normally only IRC ops have access to it.
|
||||
/// Special purpose flag, normally only IRC ops have access to it.
|
||||
/// </summary>
|
||||
Special = 512,
|
||||
|
||||
/// <summary>
|
||||
/// Matches all of the flags defined.
|
||||
/// Matches all of the flags defined.
|
||||
/// </summary>
|
||||
All = ~0
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information fields for WHOX protocol.
|
||||
/// Information fields for WHOX protocol.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum WhoxField
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not include any field at all.
|
||||
/// By doing so, ircds defaults to sending a normal WHO reply.
|
||||
/// Do not include any field at all.
|
||||
/// By doing so, ircds defaults to sending a normal WHO reply.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the querytype in the reply
|
||||
/// Includes the querytype in the reply
|
||||
/// </summary>
|
||||
QueryType = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the first channel name
|
||||
/// Includes the first channel name
|
||||
/// </summary>
|
||||
Channel = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the userID (username)
|
||||
/// Includes the userID (username)
|
||||
/// </summary>
|
||||
Username = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the IP
|
||||
/// Includes the IP
|
||||
/// </summary>
|
||||
UserIp = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the user's hostname
|
||||
/// Includes the user's hostname
|
||||
/// </summary>
|
||||
Hostname = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the server name
|
||||
/// Includes the server name
|
||||
/// </summary>
|
||||
ServerName = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the user's nick
|
||||
/// Includes the user's nick
|
||||
/// </summary>
|
||||
Nick = 64,
|
||||
|
||||
/// <summary>
|
||||
/// Includes all flags a user has
|
||||
/// Includes all flags a user has
|
||||
/// </summary>
|
||||
Flags = 128,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the "distance" in hops
|
||||
/// Includes the "distance" in hops
|
||||
/// </summary>
|
||||
Hops = 256,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the idle time (0 for remote users)
|
||||
/// Includes the idle time (0 for remote users)
|
||||
/// </summary>
|
||||
TimeIdle = 512,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the user's account name
|
||||
/// Includes the user's account name
|
||||
/// </summary>
|
||||
AccountName = 1024,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the user's op level in the channel
|
||||
/// Includes the user's op level in the channel
|
||||
/// </summary>
|
||||
OpLevel = 2048,
|
||||
|
||||
/// <summary>
|
||||
/// Includes the user's real name
|
||||
/// Includes the user's real name
|
||||
/// </summary>
|
||||
RealName = 4096,
|
||||
|
||||
/// <summary>
|
||||
/// Includes all fields defined
|
||||
/// Includes all fields defined
|
||||
/// </summary>
|
||||
All = ~0
|
||||
}
|
||||
|
@ -254,7 +288,6 @@ namespace ChatSharp
|
|||
result = string.Empty;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChatSharp\ChatSharp.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.*" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.3.246501">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChatSharp\ChatSharp.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/>
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.9"/>
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.3.310801">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.9"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ChatSharp.Tests
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace ChatSharp.Tests
|
|||
{
|
||||
try
|
||||
{
|
||||
IrcMessage fromMessage = new(@":user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
_ = new IrcMessage(@":user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -38,15 +38,16 @@ namespace ChatSharp.Tests
|
|||
public void NewValidMessage_Params()
|
||||
{
|
||||
IrcMessage fromMessage = new(@":user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
string[] compareParams = new string[] { "target", "Lorem ipsum dolor sit amet" };
|
||||
var compareParams = new[] { "target", "Lorem ipsum dolor sit amet" };
|
||||
CollectionAssert.AreEqual(fromMessage.Parameters, compareParams);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NewValidMessage_Tags()
|
||||
{
|
||||
IrcMessage fromMessage = new("@a=123;b=456;c=789 :user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
KeyValuePair<string, string>[] compareTags = new KeyValuePair<string, string>[]
|
||||
IrcMessage fromMessage =
|
||||
new("@a=123;b=456;c=789 :user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
var compareTags = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("a", "123"),
|
||||
new KeyValuePair<string, string>("b", "456"),
|
||||
|
@ -59,11 +60,11 @@ namespace ChatSharp.Tests
|
|||
public void NewValidMessage_Tags02()
|
||||
{
|
||||
IrcMessage fromMessage = new("@aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello");
|
||||
KeyValuePair<string, string>[] compareTags = new KeyValuePair<string, string>[]
|
||||
var compareTags = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("aaa", "bbb"),
|
||||
new KeyValuePair<string, string>("ccc", null),
|
||||
new KeyValuePair<string, string>("example.com/ddd", "eee"),
|
||||
new KeyValuePair<string, string>("example.com/ddd", "eee")
|
||||
};
|
||||
CollectionAssert.AreEqual(fromMessage.Tags, compareTags);
|
||||
}
|
||||
|
@ -71,12 +72,13 @@ namespace ChatSharp.Tests
|
|||
[TestMethod]
|
||||
public void NewValidMessage_TagsWithSemicolon()
|
||||
{
|
||||
IrcMessage fromMessage = new(@"@a=123\:456;b=456\:789;c=789\:123 :user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
KeyValuePair<string, string>[] compareTags = new KeyValuePair<string, string>[]
|
||||
IrcMessage fromMessage =
|
||||
new(@"@a=123\:456;b=456\:789;c=789\:123 :user!~ident@host PRIVMSG target :Lorem ipsum dolor sit amet");
|
||||
var compareTags = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("a", "123;456"),
|
||||
new KeyValuePair<string, string>("b", "456;789"),
|
||||
new KeyValuePair<string, string>("c", "789;123"),
|
||||
new KeyValuePair<string, string>("c", "789;123")
|
||||
};
|
||||
CollectionAssert.AreEqual(fromMessage.Tags, compareTags);
|
||||
}
|
||||
|
@ -85,10 +87,10 @@ namespace ChatSharp.Tests
|
|||
public void NewValidMessage_TagsNoValue()
|
||||
{
|
||||
IrcMessage fromMessage = new("@a=;b :nick!ident@host.com PRIVMSG me :Hello");
|
||||
KeyValuePair<string, string>[] compareTags = new KeyValuePair<string, string>[]
|
||||
var compareTags = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("a", ""),
|
||||
new KeyValuePair<string, string>("b", null),
|
||||
new KeyValuePair<string, string>("b", null)
|
||||
};
|
||||
CollectionAssert.AreEqual(fromMessage.Tags, compareTags);
|
||||
}
|
||||
|
@ -96,12 +98,14 @@ namespace ChatSharp.Tests
|
|||
[TestMethod]
|
||||
public void Timestamp_CompareISOString()
|
||||
{
|
||||
IrcMessage[] messages = {
|
||||
new IrcMessage("@time=2011-10-19T16:40:51.620Z :Angel!angel@example.org PRIVMSG Wiz :Hello"),
|
||||
new IrcMessage("@time=2012-06-30T23:59:59.419Z :John!~john@1.2.3.4 JOIN #chan")
|
||||
IrcMessage[] messages =
|
||||
{
|
||||
new("@time=2011-10-19T16:40:51.620Z :Angel!angel@example.org PRIVMSG Wiz :Hello"),
|
||||
new("@time=2012-06-30T23:59:59.419Z :John!~john@1.2.3.4 JOIN #chan")
|
||||
};
|
||||
|
||||
string[] timestamps = {
|
||||
string[] timestamps =
|
||||
{
|
||||
"2011-10-19T16:40:51.620Z",
|
||||
"2012-06-30T23:59:59.419Z"
|
||||
};
|
||||
|
@ -113,12 +117,14 @@ namespace ChatSharp.Tests
|
|||
[TestMethod]
|
||||
public void Timestamp_FromTimestamp()
|
||||
{
|
||||
IrcMessage[] messages = {
|
||||
new IrcMessage("@t=1504923966 :Angel!angel@example.org PRIVMSG Wiz :Hello"),
|
||||
new IrcMessage("@t=1504923972 :John!~john@1.2.3.4 JOIN #chan")
|
||||
IrcMessage[] messages =
|
||||
{
|
||||
new("@t=1504923966 :Angel!angel@example.org PRIVMSG Wiz :Hello"),
|
||||
new("@t=1504923972 :John!~john@1.2.3.4 JOIN #chan")
|
||||
};
|
||||
|
||||
string[] timestamps = {
|
||||
string[] timestamps =
|
||||
{
|
||||
"2017-09-09T02:26:06.000Z",
|
||||
"2017-09-09T02:26:12.000Z"
|
||||
};
|
||||
|
@ -130,7 +136,8 @@ namespace ChatSharp.Tests
|
|||
[TestMethod]
|
||||
public void Timestamp_FailOnLeap()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentException>(() => new IrcMessage("@time=2012-06-30T23:59:60.419Z :John!~john@1.2.3.4 JOIN #chan"));
|
||||
Assert.ThrowsException<ArgumentException>(() =>
|
||||
new IrcMessage("@time=2012-06-30T23:59:60.419Z :John!~john@1.2.3.4 JOIN #chan"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,4 +71,4 @@ namespace ChatSharp.Tests
|
|||
Assert.IsTrue(userModes.Count == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,4 +16,4 @@ using System.Runtime.InteropServices;
|
|||
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -42,13 +42,11 @@ On Linux/Mac:
|
|||
|
||||
On Windows, use Visual Studio or similar and build in Release mode.
|
||||
|
||||
Regardless of platform, you'll receive binaries in `ChatSharp/bin/Release/`.
|
||||
ChatSharp has no dependencies.
|
||||
Regardless of platform, you'll receive binaries in `ChatSharp/bin/Release/`. ChatSharp has no dependencies.
|
||||
|
||||
## Support
|
||||
|
||||
Open a [Github issue](https://github.com/SirCmpwn/ChatSharp/issues) describing
|
||||
your problem.
|
||||
Open a [Github issue](https://github.com/SirCmpwn/ChatSharp/issues) describing your problem.
|
||||
|
||||
## Development / Contributing
|
||||
|
||||
|
|
Loading…
Reference in New Issue