From 0fa5f06bd046e7d18acfe89cdcfe099718e143da Mon Sep 17 00:00:00 2001 From: Les De Ridder Date: Tue, 21 Mar 2017 02:24:33 +0100 Subject: [PATCH] Implement NAMES --- source/ircd/channel.d | 32 ++++++++++++++++++++++++++---- source/ircd/connection.d | 42 ++++++++++++++++++++++++++++++++++++++++ source/ircd/server.d | 22 +++++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/source/ircd/channel.d b/source/ircd/channel.d index 13443ea..c70a1e2 100644 --- a/source/ircd/channel.d +++ b/source/ircd/channel.d @@ -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'); + } } diff --git a/source/ircd/connection.d b/source/ircd/connection.d index 461fcd3..4f56fbe 100644 --- a/source/ircd/connection.d +++ b/source/ircd/connection.d @@ -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)); diff --git a/source/ircd/server.d b/source/ircd/server.d index d989ee4..f509c86 100644 --- a/source/ircd/server.d +++ b/source/ircd/server.d @@ -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);