diff options
author | Peter Powell <petpow@saberuk.com> | 2019-03-30 15:48:33 +0000 |
---|---|---|
committer | P. Powell <petpow@saberuk.com> | 2019-09-23 13:20:07 +0100 |
commit | e43bc49ba73840af183b70a1069c9b50ba72eb59 (patch) | |
tree | f07ce3349064eedaf45c9c259eeee8a908441452 /src | |
parent | d9de4ddd8295a4917b0b0b8260fc647b55ced683 (diff) |
Update the core message parser to allow parsing IRCv3 message tags.
Diffstat (limited to 'src')
-rw-r--r-- | src/process.cpp | 123 | ||||
-rw-r--r-- | src/protocol.cpp | 7 |
2 files changed, 105 insertions, 25 deletions
diff --git a/src/process.cpp b/src/process.cpp index 43f504f51..2bec1a83d 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -24,13 +24,21 @@ void Anope::Process(const Anope::string &buffer) if (buffer.empty()) return; + Anope::map<Anope::string> tags; Anope::string source, command; std::vector<Anope::string> params; - IRCD->Parse(buffer, source, command, params); + if (!IRCD->Parse(buffer, tags, source, command, params)) + return; if (Anope::ProtocolDebug) { + if (tags.empty()) + Log() << "No tags"; + else + for (Anope::map<Anope::string>::const_iterator it = tags.begin(); it != tags.end(); ++it) + Log() << "tags " << it->first << ": " << it->second; + Log() << "Source : " << (source.empty() ? "No source" : source); Log() << "Command: " << command; @@ -41,12 +49,6 @@ void Anope::Process(const Anope::string &buffer) Log() << "params " << i << ": " << params[i]; } - if (command.empty()) - { - Log(LOG_DEBUG) << "No command? " << buffer; - return; - } - static const Anope::string proto_name = ModuleManager::FindFirstOf(PROTOCOL) ? ModuleManager::FindFirstOf(PROTOCOL)->name : ""; MessageSource src(source); @@ -70,34 +72,55 @@ void Anope::Process(const Anope::string &buffer) else if (m->HasFlag(IRCDMESSAGE_REQUIRE_SERVER) && !source.empty() && !src.GetServer()) Log(LOG_DEBUG) << "unexpected non-server source " << source << " for " << command; else - m->Run(src, params); + m->Run(src, params, tags); } -void IRCDProto::Parse(const Anope::string &buffer, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms) +bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms) { - spacesepstream sep(buffer); - - if (buffer[0] == ':') - { - sep.GetToken(source); - source.erase(0, 1); - } + MessageTokenizer tokens(buffer); - sep.GetToken(command); + // This will always exist because of the check in Anope::Process. + Anope::string token; + tokens.GetMiddle(token); - for (Anope::string token; sep.GetToken(token);) + if (token[0] == '@') { - if (token[0] == ':') + // The line begins with message tags. + sepstream tagstream(token.substr(1), ';'); + while (tagstream.GetToken(token)) { - if (!sep.StreamEnd()) - params.push_back(token.substr(1) + " " + sep.GetRemaining()); + const Anope::string::size_type valsep = token.find('='); + if (valsep == Anope::string::npos) + { + // Tag has no value. + tags[token]; + } else - params.push_back(token.substr(1)); - break; + { + // Tag has a value + tags[token.substr(0, valsep)] = token.substr(valsep + 1); + } } - else - params.push_back(token); + + if (!tokens.GetMiddle(token)) + return false; + } + + if (token[0] == ':') + { + source = token.substr(1); + if (!tokens.GetMiddle(token)) + return false; } + + // Store the command name. + command = token; + + // Retrieve all of the parameters. + while (tokens.GetTrailing(token)) + params.push_back(token); + + return true; } Anope::string IRCDProto::Format(const Anope::string &source, const Anope::string &message) @@ -107,3 +130,53 @@ Anope::string IRCDProto::Format(const Anope::string &source, const Anope::string else return message; } + +MessageTokenizer::MessageTokenizer(const Anope::string &msg) + : message(msg) + , position(0) +{ +} + +bool MessageTokenizer::GetMiddle(Anope::string &token) +{ + // If we are past the end of the string we can't do anything. + if (position >= message.length()) + { + token.clear(); + return false; + } + + // If we can't find another separator this is the last token in the message. + Anope::string::size_type separator = message.find(' ', position); + if (separator == Anope::string::npos) + { + token = message.substr(position); + position = message.length(); + return true; + } + + token = message.substr(position, separator - position); + position = message.find_first_not_of(' ', separator); + return true; +} + +bool MessageTokenizer::GetTrailing(Anope::string &token) +{ + // If we are past the end of the string we can't do anything. + if (position >= message.length()) + { + token.clear(); + return false; + } + + // If this is true then we have a <trailing> token! + if (message[position] == ':') + { + token = message.substr(position + 1); + position = message.length(); + return true; + } + + // There is no <trailing> token so it must be a <middle> token. + return GetMiddle(token); +} diff --git a/src/protocol.cpp b/src/protocol.cpp index 3daa9f136..dd2595992 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -502,3 +502,10 @@ unsigned IRCDMessage::GetParamCount() const { return this->param_count; } + +void IRCDMessage::Run(MessageSource &source, const std::vector<Anope::string> ¶ms, const Anope::map<Anope::string> &tags) +{ + // Most IRCds don't support message tags yet so use the tagless variant. + Run(source, params); +} + |