From 80d1296c31d8e16e71f7079144618a3eae6976d1 Mon Sep 17 00:00:00 2001 From: brain Date: Sun, 16 Jul 2006 08:38:33 +0000 Subject: MAJOR tidy of line parser, some parts rewritten and major chunks removed git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@4402 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/command_parse.h | 4 +- src/command_parse.cpp | 325 ++++++------------------------------------------ src/userprocess.cpp | 69 ++++------ 3 files changed, 65 insertions(+), 333 deletions(-) diff --git a/include/command_parse.h b/include/command_parse.h index 838915dff..44f5946bc 100644 --- a/include/command_parse.h +++ b/include/command_parse.h @@ -28,7 +28,7 @@ class CommandParser : public classbase { private: int ProcessParameters(char **command_p,char *parameters); - void ProcessCommand(userrec *user, char* cmd); + void ProcessCommand(userrec *user, std::string &cmd); void SetupCommandTable(); public: command_table cmdlist; @@ -37,7 +37,7 @@ class CommandParser : public classbase bool CallHandler(const std::string &commandname,char **parameters, int pcnt, userrec *user); bool IsValidCommand(const std::string &commandname, int pcnt, userrec * user); int LoopCall(command_t *fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins); - void ProcessBuffer(const char* cmdbuf,userrec *user); + void ProcessBuffer(std::string &buffer,userrec *user); bool RemoveCommands(const char* source); bool CreateCommand(command_t *f); }; diff --git a/src/command_parse.cpp b/src/command_parse.cpp index 644860702..19729d9e4 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -345,245 +345,24 @@ bool CommandParser::CallHandler(const std::string &commandname,char **parameters return false; } -int CommandParser::ProcessParameters(char **command_p,char *parameters) +void CommandParser::ProcessCommand(userrec *user, std::string &cmd) { - int j = 0; - - if (!*parameters) - { - /* no parameters, command_p invalid! */ - return 0; - } - - if (*parameters == ':') - { - command_p[0] = parameters+1; - return 1; - } - - if (*parameters) - { - char* n = strchr(parameters,' '); - if ((!n) || (*parameters == ':')) - { - /* only one parameter */ - command_p[0] = parameters; - if (*parameters == ':') - { - if (n) - { - command_p[0]++; - } - } - - return 1; - } - } - - command_p[j++] = parameters; - - for (char* i = parameters; *i; i++) - { - if (*i == ' ') - { - command_p[j++] = i+1; - *i = '\0'; - - if (*command_p[j-1] == ':') - { - *command_p[j-1]++; /* remove dodgy ":" */ - break; - /* parameter like this marks end of the sequence */ - } - } - } - return j; /* returns total number of items in the list */ -} - -void CommandParser::ProcessCommand(userrec *user, char* cmd) -{ - char *parameters; - char *command; char *command_p[127]; - char p[MAXBUF], temp[MAXBUF]; - int j, items, cmd_found; - int total_params = 0; - - for (int i = 0; i < 127; i++) - command_p[i] = NULL; - - if (!user || !cmd || !*cmd) - { - return; - } - - char* first_space = NULL; - - /* If the command is > 2 characters (quick and dirty way to find out) */ - if (*cmd && *(cmd+1) && *(cmd+2)) - { - for (char* q = cmd; *q; q++) - { - if (*q == ' ') - { - first_space = q; - if (*(q+1) == ':') - { - total_params++; - // found a 'trailing', we dont count them after this. - break; - } - else - total_params++; - } - } - } - - // another phidjit bug... - if (total_params > 126) - { - *first_space = 0; - WriteServ(user->fd,"421 %s %s :Too many parameters given",user->nick,cmd); - return; - } - - strlcpy(temp,cmd,MAXBUF); - - std::string tmp = cmd; - - for (int i = 0; i <= MODCOUNT; i++) - { - std::string oldtmp = tmp; - modules[i]->OnServerRaw(tmp,true,user); - if (oldtmp != tmp) - { - log(DEBUG,"A Module changed the input string!"); - log(DEBUG,"New string: %s",tmp.c_str()); - log(DEBUG,"Old string: %s",oldtmp.c_str()); - break; - } - } - - strlcpy(cmd,tmp.c_str(),MAXBUF); - strlcpy(temp,cmd,MAXBUF); - - char* has_space = strchr(cmd,' '); - int cm_length = 0; - if (!has_space) - { - /* - * no parameters, lets skip the formalities and not chop up - * the string - */ - log(DEBUG,"About to preprocess command with no params"); - items = 0; - command_p[0] = NULL; - parameters = NULL; - for (char* i = cmd; *i; i++,cm_length++) - *i = toupper(*i); - command = cmd; - } - else - { - *cmd = 0; - j = 0; + int items = 0; - /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */ - for (char* i = temp; *i; i++) - { - if ((*i != 10) && (*i != 13) && (*i != 0) && (*i != 7)) - { - cmd[j++] = *i; - } - } - cmd[j] = 0; - - /* split the full string into a command plus parameters */ - parameters = p; - p[0] = ' '; - p[1] = 0; - - command = cmd; - - if (has_space) - { - for (char* i = cmd; *i; i++) - { - /* capitalise the command ONLY, leave params intact */ - *i = toupper(*i); - /* are we nearly there yet?! :P */ - if (*i == ' ') - { - command = cmd; - parameters = i+1; - *i = 0; - break; - } - } - } - else - { - for (char* i = cmd; *i; i++,cm_length++) - { - *i = toupper(*i); - } - } - } - - if (cm_length > MAXCOMMAND) - { - WriteServ(user->fd,"421 %s %s :Command too long",user->nick,command); - return; - } - - for (char* x = command; *x; x++) - { - if (((*x < 'A') || (*x > 'Z')) && (*x != '.')) - { - if (((*x < '0') || (*x> '9')) && (*x != '-')) - { - if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",*x)) - { - ServerInstance->stats->statsUnknown++; - WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command); - return; - } - } - } - } - - std::string xcommand = command; - if ((user->registered != 7) && (xcommand == "SERVER")) - { - kill_link(user,"Server connection to non-server port"); - return; - } - - /* Tweak by brain - why was this INSIDE the mainloop? */ - if (parameters) - { - if (parameters[0]) - { - items = this->ProcessParameters(command_p,parameters); - } - else - { - items = 0; - command_p[0] = NULL; - } - } - else - { - items = 0; - command_p[0] = NULL; - } + std::string para[127]; + irc::tokenstream tokens(cmd); + std::string xcommand = tokens.GetToken(); + while ((para[items] = tokens.GetToken()) != "") + command_p[items] = (char*)para[items++].c_str(); + int MOD_RESULT = 0; - FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,false)); + FOREACH_RESULT(I_OnPreCommand,OnPreCommand(xcommand,command_p,items,user,false)); if (MOD_RESULT == 1) { return; } - + nspace::hash_map::iterator cm = cmdlist.find(xcommand); if (cm != cmdlist.end()) @@ -592,29 +371,25 @@ void CommandParser::ProcessCommand(userrec *user, char* cmd) { /* activity resets the ping pending timer */ user->nping = TIME + user->pingmax; - if ((items) < cm->second->min_params) + if (items < cm->second->min_params) { - log(DEBUG,"not enough parameters: %s %s",user->nick,command); - WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command); + log(DEBUG,"not enough parameters: %s %s",user->nick,xcommand.c_str()); + WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,xcommand.c_str()); return; } if (cm->second->flags_needed) { - if (!user->modes[cm->second->flags_needed-65]) + if (!user->IsModeSet(cm->second->flags_needed)) { - log(DEBUG,"permission denied: %s %s",user->nick,command); + log(DEBUG,"permission denied: %s %s",user->nick,xcommand.c_str()); WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick); - cmd_found = 1; return; } } if ((cm->second->flags_needed) && (!user->HasPermission(xcommand))) { - log(DEBUG,"permission denied: %s %s",user->nick,command); - WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,command); - if (!IS_LOCAL(user)) - WriteOpers("*** \2WARNING\2: Command '%s' not allowed for oper '%s', dropped.",command,user->nick); - cmd_found = 1; + log(DEBUG,"permission denied: %s %s",user->nick,xcommand.c_str()); + WriteServ(user->fd,"481 %s :Permission Denied- Oper type %s does not have access to command %s",user->nick,user->oper,xcommand.c_str()); return; } /* if the command isnt USER, PASS, or NICK, and nick is empty, @@ -623,21 +398,24 @@ void CommandParser::ProcessCommand(userrec *user, char* cmd) { if ((!isnick(user->nick)) || (user->registered != 7)) { - log(DEBUG,"not registered: %s %s",user->nick,command); - WriteServ(user->fd,"451 %s :You have not registered",command); + log(DEBUG,"not registered: %s %s",user->nick,xcommand.c_str()); + WriteServ(user->fd,"451 %s :You have not registered",xcommand.c_str()); return; } } if ((user->registered == 7) && (!*user->oper) && (*Config->DisabledCommands)) { + /* XXX: We should have a disabled setting in the command object, and on rehash set the disabled flag + * in the ones which are disabled, rather than this craq + */ std::stringstream dcmds(Config->DisabledCommands); std::string thiscmd; while (dcmds >> thiscmd) { - if (!strcasecmp(thiscmd.c_str(),command)) + if (!strcasecmp(thiscmd.c_str(),xcommand.c_str())) { // command is disabled! - WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,command); + WriteServ(user->fd,"421 %s %s :This command has been disabled.",user->nick,xcommand.c_str()); return; } } @@ -645,18 +423,13 @@ void CommandParser::ProcessCommand(userrec *user, char* cmd) if ((user->registered == 7) || (cm->second == command_user) || (cm->second == command_nick) || (cm->second == command_pass)) { /* ikky /stats counters */ - if (temp) - { - cm->second->use_count++; - cm->second->total_bytes+=strlen(temp); - } + cm->second->use_count++; + cm->second->total_bytes += cmd.length(); int MOD_RESULT = 0; - FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,true)); + FOREACH_RESULT(I_OnPreCommand,OnPreCommand(xcommand,command_p,items,user,true)); if (MOD_RESULT == 1) - { return; - } /* * WARNING: nothing may come after the @@ -669,7 +442,7 @@ void CommandParser::ProcessCommand(userrec *user, char* cmd) } else { - WriteServ(user->fd,"451 %s :You have not registered",command); + WriteServ(user->fd,"451 %s :You have not registered",xcommand.c_str()); return; } } @@ -677,7 +450,7 @@ void CommandParser::ProcessCommand(userrec *user, char* cmd) else if (user) { ServerInstance->stats->statsUnknown++; - WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command); + WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,xcommand.c_str()); } } @@ -705,43 +478,21 @@ bool CommandParser::RemoveCommands(const char* source) return true; } -void CommandParser::ProcessBuffer(const char* cmdbuf,userrec *user) +void CommandParser::ProcessBuffer(std::string &buffer,userrec *user) { - char cmd[MAXBUF]; + std::string::size_type a; - if (!user || !cmdbuf || !*cmdbuf) - { - log(DEFAULT,"*** BUG *** process_buffer was given an invalid parameter"); + if (!user) return; - } - - while (*cmdbuf == ' ') cmdbuf++; // strip leading spaces - if (!*cmdbuf) - return; - - strlcpy(cmd,cmdbuf,MAXBUF); + while ((a = buffer.find("\n")) != std::string::npos) + buffer.erase(a); + while ((a = buffer.find("\r")) != std::string::npos) + buffer.erase(a); - while (charremove(cmd,10)); - while (charremove(cmd,13)); + log(DEBUG,"CMDIN: %s %s",user->nick,buffer.c_str()); - int sl = strlen(cmd)-1; - while (sl && (cmd[sl] == ' ')) // strip trailing spaces - { - cmd[sl--] = 0; - } - - if (!sl) - return; - - log(DEBUG,"CMDIN: %s %s",user->nick,cmd); - - tidystring(cmd); - - if (user && cmd) - { - this->ProcessCommand(user,cmd); - } + this->ProcessCommand(user,buffer); } bool CommandParser::CreateCommand(command_t *f) diff --git a/src/userprocess.cpp b/src/userprocess.cpp index 391c15d7a..b185bc4b5 100644 --- a/src/userprocess.cpp +++ b/src/userprocess.cpp @@ -119,30 +119,19 @@ void ProcessUser(userrec* cu) { userrec *current; int currfd; - int floodlines; + int floodlines = 0; ServerInstance->stats->statsRecv += result; /* * perform a check on the raw buffer as an array (not a string!) to remove - * characters 0 and 7 which are illegal in the RFC - replace them with spaces. - * hopefully this should stop even more people whining about "Unknown command: *" - */ - - /* - * XXX - potential replacement for the below using my beloved pointers. --w00t + * character 0 which is illegal in the RFC - replace them with spaces. * XXX - no garauntee there's not \0's in the middle of the data, * and no reason for it to be terminated either. -- Om - * - * for (char *c = data; data && *data; data++) - * { - * if (*data == 0 || *data == 7) - * data = ' '; - * } */ for (int checker = 0; checker < result; checker++) { - if ((data[checker] == 0) || (data[checker] == 7)) + if (data[checker] == 0) data[checker] = ' '; } @@ -151,7 +140,6 @@ void ProcessUser(userrec* cu) current = cu; currfd = current->fd; - floodlines = 0; // add the data to the users buffer if (result > 0) @@ -214,18 +202,13 @@ void ProcessUser(userrec* cu) // while there are complete lines to process... while (current->BufferIsReady()) { - char sanitized[MAXBUF]; - - floodlines++; if (TIME > current->reset_due) { current->reset_due = TIME + current->threshold; current->lines_in = 0; } - current->lines_in++; - - if (current->lines_in > current->flood) + if (++current->lines_in > current->flood) { log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); @@ -233,7 +216,7 @@ void ProcessUser(userrec* cu) return; } - if ((floodlines > current->flood) && (current->flood != 0)) + if ((++floodlines > current->flood) && (current->flood != 0)) { if (current->registered == 7) { @@ -254,29 +237,27 @@ void ProcessUser(userrec* cu) std::string single_line = current->GetBuffer(); current->bytes_in += single_line.length(); current->cmds_in++; - strlcpy(sanitized,single_line.c_str(),511); - - if (*sanitized) + if (single_line.length() > 512) + single_line.resize(512); + + userrec* old_comp = fd_ref_table[currfd]; + + ServerInstance->Parser->ProcessBuffer(single_line,current); + /* + * look for the user's record in case it's changed... if theyve quit, + * we cant do anything more with their buffer, so bail. + * there used to be an ugly, slow loop here. Now we have a reference + * table, life is much easier (and FASTER) + */ + userrec* new_comp = fd_ref_table[currfd]; + if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp)) { - userrec* old_comp = fd_ref_table[currfd]; - - ServerInstance->Parser->ProcessBuffer(sanitized,current); - /* - * look for the user's record in case it's changed... if theyve quit, - * we cant do anything more with their buffer, so bail. - * there used to be an ugly, slow loop here. Now we have a reference - * table, life is much easier (and FASTER) - */ - userrec* new_comp = fd_ref_table[currfd]; - if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp)) - { - return; - } - else - { - /* The user is still here, flush their buffer */ - current->FlushWriteBuf(); - } + return; + } + else + { + /* The user is still here, flush their buffer */ + current->FlushWriteBuf(); } } -- cgit v1.2.3