/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; char *ch; char *s; char *end; int i; int paramcount, mpara = 0; char *numeric = 0; struct Message *mptr; Debug((DEBUG_DEBUG, "Parsing %s:", pbuffer)); s_assert(!IsDead(client_p)); s_assert(client_p->localClient->fd >= 0); if(IsDead(client_p) || client_p->localClient->fd < 0) return; s_assert(bufend-pbuffer < 512); 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). */ sender = ch; if((s = strchr(ch, ' '))) { *s = '\0'; s++; ch = s; } i = 0; if(*sender && IsServer(client_p)) { from = find_client(sender); if(from == NULL) { from = find_server(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 == NULL) { Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)", sender, pbuffer, client_p->name)); ServerStats->is_unpf++; remove_unknown(client_p, sender, pbuffer); return; } para[0] = from->name; if(from->from != client_p) { ServerStats->is_wrdi++; Debug((DEBUG_ERROR, "Message (%s) coming from (%s)", pbuffer, client_p->name)); cancel_clients(client_p, from, pbuffer); return; } } while (*ch == ' ') ch++; } if(*ch == '\0') { ServerStats->is_empt++; Debug((DEBUG_NOTICE, "Empty message from host %s:%s", client_p->name, from->name)); return; } /* * 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 */ /* EOB is 3 chars long but is not a numeric */ 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 { int ii = 0; if((s = strchr(ch, ' '))) *s++ = '\0'; mptr = hash_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 */ if(pbuffer[0] != '\0') { if(IsPerson(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(client_p, HIDE_IP))); } ServerStats->is_unco++; return; } paramcount = mptr->parameters; mpara = mptr->maxpara; ii = bufend - ((s) ? s : ch); mptr->bytes += ii; } end = bufend - 1; /* XXX this should be done before parse() is called */ if(*end == '\n') *end-- = '\0'; if(*end == '\r') *end = '\0'; i = 0; if(s != NULL) i = string_to_array(s, para); if(mptr == (struct Message *) NULL) { do_numeric(numeric, client_p, from, i, para); return; } if(handle_command(mptr, client_p, from, i, para) < -1) { char *p; for (p = pbuffer; p <= end; p += 8) { /* HACK HACK */ /* Its expected this nasty code can be removed * or rewritten later if still needed. */ if((unsigned long) (p + 8) > (unsigned long) end) { for (; p <= end; p++) { ilog(L_CRIT, "%02x |%c", p[0], p[0]); } } else ilog(L_CRIT, "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } }
/* * 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); }
int parse(aClient *cptr, char *buffer, char *bufend) { aClient *from = cptr; char *ch, *s; int i, numeric = 0, paramcount; struct Message *mptr; #ifdef DUMP_DEBUG if(dumpfp!=NULL) { fprintf(dumpfp, "<- %s: %s\n", (cptr->name ? cptr->name : "*"), buffer); fflush(dumpfp); } #endif Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE), buffer)); if (IsDead(cptr)) return -1; s = sender; *s = '\0'; for (ch = buffer; *ch == ' '; ch++); /* skip spaces */ para[0] = from->name; if (*ch == ':') { /* * Copy the prefix to 'sender' assuming it terminates with * SPACE (or NULL, which is an error, though). */ for (++ch; *ch && *ch != ' '; ++ch) if (s < (sender + HOSTLEN)) *s++ = *ch; *s = '\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); /* * okay, this doesn't seem to do much here. * from->name _MUST_ be equal to sender. * That's what find_client does. * find_client will find servers too, and since we don't use server * masking, the find server call is useless (and very wasteful). * now, there HAS to be a from and from->name and * sender have to be the same * for us to get to the next if. but the next if * starts out with if(!from) * so this is UNREACHABLE CODE! AGH! - lucas * * if (!from || mycmp(from->name, sender)) * from = find_server(sender, (aClient *) NULL); * else if (!from && strchr(sender, '@')) * from = find_nickserv(sender, (aClient *) NULL); */ 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) { Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)", sender, buffer, cptr->name)); ircstp->is_unpf++; remove_unknown(cptr, sender, buffer); return -1; } if (from->from != cptr) { ircstp->is_wrdi++; Debug((DEBUG_ERROR, "Message (%s) coming from (%s)", buffer, cptr->name)); return cancel_clients(cptr, from, buffer); } } while (*ch == ' ') ch++; } if (*ch == '\0') { ircstp->is_empt++; Debug((DEBUG_NOTICE, "Empty message from host %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 */ /* Reparse point for /msg raw - Tux` */ reparse: /* check for numeric */ if (*(ch + 3) == ' ' && IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { mptr = (struct Message *) NULL; numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0'); paramcount = MAXPARA; ircstp->is_num++; s = ch + 3; *s++ = '\0'; } else { s = strchr(ch, ' '); if (s) *s++ = '\0'; mptr = tree_parse(ch); if ((mptr && mptr->func == m_private) && (s && !strncasecmp(s, "raw ", 4))) { ch = index(s, ':'); if (ch++) goto reparse; } else if (!mptr || !mptr->cmd) { /* * only send error messages to things that actually sent * buffers to us and only people, too. */ if (buffer[0] != '\0') { if (IsPerson(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))); } ircstp->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 (!IsServer(cptr)) { if (!NoMsgThrottle(cptr)) { #ifdef NO_OPER_FLOOD if (IsAnOper(cptr)) /* "randomly" (weighted) increase the since */ cptr->since += (cptr->receiveM % 10) ? 1 : 0; else #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' !! */ i = 1; if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; for (;;) { while (*s == ' ') *s++ = '\0'; if (*s == '\0') break; if (*s == ':') { /* The rest is a single parameter */ para[i++] = s + 1; break; } para[i++] = s; if (i >= paramcount) { if(paramcount == MAXPARA && strchr(s, ' ')) { sendto_realops_lev(DEBUG_LEV, "Overflowed MAXPARA on %s from %s", mptr ? mptr->cmd : "numeric", get_client_name(cptr, (IsServer(cptr) ? HIDEME : FALSE))); } break; } while(*s && *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 */ if (!IsRegistered(cptr) && !(mptr->flags & MF_UNREG)) { sendto_one(from, ":%s %d %s %s :Register first.", me.name, ERR_NOTREGISTERED, from->name, ch); return -1; } if (IsRegisteredUser(cptr) && (mptr->flags & MF_RIDLE)) from->user->last = timeofday; if (mptr->flags & MF_ALIAS) return mptr->func(cptr, from, i, para, &aliastab[mptr->aliasidx]); return (*mptr->func) (cptr, from, i, para); }
/* parse() * * given a raw buffer, parses it and generates parv and parc */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; char *end; int res; int numeric = 0; struct Message *mptr; struct MsgBuf msgbuf; s_assert(MyConnect(client_p)); s_assert(client_p->localClient->F != NULL); if(IsAnyDead(client_p)) return; end = bufend - 1; /* XXX this should be done before parse() is called */ if(*end == '\n') *end-- = '\0'; if(*end == '\r') *end = '\0'; res = msgbuf_parse(&msgbuf, pbuffer); if (res) { ServerStats.is_empt++; return; } if (msgbuf.origin != NULL && IsServer(client_p)) { from = find_client(msgbuf.origin); /* didnt find any matching client, issue a kill */ if(from == NULL) { ServerStats.is_unpf++; remove_unknown(client_p, msgbuf.origin, pbuffer); return; } /* fake direction, hmm. */ if(from->from != client_p) { ServerStats.is_wrdi++; cancel_clients(client_p, from); return; } } if(IsDigit(*msgbuf.cmd) && IsDigit(*(msgbuf.cmd + 1)) && IsDigit(*(msgbuf.cmd + 2))) { mptr = NULL; numeric = atoi(msgbuf.cmd); ServerStats.is_num++; } else { mptr = rb_dictionary_retrieve(cmd_dict, msgbuf.cmd); /* no command or its encap only, error */ if(!mptr || !mptr->cmd) { if(IsPerson(from)) { sendto_one(from, form_str(ERR_UNKNOWNCOMMAND), me.name, from->name, msgbuf.cmd); } ServerStats.is_unco++; return; } mptr->bytes += msgbuf.parselen; } if(mptr == NULL) { do_numeric(numeric, client_p, from, msgbuf.n_para, msgbuf.para); return; } if(handle_command(mptr, &msgbuf, client_p, from) < -1) { char *p; for (p = pbuffer; p <= end; p += 8) { /* HACK HACK */ /* Its expected this nasty code can be removed * or rewritten later if still needed. */ if((p + 8) > end) { for (; p <= end; p++) { ilog(L_MAIN, "%02x |%c", p[0], p[0]); } } else ilog(L_MAIN, "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } }
/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; char *ch; char *s; char *numeric = 0; unsigned int i = 0; struct Message *mptr = NULL; if (IsDefunct(client_p)) return; assert(client_p->localClient->fd.flags.open); assert((bufend - pbuffer) < 512); 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). */ sender = ch; if ((s = strchr(ch, ' ')) != NULL) { *s = '\0'; s++; ch = s; } if (*sender && IsServer(client_p)) { /* * XXX it could be useful to know which of these occurs most frequently. * the ID check should always come first, though, since it is so easy. */ if ((from = find_person(client_p, sender)) == NULL) { from = find_server(sender); if (from == NULL && IsCapable(client_p, CAP_TS6) && client_p->name[0] == '*' && IsDigit(*sender) && strlen(sender) == 3) { /* Dirty hack to allow messages from masked SIDs (i.e. the ones * hidden by fakename="..."). It shouldn't break anything, since * unknown SIDs don't happen during normal ircd work --adx */ from = client_p; } } /* 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 == NULL) { ServerStats->is_unpf++; remove_unknown(client_p, sender, pbuffer); return; } para[0] = from->name; if (from->from != client_p) { ServerStats->is_wrdi++; cancel_clients(client_p, from, pbuffer); return; } } while (*ch == ' ') ch++; } if (*ch == '\0') { ServerStats->is_empt++; return; } /* 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 */ /* EOB is 3 chars long but is not a numeric */ if (*(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { mptr = NULL; numeric = ch; 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 { int ii = 0; if ((s = strchr(ch, ' ')) != NULL) *s++ = '\0'; if ((mptr = find_command(ch)) == NULL) { /* 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 */ if (pbuffer[0] != '\0') { if (IsClient(from)) sendto_one(from, form_str(ERR_UNKNOWNCOMMAND), me.name, from->name, ch); } ServerStats->is_unco++; return; } assert(mptr->cmd != NULL); ii = bufend - ((s) ? s : ch); mptr->bytes += ii; } if (s != NULL) i = string_to_array(s, para); else { i = 0; para[1] = NULL; } if (mptr == NULL) do_numeric(numeric, client_p, from, i, para); else handle_command(mptr, client_p, from, i, para); }
/* parse() * * given a raw buffer, parses it and generates parv, parc and sender */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; char *ch; char *s; char *end; int i = 1; char *numeric = 0; struct Message *mptr; s_assert(MyConnect(client_p)); s_assert(client_p->localClient->fd >= 0); if(IsAnyDead(client_p)) return; for (ch = pbuffer; *ch == ' '; ch++) /* skip spaces */ /* null statement */ ; para[0] = from->name; if(*ch == ':') { ch++; /* point sender to the sender param */ sender = ch; if((s = strchr(ch, ' '))) { *s = '\0'; s++; ch = s; } if(*sender && IsServer(client_p)) { from = find_any_client(sender); /* didnt find any matching client, issue a kill */ if(from == NULL) { ServerStats->is_unpf++; remove_unknown(client_p, sender, pbuffer); return; } para[0] = from->name; /* fake direction, hmm. */ if(from->from != client_p) { ServerStats->is_wrdi++; cancel_clients(client_p, from, pbuffer); return; } } while (*ch == ' ') ch++; } if(*ch == '\0') { ServerStats->is_empt++; return; } /* at this point there must be some sort of command parameter */ /* * 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 */ /* EOB is 3 chars long but is not a numeric */ if(*(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { mptr = NULL; numeric = ch; 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 { int ii = 0; if((s = strchr(ch, ' '))) *s++ = '\0'; mptr = hash_parse(ch); /* no command or its encap only, error */ 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 */ if(pbuffer[0] != '\0') { if(IsPerson(from)) sendto_one(from, form_str(ERR_UNKNOWNCOMMAND), me.name, from->name, ch); } ServerStats->is_unco++; return; } ii = bufend - ((s) ? s : ch); mptr->bytes += ii; } end = bufend - 1; /* XXX this should be done before parse() is called */ if(*end == '\n') *end-- = '\0'; if(*end == '\r') *end = '\0'; if(s != NULL) i = string_to_array(s, para); if(mptr == NULL) { do_numeric(numeric, client_p, from, i, para); return; } if(handle_command(mptr, client_p, from, i, /* XXX discards const!!! */ (const char **)para) < -1) { char *p; for (p = pbuffer; p <= end; p += 8) { /* HACK HACK */ /* Its expected this nasty code can be removed * or rewritten later if still needed. */ if((unsigned long) (p + 8) > (unsigned long) end) { for (; p <= end; p++) { ilog(L_MAIN, "%02x |%c", p[0], p[0]); } } else ilog(L_MAIN, "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } }