Implement TOPIC

This commit is contained in:
Les De Ridder 2017-03-21 01:28:39 +01:00
parent 4f8aedddc9
commit 8a94d845e8
No known key found for this signature in database
GPG Key ID: 5EC132DFA85DB372
3 changed files with 101 additions and 9 deletions

View File

@ -9,27 +9,25 @@ import ircd.message;
class Channel
{
private string _name;
string name;
Connection[] members;
Connection owner;
string topic = "";
char[] modes;
private Server _server;
this(string name, Connection owner, Server server)
{
this._name = name;
this.name = name;
this.owner = owner;
this.members = [owner];
this._server = server;
}
@property
string name()
{
return _name;
}
void sendNames(Connection connection)
{
enum channelType = "="; //TODO: Support secret and private channels
@ -53,4 +51,26 @@ class Channel
member.send(Message(sender.mask, "NOTICE", [name, text], true));
}
}
void sendTopic(Connection connection)
{
if(topic.empty)
{
connection.send(Message(_server.name, "331", [connection.nick, name, "No topic is set"]));
}
else
{
connection.send(Message(_server.name, "332", [connection.nick, name, topic], true));
}
}
void setTopic(Connection connection, string newTopic)
{
topic = newTopic;
foreach(member; members)
{
member.send(Message(connection.mask, "TOPIC", [name, newTopic], true));
}
}
}

View File

@ -149,6 +149,10 @@ class Connection
if(!registered) sendErrNotRegistered();
else onAway(message);
break;
case "TOPIC":
if(!registered) sendErrNotRegistered();
else onTopic(message);
break;
default:
writeln("unknown command '", message.command, "'");
send(Message(_server.name, "421", [nick, message.command, "Unknown command"]));
@ -404,6 +408,47 @@ class Connection
}
}
void onTopic(Message message)
{
if(message.parameters.length == 0)
{
sendErrNeedMoreParams(message.command);
return;
}
auto channelName = message.parameters[0];
if(message.parameters.length == 1)
{
if(!_server.channels.canFind!(c => c.name == channelName && (!(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
//TODO: If RFC-strictness is off, do send ERR_NOSUCHCHANNEL
send(Message(_server.name, "331", [nick, channelName, "No topic is set"], true));
}
else
{
_server.sendChannelTopic(this, channelName);
}
}
else
{
auto newTopic = message.parameters[1];
if(!channels.canFind!(c => c.name == channelName))
{
sendErrNotOnChannel(channelName);
}
//TODO: Allow operators to set flags
else if(channels.find!(c => c.name == channelName).map!(c => c.modes.canFind('t') /* && this user isn't an operator */).array[0])
{
sendErrChanopPrivsNeeded(channelName);
}
else
{
_server.setChannelTopic(this, channelName, newTopic);
}
}
}
void sendWhoReply(string channel, Connection user, uint hopCount)
{
auto flags = user.modes.canFind('a') ? "G" : "H";
@ -433,6 +478,11 @@ class Connection
send(Message(_server.name, "431", [nick, "No nickname given"], 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));
@ -443,6 +493,11 @@ class Connection
send(Message(_server.name, "461", [nick, command, "Not enough parameters"], true));
}
void sendErrChanopPrivsNeeded(string channel)
{
send(Message(_server.name, "482", [nick, channel, "You're not channel operator"], true));
}
void sendWelcome()
{
send(Message(_server.name, "001", [nick, "Welcome to the Internet Relay Network " ~ mask], true));

View File

@ -91,6 +91,11 @@ class Server
}
channel.sendNames(connection);
if(!channel.topic.empty)
{
channel.sendTopic(connection);
}
}
void part(Connection connection, string channelName, string partMessage)
@ -163,7 +168,7 @@ class Server
.filter!(c => !operatorsOnly || c.isOperator)
.filter!(c => [c.hostname, c.servername, c.realname, c.nick].any!(n => wildcardMatch(n, mask))))
{
//TODO: Don't leak secret/private channels (even if the RFCs don't 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;
//TODO: Support hop count
origin.sendWhoReply(channelName, c, 0);
@ -194,6 +199,18 @@ class Server
user.send(Message(sender.mask, "NOTICE", [target, text], true));
}
void sendChannelTopic(Connection origin, string channelName)
{
auto channel = channels.find!(c => c.name == channelName)[0];
channel.sendTopic(origin);
}
void setChannelTopic(Connection origin, string channelName, string newTopic)
{
auto channel = channels.find!(c => c.name == channelName)[0];
channel.setTopic(origin, newTopic);
}
void listen(ushort port = 6667)
{
listenTCP(port, &acceptConnection);