Implement channel ban, exception, and invite list management
This commit is contained in:
parent
7df8c916b7
commit
f50f602eea
|
@ -6,6 +6,7 @@ import std.string;
|
||||||
import ircd.connection;
|
import ircd.connection;
|
||||||
import ircd.server;
|
import ircd.server;
|
||||||
import ircd.message;
|
import ircd.message;
|
||||||
|
import ircd.helpers;
|
||||||
|
|
||||||
class Channel
|
class Channel
|
||||||
{
|
{
|
||||||
|
@ -15,6 +16,7 @@ class Channel
|
||||||
Connection[] members;
|
Connection[] members;
|
||||||
char[] modes;
|
char[] modes;
|
||||||
char[][Connection] memberModes;
|
char[][Connection] memberModes;
|
||||||
|
string[][char] maskLists;
|
||||||
|
|
||||||
string key; //TODO: Fully implement key
|
string key; //TODO: Fully implement key
|
||||||
//TODO: Implement member limit (+l)
|
//TODO: Implement member limit (+l)
|
||||||
|
@ -24,14 +26,13 @@ class Channel
|
||||||
this(string name, Server server)
|
this(string name, Server server)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.members = [];
|
|
||||||
this._server = server;
|
this._server = server;
|
||||||
|
this.maskLists = ['b' : [], 'e' : [], 'I' : []];
|
||||||
}
|
}
|
||||||
|
|
||||||
void join(Connection connection)
|
void join(Connection connection)
|
||||||
{
|
{
|
||||||
members ~= connection;
|
members ~= connection;
|
||||||
memberModes[connection] = null;
|
|
||||||
|
|
||||||
if(members.length == 1)
|
if(members.length == 1)
|
||||||
{
|
{
|
||||||
|
@ -198,6 +199,60 @@ class Channel
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool addMaskListEntry(Connection origin, string mask, char mode)
|
||||||
|
{
|
||||||
|
if(maskLists[mode].canFind!(m => m.toIRCLower == mask.toIRCLower))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
maskLists[mode] ~= mask;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeMaskListEntry(Connection origin, string mask, char mode)
|
||||||
|
{
|
||||||
|
if(!maskLists[mode].canFind!(m => m.toIRCLower == mask.toIRCLower))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
maskLists[mode] = maskLists[mode].remove!(m => m.toIRCLower == mask.toIRCLower);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendBanList(Connection connection)
|
||||||
|
{
|
||||||
|
foreach(entry; maskLists['b'])
|
||||||
|
{
|
||||||
|
connection.send(Message(_server.name, "367", [connection.nick, name, entry], false));
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.send(Message(_server.name, "368", [connection.nick, name, "End of channel ban list"], true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendExceptList(Connection connection)
|
||||||
|
{
|
||||||
|
foreach(entry; maskLists['e'])
|
||||||
|
{
|
||||||
|
connection.send(Message(_server.name, "348", [connection.nick, name, entry], false));
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.send(Message(_server.name, "349", [connection.nick, name, "End of channel exception list"], true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendInviteList(Connection connection)
|
||||||
|
{
|
||||||
|
foreach(entry; maskLists['I'])
|
||||||
|
{
|
||||||
|
connection.send(Message(_server.name, "346", [connection.nick, name, entry], false));
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.send(Message(_server.name, "347", [connection.nick, name, "End of channel invite list"], true));
|
||||||
|
}
|
||||||
|
|
||||||
string prefixedNick(Connection member)
|
string prefixedNick(Connection member)
|
||||||
{
|
{
|
||||||
if(memberModes[member].canFind('o'))
|
if(memberModes[member].canFind('o'))
|
||||||
|
|
|
@ -79,6 +79,11 @@ class Connection
|
||||||
return !modes.canFind('i') || channels.any!(c => c.members.canFind(other));
|
return !modes.canFind('i') || channels.any!(c => c.members.canFind(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool matchesMask(string mask)
|
||||||
|
{
|
||||||
|
return wildcardMatch(prefix.toIRCLower, mask.toIRCLower);
|
||||||
|
}
|
||||||
|
|
||||||
void send(Message message)
|
void send(Message message)
|
||||||
{
|
{
|
||||||
string messageString = message.toString;
|
string messageString = message.toString;
|
||||||
|
@ -895,9 +900,22 @@ class Connection
|
||||||
{
|
{
|
||||||
channel.sendModes(this);
|
channel.sendModes(this);
|
||||||
}
|
}
|
||||||
|
//TODO: If RFC-strictness is off, also allow '+e' and '+I' (?)
|
||||||
else if(message.parameters.length == 2 && ["+b", "e", "I"].canFind(message.parameters[1]))
|
else if(message.parameters.length == 2 && ["+b", "e", "I"].canFind(message.parameters[1]))
|
||||||
{
|
{
|
||||||
notImplemented("querying ban/exception/invite lists");
|
auto listChar = message.parameters[1][$ - 1];
|
||||||
|
final switch(listChar)
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
channel.sendBanList(this);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
channel.sendExceptList(this);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
channel.sendInviteList(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -932,7 +950,7 @@ Lforeach:
|
||||||
//when RFC-strictness is off, maybe send an error when trying to do an illegal change
|
//when RFC-strictness is off, maybe send an error when trying to do an illegal change
|
||||||
switch(mode)
|
switch(mode)
|
||||||
{
|
{
|
||||||
//TODO: When RFC-strictness is on, limit mode changes with parameter to 3 per command
|
//TODO: If RFC-strictness is on, limit mode changes with parameter to 3 per command
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -966,6 +984,31 @@ Lforeach:
|
||||||
processedParameters ~= memberNick;
|
processedParameters ~= memberNick;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'b': //TODO: Implement bans
|
||||||
|
case 'e': //TODO: Implement ban exceptions
|
||||||
|
case 'I': //TODO: Implement invite lists
|
||||||
|
if(i + 1 == message.parameters.length)
|
||||||
|
{
|
||||||
|
//TODO: Figure out what to do when we need more mode parameters
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
auto mask = message.parameters[++i];
|
||||||
|
//TODO: If RFC-strictness is off, interpret '<nick>' as '<nick>!*@*'
|
||||||
|
if(!Server.isValidUserMask(mask))
|
||||||
|
{
|
||||||
|
//TODO: If RFC-strictness is off, send an error
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto success = false;
|
||||||
|
if(add) success = channel.addMaskListEntry(this, mask, mode);
|
||||||
|
else success = channel.removeMaskListEntry(this, mask, mode);
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
processedModes ~= mode;
|
||||||
|
processedParameters ~= mask;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'i': //TODO: Implement invite-only channels
|
case 'i': //TODO: Implement invite-only channels
|
||||||
case 'm': //TODO: Implement channel moderation
|
case 'm': //TODO: Implement channel moderation
|
||||||
case 'n': //TODO: Implement the no messages from clients on the outside flag
|
case 'n': //TODO: Implement the no messages from clients on the outside flag
|
||||||
|
|
|
@ -99,6 +99,14 @@ class Server
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isValidUserMask(string mask)
|
||||||
|
{
|
||||||
|
import std.regex : ctRegex, matchFirst;
|
||||||
|
|
||||||
|
auto validMaskRegex = ctRegex!r"^([^!]+)!([^@]+)@(.+)$";
|
||||||
|
return !mask.matchFirst(validMaskRegex).empty;
|
||||||
|
}
|
||||||
|
|
||||||
Connection[] findConnectionByNick(string nick)
|
Connection[] findConnectionByNick(string nick)
|
||||||
{
|
{
|
||||||
return connections.find!(c => c.nick.toIRCLower == nick.toIRCLower);
|
return connections.find!(c => c.nick.toIRCLower == nick.toIRCLower);
|
||||||
|
|
Loading…
Reference in New Issue