diff --git a/source/ircd/channel.d b/source/ircd/channel.d index 45d04e8..8d33301 100644 --- a/source/ircd/channel.d +++ b/source/ircd/channel.d @@ -36,6 +36,24 @@ class Channel } } + void part(Connection connection, string partMessage) + { + foreach(member; members) + { + if(partMessage !is null) + { + member.send(Message(connection.mask, "PART", [name, partMessage], true)); + } + else + { + member.send(Message(connection.mask, "PART", [name])); + } + } + + members = members.remove!(m => m == connection); + memberModes.remove(connection); + } + void sendNames(Connection connection, bool sendRplEndOfNames = true) { string channelType; @@ -63,16 +81,6 @@ class Channel } } - string prefixedNick(Connection member) - { - if(memberModes[member].canFind('o')) - { - return '@' ~ member.nick; - } - - return member.nick; - } - void sendPrivMsg(Connection sender, string text) { foreach(member; members.filter!(m => m.nick != sender.nick)) @@ -111,6 +119,27 @@ class Channel } } + void kick(Connection kicker, Connection user, string comment) + { + foreach(member; members) + { + member.send(Message(kicker.mask, "KICK", [name, user.nick, comment], true)); + } + + members = members.remove!(m => m == user); + memberModes.remove(user); + } + + string prefixedNick(Connection member) + { + if(memberModes[member].canFind('o')) + { + return '@' ~ member.nick; + } + + return member.nick; + } + 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 3b2c027..01b96d6 100644 --- a/source/ircd/connection.d +++ b/source/ircd/connection.d @@ -213,6 +213,9 @@ class Connection case "KILL": onKill(message); break; + case "KICK": + onKick(message); + break; default: writeln("unknown command '", message.command, "'"); send(Message(_server.name, "421", [nick, message.command, "Unknown command"])); @@ -739,6 +742,60 @@ class Connection _server.kill(this, nick, comment); } + void onKick(Message message) + { + if(message.parameters.length < 2) + { + sendErrNeedMoreParams(message.command); + return; + } + + auto channelList = message.parameters[0].split(','); + auto userList = message.parameters[1].split(','); + auto comment = message.parameters.length > 2 ? message.parameters[2] : nick; + + if(channelList.length != 1 && channelList.length != userList.length) + { + //TODO: Figure out what the right error is here + sendErrNeedMoreParams(message.command); + return; + } + + foreach(i, nick; userList) + { + auto channelName = channelList[0]; + if(channelList.length != 1) + { + channelName = channelList[i]; + } + + if(!_server.canFindChannelByName(channelName)) + { + sendErrNoSuchChannel(channelName); + } + else + { + auto channel = _server.findChannelByName(channelName)[0]; + if(!channel.members.canFind(this)) + { + sendErrNotOnChannel(channelName); + } + else if(!channel.memberModes[this].canFind('o')) + { + sendErrChanopPrivsNeeded(channelName); + } + else if(!channel.members.canFind!(m => m.nick.toIRCLower == nick.toIRCLower)) + { + sendErrUserNotInChannel(nick, channelName); + } + else + { + _server.kick(this, channelName, nick, comment); + } + } + } + } + void sendWhoReply(string channel, Connection user, uint hopCount) { auto flags = user.modes.canFind('a') ? "G" : "H"; @@ -789,6 +846,11 @@ class Connection send(Message(_server.name, "431", [nick, "No nickname given"], true)); } + void sendErrUserNotInChannel(string otherNick, string channel) + { + send(Message(_server.name, "441", [nick, otherNick, channel, "They aren't on that channel"], true)); + } + void sendErrNotOnChannel(string channel) { send(Message(_server.name, "442", [nick, channel, "You're not on that channel"], true)); diff --git a/source/ircd/server.d b/source/ircd/server.d index dde1e1b..4314021 100644 --- a/source/ircd/server.d +++ b/source/ircd/server.d @@ -156,21 +156,9 @@ class Server { auto channel = connection.channels.array.find!(c => c.name.toIRCLower == channelName.toIRCLower)[0]; - foreach(member; channel.members) - { - if(partMessage !is null) - { - member.send(Message(connection.mask, "PART", [channelName, partMessage], true)); - } - else - { - member.send(Message(connection.mask, "PART", [channelName])); - } - } + channel.part(connection, partMessage); - channel.members = channel.members.remove!(m => m == connection); - - if(channel.members.length == 0) + if(channel.members.empty) { channels = channels.remove!(c => c == channel); } @@ -183,7 +171,7 @@ class Server { peers ~= channel.members; channel.members = channel.members.remove!(m => m == connection); - if(channel.members.length == 0) + if(channel.members.empty) { channels = channels.remove!(c => c == channel); } @@ -397,6 +385,14 @@ class Server user.closeConnection(); } + void kick(Connection kicker, string channelName, string nick, string comment) + { + auto channel = findChannelByName(channelName)[0]; + auto user = findConnectionByNick(nick)[0]; + + channel.kick(kicker, user, comment); + } + void listen(ushort port = 6667) { listenTCP(port, &acceptConnection);