diff options
Diffstat (limited to 'modules/protocol/ngircd.cpp')
-rw-r--r-- | modules/protocol/ngircd.cpp | 655 |
1 files changed, 289 insertions, 366 deletions
diff --git a/modules/protocol/ngircd.cpp b/modules/protocol/ngircd.cpp index 2c03ed434..6ce997e2a 100644 --- a/modules/protocol/ngircd.cpp +++ b/modules/protocol/ngircd.cpp @@ -22,6 +22,7 @@ #include "module.h" #include "modules/protocol/rfc1459.h" +#include "modules/protocol/ngircd.h" class ngIRCdProto : public IRCDProto { @@ -190,428 +191,352 @@ class ngIRCdProto : public IRCDProto } }; -struct IRCDMessage005 : IRCDMessage +// Please see <http://www.irc.org/tech_docs/005.html> for details. +void ngircd::Numeric005::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessage005(Module *creator) : IRCDMessage(creator, "005", 1) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } - - // Please see <http://www.irc.org/tech_docs/005.html> for details. - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + size_t pos; + Anope::string parameter, data; + for (unsigned i = 0, end = params.size(); i < end; ++i) { - size_t pos; - Anope::string parameter, data; - for (unsigned i = 0, end = params.size(); i < end; ++i) + pos = params[i].find('='); + if (pos != Anope::string::npos) { - pos = params[i].find('='); - if (pos != Anope::string::npos) + parameter = params[i].substr(0, pos); + data = params[i].substr(pos+1, params[i].length()); + if (parameter == "MODES") { - parameter = params[i].substr(0, pos); - data = params[i].substr(pos+1, params[i].length()); - if (parameter == "MODES") - { - unsigned maxmodes = convertTo<unsigned>(data); - IRCD->MaxModes = maxmodes; - } - else if (parameter == "NICKLEN") + unsigned maxmodes = convertTo<unsigned>(data); + IRCD->MaxModes = maxmodes; + } + else if (parameter == "NICKLEN") + { + unsigned newlen = convertTo<unsigned>(data), len = Config->GetBlock("networkinfo")->Get<unsigned>("nicklen"); + if (len != newlen) { - unsigned newlen = convertTo<unsigned>(data), len = Config->GetBlock("networkinfo")->Get<unsigned>("nicklen"); - if (len != newlen) - { - Log() << "Warning: NICKLEN is " << newlen << " but networkinfo:nicklen is " << len; - } + Log() << "Warning: NICKLEN is " << newlen << " but networkinfo:nicklen is " << len; } } } } -}; +} -struct IRCDMessage376 : IRCDMessage +/* + * CHANINFO is used by servers to inform each other about a channel: its + * modes, channel key, user limits and its topic. The parameter combination + * <key> and <limit> is optional, as well as the <topic> parameter, so that + * there are three possible forms of this command: + * + * CHANINFO <chan> +<modes> + * CHANINFO <chan> +<modes> :<topic> + * CHANINFO <chan> +<modes> <key> <limit> :<topic> + * + * The parameter <key> must be ignored if a channel has no key (the parameter + * <modes> doesn't list the "k" channel mode). In this case <key> should + * contain "*" because the parameter <key> is required by the CHANINFO syntax + * and therefore can't be omitted. The parameter <limit> must be ignored when + * a channel has no user limit (the parameter <modes> doesn't list the "l" + * channel mode). In this case <limit> should be "0". + */ +void ngircd::ChanInfo::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessage376(Module *creator) : IRCDMessage(creator, "376", 2) { } + bool created; + Channel *c = Channel::FindOrCreate(params[0], created); - /* - * :ngircd.dev.anope.de 376 services.anope.de :End of MOTD command - * - * we do nothing here, this function exists only to - * avoid the "unknown message from server" message. - * - */ + Anope::string modes = params[1]; - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + if (params.size() == 3) { + c->ChangeTopicInternal(NULL, source.GetName(), params[2], Anope::CurTime); } -}; - -struct IRCDMessageChaninfo : IRCDMessage -{ - IRCDMessageChaninfo(Module *creator) : IRCDMessage(creator, "CHANINFO", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } - - /* - * CHANINFO is used by servers to inform each other about a channel: its - * modes, channel key, user limits and its topic. The parameter combination - * <key> and <limit> is optional, as well as the <topic> parameter, so that - * there are three possible forms of this command: - * - * CHANINFO <chan> +<modes> - * CHANINFO <chan> +<modes> :<topic> - * CHANINFO <chan> +<modes> <key> <limit> :<topic> - * - * The parameter <key> must be ignored if a channel has no key (the parameter - * <modes> doesn't list the "k" channel mode). In this case <key> should - * contain "*" because the parameter <key> is required by the CHANINFO syntax - * and therefore can't be omitted. The parameter <limit> must be ignored when - * a channel has no user limit (the parameter <modes> doesn't list the "l" - * channel mode). In this case <limit> should be "0". - */ - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + else if (params.size() == 5) { - bool created; - Channel *c = Channel::FindOrCreate(params[0], created); - - Anope::string modes = params[1]; - - if (params.size() == 3) - { - c->ChangeTopicInternal(NULL, source.GetName(), params[2], Anope::CurTime); - } - else if (params.size() == 5) + for (size_t i = 0, end = params[1].length(); i < end; ++i) { - for (size_t i = 0, end = params[1].length(); i < end; ++i) + switch(params[1][i]) { - switch(params[1][i]) - { - case 'k': - modes += " " + params[2]; - continue; - case 'l': - modes += " " + params[3]; - continue; - } + case 'k': + modes += " " + params[2]; + continue; + case 'l': + modes += " " + params[3]; + continue; } - c->ChangeTopicInternal(NULL, source.GetName(), params[4], Anope::CurTime); } - - c->SetModesInternal(source, modes); + c->ChangeTopicInternal(NULL, source.GetName(), params[4], Anope::CurTime); } -}; -struct IRCDMessageJoin : rfc1459::Join + c->SetModesInternal(source, modes); +} + +/* + * <@po||ux> DukeP: RFC 2813, 4.2.1: the JOIN command on server-server links + * separates the modes ("o") with ASCII 7, not space. And you can't see ASCII 7. + * + * if a user joins a new channel, the ircd sends <channelname>\7<umode> + */ +void ngircd::Join::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageJoin(Module *creator) : rfc1459::Join(creator, "JOIN") { } + User *user = source.GetUser(); + size_t pos = params[0].find('\7'); + Anope::string channel, modes; - /* - * <@po||ux> DukeP: RFC 2813, 4.2.1: the JOIN command on server-server links - * separates the modes ("o") with ASCII 7, not space. And you can't see ASCII 7. - * - * if a user joins a new channel, the ircd sends <channelname>\7<umode> - */ - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + if (pos != Anope::string::npos) { - User *user = source.GetUser(); - size_t pos = params[0].find('\7'); - Anope::string channel, modes; - - if (pos != Anope::string::npos) - { - channel = params[0].substr(0, pos); - modes = '+' + params[0].substr(pos+1, params[0].length()) + " " + user->nick; - } - else - { - channel = params[0]; - } + channel = params[0].substr(0, pos); + modes = '+' + params[0].substr(pos+1, params[0].length()) + " " + user->nick; + } + else + { + channel = params[0]; + } - std::vector<Anope::string> new_params; - new_params.push_back(channel); + std::vector<Anope::string> new_params; + new_params.push_back(channel); - rfc1459::Join::Run(source, new_params); + rfc1459::Join::Run(source, new_params); - if (!modes.empty()) - { - Channel *c = Channel::Find(channel); - if (c) - c->SetModesInternal(source, modes); - } + if (!modes.empty()) + { + Channel *c = Channel::Find(channel); + if (c) + c->SetModesInternal(source, modes); } -}; +} -struct IRCDMessageMetadata : IRCDMessage +/* + * Received: :ngircd.dev.anope.de METADATA DukePyrolator host :anope-e2ee5c7d + * + * params[0] = nick of the user + * params[1] = command + * params[2] = data + * + * following commands are supported: + * - "accountname": the account name of a client (can't be empty) + * - "certfp": the certificate fingerprint of a client (can't be empty) + * - "cloakhost" : the cloaked hostname of a client + * - "host": the hostname of a client (can't be empty) + * - "info": info text ("real name") of a client + * - "user": the user name (ident) of a client (can't be empty) + */ +void ngircd::Metadata::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageMetadata(Module *creator) : IRCDMessage(creator, "METADATA", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } - - /* - * Received: :ngircd.dev.anope.de METADATA DukePyrolator host :anope-e2ee5c7d - * - * params[0] = nick of the user - * params[1] = command - * params[2] = data - * - * following commands are supported: - * - "accountname": the account name of a client (can't be empty) - * - "certfp": the certificate fingerprint of a client (can't be empty) - * - "cloakhost" : the cloaked hostname of a client - * - "host": the hostname of a client (can't be empty) - * - "info": info text ("real name") of a client - * - "user": the user name (ident) of a client (can't be empty) - */ - - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + User *u = User::Find(params[0]); + if (!u) { - User *u = User::Find(params[0]); - if (!u) - { - Log() << "received METADATA for non-existent user " << params[0]; - return; - } - if (params[1].equals_cs("accountname")) - { - NickServ::Account *nc = NickServ::FindAccount(params[2]); - if (nc) - u->Login(nc); - } - else if (params[1].equals_cs("certfp")) - { - u->fingerprint = params[2]; - EventManager::Get()->Dispatch(&Event::Fingerprint::OnFingerprint, u); - } - else if (params[1].equals_cs("cloakhost")) - { - if (!params[2].empty()) - u->SetDisplayedHost(params[2]); - } - else if (params[1].equals_cs("host")) - { - u->SetCloakedHost(params[2]); - } - else if (params[1].equals_cs("info")) - { - u->SetRealname(params[2]); - } - else if (params[1].equals_cs("user")) - { - u->SetVIdent(params[2]); - } + Log() << "received METADATA for non-existent user " << params[0]; + return; } -}; + if (params[1].equals_cs("accountname")) + { + NickServ::Account *nc = NickServ::FindAccount(params[2]); + if (nc) + u->Login(nc); + } + else if (params[1].equals_cs("certfp")) + { + u->fingerprint = params[2]; + EventManager::Get()->Dispatch(&Event::Fingerprint::OnFingerprint, u); + } + else if (params[1].equals_cs("cloakhost")) + { + if (!params[2].empty()) + u->SetDisplayedHost(params[2]); + } + else if (params[1].equals_cs("host")) + { + u->SetCloakedHost(params[2]); + } + else if (params[1].equals_cs("info")) + { + u->SetRealname(params[2]); + } + else if (params[1].equals_cs("user")) + { + u->SetVIdent(params[2]); + } +} -struct IRCDMessageMode : IRCDMessage +/* + * Received: :DukeP MODE #anope +b *!*@*.aol.com + * Received: :DukeP MODE #anope +h DukeP + * params[0] = channel or nick + * params[1] = modes + * params[n] = parameters + */ +void ngircd::Mode::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageMode(Module *creator) : IRCDMessage(creator, "MODE", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } + Anope::string modes = params[1]; - /* - * Received: :DukeP MODE #anope +b *!*@*.aol.com - * Received: :DukeP MODE #anope +h DukeP - * params[0] = channel or nick - * params[1] = modes - * params[n] = parameters - */ + for (size_t i = 2; i < params.size(); ++i) + modes += " " + params[i]; - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + if (IRCD->IsChannelValid(params[0])) { - Anope::string modes = params[1]; - - for (size_t i = 2; i < params.size(); ++i) - modes += " " + params[i]; - - if (IRCD->IsChannelValid(params[0])) - { - Channel *c = Channel::Find(params[0]); - - if (c) - c->SetModesInternal(source, modes); - } - else - { - User *u = User::Find(params[0]); + Channel *c = Channel::Find(params[0]); - if (u) - u->SetModesInternal(source, "%s", params[1].c_str()); - } + if (c) + c->SetModesInternal(source, modes); } -}; - -struct IRCDMessageNick : IRCDMessage -{ - IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 1) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } - - /* - * NICK - NEW - * Received: :dev.anope.de NICK DukeP_ 1 ~DukePyro ip-2-201-236-154.web.vodafone.de 1 + :DukePyrolator - * Parameters: <nickname> <hopcount> <username> <host> <servertoken> <umode> :<realname> - * source = server - * params[0] = nick - * params[1] = hopcount - * params[2] = username/ident - * params[3] = host - * params[4] = servertoken - * params[5] = modes - * params[6] = info - * - * NICK - change - * Received: :DukeP_ NICK :test2 - * source = oldnick - * params[0] = newnick - * - */ - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + else { - if (params.size() == 1) - { - // we have a nickchange - User *u = source.GetUser(); + User *u = User::Find(params[0]); - if (u) - u->ChangeNick(params[0]); - } - else if (params.size() == 7) - { - // a new user is connecting to the network - Server *s = Server::Find(params[4]); - if (s == NULL) - { - Log(LOG_DEBUG) << "User " << params[0] << " introduced from non-existent server " << params[4] << "?"; - return; - } - User::OnIntroduce(params[0], params[2], params[3], "", "", s, params[6], Anope::CurTime, params[5], "", NULL); - Log(LOG_DEBUG) << "Registered nick \"" << params[0] << "\" on server " << s->GetName() << "."; - } - else - { - Log(LOG_DEBUG) << "Received NICK with invalid number of parameters. source = " << source.GetName() << "params[0] = " << params[0] << "params.size() = " << params.size(); - } + if (u) + u->SetModesInternal(source, "%s", params[1].c_str()); } -}; +} -struct IRCDMessageNJoin : IRCDMessage +/* + * NICK - NEW + * Received: :dev.anope.de NICK DukeP_ 1 ~DukePyro ip-2-201-236-154.web.vodafone.de 1 + :DukePyrolator + * Parameters: <nickname> <hopcount> <username> <host> <servertoken> <umode> :<realname> + * source = server + * params[0] = nick + * params[1] = hopcount + * params[2] = username/ident + * params[3] = host + * params[4] = servertoken + * params[5] = modes + * params[6] = info + * + * NICK - change + * Received: :DukeP_ NICK :test2 + * source = oldnick + * params[0] = newnick + * + */ +void ngircd::Nick::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageNJoin(Module *creator) : IRCDMessage(creator, "NJOIN",2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }; - - /* - * RFC 2813, 4.2.2: Njoin Message: - * The NJOIN message is used between servers only. - * It is used when two servers connect to each other to exchange - * the list of channel members for each channel. - * - * Even though the same function can be performed by using a succession - * of JOIN, this message SHOULD be used instead as it is more efficient. - * - * Received: :dev.anope.de NJOIN #test :DukeP2,@DukeP,%test,+test2 - */ - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + if (params.size() == 1) { - std::list<rfc1459::Join::SJoinUser> users; + // we have a nickchange + User *u = source.GetUser(); - commasepstream sep(params[1]); - Anope::string buf; - while (sep.GetToken(buf)) + if (u) + u->ChangeNick(params[0]); + } + else if (params.size() == 7) + { + // a new user is connecting to the network + Server *s = Server::Find(params[4]); + if (s == nullptr) { - - rfc1459::Join::SJoinUser sju; - - /* Get prefixes from the nick */ - for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));) - { - buf.erase(buf.begin()); - sju.first.AddMode(ch); - } - - sju.second = User::Find(buf); - if (!sju.second) - { - Log(LOG_DEBUG) << "NJOIN for non-existent user " << buf << " on " << params[0]; - continue; - } - users.push_back(sju); + Log(LOG_DEBUG) << "User " << params[0] << " introduced from non-existent server " << params[4] << "?"; + return; } - - rfc1459::Join::SJoin(source, params[0], 0, "", users); + User::OnIntroduce(params[0], params[2], params[3], "", "", s, params[6], Anope::CurTime, params[5], "", NULL); + Log(LOG_DEBUG) << "Registered nick \"" << params[0] << "\" on server " << s->GetName() << "."; } -}; - -struct IRCDMessagePong : IRCDMessage -{ - IRCDMessagePong(Module *creator) : IRCDMessage(creator, "PONG", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } - - /* - * ngIRCd does not send an EOB, so we send a PING immediately - * when receiving a new server and then finish sync once we - * get a pong back from that server. - */ - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + else { - if (!source.GetServer()->IsSynced()) - source.GetServer()->Sync(false); + Log(LOG_DEBUG) << "Received NICK with invalid number of parameters. source = " << source.GetName() << "params[0] = " << params[0] << "params.size() = " << params.size(); } -}; +} -struct IRCDMessageServer : IRCDMessage +/* + * RFC 2813, 4.2.2: Njoin Message: + * The NJOIN message is used between servers only. + * It is used when two servers connect to each other to exchange + * the list of channel members for each channel. + * + * Even though the same function can be performed by using a succession + * of JOIN, this message SHOULD be used instead as it is more efficient. + * + * Received: :dev.anope.de NJOIN #test :DukeP2,@DukeP,%test,+test2 + */ +void ngircd::NJoin::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } + std::list<rfc1459::Join::SJoinUser> users; - /* - * New directly linked server: - * - * SERVER tolsun.oulu.fi 1 :Experimental server - * New server tolsun.oulu.fi introducing itself - * and attempting to register. - * - * params[0] = servername - * params[1] = hop count - * params[2] = server description - * - * New remote server in the network: - * - * :tolsun.oulu.fi SERVER csd.bu.edu 5 34 :BU Central Server - * Server tolsun.oulu.fi is our uplink for csd.bu.edu - * which is 5 hops away. The token "34" will be used - * by tolsun.oulu.fi when introducing new users or - * services connected to csd.bu.edu. - * - * params[0] = servername - * params[1] = hop count - * params[2] = server numeric - * params[3] = server description - */ - - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override + commasepstream sep(params[1]); + Anope::string buf; + while (sep.GetToken(buf)) { - if (params.size() == 3) + + rfc1459::Join::SJoinUser sju; + + /* Get prefixes from the nick */ + for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));) { - // our uplink is introducing itself - new Server(Me, params[0], 1, params[2], "1"); + buf.erase(buf.begin()); + sju.first.AddMode(ch); } - else + + sju.second = User::Find(buf); + if (!sju.second) { - // our uplink is introducing a new server - unsigned int hops = params[1].is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; - new Server(source.GetServer(), params[0], hops, params[3], params[2]); + Log(LOG_DEBUG) << "NJOIN for non-existent user " << buf << " on " << params[0]; + continue; } - /* - * ngIRCd does not send an EOB, so we send a PING immediately - * when receiving a new server and then finish sync once we - * get a pong back from that server. - */ - IRCD->SendPing(Me->GetName(), params[0]); + users.push_back(sju); } -}; -struct IRCDMessageTopic : IRCDMessage + rfc1459::Join::SJoin(source, params[0], 0, "", users); +} + +/* + * ngIRCd does not send an EOB, so we send a PING immediately + * when receiving a new server and then finish sync once we + * get a pong back from that server. + */ +void ngircd::Pong::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { - IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } + if (!source.GetServer()->IsSynced()) + source.GetServer()->Sync(false); +} - // Received: :DukeP TOPIC #anope :test - void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override +/* + * New directly linked server: + * + * SERVER tolsun.oulu.fi 1 :Experimental server + * New server tolsun.oulu.fi introducing itself + * and attempting to register. + * + * params[0] = servername + * params[1] = hop count + * params[2] = server description + * + * New remote server in the network: + * + * :tolsun.oulu.fi SERVER csd.bu.edu 5 34 :BU Central Server + * Server tolsun.oulu.fi is our uplink for csd.bu.edu + * which is 5 hops away. The token "34" will be used + * by tolsun.oulu.fi when introducing new users or + * services connected to csd.bu.edu. + * + * params[0] = servername + * params[1] = hop count + * params[2] = server numeric + * params[3] = server description + */ + +void ngircd::ServerMessage::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) +{ + if (params.size() == 3) { - Channel *c = Channel::Find(params[0]); - if (!c) - { - Log(LOG_DEBUG) << "TOPIC for non-existent channel " << params[0]; - return; - } - c->ChangeTopicInternal(source.GetUser(), source.GetName(), params[1], Anope::CurTime); + // our uplink is introducing itself + new Server(Me, params[0], 1, params[2], "1"); } -}; + else + { + // our uplink is introducing a new server + unsigned int hops = 0; + try + { + hops = convertTo<unsigned>(params[1]); + } + catch (const ConvertException &) { } + new Server(source.GetServer(), params[0], hops, params[3], params[2]); + } + /* + * ngIRCd does not send an EOB, so we send a PING immediately + * when receiving a new server and then finish sync once we + * get a pong back from that server. + */ + IRCD->SendPing(Me->GetName(), params[0]); +} class ProtongIRCd : public Module , public EventHook<Event::UserNickChange> @@ -633,21 +558,20 @@ class ProtongIRCd : public Module rfc1459::SQuit message_squit; rfc1459::Stats message_stats; rfc1459::Time message_time; + rfc1459::Topic message_topic; rfc1459::Version message_version; rfc1459::Whois message_whois; /* Our message handlers */ - IRCDMessage005 message_005; - IRCDMessage376 message_376; - IRCDMessageChaninfo message_chaninfo; - IRCDMessageJoin message_join; - IRCDMessageMetadata message_metadata; - IRCDMessageMode message_mode; - IRCDMessageNick message_nick; - IRCDMessageNJoin message_njoin; - IRCDMessagePong message_pong; - IRCDMessageServer message_server; - IRCDMessageTopic message_topic; + ngircd::Numeric005 message_005; + ngircd::ChanInfo message_chaninfo; + ngircd::Join message_join; + ngircd::Metadata message_metadata; + ngircd::Mode message_mode; + ngircd::Nick message_nick; + ngircd::NJoin message_njoin; + ngircd::Pong message_pong; + ngircd::ServerMessage message_server; public: ProtongIRCd(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR) @@ -672,7 +596,6 @@ class ProtongIRCd : public Module , message_whois(this) , message_005(this) - , message_376(this) , message_chaninfo(this) , message_join(this) , message_metadata(this) |