Compare commits
13 Commits
7a8b28f0f4
...
f70b9196c9
Author | SHA1 | Date |
---|---|---|
Les De Ridder | f70b9196c9 | |
Les De Ridder | 2aaa367c10 | |
Les De Ridder | 5bb99c2a8c | |
Les De Ridder | 3f5f1f9ada | |
Les De Ridder | cd7613ed70 | |
Les De Ridder | b5616c4a0b | |
Les De Ridder | a3f306b9ba | |
Les De Ridder | f6eece74bf | |
Les De Ridder | 49f8cfa3ce | |
Les De Ridder | a59fdc67ce | |
Les De Ridder | 21368785d6 | |
Les De Ridder | 3c06c1b738 | |
Les De Ridder | 66175b4168 |
|
@ -5,6 +5,6 @@ __dummy.html
|
||||||
*.obj
|
*.obj
|
||||||
__test__*__
|
__test__*__
|
||||||
out/
|
out/
|
||||||
source/ircd/packageVersion.d
|
source/ircd/versionInfo.d
|
||||||
motd
|
motd
|
||||||
config.sdl
|
config.sdl
|
||||||
|
|
2
dub.sdl
2
dub.sdl
|
@ -7,7 +7,7 @@ targetType "executable"
|
||||||
dependency "vibe-core" version="~>1.8.1"
|
dependency "vibe-core" version="~>1.8.1"
|
||||||
dependency "vibe-d:stream" version="~>0.9.0-alpha.1"
|
dependency "vibe-d:stream" version="~>0.9.0-alpha.1"
|
||||||
dependency "sdlang-d" version="~>0.10.5"
|
dependency "sdlang-d" version="~>0.10.5"
|
||||||
preGenerateCommands "./generate-package-version.fish"
|
preBuildCommands "./generate-version-info.fish"
|
||||||
versions "VibeDefaultMain"
|
versions "VibeDefaultMain"
|
||||||
targetPath "out"
|
targetPath "out"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/usr/bin/fish
|
|
||||||
|
|
||||||
set packageVersion (git describe)
|
|
||||||
|
|
||||||
echo "module ircd.packageVersion; enum packageVersion = \"$packageVersion\";" > source/ircd/packageVersion.d
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/fish
|
||||||
|
|
||||||
|
set gitVersion (git describe)
|
||||||
|
set buildDate (date --iso-8601=seconds)
|
||||||
|
|
||||||
|
echo -e "/* This file is generated on build! */\n\nmodule ircd.versionInfo;\n\nenum gitVersion = \"$gitVersion\";\nenum buildDate = \"$buildDate\";" > source/ircd/versionInfo.d
|
|
@ -224,7 +224,14 @@ class Channel
|
||||||
|
|
||||||
modes ~= mode;
|
modes ~= mode;
|
||||||
|
|
||||||
//TODO: If RFC-strictness is off, clear the invite list when +i is set
|
//NOTE: The RFCs don't specify that the invite list should be cleared on +i
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
if (mode == 'i')
|
||||||
|
{
|
||||||
|
inviteHolders = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -349,6 +356,9 @@ class Channel
|
||||||
|
|
||||||
string nickPrefix(Connection member)
|
string nickPrefix(Connection member)
|
||||||
{
|
{
|
||||||
|
if (!members.canFind(member))
|
||||||
|
return null;
|
||||||
|
|
||||||
if (memberModes[member].canFind('o'))
|
if (memberModes[member].canFind('o'))
|
||||||
{
|
{
|
||||||
return "@";
|
return "@";
|
||||||
|
@ -382,7 +392,8 @@ class Channel
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (maskLists['b'].any!(m => connection.matchesMask(m))
|
else if (maskLists['b'].any!(m => connection.matchesMask(m))
|
||||||
&& !maskLists['e'].any!(m => connection.matchesMask(m)))
|
&& !maskLists['e'].any!(m => connection.matchesMask(m))
|
||||||
|
&& nickPrefix(connection).length == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import vibe.core.core;
|
||||||
import vibe.core.net;
|
import vibe.core.net;
|
||||||
import vibe.stream.operations : readLine;
|
import vibe.stream.operations : readLine;
|
||||||
|
|
||||||
|
import ircd.versionInfo;
|
||||||
|
|
||||||
import ircd.message;
|
import ircd.message;
|
||||||
import ircd.server;
|
import ircd.server;
|
||||||
import ircd.channel;
|
import ircd.channel;
|
||||||
|
@ -48,9 +50,14 @@ class Connection
|
||||||
return nick ~ "!" ~ user ~ "@" ~ hostname;
|
return nick ~ "!" ~ user ~ "@" ~ hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property bool registrationAttempted()
|
||||||
|
{
|
||||||
|
return nick !is null && user !is null;
|
||||||
|
}
|
||||||
|
|
||||||
@property bool registered()
|
@property bool registered()
|
||||||
{
|
{
|
||||||
return nick !is null && user !is null && _server.isPassCorrect(pass);
|
return registrationAttempted && (!_server.hasPass || _server.isPassCorrect(pass));
|
||||||
}
|
}
|
||||||
|
|
||||||
@property bool isOperator()
|
@property bool isOperator()
|
||||||
|
@ -61,9 +68,10 @@ class Connection
|
||||||
@property string servername()
|
@property string servername()
|
||||||
{
|
{
|
||||||
return _server.name;
|
return _server.name;
|
||||||
} //TODO: Support server linking
|
}
|
||||||
|
|
||||||
//TODO: Maybe replace string's opEquals (or make a new string class/struct) to compare with toIRCLower
|
//TODO: Support server linking
|
||||||
|
//TODO: Maybe 'replace' string's opEquals (or make a new string class/struct) to compare with toIRCLower
|
||||||
//TODO: Read errata
|
//TODO: Read errata
|
||||||
|
|
||||||
this(TCPConnection connection, Server server)
|
this(TCPConnection connection, Server server)
|
||||||
|
@ -118,6 +126,7 @@ class Connection
|
||||||
|
|
||||||
void closeConnection()
|
void closeConnection()
|
||||||
{
|
{
|
||||||
|
connected = false;
|
||||||
_connection.close();
|
_connection.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +167,14 @@ class Connection
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: If RFC-strictness is off, ignore command case
|
//NOTE: The RFCs don't specify whether commands are case-sensitive
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
message.command = message.command.map!toUpper.to!string;
|
||||||
|
}
|
||||||
|
|
||||||
//NOTE: The RFCs don't specify what 'being idle' means
|
//NOTE: The RFCs don't specify what 'being idle' means
|
||||||
// We assume that it's sending any message that isn't a PING/PONG.
|
// We assume that it's sending any message that isn't a PING/PONG.
|
||||||
if (message.command != "PING" && message.command != "PONG")
|
if (message.command != "PING" && message.command != "PONG")
|
||||||
{
|
{
|
||||||
lastMessageTime = Clock.currTime;
|
lastMessageTime = Clock.currTime;
|
||||||
|
@ -313,6 +326,10 @@ class Connection
|
||||||
{
|
{
|
||||||
sendWelcome();
|
sendWelcome();
|
||||||
}
|
}
|
||||||
|
else if (registrationAttempted)
|
||||||
|
{
|
||||||
|
onIncorrectPassword();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUser(Message message)
|
void onUser(Message message)
|
||||||
|
@ -343,12 +360,14 @@ class Connection
|
||||||
{
|
{
|
||||||
sendWelcome();
|
sendWelcome();
|
||||||
}
|
}
|
||||||
|
else if (registrationAttempted)
|
||||||
|
{
|
||||||
|
onIncorrectPassword();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPass(Message message)
|
void onPass(Message message)
|
||||||
{
|
{
|
||||||
//TODO: Make sure PASS is sent before the NICK/USER combination
|
|
||||||
|
|
||||||
if (message.parameters.length < 1)
|
if (message.parameters.length < 1)
|
||||||
{
|
{
|
||||||
sendErrNeedMoreParams(message.command);
|
sendErrNeedMoreParams(message.command);
|
||||||
|
@ -364,12 +383,6 @@ class Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
pass = message.parameters[0];
|
pass = message.parameters[0];
|
||||||
|
|
||||||
if (!_server.isPassCorrect(pass))
|
|
||||||
{
|
|
||||||
//NOTE: The RFCs don't allow ERR_PASSWDMISMATCH as a response to PASS
|
|
||||||
//TODO: If RFC-strictness is off, do send ERR_PASSWDMISMATCH
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onQuit(Message message)
|
void onQuit(Message message)
|
||||||
|
@ -443,7 +456,9 @@ class Connection
|
||||||
nick, channelName, "Cannot join channel (+i)"
|
nick, channelName, "Cannot join channel (+i)"
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
else if (channel.maskLists['b'].any!(m => matchesMask(m)))
|
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", [
|
send(Message(_server.name, "474", [
|
||||||
nick, channelName, "Cannot join channel (+b)"
|
nick, channelName, "Cannot join channel (+b)"
|
||||||
|
@ -645,10 +660,16 @@ class Connection
|
||||||
&& (!(c.modes.canFind('s') || c.modes.canFind('p')) || c.members.canFind(this))))
|
&& (!(c.modes.canFind('s') || c.modes.canFind('p')) || c.members.canFind(this))))
|
||||||
{
|
{
|
||||||
//NOTE: The RFCs don't allow ERR_NOSUCHCHANNEL as a response to TOPIC
|
//NOTE: The RFCs don't allow ERR_NOSUCHCHANNEL as a response to TOPIC
|
||||||
//TODO: If RFC-strictness is off, do send ERR_NOSUCHCHANNEL
|
version (BasicFixes)
|
||||||
send(Message(_server.name, "331", [
|
{
|
||||||
nick, channelName, "No topic is set"
|
sendErrNoSuchChannel(channelName);
|
||||||
], true));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send(Message(_server.name, "331", [
|
||||||
|
nick, channelName, "No topic is set"
|
||||||
|
], true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -844,10 +865,10 @@ class Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: The RFCs are ambiguous about the parameter(s).
|
//NOTE: The RFCs are ambiguous about the parameter(s).
|
||||||
// It specifies one allowed parameter type, a space-separated list of nicknames (i.e. prefixed with ':').
|
// It specifies one allowed parameter type, a space-separated list of nicknames (i.e. prefixed with ':').
|
||||||
// However, the nicknames in the example are sent as separate parameters, not as a single string prefixed with ':'.
|
// However, the nicknames in the example are sent as separate parameters, not as a single string prefixed with ':'.
|
||||||
// For this implementation, we assume the example is wrong, like most clients seem to assume as well.
|
// For this implementation, we assume the example is wrong, like most clients seem to assume as well.
|
||||||
// (Other server implementations usually seem to support both interpretations.)
|
// (Other server implementations usually seem to support both interpretations.)
|
||||||
_server.ison(this, message.parameters[0].split);
|
_server.ison(this, message.parameters[0].split);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,7 +940,6 @@ class Connection
|
||||||
|
|
||||||
if (channelList.length != 1 && channelList.length != userList.length)
|
if (channelList.length != 1 && channelList.length != userList.length)
|
||||||
{
|
{
|
||||||
//TODO: Figure out what the right error is here
|
|
||||||
sendErrNeedMoreParams(message.command);
|
sendErrNeedMoreParams(message.command);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -978,7 +998,11 @@ class Connection
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, send an error
|
//NOTE: The RFCs don't allow ERR_NOSUCHNICK as a reponse to MODE
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
sendErrNoSuchNick(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,10 +1012,22 @@ class Connection
|
||||||
|
|
||||||
if (target.toIRCLower != nick.toIRCLower)
|
if (target.toIRCLower != nick.toIRCLower)
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, use a different error message when viewing modes and when changing modes
|
//NOTE: The RFCs don't specify a different message for viewing other users' modes
|
||||||
send(Message(_server.name, "502", [
|
version (BasicFixes)
|
||||||
nick, "Cannot change mode for other users"
|
{
|
||||||
], true));
|
if (message.parameters.length > 1)
|
||||||
|
{
|
||||||
|
send(Message(_server.name, "502", [nick, "Cannot change mode for other users"], true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send(Message(_server.name, "502", [nick, "Cannot view mode of other users"], true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send(Message(_server.name, "502", [nick, "Cannot change mode for other users"], true));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,7 +1042,11 @@ class Connection
|
||||||
auto add = modeString[0] == '+';
|
auto add = modeString[0] == '+';
|
||||||
if (!add && modeString[0] != '-')
|
if (!add && modeString[0] != '-')
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, send a malformed message error
|
//NOTE: The RFCs don't specify what should happen on malformed mode operations
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
sendMalformedMessageError(message.command, "Invalid mode operation: " ~ modeString[0]);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,19 +1058,18 @@ class Connection
|
||||||
auto changedModes = modeString[1 .. $];
|
auto changedModes = modeString[1 .. $];
|
||||||
foreach (mode; changedModes)
|
foreach (mode; changedModes)
|
||||||
{
|
{
|
||||||
//when RFC-strictness is off, maybe send an error when trying to do an illegal change
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'w':
|
case 'w':
|
||||||
case 's':
|
case 's':
|
||||||
if (add)
|
if (add)
|
||||||
modes ~= mode;
|
modes ~= mode;
|
||||||
else
|
else
|
||||||
removeMode(mode);
|
removeMode(mode);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'O':
|
case 'O':
|
||||||
if (!add)
|
if (!add)
|
||||||
removeMode(mode);
|
removeMode(mode);
|
||||||
break;
|
break;
|
||||||
|
@ -1057,17 +1096,31 @@ class Connection
|
||||||
auto channelRange = _server.findChannelByName(message.parameters[0]);
|
auto channelRange = _server.findChannelByName(message.parameters[0]);
|
||||||
if (channelRange.empty)
|
if (channelRange.empty)
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, send an error message when the channel doesn't exist
|
//NOTE: The RFCs don't allow ERR_NOSUCHCHANNEL as a response to MODE
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
sendErrNoSuchChannel(message.parameters[0]);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto channel = channelRange[0];
|
auto channel = channelRange[0];
|
||||||
|
|
||||||
|
//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)
|
if (message.parameters.length == 1)
|
||||||
{
|
{
|
||||||
channel.sendModes(this);
|
channel.sendModes(this);
|
||||||
}
|
}
|
||||||
//TODO: If RFC-strictness is off, also allow '+e' and '+I' (?)
|
else if (message.parameters.length == 2 && listQueryModes.canFind(message.parameters[1]))
|
||||||
else if (message.parameters.length == 2 && ["+b", "e", "I"].canFind(message.parameters[1]))
|
|
||||||
{
|
{
|
||||||
auto listChar = message.parameters[1][$ - 1];
|
auto listChar = message.parameters[1][$ - 1];
|
||||||
final switch (listChar)
|
final switch (listChar)
|
||||||
|
@ -1097,7 +1150,11 @@ class Connection
|
||||||
auto add = modeString[0] == '+';
|
auto add = modeString[0] == '+';
|
||||||
if (!add && modeString[0] != '-')
|
if (!add && modeString[0] != '-')
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, send a malformed message error
|
//NOTE: The RFCs don't specify what should happen on malformed mode operations
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
sendMalformedMessageError(message.command, "Invalid mode operation: " ~ modeString[0]);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,7 +1169,6 @@ class Connection
|
||||||
auto changedModes = modeString[1 .. $];
|
auto changedModes = modeString[1 .. $];
|
||||||
Lforeach: foreach (mode; changedModes)
|
Lforeach: foreach (mode; changedModes)
|
||||||
{
|
{
|
||||||
//when RFC-strictness is off, maybe send an error when trying to do an illegal change
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
//TODO: If 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
|
||||||
|
@ -1121,7 +1177,6 @@ class Connection
|
||||||
case 'v':
|
case 'v':
|
||||||
if (i + 1 == message.parameters.length)
|
if (i + 1 == message.parameters.length)
|
||||||
{
|
{
|
||||||
//TODO: Figure out what to do when we need more mode parameters
|
|
||||||
break Lforeach;
|
break Lforeach;
|
||||||
}
|
}
|
||||||
auto memberNick = message.parameters[++i];
|
auto memberNick = message.parameters[++i];
|
||||||
|
@ -1151,20 +1206,34 @@ class Connection
|
||||||
processedParameters ~= memberNick;
|
processedParameters ~= memberNick;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'b': //TODO: Implement bans
|
case 'b':
|
||||||
case 'e': //TODO: Implement ban exceptions
|
case 'e':
|
||||||
case 'I': //TODO: Implement invite lists
|
case 'I':
|
||||||
if (i + 1 == message.parameters.length)
|
if (i + 1 == message.parameters.length)
|
||||||
{
|
{
|
||||||
//TODO: Figure out what to do when we need more mode parameters
|
|
||||||
break Lforeach;
|
break Lforeach;
|
||||||
}
|
}
|
||||||
auto mask = message.parameters[++i];
|
auto mask = message.parameters[++i];
|
||||||
//TODO: If RFC-strictness is off, interpret '<nick>' as '<nick>!*@*'
|
|
||||||
if (!Server.isValidUserMask(mask))
|
if (!Server.isValidUserMask(mask))
|
||||||
{
|
{
|
||||||
//TODO: If RFC-strictness is off, send an error
|
//NOTE: The RFCs don't specify whether nicks are valid masks
|
||||||
break Lforeach;
|
//NOTE: The RFCs don't allow an error reply on an invalid user mask
|
||||||
|
version (BasicFixes)
|
||||||
|
{
|
||||||
|
if (Server.isValidNick(mask))
|
||||||
|
{
|
||||||
|
mask ~= "!*@*";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendMalformedMessageError(message.command, "Invalid user mask: " ~ mask);
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break Lforeach;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
|
@ -1181,7 +1250,6 @@ class Connection
|
||||||
case 'k':
|
case 'k':
|
||||||
if (i + 1 == message.parameters.length)
|
if (i + 1 == message.parameters.length)
|
||||||
{
|
{
|
||||||
//TODO: Figure out what to do when we need more mode parameters
|
|
||||||
break Lforeach;
|
break Lforeach;
|
||||||
}
|
}
|
||||||
auto key = message.parameters[++i];
|
auto key = message.parameters[++i];
|
||||||
|
@ -1202,7 +1270,6 @@ class Connection
|
||||||
{
|
{
|
||||||
if (i + 1 == message.parameters.length)
|
if (i + 1 == message.parameters.length)
|
||||||
{
|
{
|
||||||
//TODO: Figure out what to do when we need more mode parameters
|
|
||||||
break Lforeach;
|
break Lforeach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1230,9 +1297,9 @@ class Connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'i': //TODO: Implement invite-only channels
|
case 'i':
|
||||||
case 'm': //TODO: Implement channel moderation
|
case 'm':
|
||||||
case 'n': //TODO: Implement the no messages from clients on the outside flag
|
case 'n':
|
||||||
case 'p':
|
case 'p':
|
||||||
case 's':
|
case 's':
|
||||||
case 't':
|
case 't':
|
||||||
|
@ -1408,13 +1475,42 @@ class Connection
|
||||||
], true));
|
], true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendMalformedMessageError(string command, string description)
|
||||||
|
{
|
||||||
|
send(Message(_server.name, "ERROR", [command, "Malformed message: " ~ description], true));
|
||||||
|
}
|
||||||
|
|
||||||
void sendWelcome()
|
void sendWelcome()
|
||||||
{
|
{
|
||||||
send(Message(_server.name, "001", [
|
//NOTE: According to the RFCs these aren't ':'-prefixed strings but separate parameters
|
||||||
nick, "Welcome to the Internet Relay Network " ~ prefix
|
|
||||||
], true));
|
|
||||||
|
|
||||||
//TODO: If RFC-strictness is off, also send 002, 003, and 004
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: The RFCs don't actually specify what should happen here
|
||||||
|
closeConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
string getHost()
|
string getHost()
|
||||||
|
|
|
@ -12,7 +12,7 @@ import std.string;
|
||||||
import vibe.core.core;
|
import vibe.core.core;
|
||||||
import vibe.core.net;
|
import vibe.core.net;
|
||||||
|
|
||||||
import ircd.packageVersion;
|
import ircd.versionInfo;
|
||||||
|
|
||||||
import ircd.message;
|
import ircd.message;
|
||||||
import ircd.connection;
|
import ircd.connection;
|
||||||
|
@ -24,7 +24,7 @@ class Server
|
||||||
{
|
{
|
||||||
Connection[] connections;
|
Connection[] connections;
|
||||||
|
|
||||||
enum versionString = "salty-ircd-" ~ packageVersion;
|
enum versionString = "salty-ircd-" ~ gitVersion;
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
enum string info = "A salty-ircd server"; //TODO: Make server info configurable
|
enum string info = "A salty-ircd server"; //TODO: Make server info configurable
|
||||||
|
@ -229,8 +229,8 @@ class Server
|
||||||
{
|
{
|
||||||
foreach (c; connections.filter!(c => c.visibleTo(origin))
|
foreach (c; connections.filter!(c => c.visibleTo(origin))
|
||||||
.filter!(c => !operatorsOnly || c.isOperator)
|
.filter!(c => !operatorsOnly || c.isOperator)
|
||||||
.filter!(c => [c.hostname, c.servername, c.realname,
|
.filter!(c => [c.hostname, c.servername, c.realname, c.nick]
|
||||||
c.nick].any!(n => wildcardMatch(n, mask))))
|
.any!(n => wildcardMatch(n, mask))))
|
||||||
{
|
{
|
||||||
//TODO: Don't leak secret/private channels if RFC-strictness is off (the RFCs don't seem to say anything about it?)
|
//TODO: Don't leak secret/private channels if RFC-strictness is off (the RFCs don't seem to say anything about it?)
|
||||||
auto channelName = c.channels.empty ? "*" : c.channels.array[0].name;
|
auto channelName = c.channels.empty ? "*" : c.channels.array[0].name;
|
||||||
|
@ -510,6 +510,11 @@ class Server
|
||||||
return pass == _pass;
|
return pass == _pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasPass()
|
||||||
|
{
|
||||||
|
return _pass != null;
|
||||||
|
}
|
||||||
|
|
||||||
void listen(ushort port = 6667)
|
void listen(ushort port = 6667)
|
||||||
{
|
{
|
||||||
listenTCP(port, &acceptConnection);
|
listenTCP(port, &acceptConnection);
|
||||||
|
|
|
@ -11,6 +11,9 @@ module ircd.versions;
|
||||||
(* NotStrict: enabled when any versions are enabled that disable RFC-strictness, i.e. any of the above)
|
(* NotStrict: enabled when any versions are enabled that disable RFC-strictness, i.e. any of the above)
|
||||||
+/
|
+/
|
||||||
|
|
||||||
|
//TODO: Implement 'SupportTLS'
|
||||||
|
//TODO: Implement 'MaxNickLengthConfigurable'
|
||||||
|
|
||||||
version (Modern)
|
version (Modern)
|
||||||
{
|
{
|
||||||
version = SupportTLS;
|
version = SupportTLS;
|
||||||
|
|
Loading…
Reference in New Issue