Refactor numeric replies
This commit is contained in:
parent
be963dcf29
commit
d62993c800
|
@ -8,6 +8,7 @@ import ircd.connection;
|
|||
import ircd.server;
|
||||
import ircd.message;
|
||||
import ircd.helpers;
|
||||
import ircd.numerics;
|
||||
|
||||
//TODO: Make this a struct?
|
||||
class Channel
|
||||
|
@ -96,16 +97,14 @@ class Channel
|
|||
|
||||
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 => prefixedNick(m))
|
||||
.join(' ')
|
||||
], true));
|
||||
connection.sendNumeric!RPL_NAMREPLY(channelType, name,
|
||||
members.filter!(m => onChannel || !m.modes.canFind('i'))
|
||||
.map!(m => prefixedNick(m))
|
||||
.join(' '));
|
||||
|
||||
if (sendRplEndOfNames)
|
||||
{
|
||||
connection.sendRplEndOfNames(name);
|
||||
connection.sendNumeric!RPL_ENDOFNAMES(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,17 +127,9 @@ class Channel
|
|||
void sendTopic(Connection connection)
|
||||
{
|
||||
if (topic.empty)
|
||||
{
|
||||
connection.send(Message(_server.name, "331", [
|
||||
connection.nick, name, "No topic is set"
|
||||
]));
|
||||
}
|
||||
connection.sendNumeric!RPL_NOTOPIC(name);
|
||||
else
|
||||
{
|
||||
connection.send(Message(_server.name, "332", [
|
||||
connection.nick, name, topic
|
||||
], true));
|
||||
}
|
||||
connection.sendNumeric!RPL_TOPIC(name, topic);
|
||||
}
|
||||
|
||||
void setTopic(Connection connection, string newTopic)
|
||||
|
@ -183,9 +174,8 @@ class Channel
|
|||
specialModeParameters ~= memberLimit.to!string;
|
||||
}
|
||||
|
||||
user.send(Message(_server.name, "324", [
|
||||
user.nick, name, "+" ~ modes.idup ~ specialModes
|
||||
] ~ specialModeParameters));
|
||||
user.sendNumeric!RPL_CHANNELMODEIS([name,
|
||||
"+" ~ modes.idup ~ specialModes] ~ specialModeParameters);
|
||||
}
|
||||
|
||||
bool setMemberMode(Connection target, char mode)
|
||||
|
@ -280,42 +270,30 @@ class Channel
|
|||
{
|
||||
foreach (entry; maskLists['b'])
|
||||
{
|
||||
connection.send(Message(_server.name, "367", [
|
||||
connection.nick, name, entry
|
||||
], false));
|
||||
connection.sendNumeric!RPL_BANLIST(name, entry);
|
||||
}
|
||||
|
||||
connection.send(Message(_server.name, "368", [
|
||||
connection.nick, name, "End of channel ban list"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_ENDOFBANLIST(name);
|
||||
}
|
||||
|
||||
void sendExceptList(Connection connection)
|
||||
{
|
||||
foreach (entry; maskLists['e'])
|
||||
{
|
||||
connection.send(Message(_server.name, "348", [
|
||||
connection.nick, name, entry
|
||||
], false));
|
||||
connection.sendNumeric!RPL_EXCEPTLIST(name, entry);
|
||||
}
|
||||
|
||||
connection.send(Message(_server.name, "349", [
|
||||
connection.nick, name, "End of channel exception list"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_ENDOFEXCEPTLIST(name);
|
||||
}
|
||||
|
||||
void sendInviteList(Connection connection)
|
||||
{
|
||||
foreach (entry; maskLists['I'])
|
||||
{
|
||||
connection.send(Message(_server.name, "346", [
|
||||
connection.nick, name, entry
|
||||
], false));
|
||||
connection.sendNumeric!RPL_INVITELIST(name, entry);
|
||||
}
|
||||
|
||||
connection.send(Message(_server.name, "347", [
|
||||
connection.nick, name, "End of channel invite list"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_ENDOFINVITELIST(name);
|
||||
}
|
||||
|
||||
bool setKey(string key)
|
||||
|
|
|
@ -19,6 +19,7 @@ import ircd.message;
|
|||
import ircd.server;
|
||||
import ircd.channel;
|
||||
import ircd.helpers;
|
||||
import ircd.numerics;
|
||||
|
||||
//TODO: Make this a struct?
|
||||
class Connection
|
||||
|
@ -124,6 +125,12 @@ class Connection
|
|||
_connection.write(messageString ~ "\r\n");
|
||||
}
|
||||
|
||||
void sendNumeric(alias numeric)(string[] params...)
|
||||
{
|
||||
auto message = Message(_server.name, numeric.number, [nick] ~ params ~ numeric.params);
|
||||
send(message);
|
||||
}
|
||||
|
||||
void closeConnection()
|
||||
{
|
||||
connected = false;
|
||||
|
@ -187,7 +194,10 @@ class Connection
|
|||
if (!registered && !["NICK", "USER", "PASS", "PING", "PONG",
|
||||
"QUIT"].canFind(message.command))
|
||||
{
|
||||
sendErrNotRegistered();
|
||||
//NOTE: This actually does not work if NICK hasn't been sent
|
||||
// The first parameter for numerics is the client's nick.
|
||||
// This makes it technically impossible to correctly implement the RFCs.
|
||||
sendNumeric!ERR_NOTREGISTERED();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -276,9 +286,7 @@ class Connection
|
|||
break;
|
||||
default:
|
||||
writeln("unknown command '", message.command, "'");
|
||||
send(Message(_server.name, "421", [
|
||||
nick, message.command, "Unknown command"
|
||||
]));
|
||||
sendNumeric!ERR_UNKNOWNCOMMAND();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -292,7 +300,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
sendErrNoNickGiven();
|
||||
sendNumeric!ERR_NONICKNAMEGIVEN();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -300,17 +308,13 @@ class Connection
|
|||
|
||||
if (!_server.isNickAvailable(newNick) && newNick.toIRCLower != nick.toIRCLower)
|
||||
{
|
||||
send(Message(_server.name, "433", [
|
||||
nick, newNick, "Nickname is already in use"
|
||||
]));
|
||||
sendNumeric!ERR_NICKNAMEINUSE(newNick);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_server.isValidNick(newNick))
|
||||
{
|
||||
send(Message(_server.name, "432", [
|
||||
nick, newNick, "Erroneous nickname"
|
||||
]));
|
||||
sendNumeric!ERR_ERRONEUSNICKNAME(newNick);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -338,15 +342,13 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 4)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user !is null)
|
||||
{
|
||||
send(Message(_server.name, "462", [
|
||||
nick, "Unauthorized command (already registered)"
|
||||
], true));
|
||||
sendNumeric!ERR_ALREADYREGISTRED();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -372,15 +374,13 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 1)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (registered)
|
||||
{
|
||||
send(Message(_server.name, "462", [
|
||||
nick, "Unauthorized command (already registered)"
|
||||
], true));
|
||||
sendNumeric!ERR_ALREADYREGISTRED();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -406,7 +406,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,7 @@ class Connection
|
|||
{
|
||||
if (!Server.isValidChannelName(channelName))
|
||||
{
|
||||
sendErrNoSuchChannel(channelName);
|
||||
sendNumeric!ERR_NOSUCHCHANNEL(channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -446,32 +446,24 @@ class Connection
|
|||
if (!channel.memberLimit.isNull
|
||||
&& channel.members.length >= channel.memberLimit.get)
|
||||
{
|
||||
send(Message(_server.name, "471", [
|
||||
nick, channelName, "Cannot join channel (+l)"
|
||||
]));
|
||||
sendNumeric!ERR_CHANNELISFULL(channelName);
|
||||
}
|
||||
else if (channel.modes.canFind('i')
|
||||
&& !(channel.maskLists['I'].any!(m => matchesMask(m))
|
||||
|| channel.inviteHolders.canFind(this)))
|
||||
{
|
||||
send(Message(_server.name, "473", [
|
||||
nick, channelName, "Cannot join channel (+i)"
|
||||
]));
|
||||
sendNumeric!ERR_INVITEONLYCHAN(channelName);
|
||||
}
|
||||
else if (channel.maskLists['b'].any!(m => matchesMask(m))
|
||||
&& !channel.maskLists['e'].any!(m => matchesMask(m))
|
||||
&& !channel.inviteHolders.canFind(this))
|
||||
{
|
||||
send(Message(_server.name, "474", [
|
||||
nick, channelName, "Cannot join channel (+b)"
|
||||
]));
|
||||
sendNumeric!ERR_BANNEDFROMCHAN(channelName);
|
||||
}
|
||||
else if (channel.key !is null && (channelKeys.length < i + 1
|
||||
|| channelKeys[i] != channel.key))
|
||||
{
|
||||
send(Message(_server.name, "475", [
|
||||
nick, channelName, "Cannot join channel (+k)"
|
||||
]));
|
||||
sendNumeric!ERR_BADCHANNELKEY(channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -486,7 +478,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -495,25 +487,19 @@ class Connection
|
|||
{
|
||||
if (!Server.isValidChannelName(channel))
|
||||
{
|
||||
sendErrNoSuchChannel(channel);
|
||||
sendNumeric!ERR_NOSUCHCHANNEL(channel);
|
||||
}
|
||||
else if (!_server.canFindChannelByName(channel)
|
||||
|| !channels.canFind!(c => c.name.toIRCLower == channel.toIRCLower))
|
||||
{
|
||||
send(Message(_server.name, "442", [
|
||||
nick, channel, "You're not on that channel"
|
||||
], true));
|
||||
sendNumeric!ERR_NOTONCHANNEL(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (message.parameters.length > 1)
|
||||
{
|
||||
_server.part(this, channel, message.parameters[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server.part(this, channel, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -526,14 +512,12 @@ class Connection
|
|||
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
send(Message(_server.name, "411", [
|
||||
nick, "No recipient given (PRIVMSG)"
|
||||
], true));
|
||||
sendNumeric!ERR_NORECIPIENT_PRIVMSG();
|
||||
return;
|
||||
}
|
||||
if (message.parameters.length == 1)
|
||||
{
|
||||
send(Message(_server.name, "412", [nick, "No text to send"], true));
|
||||
sendNumeric!ERR_NOTEXTTOSEND();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -542,13 +526,11 @@ class Connection
|
|||
auto channelRange = _server.findChannelByName(target);
|
||||
if (channelRange.empty)
|
||||
{
|
||||
sendErrNoSuchNick(target);
|
||||
sendNumeric!ERR_NOSUCHNICK(target);
|
||||
}
|
||||
else if (!channelRange[0].canReceiveMessagesFromUser(this))
|
||||
{
|
||||
send(Message(_server.name, "404", [
|
||||
nick, target, "Cannot send to channel"
|
||||
], true));
|
||||
sendNumeric!ERR_CANNOTSENDTOCHAN(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -559,7 +541,7 @@ class Connection
|
|||
{
|
||||
if (!_server.canFindConnectionByNick(target))
|
||||
{
|
||||
sendErrNoSuchNick(target);
|
||||
sendNumeric!ERR_NOSUCHNICK(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -568,30 +550,35 @@ class Connection
|
|||
auto targetUser = _server.findConnectionByNick(target)[0];
|
||||
if (targetUser.modes.canFind('a'))
|
||||
{
|
||||
sendRplAway(target, targetUser.awayMessage);
|
||||
sendNumeric!RPL_AWAY(target, targetUser.awayMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//is this the right reply?
|
||||
sendErrNoSuchNick(target);
|
||||
sendNumeric!ERR_NOSUCHNICK(target);
|
||||
}
|
||||
}
|
||||
|
||||
void onNotice(Message message)
|
||||
{
|
||||
//TODO: Support special message targets
|
||||
auto target = message.parameters[0];
|
||||
auto text = message.parameters[1];
|
||||
|
||||
//TODO: Figure out what we are allowed to send exactly
|
||||
|
||||
if (message.parameters.length < 2)
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
sendNumeric!ERR_NORECIPIENT_NOTICE();
|
||||
return;
|
||||
}
|
||||
auto target = message.parameters[0];
|
||||
|
||||
if (message.parameters.length == 1)
|
||||
{
|
||||
sendNumeric!ERR_NOTEXTTOSEND();
|
||||
return;
|
||||
}
|
||||
auto text = message.parameters[1];
|
||||
|
||||
//TODO: Fix replies
|
||||
if (Server.isValidChannelName(target) && _server.canFindChannelByName(target))
|
||||
{
|
||||
_server.noticeToChannel(this, target, text);
|
||||
|
@ -624,7 +611,7 @@ class Connection
|
|||
}
|
||||
|
||||
auto name = message.parameters.length == 0 ? "*" : message.parameters[0];
|
||||
send(Message(_server.name, "315", [nick, name, "End of WHO list"], true));
|
||||
sendNumeric!RPL_ENDOFWHO(name);
|
||||
}
|
||||
|
||||
void onAway(Message message)
|
||||
|
@ -633,17 +620,13 @@ class Connection
|
|||
{
|
||||
removeMode('a');
|
||||
awayMessage = null;
|
||||
send(Message(_server.name, "305", [
|
||||
nick, "You are no longer marked as being away"
|
||||
], true));
|
||||
sendNumeric!RPL_UNAWAY();
|
||||
}
|
||||
else
|
||||
{
|
||||
modes ~= 'a';
|
||||
awayMessage = message.parameters[0];
|
||||
send(Message(_server.name, "306", [
|
||||
nick, "You have been marked as being away"
|
||||
], true));
|
||||
sendNumeric!RPL_NOWAWAY();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -651,7 +634,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length == 0)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -663,15 +646,9 @@ class Connection
|
|||
{
|
||||
//NOTE: The RFCs don't allow ERR_NOSUCHCHANNEL as a response to TOPIC
|
||||
version (BasicFixes)
|
||||
{
|
||||
sendErrNoSuchChannel(channelName);
|
||||
}
|
||||
sendNumeric!ERR_NOSUCHCHANNEL(channelName);
|
||||
else
|
||||
{
|
||||
send(Message(_server.name, "331", [
|
||||
nick, channelName, "No topic is set"
|
||||
], true));
|
||||
}
|
||||
sendNumeric!RPL_NOTOPIC(channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -683,13 +660,13 @@ class Connection
|
|||
auto newTopic = message.parameters[1];
|
||||
if (!channels.canFind!(c => c.name.toIRCLower == channelName.toIRCLower))
|
||||
{
|
||||
sendErrNotOnChannel(channelName);
|
||||
sendNumeric!ERR_NOTONCHANNEL(channelName);
|
||||
}
|
||||
else if (channels.find!(c => c.name.toIRCLower == channelName.toIRCLower)
|
||||
.map!(c => c.modes.canFind('t') && !c.memberModes[this].canFind('o'))
|
||||
.array[0])
|
||||
{
|
||||
sendErrChanopPrivsNeeded(channelName);
|
||||
sendNumeric!ERR_CHANOPRIVSNEEDED(channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -721,7 +698,7 @@ class Connection
|
|||
}
|
||||
else
|
||||
{
|
||||
sendRplEndOfNames(channelName);
|
||||
sendNumeric!RPL_ENDOFNAMES(channelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -750,7 +727,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 2)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -758,7 +735,7 @@ class Connection
|
|||
auto targetUserRange = _server.findConnectionByNick(targetNick);
|
||||
if (targetUserRange.empty)
|
||||
{
|
||||
sendErrNoSuchNick(targetNick);
|
||||
sendNumeric!ERR_NOSUCHNICK(targetNick);
|
||||
return;
|
||||
}
|
||||
auto targetUser = targetUserRange[0];
|
||||
|
@ -769,11 +746,11 @@ class Connection
|
|||
{
|
||||
_server.invite(this, targetUser.nick, channelName);
|
||||
|
||||
sendRplInviting(channelName, targetUser.nick);
|
||||
sendNumeric!RPL_INVITING(targetUser.nick, channelName);
|
||||
|
||||
if (targetUser.modes.canFind('a'))
|
||||
{
|
||||
sendRplAway(targetUser.nick, targetUser.awayMessage);
|
||||
sendNumeric!RPL_AWAY(targetUser.nick, targetUser.awayMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -781,28 +758,25 @@ class Connection
|
|||
auto channel = channelRange[0];
|
||||
if (!channel.members.canFind(this))
|
||||
{
|
||||
sendErrNotOnChannel(channel.name);
|
||||
sendNumeric!ERR_NOTONCHANNEL(channel.name);
|
||||
}
|
||||
else if (channel.members.canFind(targetUser))
|
||||
{
|
||||
send(Message(_server.name, "443", [
|
||||
nick, targetUser.nick, channel.name,
|
||||
"is already on channel"
|
||||
], true));
|
||||
sendNumeric!ERR_USERONCHANNEL(targetUser.nick, channel.name);
|
||||
}
|
||||
else if (channel.modes.canFind('i') && !channel.memberModes[this].canFind('o'))
|
||||
{
|
||||
sendErrChanopPrivsNeeded(channel.name);
|
||||
sendNumeric!ERR_CHANOPRIVSNEEDED(channel.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server.invite(this, targetUser.nick, channel.name);
|
||||
|
||||
sendRplInviting(channel.name, targetUser.nick);
|
||||
sendNumeric!RPL_INVITING(targetUser.nick, channel.name);
|
||||
|
||||
if (targetUser.modes.canFind('a'))
|
||||
{
|
||||
sendRplAway(targetUser.nick, targetUser.awayMessage);
|
||||
sendNumeric!RPL_AWAY(targetUser.nick, targetUser.awayMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -837,7 +811,7 @@ class Connection
|
|||
}
|
||||
else if (_server.motd is null)
|
||||
{
|
||||
send(Message(_server.name, "422", [nick, "MOTD File is missing"], true));
|
||||
sendNumeric!ERR_NOMOTD();
|
||||
return;
|
||||
}
|
||||
_server.sendMotd(this);
|
||||
|
@ -862,7 +836,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 1)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -878,7 +852,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 1)
|
||||
{
|
||||
sendErrNoNickGiven();
|
||||
sendNumeric!ERR_NONICKNAMEGIVEN();
|
||||
return;
|
||||
}
|
||||
else if (message.parameters.length > 1)
|
||||
|
@ -892,34 +866,34 @@ class Connection
|
|||
if (!_server.canFindConnectionByNick(mask)
|
||||
|| !_server.findConnectionByNick(mask)[0].visibleTo(this))
|
||||
{
|
||||
sendErrNoSuchNick(mask);
|
||||
sendNumeric!ERR_NOSUCHNICK(mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server.whois(this, mask);
|
||||
}
|
||||
|
||||
send(Message(_server.name, "318", [nick, mask, "End of WHOIS list"], true));
|
||||
sendNumeric!RPL_ENDOFWHOIS(mask);
|
||||
}
|
||||
|
||||
void onKill(Message message)
|
||||
{
|
||||
if (!isOperator)
|
||||
{
|
||||
sendErrNoPrivileges();
|
||||
sendNumeric!ERR_NOPRIVILEGES();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.parameters.length < 2)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
auto nick = message.parameters[0];
|
||||
if (!_server.canFindConnectionByNick(nick))
|
||||
{
|
||||
sendErrNoSuchNick(nick);
|
||||
sendNumeric!ERR_NOSUCHNICK(nick);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -932,7 +906,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.length < 2)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -942,7 +916,7 @@ class Connection
|
|||
|
||||
if (channelList.length != 1 && channelList.length != userList.length)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -956,22 +930,22 @@ class Connection
|
|||
|
||||
if (!_server.canFindChannelByName(channelName))
|
||||
{
|
||||
sendErrNoSuchChannel(channelName);
|
||||
sendNumeric!ERR_NOSUCHCHANNEL(channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto channel = _server.findChannelByName(channelName)[0];
|
||||
if (!channel.members.canFind(this))
|
||||
{
|
||||
sendErrNotOnChannel(channelName);
|
||||
sendNumeric!ERR_NOTONCHANNEL(channelName);
|
||||
}
|
||||
else if (!channel.memberModes[this].canFind('o'))
|
||||
{
|
||||
sendErrChanopPrivsNeeded(channelName);
|
||||
sendNumeric!ERR_CHANOPRIVSNEEDED(channelName);
|
||||
}
|
||||
else if (!channel.members.canFind!(m => m.nick.toIRCLower == nick.toIRCLower))
|
||||
{
|
||||
sendErrUserNotInChannel(nick, channelName);
|
||||
sendNumeric!ERR_USERNOTINCHANNEL(nick, channelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -985,7 +959,7 @@ class Connection
|
|||
{
|
||||
if (message.parameters.empty)
|
||||
{
|
||||
sendErrNeedMoreParams(message.command);
|
||||
sendNumeric!ERR_NEEDMOREPARAMS(message.command);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1003,7 +977,7 @@ class Connection
|
|||
//NOTE: The RFCs don't allow ERR_NOSUCHNICK as a reponse to MODE
|
||||
version (BasicFixes)
|
||||
{
|
||||
sendErrNoSuchNick(target);
|
||||
sendNumeric!ERR_NOSUCHNICK(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1018,30 +992,20 @@ class Connection
|
|||
version (BasicFixes)
|
||||
{
|
||||
if (message.parameters.length > 1)
|
||||
{
|
||||
send(Message(_server.name, "502", [
|
||||
nick, "Cannot change mode for other users"
|
||||
], true));
|
||||
}
|
||||
sendNumeric!ERR_USERSDONTMATCH();
|
||||
else
|
||||
{
|
||||
send(Message(_server.name, "502", [
|
||||
nick, "Cannot view mode of other users"
|
||||
], true));
|
||||
}
|
||||
sendNumeric!ERR_USERSDONTMATCH_ALT();
|
||||
}
|
||||
else
|
||||
{
|
||||
send(Message(_server.name, "502", [
|
||||
nick, "Cannot change mode for other users"
|
||||
], true));
|
||||
sendNumeric!ERR_USERSDONTMATCH();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.parameters.length == 1)
|
||||
{
|
||||
send(Message(_server.name, "221", [nick, "+" ~ modes.idup]));
|
||||
sendNumeric!RPL_UMODEIS("+" ~ modes.idup);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1060,9 +1024,7 @@ class Connection
|
|||
}
|
||||
|
||||
if (modeString.length == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto changedModes = modeString[1 .. $];
|
||||
foreach (mode; changedModes)
|
||||
|
@ -1090,9 +1052,7 @@ class Connection
|
|||
//ignore
|
||||
break;
|
||||
default:
|
||||
send(Message(_server.name, "501", [
|
||||
nick, "Unknown MODE flag"
|
||||
], true));
|
||||
sendNumeric!ERR_UMODEUNKNOWNFLAG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1108,7 +1068,7 @@ class Connection
|
|||
//NOTE: The RFCs don't allow ERR_NOSUCHCHANNEL as a response to MODE
|
||||
version (BasicFixes)
|
||||
{
|
||||
sendErrNoSuchChannel(message.parameters[0]);
|
||||
sendNumeric!ERR_NOSUCHCHANNEL(message.parameters[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1117,13 +1077,9 @@ class Connection
|
|||
//NOTE: The RFCs are inconsistent on channel mode query syntax for mask list modes
|
||||
// ('MODE #chan +b', but 'MODE #chan e' and 'MODE #chan I')
|
||||
version (BasicFixes)
|
||||
{
|
||||
enum listQueryModes = ["+b", "+e", "+I", "e", "I"];
|
||||
}
|
||||
else
|
||||
{
|
||||
enum listQueryModes = ["+b", "e", "I"];
|
||||
}
|
||||
|
||||
if (message.parameters.length == 1)
|
||||
{
|
||||
|
@ -1149,7 +1105,7 @@ class Connection
|
|||
{
|
||||
if (!channel.memberModes[this].canFind('o'))
|
||||
{
|
||||
sendErrChanopPrivsNeeded(channel.name);
|
||||
sendNumeric!ERR_CHANOPRIVSNEEDED(channel.name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1169,9 +1125,7 @@ class Connection
|
|||
}
|
||||
|
||||
if (modeString.length == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char[] processedModes;
|
||||
string[] processedParameters;
|
||||
|
@ -1194,14 +1148,14 @@ class Connection
|
|||
auto memberRange = _server.findConnectionByNick(memberNick);
|
||||
if (memberRange.empty)
|
||||
{
|
||||
sendErrNoSuchNick(memberNick);
|
||||
sendNumeric!ERR_NOSUCHNICK(memberNick);
|
||||
break Lforeach;
|
||||
}
|
||||
|
||||
auto member = memberRange[0];
|
||||
if (!channel.members.canFind(member))
|
||||
{
|
||||
sendErrUserNotInChannel(memberNick, channel.name);
|
||||
sendNumeric!ERR_USERNOTINCHANNEL(memberNick, channel.name);
|
||||
break Lforeach;
|
||||
}
|
||||
|
||||
|
@ -1280,20 +1234,14 @@ class Connection
|
|||
if (add)
|
||||
{
|
||||
if (i + 1 == message.parameters.length)
|
||||
{
|
||||
break Lforeach;
|
||||
}
|
||||
|
||||
auto limitString = message.parameters[++i];
|
||||
uint limit = 0;
|
||||
try
|
||||
{
|
||||
limit = limitString.to!uint;
|
||||
}
|
||||
catch (Throwable)
|
||||
{
|
||||
break Lforeach;
|
||||
}
|
||||
|
||||
channel.setMemberLimit(limit);
|
||||
|
||||
|
@ -1319,16 +1267,13 @@ class Connection
|
|||
success = channel.setMode(mode);
|
||||
else
|
||||
success = channel.unsetMode(mode);
|
||||
|
||||
if (success)
|
||||
{
|
||||
processedModes ~= mode;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
send(Message(_server.name, "472", [
|
||||
nick, [mode],
|
||||
"is unknown mode char to me for " ~ channel.name
|
||||
], true));
|
||||
sendNumeric!ERR_UNKNOWNMODE([mode],
|
||||
"is unknown mode char to me for " ~ channel.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1374,13 +1319,9 @@ class Connection
|
|||
break;
|
||||
}
|
||||
|
||||
send(Message(_server.name, "219", [
|
||||
nick, [statsLetter].idup, "End of STATS report"
|
||||
], true));
|
||||
sendNumeric!RPL_ENDOFSTATS([statsLetter].idup);
|
||||
}
|
||||
|
||||
//TODO: Refactor numeric replies
|
||||
|
||||
void sendWhoReply(string channel, Connection user, string nickPrefix, uint hopCount)
|
||||
{
|
||||
auto flags = user.modes.canFind('a') ? "G" : "H";
|
||||
|
@ -1388,95 +1329,8 @@ class Connection
|
|||
flags ~= "*";
|
||||
flags ~= nickPrefix;
|
||||
|
||||
send(Message(_server.name, "352", [
|
||||
nick, channel, user.user, user.hostname, user.servername,
|
||||
user.nick, flags, hopCount.to!string ~ " " ~ user.realname
|
||||
], true));
|
||||
}
|
||||
|
||||
void sendRplAway(string target, string message)
|
||||
{
|
||||
send(Message(_server.name, "301", [nick, target, message], true));
|
||||
}
|
||||
|
||||
void sendRplList(string channelName, ulong visibleCount, string topic)
|
||||
{
|
||||
send(Message(_server.name, "322", [
|
||||
nick, channelName, visibleCount.to!string, topic
|
||||
], true));
|
||||
}
|
||||
|
||||
void sendRplListEnd()
|
||||
{
|
||||
send(Message(_server.name, "323", [nick, "End of LIST"], true));
|
||||
}
|
||||
|
||||
void sendRplInviting(string channelName, string name)
|
||||
{
|
||||
//TODO: If errata are being ignored, send nick and channel name in reverse order
|
||||
send(Message(_server.name, "341", [nick, name, channelName]));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void sendErrNoSuchChannel(string name)
|
||||
{
|
||||
send(Message(_server.name, "403", [nick, name, "No such channel"], true));
|
||||
}
|
||||
|
||||
void sendErrNoNickGiven()
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void sendErrNotRegistered()
|
||||
{
|
||||
send(Message(_server.name, "451", ["(You)", "You have not registered"], true));
|
||||
}
|
||||
|
||||
void sendErrNeedMoreParams(string command)
|
||||
{
|
||||
send(Message(_server.name, "461", [
|
||||
nick, command, "Not enough parameters"
|
||||
], true));
|
||||
}
|
||||
|
||||
void sendErrNoPrivileges()
|
||||
{
|
||||
send(Message(_server.name, "481", [
|
||||
nick, "Permission Denied- You're not an IRC operator"
|
||||
], true));
|
||||
}
|
||||
|
||||
void sendErrChanopPrivsNeeded(string channel)
|
||||
{
|
||||
send(Message(_server.name, "482", [
|
||||
nick, channel, "You're not channel operator"
|
||||
], true));
|
||||
sendNumeric!RPL_WHOREPLY(channel, user.user, user.hostname, user.servername,
|
||||
user.nick, flags, hopCount.to!string ~ " " ~ user.realname);
|
||||
}
|
||||
|
||||
void notImplemented(string description)
|
||||
|
@ -1500,30 +1354,19 @@ class Connection
|
|||
enum availableUserModes = "aiwroOs";
|
||||
enum availableChannelModes = "OovaimnqpsrtklbeI";
|
||||
|
||||
send(Message(_server.name, "001", [
|
||||
nick, "Welcome", "to", "the", "Internet", "Relay", "Network",
|
||||
prefix
|
||||
], false));
|
||||
send(Message(_server.name, "002", [
|
||||
nick, "Your", "host", "is", _server.name ~ ",", "running",
|
||||
"version", _server.versionString
|
||||
], false));
|
||||
send(Message(_server.name, "003", [
|
||||
nick, "This", "server", "was", "created", buildDate
|
||||
], false));
|
||||
send(Message(_server.name, "004", [
|
||||
nick, _server.name, _server.versionString,
|
||||
availableUserModes, availableChannelModes
|
||||
], false));
|
||||
sendNumeric!RPL_WELCOME("Welcome", "to", "the", "Internet", "Relay", "Network", prefix);
|
||||
sendNumeric!RPL_YOURHOST("Your", "host", "is", _server.name ~ ",",
|
||||
"running", "version", _server.versionString);
|
||||
sendNumeric!RPL_CREATED("This", "server", "was", "created", buildDate);
|
||||
sendNumeric!RPL_MYINFO(_server.name, _server.versionString,
|
||||
availableUserModes, availableChannelModes);
|
||||
}
|
||||
|
||||
void onIncorrectPassword()
|
||||
{
|
||||
//NOTE: The RFCs don't allow ERR_PASSWDMISMATCH as a response to NICK/USER
|
||||
version (BasicFixes)
|
||||
{
|
||||
send(Message(_server.name, "464", [nick, "Password incorrect"], true));
|
||||
}
|
||||
sendNumeric!ERR_PASSWDMISMATCH();
|
||||
|
||||
//NOTE: The RFCs don't actually specify what should happen here
|
||||
closeConnection();
|
||||
|
@ -1552,13 +1395,10 @@ class Connection
|
|||
char[] modes;
|
||||
|
||||
if (mask & 0b100)
|
||||
{
|
||||
modes ~= 'w';
|
||||
}
|
||||
|
||||
if (mask & 0b1000)
|
||||
{
|
||||
modes ~= 'i';
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
module ircd.numerics;
|
||||
|
||||
struct SimpleNumeric
|
||||
{
|
||||
string number;
|
||||
string[] params;
|
||||
}
|
||||
|
||||
private alias N = SimpleNumeric;
|
||||
|
||||
enum : SimpleNumeric
|
||||
{
|
||||
//Command responses
|
||||
RPL_WELCOME = N("001", []),
|
||||
RPL_YOURHOST = N("002", []),
|
||||
RPL_CREATED = N("003", []),
|
||||
RPL_MYINFO = N("004", []),
|
||||
RPL_STATSCOMMANDS = N("212", []),
|
||||
RPL_ENDOFSTATS = N("219", ["End of STATS report"]),
|
||||
RPL_UMODEIS = N("221", []),
|
||||
RPL_STATSUPTIME = N("242", []),
|
||||
RPL_LUSERCLIENT = N("251", []),
|
||||
RPL_LUSEROP = N("252", ["operator(s) online"]),
|
||||
RPL_LUSERUNKNOWN = N("253", ["unknown connection(s)"]),
|
||||
RPL_LUSERCHANNELS = N("254", ["channels formed"]),
|
||||
RPL_LUSERME = N("255", []),
|
||||
RPL_AWAY = N("301", []),
|
||||
RPL_ISON = N("303", []),
|
||||
RPL_UNAWAY = N("305", ["You are no longer marked as being away"]),
|
||||
RPL_NOWAWAY = N("306", ["You have been marked as being away"]),
|
||||
RPL_WHOISUSER = N("311", []),
|
||||
RPL_WHOISSERVER = N("312", []),
|
||||
RPL_WHOISOPERATOR = N("313", ["is an IRC operator"]),
|
||||
RPL_ENDOFWHO = N("315", ["End of WHO list"]),
|
||||
RPL_WHOISIDLE = N("317", ["seconds idle"]),
|
||||
RPL_ENDOFWHOIS = N("318", ["End of WHOIS list"]),
|
||||
RPL_WHOISCHANNELS = N("319", []),
|
||||
RPL_LIST = N("322", []),
|
||||
RPL_LISTEND = N("323", ["End of LIST"]),
|
||||
RPL_CHANNELMODEIS = N("324", []),
|
||||
RPL_NOTOPIC = N("331", ["No topic is set"]),
|
||||
RPL_TOPIC = N("332", []),
|
||||
RPL_INVITING = N("341", []),
|
||||
RPL_INVITELIST = N("346", []),
|
||||
RPL_ENDOFINVITELIST = N("347", ["End of channel invite list"]),
|
||||
RPL_EXCEPTLIST = N("348", []),
|
||||
RPL_ENDOFEXCEPTLIST = N("349", ["End of channel exception list"]),
|
||||
RPL_VERSION = N("351", []),
|
||||
RPL_WHOREPLY = N("352", []),
|
||||
RPL_NAMREPLY = N("353", []),
|
||||
RPL_ENDOFNAMES = N("366", ["End of NAMES list"]),
|
||||
RPL_BANLIST = N("367", []),
|
||||
RPL_ENDOFBANLIST = N("368", ["End of channel ban list"]),
|
||||
RPL_MOTD = N("372", []),
|
||||
RPL_MOTDSTART = N("375", []),
|
||||
RPL_ENDOFMOTD = N("376", ["End of MOTD command"]),
|
||||
RPL_TIME = N("391", []),
|
||||
|
||||
//Error replies
|
||||
ERR_NOSUCHNICK = N("401", ["No such nick/channel"]),
|
||||
ERR_NOSUCHCHANNEL = N("403", ["No such channel"]),
|
||||
ERR_CANNOTSENDTOCHAN = N("404", ["Cannot send to channel"]),
|
||||
ERR_NORECIPIENT_PRIVMSG = N("411", ["No recipient given (PRIVMSG)"]),
|
||||
ERR_NORECIPIENT_NOTICE = N("411", ["No recipient given (NOTICE)"]),
|
||||
ERR_NOTEXTTOSEND = N("412", ["No text to send"]),
|
||||
ERR_UNKNOWNCOMMAND = N("421", ["Unknown command"]),
|
||||
ERR_NOMOTD = N("422", ["MOTD File is missing"]),
|
||||
ERR_NONICKNAMEGIVEN = N("431", ["No nickname given"]),
|
||||
ERR_ERRONEUSNICKNAME = N("432", ["Erroneous nickname"]),
|
||||
ERR_NICKNAMEINUSE = N("433", ["Nickname is already in use"]),
|
||||
ERR_USERNOTINCHANNEL = N("441", ["They aren't on that channel"]),
|
||||
ERR_NOTONCHANNEL = N("442", ["You're not on that channel"]),
|
||||
ERR_USERONCHANNEL = N("443", ["is already on channel"]),
|
||||
ERR_NOTREGISTERED = N("451", ["You have not registered"]),
|
||||
ERR_NEEDMOREPARAMS = N("461", ["Not enough parameters"]),
|
||||
ERR_ALREADYREGISTRED /* sic */ = N("462", ["Unauthorized command (already registered)"]),
|
||||
ERR_PASSWDMISMATCH = N("464", ["Password incorrect"]),
|
||||
ERR_CHANNELISFULL = N("471", ["Cannot join channel (+l)"]),
|
||||
ERR_UNKNOWNMODE = N("472", []),
|
||||
ERR_INVITEONLYCHAN = N("473", ["Cannot join channel (+i)"]),
|
||||
ERR_BANNEDFROMCHAN = N("474", ["Cannot join channel (+b)"]),
|
||||
ERR_BADCHANNELKEY = N("475", ["Cannot join channel (+k)"]),
|
||||
ERR_NOPRIVILEGES = N("481", ["Permission Denied- You're not an IRC operator"]),
|
||||
ERR_CHANOPRIVSNEEDED = N("482", ["You're not channel operator"]),
|
||||
ERR_UMODEUNKNOWNFLAG = N("501", ["Unknown MODE flag"]),
|
||||
ERR_USERSDONTMATCH = N("502", ["Cannot change mode for other users"]),
|
||||
ERR_USERSDONTMATCH_ALT = N("502", ["Cannot view mode of other users"]), //non-standard message (NotStrict-only)
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import ircd.message;
|
|||
import ircd.connection;
|
||||
import ircd.channel;
|
||||
import ircd.helpers;
|
||||
import ircd.numerics;
|
||||
|
||||
//TODO: Make this a struct?
|
||||
class Server
|
||||
|
@ -294,24 +295,23 @@ class Server
|
|||
&& !ch.modes.canFind('p')).empty);
|
||||
if (!otherUsers.empty)
|
||||
{
|
||||
connection.send(Message(name, "353", [
|
||||
connection.nick, "=", "*",
|
||||
otherUsers.map!(m => m.nick).join(' ')
|
||||
], true));
|
||||
connection.sendNumeric!RPL_NAMREPLY("=", "*", otherUsers.map!(m => m.nick).join(' '));
|
||||
}
|
||||
|
||||
connection.sendRplEndOfNames("*");
|
||||
connection.sendNumeric!RPL_ENDOFNAMES("*");
|
||||
}
|
||||
|
||||
void sendFullList(Connection connection)
|
||||
{
|
||||
foreach (channel; channels.filter!(c => c.visibleTo(connection)))
|
||||
{
|
||||
connection.sendRplList(channel.name,
|
||||
channel.members.filter!(m => m.visibleTo(connection))
|
||||
.array.length, channel.topic);
|
||||
connection.sendNumeric!RPL_LIST(channel.name, channel.members
|
||||
.filter!(m => m.visibleTo(connection))
|
||||
.array
|
||||
.length
|
||||
.to!string, channel.topic);
|
||||
}
|
||||
connection.sendRplListEnd();
|
||||
connection.sendNumeric!RPL_LISTEND();
|
||||
}
|
||||
|
||||
void sendPartialList(Connection connection, string[] channelNames)
|
||||
|
@ -319,24 +319,25 @@ class Server
|
|||
foreach (channel; channels.filter!(c => channelNames.canFind(c.name)
|
||||
&& c.visibleTo(connection)))
|
||||
{
|
||||
connection.sendRplList(channel.name,
|
||||
channel.members.filter!(m => m.visibleTo(connection))
|
||||
.array.length, channel.topic);
|
||||
connection.sendNumeric!RPL_LIST(channel.name, channel.members
|
||||
.filter!(m => m.visibleTo(connection))
|
||||
.array
|
||||
.length
|
||||
.to!string, channel.topic);
|
||||
}
|
||||
connection.sendRplListEnd();
|
||||
connection.sendNumeric!RPL_LISTEND();
|
||||
}
|
||||
|
||||
void sendVersion(Connection connection)
|
||||
{
|
||||
connection.send(Message(name, "351", [
|
||||
connection.nick, versionString ~ ".", name, ""
|
||||
], true));
|
||||
//TODO: Include enabled versions in comments?
|
||||
connection.sendNumeric!RPL_VERSION(versionString ~ ".", name, ":");
|
||||
}
|
||||
|
||||
void sendTime(Connection connection)
|
||||
{
|
||||
auto timeString = Clock.currTime.toISOExtString;
|
||||
connection.send(Message(name, "391", [connection.nick, name, timeString], true));
|
||||
connection.sendNumeric!RPL_TIME(name, timeString);
|
||||
}
|
||||
|
||||
void invite(Connection inviter, string target, string channelName)
|
||||
|
@ -351,17 +352,13 @@ class Server
|
|||
|
||||
void sendMotd(Connection connection)
|
||||
{
|
||||
connection.send(Message(name, "375", [
|
||||
connection.nick, ":- " ~ name ~ " Message of the day - "
|
||||
], true));
|
||||
connection.sendNumeric!RPL_MOTDSTART("- " ~ name ~ " Message of the day - ");
|
||||
foreach (line; motd.splitLines)
|
||||
{
|
||||
//TODO: Implement line wrapping
|
||||
connection.send(Message(name, "372", [connection.nick, ":- " ~ line], true));
|
||||
connection.sendNumeric!RPL_MOTD("- " ~ line);
|
||||
}
|
||||
connection.send(Message(name, "376", [
|
||||
connection.nick, "End of MOTD command"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_ENDOFMOTD();
|
||||
}
|
||||
|
||||
void sendLusers(Connection connection)
|
||||
|
@ -369,79 +366,58 @@ class Server
|
|||
//TODO: If RFC-strictness is off, use '1 server' instead of '1 servers' if the network (or the part of the network of the query) has only one server
|
||||
|
||||
//TODO: Support services and multiple servers
|
||||
connection.send(Message(name, "251", [
|
||||
connection.nick,
|
||||
"There are " ~ connections.filter!(c => c.registered)
|
||||
.count
|
||||
.to!string ~ " users and 0 services on 1 servers"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_LUSERCLIENT(
|
||||
"There are " ~ connections.filter!(c => c.registered)
|
||||
.count
|
||||
.to!string ~ " users and 0 services on 1 servers");
|
||||
|
||||
if (connections.any!(c => c.isOperator))
|
||||
{
|
||||
connection.send(Message(name, "252", [
|
||||
connection.nick,
|
||||
connections.count!(c => c.isOperator)
|
||||
.to!string, "operator(s) online"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_LUSEROP(connections.count!(c => c.isOperator)
|
||||
.to!string);
|
||||
}
|
||||
|
||||
if (connections.any!(c => !c.registered))
|
||||
{
|
||||
connection.send(Message(name, "253", [
|
||||
connection.nick,
|
||||
connections.count!(c => !c.registered)
|
||||
.to!string, "unknown connection(s)"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_LUSERUNKNOWN(connections.count!(c => !c.registered)
|
||||
.to!string);
|
||||
}
|
||||
|
||||
if (channels.length > 0)
|
||||
{
|
||||
connection.send(Message(name, "254", [
|
||||
connection.nick, channels.length.to!string,
|
||||
"channels formed"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_LUSERCHANNELS(channels.length.to!string);
|
||||
}
|
||||
|
||||
connection.send(Message(name, "255", [
|
||||
connection.nick,
|
||||
"I have " ~ connections.length.to!string ~ " clients and 1 servers"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_LUSERME(
|
||||
"I have " ~ connections.length.to!string ~ " clients and 1 servers");
|
||||
}
|
||||
|
||||
void ison(Connection connection, string[] nicks)
|
||||
{
|
||||
auto reply = nicks.filter!(n => canFindConnectionByNick(n)).join(' ');
|
||||
|
||||
connection.send(Message(name, "303", [connection.nick, reply], true));
|
||||
connection.sendNumeric!RPL_ISON(reply);
|
||||
}
|
||||
|
||||
void whois(Connection connection, string mask)
|
||||
{
|
||||
auto user = findConnectionByNick(mask)[0];
|
||||
|
||||
connection.send(Message(name, "311", [
|
||||
connection.nick, user.nick, user.user, user.hostname, "*",
|
||||
user.hostname
|
||||
], true));
|
||||
connection.sendNumeric!RPL_WHOISUSER(user.nick, user.user,
|
||||
user.hostname, "*", user.realname);
|
||||
|
||||
//TODO: Send information about the user's actual server (which is not necessarily this one)
|
||||
connection.send(Message(name, "312", [
|
||||
connection.nick, user.nick, name, info
|
||||
], true));
|
||||
connection.sendNumeric!RPL_WHOISSERVER(user.nick, name, info);
|
||||
|
||||
if (user.isOperator)
|
||||
{
|
||||
connection.send(Message(name, "313", [
|
||||
connection.nick, user.nick, "is an IRC operator"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_WHOISOPERATOR(user.nick);
|
||||
}
|
||||
|
||||
auto idleSeconds = (Clock.currTime - user.lastMessageTime).total!"seconds";
|
||||
connection.send(Message(name, "317", [
|
||||
connection.nick, user.nick, idleSeconds.to!string,
|
||||
"seconds idle"
|
||||
], true));
|
||||
connection.sendNumeric!RPL_WHOISIDLE(user.nick, idleSeconds.to!string);
|
||||
|
||||
auto userChannels = user.channels.map!(c => c.nickPrefix(user) ~ c.name).join(' ');
|
||||
connection.send(Message(name, "319", [
|
||||
connection.nick, user.nick, userChannels
|
||||
], true));
|
||||
connection.sendNumeric!RPL_WHOISCHANNELS(user.nick, userChannels);
|
||||
}
|
||||
|
||||
void kill(Connection killer, string nick, string comment)
|
||||
|
@ -482,10 +458,8 @@ class Server
|
|||
foreach (command, count; _commandUsage)
|
||||
{
|
||||
//TODO: Implement remote count
|
||||
connection.send(Message(name, "212", [
|
||||
connection.nick, command, count.to!string,
|
||||
_commandBytes[command].to!string, "0"
|
||||
], false));
|
||||
connection.sendNumeric!RPL_STATSCOMMANDS(command,
|
||||
count.to!string, _commandBytes[command].to!string, "0");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,7 +471,7 @@ class Server
|
|||
|
||||
auto uptimeString = format!"Server Up %d days %d:%02d:%02d"(uptime.days,
|
||||
uptime.hours, uptime.minutes, uptime.seconds);
|
||||
connection.send(Message(name, "242", [connection.nick, uptimeString], true));
|
||||
connection.sendNumeric!RPL_STATSUPTIME(uptimeString);
|
||||
}
|
||||
|
||||
void setPass(string pass)
|
||||
|
|
Loading…
Reference in New Issue