summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Powell <petpow@saberuk.com>2019-03-30 15:48:33 +0000
committerP. Powell <petpow@saberuk.com>2019-09-23 13:20:07 +0100
commite43bc49ba73840af183b70a1069c9b50ba72eb59 (patch)
treef07ce3349064eedaf45c9c259eeee8a908441452 /src
parentd9de4ddd8295a4917b0b0b8260fc647b55ced683 (diff)
Update the core message parser to allow parsing IRCv3 message tags.
Diffstat (limited to 'src')
-rw-r--r--src/process.cpp123
-rw-r--r--src/protocol.cpp7
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> &params)
+bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> &params)
{
- 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> &params, const Anope::map<Anope::string> &tags)
+{
+ // Most IRCds don't support message tags yet so use the tagless variant.
+ Run(source, params);
+}
+