Partially implement channel mode messasge
This commit is contained in:
parent
d4aaea4f99
commit
e507a38e0d
|
@ -16,6 +16,9 @@ class Channel
|
||||||
char[] modes;
|
char[] modes;
|
||||||
char[][Connection] memberModes;
|
char[][Connection] memberModes;
|
||||||
|
|
||||||
|
string key; //TODO: Fully implement key
|
||||||
|
//TODO: Implement member limit (+l)
|
||||||
|
|
||||||
private Server _server;
|
private Server _server;
|
||||||
|
|
||||||
this(string name, Server server)
|
this(string name, Server server)
|
||||||
|
@ -130,12 +133,81 @@ class Channel
|
||||||
memberModes.remove(user);
|
memberModes.remove(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendModes(Connection user)
|
||||||
|
{
|
||||||
|
if(members.canFind(user) && key !is null)
|
||||||
|
{
|
||||||
|
user.send(Message(_server.name, "324", [user.nick, name, "+" ~ modes.idup ~ "k", key]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user.send(Message(_server.name, "324", [user.nick, name, "+" ~ modes.idup]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setMemberMode(Connection setter, Connection target, char mode)
|
||||||
|
{
|
||||||
|
if(memberModes[target].canFind(mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memberModes[target] ~= mode;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unsetMemberMode(Connection setter, Connection target, char mode)
|
||||||
|
{
|
||||||
|
if(!memberModes[target].canFind(mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: byCodeUnit is necessary due to auto-decoding (https://wiki.dlang.org/Language_issues#Unicode_and_ranges)
|
||||||
|
import std.utf : byCodeUnit;
|
||||||
|
import std.range : array;
|
||||||
|
memberModes[target] = memberModes[target].byCodeUnit.remove!(m => m == mode).array;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setMode(Connection setter, char mode)
|
||||||
|
{
|
||||||
|
if(modes.canFind(mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
modes ~= mode;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unsetMode(Connection setter, char mode)
|
||||||
|
{
|
||||||
|
if(!modes.canFind(mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: byCodeUnit is necessary due to auto-decoding (https://wiki.dlang.org/Language_issues#Unicode_and_ranges)
|
||||||
|
import std.utf : byCodeUnit;
|
||||||
|
import std.range : array;
|
||||||
|
modes = modes.byCodeUnit.remove!(m => m == mode).array;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
string prefixedNick(Connection member)
|
string prefixedNick(Connection member)
|
||||||
{
|
{
|
||||||
if(memberModes[member].canFind('o'))
|
if(memberModes[member].canFind('o'))
|
||||||
{
|
{
|
||||||
return '@' ~ member.nick;
|
return '@' ~ member.nick;
|
||||||
}
|
}
|
||||||
|
else if(memberModes[member].canFind('v'))
|
||||||
|
{
|
||||||
|
return '+' ~ member.nick;
|
||||||
|
}
|
||||||
|
|
||||||
return member.nick;
|
return member.nick;
|
||||||
}
|
}
|
||||||
|
|
|
@ -507,8 +507,7 @@ class Connection
|
||||||
{
|
{
|
||||||
sendErrNotOnChannel(channelName);
|
sendErrNotOnChannel(channelName);
|
||||||
}
|
}
|
||||||
//TODO: Allow operators to set flags
|
else if(channels.find!(c => c.name.toIRCLower == channelName.toIRCLower).map!(c => c.modes.canFind('t') && !c.memberModes[this].canFind('o')).array[0])
|
||||||
else if(channels.find!(c => c.name.toIRCLower == channelName.toIRCLower).map!(c => c.modes.canFind('t') /* && this user isn't an operator */).array[0])
|
|
||||||
{
|
{
|
||||||
sendErrChanopPrivsNeeded(channelName);
|
sendErrChanopPrivsNeeded(channelName);
|
||||||
}
|
}
|
||||||
|
@ -607,7 +606,7 @@ class Connection
|
||||||
{
|
{
|
||||||
send(Message(_server.name, "443", [nick, targetUser.nick, channel.name, "is already on channel"], true));
|
send(Message(_server.name, "443", [nick, targetUser.nick, channel.name, "is already on channel"], true));
|
||||||
}
|
}
|
||||||
else if(channel.modes.canFind('i') /* TODO: and this connection isn't a chanop */)
|
else if(channel.modes.canFind('i') && !channel.memberModes[this].canFind('o'))
|
||||||
{
|
{
|
||||||
sendErrChanopPrivsNeeded(channel.name);
|
sendErrChanopPrivsNeeded(channel.name);
|
||||||
}
|
}
|
||||||
|
@ -832,7 +831,7 @@ class Connection
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message.parameters.count == 1)
|
if(message.parameters.length == 1)
|
||||||
{
|
{
|
||||||
send(Message(_server.name, "221", [nick, "+" ~ modes.idup]));
|
send(Message(_server.name, "221", [nick, "+" ~ modes.idup]));
|
||||||
}
|
}
|
||||||
|
@ -885,7 +884,116 @@ class Connection
|
||||||
|
|
||||||
void onChannelMode(Message message)
|
void onChannelMode(Message message)
|
||||||
{
|
{
|
||||||
notImplemented("channel mode message");
|
auto channelRange = _server.findChannelByName(message.parameters[0]);
|
||||||
|
if(channelRange.empty)
|
||||||
|
{
|
||||||
|
//TODO: If RFC-strictness is off, send an error message when the channel doesn't exist
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto channel = channelRange[0];
|
||||||
|
|
||||||
|
if(message.parameters.length == 1)
|
||||||
|
{
|
||||||
|
channel.sendModes(this);
|
||||||
|
}
|
||||||
|
else if(message.parameters.length == 2 && ["+b", "e", "I"].canFind(message.parameters[1]))
|
||||||
|
{
|
||||||
|
notImplemented("querying ban/exception/invite lists");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!channel.memberModes[this].canFind('o'))
|
||||||
|
{
|
||||||
|
sendErrChanopPrivsNeeded(channel.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i = 1; i < message.parameters.length; i++)
|
||||||
|
{
|
||||||
|
auto modeString = message.parameters[i];
|
||||||
|
auto add = modeString[0] == '+';
|
||||||
|
if(!add && modeString[0] != '-')
|
||||||
|
{
|
||||||
|
//TODO: If RFC-strictness is off, send a malformed message error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modeString.length == 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] processedModes;
|
||||||
|
string[] processedParameters;
|
||||||
|
|
||||||
|
auto changedModes = modeString[1 .. $];
|
||||||
|
Lforeach:
|
||||||
|
foreach(mode; changedModes)
|
||||||
|
{
|
||||||
|
//when RFC-strictness is off, maybe send an error when trying to do an illegal change
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case 'o':
|
||||||
|
case 'v':
|
||||||
|
if(i + 1 == message.parameters.length)
|
||||||
|
{
|
||||||
|
//TODO: Figure out what to do when we need more mode parameters
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
auto memberNick = message.parameters[++i];
|
||||||
|
|
||||||
|
auto memberRange = _server.findConnectionByNick(memberNick);
|
||||||
|
if(memberRange.empty)
|
||||||
|
{
|
||||||
|
sendErrNoSuchNick(memberNick);
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto member = memberRange[0];
|
||||||
|
if(!channel.members.canFind(member))
|
||||||
|
{
|
||||||
|
sendErrUserNotInChannel(memberNick, channel.name);
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto success = false;
|
||||||
|
if(add) success = channel.setMemberMode(this, member, mode);
|
||||||
|
else success = channel.unsetMemberMode(this, member, mode);
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
processedModes ~= mode;
|
||||||
|
processedParameters ~= memberNick;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'i': //TODO: Implement invite-only channels
|
||||||
|
case 'm': //TODO: Implement channel moderation
|
||||||
|
case 'n': //TODO: Implement the no messages from clients on the outside flag
|
||||||
|
case 'p':
|
||||||
|
case 's':
|
||||||
|
case 't':
|
||||||
|
auto success = false;
|
||||||
|
if(add) channel.setMode(this, mode);
|
||||||
|
else channel.unsetMode(this, mode);
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
processedModes ~= mode;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
send(Message(_server.name, "472", [nick, [mode], "is unknown mode char to me for " ~ channel.name], true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!processedModes.empty)
|
||||||
|
{
|
||||||
|
foreach(member; channel.members)
|
||||||
|
{
|
||||||
|
member.send(Message(mask, "MODE", [channel.name, (add ? '+' : '-') ~ processedModes.idup] ~ processedParameters, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendWhoReply(string channel, Connection user, uint hopCount)
|
void sendWhoReply(string channel, Connection user, uint hopCount)
|
||||||
|
|
Loading…
Reference in New Issue