mirror of
https://github.com/anope/anope.git
synced 2026-06-25 14:06:37 +02:00
Update the core message parser to allow parsing IRCv3 message tags.
This commit is contained in:
+99
-26
@@ -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);
|
||||
MessageTokenizer tokens(buffer);
|
||||
|
||||
if (buffer[0] == ':')
|
||||
// This will always exist because of the check in Anope::Process.
|
||||
Anope::string token;
|
||||
tokens.GetMiddle(token);
|
||||
|
||||
if (token[0] == '@')
|
||||
{
|
||||
sep.GetToken(source);
|
||||
source.erase(0, 1);
|
||||
}
|
||||
|
||||
sep.GetToken(command);
|
||||
|
||||
for (Anope::string token; sep.GetToken(token);)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user