Support IRCv3.1 multi-prefix capability

- This client capability will make the server send us all prefixes a user may have in NAMES and WHO messages.

- http://ircv3.net/specs/extensions/multi-prefix-3.1.html
This commit is contained in:
Alexandre Oliveira 2017-08-25 22:13:59 -03:00
parent fac0878e00
commit 879580ccde
7 changed files with 135 additions and 30 deletions

View File

@ -58,31 +58,25 @@ namespace ChatSharp.Handlers
{
var channel = client.Channels[message.Parameters[2]];
var users = message.Parameters[3].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var nick in users)
foreach (var rawNick in users)
{
if (string.IsNullOrWhiteSpace(nick))
if (string.IsNullOrWhiteSpace(rawNick))
continue;
var mode = client.ServerInfo.GetModeForPrefix(nick[0]);
if (mode == null)
{
var user = client.Users.GetOrAdd(nick);
if (!user.Channels.Contains(channel))
user.Channels.Add(channel);
if (!user.ChannelModes.ContainsKey(channel))
user.ChannelModes.Add(channel, null);
else
user.ChannelModes[channel] = null;
}
var nick = rawNick;
var modes = client.ServerInfo.GetModesForNick(nick);
if (modes.Count > 0)
nick = rawNick.Remove(0, modes.Count);
var user = client.Users.GetOrAdd(nick);
if (!user.Channels.Contains(channel))
user.Channels.Add(channel);
if (!user.ChannelModes.ContainsKey(channel))
user.ChannelModes.Add(channel, modes);
else
{
var user = client.Users.GetOrAdd(nick.Substring(1));
if (!user.Channels.Contains(channel))
user.Channels.Add(channel);
if (!user.ChannelModes.ContainsKey(channel))
user.ChannelModes.Add(channel, mode.Value);
else
user.ChannelModes[channel] = mode.Value;
}
user.ChannelModes[channel] = modes;
}
}

View File

@ -1,5 +1,6 @@
using ChatSharp.Events;
using System.Linq;
using System.Collections.Generic;
using System;
namespace ChatSharp.Handlers
@ -182,15 +183,16 @@ namespace ChatSharp.Handlers
new UserPoolView(channel.Users.Where(u =>
{
if (!u.ChannelModes.ContainsKey(channel))
u.ChannelModes.Add(channel, null);
return u.ChannelModes[channel] == c;
u.ChannelModes.Add(channel, new List<char?>());
return u.ChannelModes[channel].Contains(c);
})));
}
var user = new IrcUser(message.Parameters[i]);
if (add)
{
if (!channel.UsersByMode[c].Contains(user.Nick))
user.ChannelModes[channel] = c;
if (!user.ChannelModes[channel].Contains(c))
user.ChannelModes[channel].Add(c);
}
else
{

View File

@ -158,7 +158,7 @@ namespace ChatSharp
Users = new UserPool();
Users.Add(User); // Add self to user pool
Capabilities = new CapabilityPool();
Capabilities.AddRange(new string[] { "server-time" }); // List of supported capabilities
Capabilities.AddRange(new string[] { "server-time", "multi-prefix" }); // List of supported capabilities
}
/// <summary>

View File

@ -12,7 +12,7 @@ namespace ChatSharp
internal IrcUser()
{
Channels = new ChannelCollection();
ChannelModes = new Dictionary<IrcChannel, char?>();
ChannelModes = new Dictionary<IrcChannel, List<char?>>();
}
/// <summary>
@ -98,7 +98,7 @@ namespace ChatSharp
/// <value>The channels.</value>
public ChannelCollection Channels { get; set; }
internal Dictionary<IrcChannel, char?> ChannelModes { get; set; }
internal Dictionary<IrcChannel, List<char?>> ChannelModes { get; set; }
/// <summary>
/// This user's hostmask (nick!user@host).

View File

@ -1,3 +1,6 @@
using System.Collections.Generic;
using System.Linq;
namespace ChatSharp
{
/// <summary>
@ -8,7 +11,7 @@ namespace ChatSharp
internal ServerInfo()
{
// Guess for some defaults
Prefixes = new[] { "ov", "@+" };
Prefixes = new[] { "ovhaq", "@+%&~" };
SupportedChannelModes = new ChannelModes();
IsGuess = true;
}
@ -23,6 +26,35 @@ namespace ChatSharp
return Prefixes[0][Prefixes[1].IndexOf(prefix)];
}
/// <summary>
/// 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)
{
var supportedPrefixes = Prefixes[1];
List<char?> modeList = new List<char?>();
List<char> nickPrefixes = new List<char>();
foreach (char prefix in supportedPrefixes)
{
if (nick.Contains(prefix))
{
nick.Remove(nick.IndexOf(prefix));
if (!nickPrefixes.Contains(prefix))
{
nickPrefixes.Add(prefix);
var mode = GetModeForPrefix(prefix);
if (!modeList.Contains(mode))
modeList.Add(mode);
}
}
}
return modeList;
}
/// <summary>
/// ChatSharp makes some assumptions about what the server supports in order to function properly.
/// If it has not recieved a 005 message giving it accurate information, this value will be true.
@ -97,7 +129,7 @@ namespace ChatSharp
ParameterizedSettings = "k";
OptionallyParameterizedSettings = "flj";
Settings = string.Empty;
ChannelUserModes = "vo"; // I have no idea what I'm doing here
ChannelUserModes = "vhoaq"; // I have no idea what I'm doing here
}
/// <summary>

View File

@ -49,6 +49,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="IrcMessageTests.cs" />
<Compile Include="IrcUserTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,76 @@
using System;
using ChatSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ChatSharp.Tests
{
[TestClass]
public class IrcUserTests
{
[TestMethod]
public void GetUserModes_NotNull_FiveModes()
{
IrcUser user = new IrcUser("~&@%+aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 5);
}
[TestMethod]
public void GetUserModes_NotNull_FourModes()
{
IrcUser user = new IrcUser("&@%+aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 4);
}
[TestMethod]
public void GetUserModes_NotNull_ThreeModes()
{
IrcUser user = new IrcUser("@%+aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 3);
}
[TestMethod]
public void GetUserModes_NotNull_TwoModes()
{
IrcUser user = new IrcUser("%+aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 2);
}
[TestMethod]
public void GetUserModes_NotNull_OneMode()
{
IrcUser user = new IrcUser("+aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 1);
}
[TestMethod]
public void GetUserModes_IsNull()
{
IrcUser user = new IrcUser("aji", "user");
IrcClient client = new IrcClient("irc.address", user);
var userModes = client.ServerInfo.GetModesForNick(user.Nick);
Assert.IsTrue(userModes.Count == 0);
}
}
}