X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcommand_parse.cpp;h=7a732f8b5c7acc43242f8a1b1b4538a8bcf88f5c;hb=4047a143fc1d16350db70c94b9ea77d79de05714;hp=d1ae987290bc0a506dca75436237c7b5abafcb28;hpb=1031f333332cf1b09db4fd632f141143ee637c34;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/command_parse.cpp b/src/command_parse.cpp index d1ae98729..7a732f8b5 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -23,28 +23,27 @@ #include "inspircd.h" -int InspIRCd::PassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype) +bool InspIRCd::PassCompare(Extensible* ex, const std::string& data, const std::string& input, const std::string& hashtype) { ModResult res; FIRST_MOD_RESULT(OnPassCompare, res, (ex, data, input, hashtype)); /* Module matched */ if (res == MOD_RES_ALLOW) - return 0; + return true; /* Module explicitly didnt match */ if (res == MOD_RES_DENY) - return 1; + return false; /* We dont handle any hash types except for plaintext - Thanks tra26 */ if (!hashtype.empty() && hashtype != "plaintext") - /* See below. 1 because they dont match */ - return 1; + return false; - return (data != input); // this seems back to front, but returns 0 if they *match*, 1 else + return TimingSafeCompare(data, input); } -bool CommandParser::LoopCall(User* user, Command* handler, const std::vector& parameters, unsigned int splithere, int extra, bool usemax) +bool CommandParser::LoopCall(User* user, Command* handler, const CommandBase::Params& parameters, unsigned int splithere, int extra, bool usemax) { if (splithere >= parameters.size()) return false; @@ -61,7 +60,7 @@ bool CommandParser::LoopCall(User* user, Command* handler, const std::vector dupes; + insp::flat_set dupes; bool check_dupes = (extra < 0); /* Create two sepstreams, if we have only one list, then initialize the second sepstream with @@ -81,9 +80,9 @@ bool CommandParser::LoopCall(User* user, Command* handler, const std::vectorConfig->MaxTargets)) { - if ((!check_dupes) || (dupes.insert(item.c_str()).second)) + if ((!check_dupes) || (dupes.insert(item).second)) { - std::vector new_parameters(parameters); + CommandBase::Params new_parameters(parameters); new_parameters[splithere] = item; if (extra >= 0) @@ -94,13 +93,14 @@ bool CommandParser::LoopCall(User* user, Command* handler, const std::vectorHandle(new_parameters, user); + CommandBase::Params params(new_parameters, parameters.GetTags()); + CmdResult result = handler->Handle(user, params); if (localuser) { - // Run the OnPostCommand hook with the last parameter (original line) being empty - // to indicate that the command had more targets in its original form. + // Run the OnPostCommand hook with the last parameter being true to indicate + // that the event is being called in a loop. item.clear(); - FOREACH_MOD(OnPostCommand, (handler, new_parameters, localuser, result, item)); + FOREACH_MOD(OnPostCommand, (handler, new_parameters, localuser, result, true)); } } } @@ -110,7 +110,7 @@ bool CommandParser::LoopCall(User* user, Command* handler, const std::vectorsecond; @@ -119,9 +119,9 @@ Command* CommandParser::GetHandler(const std::string &commandname) // calls a handler function for a command -CmdResult CommandParser::CallHandler(const std::string &commandname, const std::vector& parameters, User *user) +CmdResult CommandParser::CallHandler(const std::string& commandname, const CommandBase::Params& parameters, User* user, Command** cmd) { - Commandtable::iterator n = cmdlist.find(commandname); + CommandMap::iterator n = cmdlist.find(commandname); if (n != cmdlist.end()) { @@ -151,47 +151,43 @@ CmdResult CommandParser::CallHandler(const std::string &commandname, const std:: if (bOkay) { - return n->second->Handle(parameters,user); + if (cmd) + *cmd = n->second; + + ClientProtocol::TagMap tags; + return n->second->Handle(user, CommandBase::Params(parameters, tags)); } } } return CMD_INVALID; } -void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) +void CommandParser::ProcessCommand(LocalUser* user, std::string& command, CommandBase::Params& command_p) { - std::vector command_p; - irc::tokenstream tokens(cmd); - std::string command, token; - tokens.GetToken(command); - - /* A client sent a nick prefix on their command (ick) - * rhapsody and some braindead bouncers do this -- - * the rfc says they shouldnt but also says the ircd should - * discard it if they do. - */ - if (command[0] == ':') - tokens.GetToken(command); - - while (tokens.GetToken(token)) - command_p.push_back(token); - - std::transform(command.begin(), command.end(), command.begin(), ::toupper); - /* find the command, check it exists */ Command* handler = GetHandler(command); + // Penalty to give if the command fails before the handler is executed + unsigned int failpenalty = 0; + /* Modify the user's penalty regardless of whether or not the command exists */ if (!user->HasPrivPermission("users/flood/no-throttle")) { // If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap - user->CommandFloodPenalty += handler ? handler->Penalty * 1000 : 2000; + unsigned int penalty = (handler ? handler->Penalty * 1000 : 2000); + user->CommandFloodPenalty += penalty; + + // Increase their penalty later if we fail and the command has 0 penalty by default (i.e. in Command::Penalty) to + // throttle sending ERR_* from the command parser. If the command does have a non-zero penalty then this is not + // needed because we've increased their penalty above. + if (penalty == 0) + failpenalty = 1000; } if (!handler) { ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd)); + FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false)); if (MOD_RESULT == MOD_RES_DENY) return; @@ -206,8 +202,8 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) if (!handler) { if (user->registered == REG_ALL) - user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str()); - ServerInstance->stats->statsUnknown++; + user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command"); + ServerInstance->stats.Unknown++; return; } } @@ -225,12 +221,12 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) */ // Iterator to the last parameter that will be kept - const std::vector::iterator lastkeep = command_p.begin() + (handler->max_params - 1); + const CommandBase::Params::iterator lastkeep = command_p.begin() + (handler->max_params - 1); // Iterator to the first excess parameter - const std::vector::iterator firstexcess = lastkeep + 1; + const CommandBase::Params::iterator firstexcess = lastkeep + 1; // Append all excess parameter(s) to the last parameter, seperated by spaces - for (std::vector::const_iterator i = firstexcess; i != command_p.end(); ++i) + for (CommandBase::Params::const_iterator i = firstexcess; i != command_p.end(); ++i) { lastkeep->push_back(' '); lastkeep->append(*i); @@ -245,7 +241,7 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) * truncate to max_params if necessary. -- w00t */ ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd)); + FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false)); if (MOD_RESULT == MOD_RES_DENY) return; @@ -256,50 +252,36 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) { if (!user->IsModeSet(handler->flags_needed)) { - user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - You do not have the required operator privileges",user->nick.c_str()); + user->CommandFloodPenalty += failpenalty; + user->WriteNumeric(ERR_NOPRIVILEGES, "Permission Denied - You do not have the required operator privileges"); return; } if (!user->HasPermission(command)) { - user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to command %s", - user->nick.c_str(), user->oper->name.c_str(), command.c_str()); + user->CommandFloodPenalty += failpenalty; + user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to command %s", + user->oper->name.c_str(), command.c_str())); return; } } - if ((user->registered == REG_ALL) && (!user->IsOper()) && (handler->IsDisabled())) - { - /* command is disabled! */ - if (ServerInstance->Config->DisabledDontExist) - { - user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str()); - } - else - { - user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :This command has been disabled.", - user->nick.c_str(), command.c_str()); - } - - ServerInstance->SNO->WriteToSnoMask('t', "%s denied for %s (%s@%s)", - command.c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - return; - } - if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param)) command_p.pop_back(); if (command_p.size() < handler->min_params) { - user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s %s :Not enough parameters.", user->nick.c_str(), command.c_str()); + user->CommandFloodPenalty += failpenalty; + user->WriteNumeric(ERR_NEEDMOREPARAMS, command, "Not enough parameters."); if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length())) - user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), handler->name.c_str(), handler->syntax.c_str()); + user->WriteNumeric(RPL_SYNTAX, handler->name, handler->syntax); return; } if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg())) { - user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str()); + user->CommandFloodPenalty += failpenalty; + user->WriteNumeric(ERR_NOTREGISTERED, command, "You have not registered"); } else { @@ -307,43 +289,79 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) handler->use_count++; /* module calls too */ - FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, true, cmd)); + FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, true)); if (MOD_RESULT == MOD_RES_DENY) return; /* * WARNING: be careful, the user may be deleted soon */ - CmdResult result = handler->Handle(command_p, user); + CmdResult result = handler->Handle(user, command_p); - FOREACH_MOD(OnPostCommand, (handler, command_p, user, result, cmd)); + FOREACH_MOD(OnPostCommand, (handler, command_p, user, result, false)); } } void CommandParser::RemoveCommand(Command* x) { - Commandtable::iterator n = cmdlist.find(x->name); + CommandMap::iterator n = cmdlist.find(x->name); if (n != cmdlist.end() && n->second == x) cmdlist.erase(n); } +CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) + : ServiceProvider(mod, cmd, SERVICE_COMMAND) + , flags_needed(0) + , min_params(minpara) + , max_params(maxpara) + , use_count(0) + , works_before_reg(false) + , allow_empty_last_param(true) + , Penalty(1) +{ +} + CommandBase::~CommandBase() { } +void CommandBase::EncodeParameter(std::string& parameter, unsigned int index) +{ +} + +RouteDescriptor CommandBase::GetRouting(User* user, const Params& parameters) +{ + return ROUTE_LOCALONLY; +} + +Command::Command(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) + : CommandBase(mod, cmd, minpara, maxpara) + , force_manual_route(false) +{ +} + Command::~Command() { - ServerInstance->Parser->RemoveCommand(this); + ServerInstance->Parser.RemoveCommand(this); } -void CommandParser::ProcessBuffer(std::string &buffer,LocalUser *user) +void Command::RegisterService() { - if (!user || buffer.empty()) + if (!ServerInstance->Parser.AddCommand(this)) + throw ModuleException("Command already exists: " + name); +} + +void CommandParser::ProcessBuffer(LocalUser* user, const std::string& buffer) +{ + ClientProtocol::ParseOutput parseoutput; + if (!user->serializer->Parse(user, buffer, parseoutput)) return; - ServerInstance->Logs->Log("USERINPUT", LOG_RAWIO, "C[%s] I :%s %s", - user->uuid.c_str(), user->nick.c_str(), buffer.c_str()); - ProcessCommand(user,buffer); + std::string& command = parseoutput.cmd; + std::transform(command.begin(), command.end(), command.begin(), ::toupper); + + CommandBase::Params parameters(parseoutput.params, parseoutput.tags); + ProcessCommand(user, command, parameters); } bool CommandParser::AddCommand(Command *f) @@ -361,7 +379,7 @@ CommandParser::CommandParser() { } -std::string CommandParser::TranslateUIDs(const std::vector& to, const std::vector& source, bool prefix_final, CommandBase* custom_translator) +std::string CommandParser::TranslateUIDs(const std::vector& to, const CommandBase::Params& source, bool prefix_final, CommandBase* custom_translator) { std::vector::const_iterator types = to.begin(); std::string dest; @@ -415,7 +433,7 @@ void CommandParser::TranslateSingleParam(TranslateType to, const std::string& it } // If no custom translator was given, fall through } - case TR_TEXT: + /*@fallthrough@*/ default: /* Do nothing */ dest.append(item);