Implement channel ban, exception, and invite list management

This commit is contained in:
Les De Ridder 2017-05-14 04:59:11 +02:00
parent 7df8c916b7
commit f50f602eea
No known key found for this signature in database
GPG Key ID: 5EC132DFA85DB372
3 changed files with 110 additions and 4 deletions

View File

@ -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'))

View File

@ -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

View File

@ -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);