Implement NAMES

This commit is contained in:
Les De Ridder 2017-03-21 02:24:33 +01:00
parent 8a94d845e8
commit 0fa5f06bd0
No known key found for this signature in database
GPG Key ID: 5EC132DFA85DB372
3 changed files with 92 additions and 4 deletions

View File

@ -28,12 +28,31 @@ class Channel
this._server = server;
}
void sendNames(Connection connection)
void sendNames(Connection connection, bool sendRplEndOfNames = true)
{
enum channelType = "="; //TODO: Support secret and private channels
string channelType;
connection.send(Message(_server.name, "353", [connection.nick, channelType, name, members.map!(m => m.nick).join(' ')], true));
connection.send(Message(_server.name, "366", [connection.nick, name, "End of NAMES list"], true));
if(modes.canFind('s'))
{
channelType = "@";
}
else if(modes.canFind('p'))
{
channelType = "*";
}
else
{
channelType = "=";
}
auto onChannel = members.canFind(connection);
connection.send(Message(_server.name, "353", [connection.nick, channelType, name, members.filter!(m => onChannel || !m.modes.canFind('i')).map!(m => m.nick).join(' ')], true));
if(sendRplEndOfNames)
{
connection.sendRplEndOfNames(name);
}
}
void sendPrivMsg(Connection sender, string text)
@ -73,4 +92,9 @@ class Channel
member.send(Message(connection.mask, "TOPIC", [name, newTopic], true));
}
}
bool visibleTo(Connection connection)
{
return members.canFind(connection) || !modes.canFind('s') && !modes.canFind('p');
}
}

View File

@ -153,6 +153,10 @@ class Connection
if(!registered) sendErrNotRegistered();
else onTopic(message);
break;
case "NAMES":
if(!registered) sendErrNotRegistered();
else onNames(message);
break;
default:
writeln("unknown command '", message.command, "'");
send(Message(_server.name, "421", [nick, message.command, "Unknown command"]));
@ -449,6 +453,34 @@ class Connection
}
}
void onNames(Message message)
{
if(message.parameters.length > 1)
{
notImplemented("forwarding NAMES to another server");
return;
}
if(message.parameters.length == 0)
{
_server.sendGlobalNames(this);
}
else
{
foreach(channelName; message.parameters[0].split(','))
{
if(_server.channels.canFind!(c => c.name == channelName && c.visibleTo(this)))
{
_server.sendChannelNames(this, channelName);
}
else
{
sendRplEndOfNames(channelName);
}
}
}
}
void sendWhoReply(string channel, Connection user, uint hopCount)
{
auto flags = user.modes.canFind('a') ? "G" : "H";
@ -463,6 +495,11 @@ class Connection
send(Message(_server.name, "301", [nick, target, message], true));
}
void sendRplEndOfNames(string channelName)
{
send(Message(_server.name, "366", [nick, channelName, "End of NAMES list"], true));
}
void sendErrNoSuchNick(string name)
{
send(Message(_server.name, "401", [nick, name, "No such nick/channel"], true));
@ -498,6 +535,11 @@ class Connection
send(Message(_server.name, "482", [nick, channel, "You're not channel operator"], true));
}
void notImplemented(string description)
{
send(Message(_server.name, "ERROR", ["Not implemented yet (" ~ description ~ ")"], true));
}
void sendWelcome()
{
send(Message(_server.name, "001", [nick, "Welcome to the Internet Relay Network " ~ mask], true));

View File

@ -211,6 +211,28 @@ class Server
channel.setTopic(origin, newTopic);
}
void sendChannelNames(Connection connection, string channelName)
{
auto channel = channels.find!(c => c.name == channelName)[0];
channel.sendNames(connection);
}
void sendGlobalNames(Connection connection)
{
foreach(channel; channels.filter!(c => c.visibleTo(connection)))
{
channel.sendNames(connection, false);
}
auto otherUsers = connections.filter!(c => !c.modes.canFind('i') && c.channels.filter!(ch => !ch.modes.canFind('s') && !ch.modes.canFind('p')).empty);
if(!otherUsers.empty)
{
connection.send(Message(name, "353", [connection.nick, "=", "*", otherUsers.map!(m => m.nick).join(' ')], true));
}
connection.sendRplEndOfNames("*");
}
void listen(ushort port = 6667)
{
listenTCP(port, &acceptConnection);