/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ int parse(aClient *cptr, char *pbuffer, char *bufend) { aClient *from = cptr; char *ch; char *s; size_t i; char* numeric = 0; unsigned int paramcount; struct Message *mptr; Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE), pbuffer)); if (IsDead(cptr)) return -1; s = sender; *s = '\0'; for (ch = pbuffer; *ch == ' '; ch++) /* skip spaces */ /* null statement */ ; para[0] = from->name; if (*ch == ':') { ch++; /* ** Copy the prefix to 'sender' assuming it terminates ** with SPACE (or NULL, which is an error, though). */ for (i = 0; *ch && *ch != ' '; i++ ) { if (i < (sizeof(sender)-1)) *s++ = *ch; /* leave room for NULL */ ch++; } *s = '\0'; i = 0; /* ** Actually, only messages coming from servers can have ** the prefix--prefix silently ignored, if coming from ** a user client... ** ** ...sigh, the current release "v2.2PL1" generates also ** null prefixes, at least to NOTIFY messages (e.g. it ** puts "sptr->nickname" as prefix from server structures ** where it's null--the following will handle this case ** as "no prefix" at all --msa (": NOTICE nick ...") */ if (*sender && IsServer(cptr)) { from = find_client(sender, (aClient *) NULL); if (!from || !match(from->name, sender)) from = find_server(sender); para[0] = sender; /* Hmm! If the client corresponding to the * prefix is not found--what is the correct * action??? Now, I will ignore the message * (old IRC just let it through as if the * prefix just wasn't there...) --msa */ if (!from) { sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Unknown prefix (%s) from (%s)", sender, cptr->name); Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)", sender, pbuffer, cptr->name)); ServerStats->is_unpf++; remove_unknown(cptr, sender, pbuffer); return -1; } if (from->from != cptr) { ServerStats->is_wrdi++; Debug((DEBUG_ERROR, "Message (%s) coming from (%s)", buffer, cptr->name)); sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Message coming from (%s), but %s is at %s", cptr->name, from->name, from->from->name); return cancel_clients(cptr, from, pbuffer); } } while (*ch == ' ') ch++; } if (*ch == '\0') { ServerStats->is_empt++; Debug((DEBUG_NOTICE, "Empty message from host %s:%s", cptr->name, from->name)); if (IsServer(cptr)) sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Empty message from %s:%s", cptr->name, from->name); return(-1); } /* ** Extract the command code from the packet. Point s to the end ** of the command code and calculate the length using pointer ** arithmetic. Note: only need length for numerics and *all* ** numerics must have parameters and thus a space after the command ** code. -avalon * * ummm???? - Dianora */ if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) ) { mptr = (struct Message *)NULL; numeric = ch; paramcount = MAXPARA; ServerStats->is_num++; s = ch + 3; /* I know this is ' ' from above if */ *s++ = '\0'; /* blow away the ' ', and point s to next part */ } else { s = strchr(ch, ' '); /* moved from above,now need it here */ if (s) *s++ = '\0'; mptr = tree_parse(ch); if (!mptr || !mptr->cmd) { /* * Note: Give error message *only* to recognized * persons. It's a nightmare situation to have * two programs sending "Unknown command"'s or * equivalent to each other at full blast.... * If it has got to person state, it at least * seems to be well behaving. Perhaps this message * should never be generated, though... --msa * Hm, when is the buffer empty -- if a command * code has been found ?? -Armin * * Same thing goes for remote commands. If their local * server accepted it, then we should not be sending * a warning message. */ if (pbuffer[0] != '\0') { if (IsPerson(from) && MyClient(from)) sendto_one(from, ":%s %d %s %s :Unknown command", me.name, ERR_UNKNOWNCOMMAND, from->name, ch); Debug((DEBUG_ERROR,"Unknown (%s) from %s", ch, get_client_name(cptr, TRUE))); } ServerStats->is_unco++; return(-1); } paramcount = mptr->parameters; i = bufend - ((s) ? s : ch); mptr->bytes += i; /* Allow only 1 msg per 2 seconds * (on average) to prevent dumping. * to keep the response rate up, * bursts of up to 5 msgs are allowed * -SRB * Opers can send 1 msg per second, burst of ~20 * -Taner */ if ((mptr->flags & 1) && !(IsServer(cptr))) { #ifdef NO_OPER_FLOOD #ifndef TRUE_NO_OPER_FLOOD /* note: both have to be defined for the real no-flood */ if (NoFloodProtection(cptr)) /* "randomly" (weighted) increase the since */ cptr->since += (cptr->receiveM % 5) ? 1 : 0; else #else if (!NoFloodProtection(cptr)) #endif #endif cptr->since += (2 + i / 120); } } /* ** Must the following loop really be so devious? On ** surface it splits the message to parameters from ** blank spaces. But, if paramcount has been reached, ** the rest of the message goes into this last parameter ** (about same effect as ":" has...) --msa */ /* Note initially true: s==NULL || *(s-1) == '\0' !! */ /* ZZZ hmmmmmmmm whats this then? */ #if 0 if (me.user) para[0] = sender; #endif i = 1; if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; for (;;) { while(*s == ' ') /* tabs are not considered space */ *s++ = '\0'; if(!*s) break; if (*s == ':') { /* ** The rest is single parameter--can ** include blanks also. */ para[i++] = s + 1; break; } else { para[i++] = s; if (i > paramcount) { break; } /* scan for end of string, either ' ' or '\0' */ while (IsNonEOS(*s)) s++; } } } para[i] = NULL; if (mptr == (struct Message *)NULL) return (do_numeric(numeric, cptr, from, i, para)); mptr->count++; /* patch to avoid server flooding from unregistered connects */ /* check allow_unregistered_use flag I've set up instead of function comparing *yech* - Dianora */ if (!IsRegistered(cptr) && !mptr->allow_unregistered_use ) { /* if its from a possible server connection * ignore it.. more than likely its a header thats sneaked through */ if(IsHandshake(cptr) || IsConnecting(cptr) || IsServer(cptr)) return -1; sendto_one(from, ":%s %d %s %s :Register first.", me.name, ERR_NOTREGISTERED, BadPtr(from->name) ? "*" : from->name, ch); return -1; } /* Silently drop the messages that can't be used in the honeypot */ if (IsHoneypot(cptr) && !mptr->allow_honeypot) return -1; /* Again, instead of function address comparing, see if * this function resets idle time as given from mptr * if IDLE_FROM_MSG is undefined, the sense of the flag is reversed. * i.e. if the flag is 0, then reset idle time, otherwise don't reset it. * * - Dianora */ if (IsRegisteredUser(from) && mptr->reset_idle) { /* If a local registered user, propagate anti-idle updates as needed */ if (MyClient(from) && from->user && ((from->user->last_sent + MAX_IDLE_DESYNC) < CurrentTime)) { #if 0 /* Note the misnamed message, this indicates that they are NOT idle */ #ifdef HAVE_LONG_LONG sendto_serv_butone(NULL, ":%s IDLE %s %.1lld", cptr->name, from->name, (long long)CurrentTime); #else sendto_serv_butone(NULL, ":%s IDLE %s %.1ld", cptr->name, from->name, (long)CurrentTime); #endif #endif from->user->last_sent = CurrentTime; } from->user->last = CurrentTime; } /* don't allow other commands while a list is blocked. since we treat them specially with respect to sendq. */ if ((IsDoingList(cptr)) && (*mptr->func != m_list)) return -1; return (*mptr->func)(cptr, from, i, para); }
/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ int new_parse(char *buffer, char *bufend) { char *ch; char *s; int i; char* numeric = 0; int paramcount=MAXPARA; int parc; s = sender; *s = '\0'; ch = buffer; while(*ch == ' ') ch++; para[0] = name; #ifdef NEW_PARSE if (*ch == ':') { ch++; /* ** Copy the prefix to 'sender' assuming it terminates ** with SPACE (or NULL, which is an error, though). */ for (i = 0; *ch && *ch != ' '; i++ ) { if (i < (sizeof(sender)-1)) *s++ = *ch++; /* leave room for NULL */ } *s = '\0'; while (*ch == ' ') ch++; } #else if (*ch == ':') { /* ** Copy the prefix to 'sender' assuming it terminates ** with SPACE (or NULL, which is an error, though). */ for (++ch, i = 0; *ch && *ch != ' '; ++ch ) if (s < (sender + sizeof(sender)-1)) *s++ = *ch; /* leave room for NULL */ *s = '\0'; while (*ch == ' ') ch++; } #endif if(show) printf("new parse sender [%s] i = %d\n", sender, i); if (*ch == '\0') { fprintf(stderr,"empty message\n"); } /* ** Extract the command code from the packet. Point s to the end ** of the command code and calculate the length using pointer ** arithmetic. Note: only need length for numerics and *all* ** numerics must have parameters and thus a space after the command ** code. -avalon * * ummm???? - Dianora */ if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) ) { numeric = ch; paramcount = MAXPARA; s = ch + 3; /* I know this is ' ' from above if */ *s++ = '\0'; /* blow away the ' ', and point s to next part */ } else { s = strchr(ch, ' '); /* moved from above,now need it here */ if (s) *s++ = '\0'; paramcount = 3; i = bufend - ((s) ? s : ch); if (show) { printf("new parse s = %lX ch = %lX\n", s , ch ); printf("new parse i = bufend - ((s) ? s : ch) = %d \n", i ); printf("new parse: paramcount %d i = %d\n", paramcount, i ); } } /* ** Must the following loop really be so devious? * * nope. * ** On surface it splits the message to parameters from ** blank spaces. But, if paramcount has been reached, ** the rest of the message goes into this last parameter ** (about same effect as ":" has...) --msa */ /* Note initially true: s==NULL || *(s-1) == '\0' !! */ para[0] = sender; i = 1; if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; #ifdef NEW_PARSE for (;;) { /* Never BAD CODE again */ while(*s == ' ') /* tabs are not considered space */ s++; if (*s == ':') { /* ** The rest is single parameter--can ** include blanks also. */ para[i++] = s + 1; break; } else { para[i++] = s; if (i > paramcount) { break; } else { /* scan for end of string, either ' ' or '\0' */ while (IsNonEOS(*s)) s++; if(*s == '\0') break; else *s++ = '\0'; } } } } para[i] = NULL; parc = i; #else for (;;) { /* ** Never "FRANCE " again!! ;-) Clean ** out *all* blanks.. --msa */ while (*s == ' ') *s++ = '\0'; if (*s == '\0') break; if (*s == ':') { /* ** The rest is single parameter--can ** include blanks also. */ para[++i] = s + 1; break; } para[++i] = s; if (i >= paramcount) break; for (; *s != ' ' && *s; s++) /* null statement */ ; } }