This commit was generated by cvs2svn to compensate for changes in r2,
[ircu2.10.12-pk.git] / ircd / parse.c
1 /*
2  * IRC - Internet Relay Chat, common/parse.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "sys.h"
22 #include "h.h"
23 #include "struct.h"
24 #include "s_serv.h"
25 #include "send.h"
26 #include "parse.h"
27 #include "common.h"
28 #include "s_bsd.h"
29 #include "msg.h"
30 #include "s_user.h"
31 #include "s_serv.h"
32 #include "channel.h"
33 #include "whowas.h"
34 #include "s_ping.h"
35 #include "s_conf.h"
36 #include "res.h"
37 #include "map.h"
38 #include "hash.h"
39 #include "numeric.h"
40 #include "ircd.h"
41 #include "s_misc.h"
42 #include "common.h"
43 #include "s_numeric.h"
44 #include "numnicks.h"
45 #include "opercmds.h"
46 #include "querycmds.h"
47 #include "whocmds.h"
48
49 RCSTAG_CC("$Id$");
50
51 /* *INDENT-OFF* */
52
53 aMessage msgtab[] = {
54     {CLASS_PRIVATE,     MSG_PRIVATE,    TOK_PRIVATE,    m_private,      0, MAXPARA,     MFLG_SLOW,      0L},
55     {CLASS_NICK,        MSG_NICK,       TOK_NICK,       m_nick,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
56     {CLASS_NOTICE,      MSG_NOTICE,     TOK_NOTICE,     m_notice,       0, MAXPARA,     MFLG_SLOW,      0L},
57     {CLASS_WALLCHOPS,   MSG_WALLCHOPS,  TOK_WALLCHOPS,  m_wallchops,    0, MAXPARA,     MFLG_SLOW,      0L},
58     {CLASS_CPRIVMSG,    MSG_CPRIVMSG,   TOK_CPRIVMSG,   m_cprivmsg,     0, MAXPARA,     MFLG_SLOW,      0L},
59     {CLASS_CNOTICE,     MSG_CNOTICE,    TOK_CNOTICE,    m_cnotice,      0, MAXPARA,     MFLG_SLOW,      0L},
60     {CLASS_JOIN,        MSG_JOIN,       TOK_JOIN,       m_join,         0, MAXPARA,     MFLG_SLOW,      0L},
61     {CLASS_MODE,        MSG_MODE,       TOK_MODE,       m_mode,         0, MAXPARA,     MFLG_SLOW,      0L},
62     {CLASS_BURST,       MSG_BURST,      TOK_BURST,      m_burst,        0, MAXPARA,     MFLG_SLOW,      0L},
63     {CLASS_CREATE,      MSG_CREATE,     TOK_CREATE,     m_create,       0, MAXPARA,     MFLG_SLOW,      0L},
64     {CLASS_DESTRUCT,    MSG_DESTRUCT,   TOK_DESTRUCT,   m_destruct,     0, MAXPARA,     MFLG_SLOW,      0L},
65     {CLASS_QUIT,        MSG_QUIT,       TOK_QUIT,       m_quit,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
66     {CLASS_PART,        MSG_PART,       TOK_PART,       m_part,         0, MAXPARA,     MFLG_SLOW,      0L},
67     {CLASS_TOPIC,       MSG_TOPIC,      TOK_TOPIC,      m_topic,        0, MAXPARA,     MFLG_SLOW,      0L},
68     {CLASS_INVITE,      MSG_INVITE,     TOK_INVITE,     m_invite,       0, MAXPARA,     MFLG_SLOW,      0L},
69     {CLASS_KICK,        MSG_KICK,       TOK_KICK,       m_kick,         0, MAXPARA,     MFLG_SLOW,      0L},
70     {CLASS_WALLOPS,     MSG_WALLOPS,    TOK_WALLOPS,    m_wallops,      0, MAXPARA,     MFLG_SLOW,      0L},
71     {CLASS_DESYNCH,     MSG_DESYNCH,    TOK_DESYNCH,    m_desynch,      0, MAXPARA,     MFLG_SLOW,      0L},
72     {CLASS_PING,        MSG_PING,       TOK_PING,       m_ping,         0, MAXPARA,     MFLG_SLOW,      0L},
73     {CLASS_PONG,        MSG_PONG,       TOK_PONG,       m_pong,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
74     {CLASS_ERROR,       MSG_ERROR,      TOK_ERROR,      m_error,        0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
75     {CLASS_KILL,        MSG_KILL,       TOK_KILL,       m_kill,         0, MAXPARA,     MFLG_SLOW,      0L},
76     {CLASS_USER,        MSG_USER,       TOK_USER,       m_user,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
77     {CLASS_AWAY,        MSG_AWAY,       TOK_AWAY,       m_away,         0, MAXPARA,     MFLG_SLOW,      0L},
78     {CLASS_ISON,        MSG_ISON,       TOK_ISON,       m_ison,         0, 1,           MFLG_SLOW,      0L},
79     {CLASS_SERVER,      MSG_SERVER,     TOK_SERVER,     m_server,       0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
80     {CLASS_SQUIT,       MSG_SQUIT,      TOK_SQUIT,      m_squit,        0, MAXPARA,     MFLG_SLOW,      0L},
81     {CLASS_WHOIS,       MSG_WHOIS,      TOK_WHOIS,      m_whois,        0, MAXPARA,     MFLG_SLOW,      0L},
82     {CLASS_WHO,         MSG_WHO,        TOK_WHO,        m_who,          0, MAXPARA,     MFLG_SLOW,      0L},
83     {CLASS_WHOWAS,      MSG_WHOWAS,     TOK_WHOWAS,     m_whowas,       0, MAXPARA,     MFLG_SLOW,      0L},
84     {CLASS_LIST,        MSG_LIST,       TOK_LIST,       m_list,         0, MAXPARA,     MFLG_SLOW,      0L},
85     {CLASS_NAMES,       MSG_NAMES,      TOK_NAMES,      m_names,        0, MAXPARA,     MFLG_SLOW,      0L},
86     {CLASS_USERHOST,    MSG_USERHOST,   TOK_USERHOST,   m_userhost,     0, 1,           MFLG_SLOW,      0L},
87     {CLASS_USERIP,      MSG_USERIP,     TOK_USERIP,     m_userip,       0, 1,           MFLG_SLOW,      0L},
88     {CLASS_TRACE,       MSG_TRACE,      TOK_TRACE,      m_trace,        0, MAXPARA,     MFLG_SLOW,      0L},
89     {CLASS_PASS,        MSG_PASS,       TOK_PASS,       m_pass,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
90     {CLASS_LUSERS,      MSG_LUSERS,     TOK_LUSERS,     m_lusers,       0, MAXPARA,     MFLG_SLOW,      0L},
91     {CLASS_TIME,        MSG_TIME,       TOK_TIME,       m_time,         0, MAXPARA,     MFLG_SLOW,      0L},
92     {CLASS_SETTIME,     MSG_SETTIME,    TOK_SETTIME,    m_settime,      0, MAXPARA,     MFLG_SLOW,      0L},
93     {CLASS_RPING,       MSG_RPING,      TOK_RPING,      m_rping,        0, MAXPARA,     MFLG_SLOW,      0L},
94     {CLASS_RPONG,       MSG_RPONG,      TOK_RPONG,      m_rpong,        0, MAXPARA,     MFLG_SLOW,      0L},
95     {CLASS_OPER,        MSG_OPER,       TOK_OPER,       m_oper,         0, MAXPARA,     MFLG_SLOW,      0L},
96     {CLASS_CONNECT,     MSG_CONNECT,    TOK_CONNECT,    m_connect,      0, MAXPARA,     MFLG_SLOW,      0L},
97     {CLASS_UPING,       MSG_UPING,      TOK_UPING,      m_uping,        0, MAXPARA,     MFLG_SLOW,      0L},
98     {CLASS_MAP,         MSG_MAP,        TOK_MAP,        m_map,          0, MAXPARA,     MFLG_SLOW,      0L},
99     {CLASS_VERSION,     MSG_VERSION,    TOK_VERSION,    m_version,      0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
100     {CLASS_STATS,       MSG_STATS,      TOK_STATS,      m_stats,        0, MAXPARA,     MFLG_SLOW,      0L},
101     {CLASS_LINKS,       MSG_LINKS,      TOK_LINKS,      m_links,        0, MAXPARA,     MFLG_SLOW,      0L},
102     {CLASS_ADMIN,       MSG_ADMIN,      TOK_ADMIN,      m_admin,        0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
103     {CLASS_HELP,        MSG_HELP,       TOK_HELP,       m_help,         0, MAXPARA,     MFLG_SLOW,      0L},
104     {CLASS_INFO,        MSG_INFO,       TOK_INFO,       m_info,         0, MAXPARA,     MFLG_SLOW,      0L},
105     {CLASS_MOTD,        MSG_MOTD,       TOK_MOTD,       m_motd,         0, MAXPARA,     MFLG_SLOW,      0L},
106     {CLASS_CLOSE,       MSG_CLOSE,      TOK_CLOSE,      m_close,        0, MAXPARA,     MFLG_SLOW,      0L},
107     {CLASS_SILENCE,     MSG_SILENCE,    TOK_SILENCE,    m_silence,      0, MAXPARA,     MFLG_SLOW,      0L},
108     {CLASS_GLINE,       MSG_GLINE,      TOK_GLINE,      m_gline,        0, MAXPARA,     MFLG_SLOW,      0L},
109     {CLASS_END_OF_BURST, MSG_END_OF_BURST, TOK_END_OF_BURST, m_end_of_burst, 0, MAXPARA, MFLG_SLOW,     0L},
110     {CLASS_END_OF_BURST_ACK, MSG_END_OF_BURST_ACK, TOK_END_OF_BURST_ACK, m_end_of_burst_ack, 0, MAXPARA, 1, 0L},
111     {CLASS_HASH,        MSG_HASH,       TOK_HASH,       m_hash,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
112     {CLASS_DNS,         MSG_DNS,        TOK_DNS,        m_dns,          0, MAXPARA,     MFLG_SLOW,      0L},
113 #if defined(OPER_REHASH) || defined(LOCOP_REHASH)
114     {CLASS_REHASH,      MSG_REHASH,     TOK_REHASH,     m_rehash,       0, MAXPARA,     MFLG_SLOW,      0L},
115 #endif
116 #if defined(OPER_RESTART) || defined(LOCOP_RESTART)
117     {CLASS_RESTART,     MSG_RESTART,    TOK_RESTART,    m_restart,      0, MAXPARA,     MFLG_SLOW,      0L},
118 #endif
119 #if defined(OPER_DIE) || defined(LOCOP_DIE)
120     {CLASS_DIE,         MSG_DIE,        TOK_DIE,        m_die,          0, MAXPARA,     MFLG_SLOW,      0L},
121 #endif
122     {0, (char *)0, (char *)0, (int (*)(aClient *, aClient *, int, char **))0,   0, 0, 0, 0L}
123 }                                                                                                                                   ;
124 /* *INDENT-ON* */
125
126 #ifdef GODMODE
127 extern int sdbflag;
128 #endif /* GODMODE */
129
130 static char *para[MAXPARA + 2]; /* leave room for prefix and null */
131
132 /*
133  * Message Tree stuff mostly written by orabidoo, with changes by Dianora.
134  * Adapted to Undernet, adding token support, etc by comstud 10/06/97
135  */
136
137 static aMessageTree msg_tree_cmd;
138 static aMessageTree msg_tree_tok;
139
140 /*
141  * Guts of making the token tree...
142  */
143 static aMessage **do_msg_tree_tok(aMessageTree *mtree, char *prefix,
144     aMessage **mptr)
145 {
146   char newprefix[64];           /* Must be longer than every command name */
147   int c, c2, lp;
148   aMessageTree *mtree1;
149
150   lp = strlen(prefix);
151   if (!lp || !strncmp((*mptr)->tok, prefix, lp))
152   {
153     if (!mptr[1] || (lp && strncmp(mptr[1]->tok, prefix, lp)))
154     {
155       /* last command in the message struct or last command in this prefix */
156       mtree->final = (*mptr)->tok + lp;
157       mtree->msg = *mptr;
158       for (c = 0; c < 26; ++c)
159         mtree->pointers[c] = NULL;
160       return mptr + 1;
161     }
162     /* command in this prefix */
163     if (!strCasediff((*mptr)->tok, prefix))
164     {
165       mtree->final = "";
166       mtree->msg = *mptr++;
167     }
168     else
169       mtree->final = NULL;
170
171     for (c = 'A'; c <= 'Z'; ++c)
172     {
173       if ((*mptr)->tok[lp] == c)
174       {
175         mtree1 = (aMessageTree *)RunMalloc(sizeof(aMessageTree));
176         mtree1->final = NULL;
177         mtree->pointers[c - 'A'] = mtree1;
178         strcpy(newprefix, prefix);
179         newprefix[lp] = c;
180         newprefix[lp + 1] = '\0';
181         mptr = do_msg_tree_tok(mtree1, newprefix, mptr);
182         if (!*mptr || strncmp((*mptr)->tok, prefix, lp))
183         {
184           for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
185             mtree->pointers[c2] = NULL;
186           return mptr;
187         }
188       }
189       else
190         mtree->pointers[c - 'A'] = NULL;
191     }
192     return mptr;
193   }
194   MyCoreDump;                   /* This should never happen */
195   exit(1);
196 }
197
198 /*
199  * Guts of making the command tree...
200  */
201 static aMessage *do_msg_tree_cmd(aMessageTree *mtree, char *prefix,
202     aMessage *mptr)
203 {
204   char newprefix[64];           /* Must be longer than every command name */
205   int c, c2, lp;
206   aMessageTree *mtree1;
207
208   lp = strlen(prefix);
209   if (!lp || !strncmp(mptr->cmd, prefix, lp))
210   {
211     if (!mptr[1].cmd || (lp && strncmp(mptr[1].cmd, prefix, lp)))
212     {
213       /* last command in the message struct or last command in this prefix */
214       mtree->final = mptr->cmd + lp;
215       mtree->msg = mptr;
216       for (c = 0; c < 26; ++c)
217         mtree->pointers[c] = NULL;
218       return mptr + 1;
219     }
220     /* command in this prefix */
221     if (!strCasediff(mptr->cmd, prefix))
222     {
223       mtree->final = "";
224       mtree->msg = mptr++;
225     }
226     else
227       mtree->final = NULL;
228
229     for (c = 'A'; c <= 'Z'; ++c)
230     {
231       if (mptr->cmd[lp] == c)
232       {
233         mtree1 = (aMessageTree *)RunMalloc(sizeof(aMessageTree));
234         mtree1->final = NULL;
235         mtree->pointers[c - 'A'] = mtree1;
236         strcpy(newprefix, prefix);
237         newprefix[lp] = c;
238         newprefix[lp + 1] = '\0';
239         mptr = do_msg_tree_cmd(mtree1, newprefix, mptr);
240         if (!mptr->cmd || strncmp(mptr->cmd, prefix, lp))
241         {
242           for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
243             mtree->pointers[c2] = NULL;
244           return mptr;
245         }
246       }
247       else
248         mtree->pointers[c - 'A'] = NULL;
249     }
250     return mptr;
251   }
252   MyCoreDump;                   /* This should never happen */
253   exit(1);
254 }
255
256 static int mcmdcmp(const struct Message *m1, const struct Message *m2)
257 {
258   return strcmp(m1->cmd, m2->cmd);
259 }
260
261 static int mtokcmp(const struct Message **m1, const struct Message **m2)
262 {
263   return strcmp((*m1)->tok, (*m2)->tok);
264 }
265
266 /*
267  * Sort the command names.
268  * Create table of pointers into msgtab for tokens.
269  * Create trees for ->cmd and ->tok and free the token pointers.
270  */
271 void initmsgtree(void)
272 {
273   Reg1 int i;
274   Reg2 aMessage *msg = msgtab;
275   Reg3 int ii;
276   aMessage **msgtab_tok;
277   aMessage **msgtok;
278
279   for (i = 0; msg->cmd; ++i, ++msg)
280     continue;
281   qsort(msgtab, i, sizeof(aMessage),
282       (int (*)(const void *, const void *))mcmdcmp);
283   msgtab_tok = (aMessage **)RunMalloc((i + 1) * sizeof(aMessage *));
284   for (ii = 0; ii < i; ++ii)
285     msgtab_tok[ii] = msgtab + ii;
286   msgtab_tok[i] = NULL;         /* Needed by `do_msg_tree_tok' */
287   qsort(msgtab_tok, i, sizeof(aMessage *),
288       (int (*)(const void *, const void *))mtokcmp);
289   msg = do_msg_tree_cmd(&msg_tree_cmd, "", msgtab);
290   msgtok = do_msg_tree_tok(&msg_tree_tok, "", msgtab_tok);
291   RunFree(msgtab_tok);
292 }
293
294 /*
295  * Generic tree parser which works for both commands and tokens.
296  * Optimized by Run.
297  */
298 static struct Message *msg_tree_parse(register char *cmd, aMessageTree *root)
299 {
300   register aMessageTree *mtree;
301   register unsigned char r = (0xdf & (unsigned char)*cmd) - 'A';
302   if (r > 25 || !(mtree = root->pointers[r]))
303     return NULL;
304   for (;;)
305   {
306     r = 0xdf & (unsigned char)*++cmd;
307     if (mtree->final && *mtree->final == r)
308       return mtree->msg;
309     if ((r -= 'A') > 25 || !(mtree = mtree->pointers[r]))
310       return NULL;
311   }
312 }
313
314 /*
315  * This one is identical to the one above, but it is slower because it
316  * makes sure that `cmd' matches the _full_ command, exactly.
317  * This is to avoid confusion with commands like /quake on clients
318  * that send unknown commands directly to the server.
319  */
320 static struct Message *msg_tree_parse_client(register char *cmd,
321     aMessageTree *root)
322 {
323   register aMessageTree *mtree;
324   register unsigned char q = (0xdf & (unsigned char)*cmd) - 'A';
325   if (q > 25 || !(mtree = root->pointers[q]))
326     return NULL;
327   for (;;)
328   {
329     q = 0xdf & (unsigned char)*++cmd;
330     if (mtree->final && !strCasediff(mtree->final, cmd))
331       return mtree->msg;
332     if ((q -= 'A') > 25 || !(mtree = mtree->pointers[q]))
333       return NULL;
334   }
335 }
336
337 /*
338  * parse a buffer.
339  *
340  * NOTE: parse_*() should not be called recusively by any other fucntions!
341  */
342 int parse_client(aClient *cptr, char *buffer, char *bufend)
343 {
344   Reg1 aClient *from = cptr;
345   Reg2 char *ch, *s;
346   Reg3 int i, paramcount, noprefix = 0;
347   aMessage *mptr;
348
349   Debug((DEBUG_DEBUG, "Parsing: %s", buffer));
350   StoreBuffer((buffer, cptr));  /* Store the buffer now, before
351                                    we start working on it */
352
353   if (IsDead(cptr))
354     return 0;
355
356   para[0] = from->name;
357   for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
358   if (*ch == ':')               /* Is any client doing this ? */
359   {
360     for (++ch; *ch && *ch != ' '; ++ch);        /* Ignore sender prefix from client */
361     while (*ch == ' ')
362       ch++;                     /* Advance to command */
363   }
364   else
365     noprefix = 1;
366   if (*ch == '\0')
367   {
368     ircstp->is_empt++;
369     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
370         cptr->name, from->name));
371     return (-1);
372   }
373
374   if ((s = strchr(ch, ' ')))
375     *s++ = '\0';
376
377   /*
378    * This is a client/unregistered entity.
379    * Check long command list only.
380    */
381   if (!(mptr = msg_tree_parse_client(ch, &msg_tree_cmd)))
382   {
383     /*
384      * Note: Give error message *only* to recognized
385      * persons. It's a nightmare situation to have
386      * two programs sending "Unknown command"'s or
387      * equivalent to each other at full blast....
388      * If it has got to person state, it at least
389      * seems to be well behaving. Perhaps this message
390      * should never be generated, though...  --msa
391      * Hm, when is the buffer empty -- if a command
392      * code has been found ?? -Armin
393      */
394     if (buffer[0] != '\0')
395     {
396       if (IsUser(from))
397         sendto_one(from, ":%s %d %s %s :Unknown command",
398             me.name, ERR_UNKNOWNCOMMAND, from->name, ch);
399       Debug((DEBUG_ERROR, "Unknown (%s) from %s",
400           ch, get_client_name(cptr, TRUE)));
401     }
402     ircstp->is_unco++;
403     return (-1);
404   }
405   LogMessage((cptr, mptr->msgclass));
406
407   paramcount = mptr->parameters;
408   i = bufend - ((s) ? s : ch);
409   mptr->bytes += i;
410   if ((mptr->flags & MFLG_SLOW))
411     cptr->since += (2 + i / 120);
412   /*
413    * Allow only 1 msg per 2 seconds
414    * (on average) to prevent dumping.
415    * to keep the response rate up,
416    * bursts of up to 5 msgs are allowed
417    * -SRB
418    */
419
420   /*
421    * Must the following loop really be so devious? On
422    * surface it splits the message to parameters from
423    * blank spaces. But, if paramcount has been reached,
424    * the rest of the message goes into this last parameter
425    * (about same effect as ":" has...) --msa
426    */
427
428   /* Note initially true: s==NULL || *(s-1) == '\0' !! */
429
430   i = 0;
431   if (s)
432   {
433     if (paramcount > MAXPARA)
434       paramcount = MAXPARA;
435     for (;;)
436     {
437       /*
438        * Never "FRANCE " again!! ;-) Clean
439        * out *all* blanks.. --msa
440        */
441       while (*s == ' ')
442         *s++ = '\0';
443
444       if (*s == '\0')
445         break;
446       if (*s == ':')
447       {
448         /*
449          * The rest is single parameter--can
450          * include blanks also.
451          */
452         para[++i] = s + 1;
453         break;
454       }
455       para[++i] = s;
456       if (i >= paramcount)
457         break;
458       for (; *s != ' ' && *s; s++);
459     }
460   }
461   para[++i] = NULL;
462   mptr->count++;
463   /* The "unregistered command check" was ugly and mildly inefficient.
464    * I fixed it. :)  --Shadow
465    */
466   if (!IsUser(cptr) && !(mptr->flags & MFLG_UNREG))
467   {
468     sendto_one(from, ":%s %d * %s :Register first.",
469         me.name, ERR_NOTREGISTERED, ch);
470     return -1;
471   }
472   if (IsUser(cptr) &&
473 #ifdef  IDLE_FROM_MSG
474       mptr->func == m_private)
475 #else
476       mptr->func != m_ping && mptr->func != m_pong)
477 #endif
478       from->user->last = now;
479
480   return (*mptr->func) (cptr, from, i, para);
481 }
482
483 int parse_server(aClient *cptr, char *buffer, char *bufend)
484 {
485   Reg1 aClient *from = cptr;
486   Reg2 char *ch = buffer, *s;
487   Reg3 int len, i, numeric = 0, paramcount;
488   aMessage *mptr;
489
490   Debug((DEBUG_DEBUG, "Parsing: %s", buffer));
491   StoreBuffer((buffer, cptr));  /* Store the buffer now, before
492                                  * we start working on it. */
493
494 #ifdef GODMODE
495   len = strlen(buffer);
496   sdbflag = 1;
497   if (len > 402)
498   {
499     char c = buffer[200];
500     buffer[200] = 0;
501     sendto_ops("RCV:%-8.8s(%.4d): \"%s...%s\"",
502         cptr->name, len, buffer, &buffer[len - 200]);
503     buffer[200] = c;
504   }
505   else
506     sendto_ops("RCV:%-8.8s(%.4d): \"%s\"", cptr->name, len, buffer);
507   sdbflag = 0;
508 #endif /* GODMODE */
509
510   if (IsDead(cptr))
511     return 0;
512
513   para[0] = from->name;
514
515   /*
516    * A server ALWAYS sends a prefix. When it starts with a ':' it's the
517    * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric
518    * nick or server
519    */
520   if (*ch == ':')
521   {
522     /* Let para[0] point to the name of the sender */
523     para[0] = ch + 1;
524     if (!(ch = strchr(ch, ' ')))
525       return -1;
526     *ch++ = '\0';
527
528     /* And let `from' point to its client structure,
529        opps.. a server is _also_ a client --Nem */
530     from = FindClient(para[0]);
531
532     /*
533      * If the client corresponding to the
534      * prefix is not found. We must ignore it,
535      * it is simply a lagged message travelling
536      * upstream a SQUIT that removed the client
537      * --Run
538      */
539     if (!from)
540     {
541       Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
542           para[0], buffer, cptr->name));
543       ircstp->is_unpf++;
544       while (*ch == ' ')
545         ch++;
546       /*
547        * However, the only thing that MUST be
548        * allowed to travel upstream against an
549        * squit, is an SQUIT itself (the timestamp
550        * protects us from being used wrong)
551        */
552       if (ch[1] == 'Q')
553       {
554         para[0] = cptr->name;
555         from = cptr;
556       }
557       else
558         return 0;
559     }
560     else if (from->from != cptr)
561     {
562       ircstp->is_wrdi++;
563       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
564           buffer, cptr->name));
565       return 0;
566     }
567   }
568   else if (Protocol(cptr) > 9)  /* Well, not ALWAYS, 2.9 can send no prefix */
569   {
570     char numeric_prefix[6];
571     int i;
572     for (i = 0; i < 5; ++i)
573     {
574       if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
575       {
576         break;
577       }
578     }
579     numeric_prefix[i] = '\0';
580     /*
581      * We got a numeric nick as prefix
582      * 1 or 2 character prefixes are from servers
583      * 3 or 5 chars are from clients
584      */
585     if (' ' == ch[1] || ' ' == ch[2])
586       from = FindNServer(numeric_prefix);
587     else
588       from = findNUser(numeric_prefix);
589
590     do
591     {
592       ++ch;
593     }
594     while (*ch != ' ' && *ch);
595
596     /*
597      * If the client corresponding to the
598      * prefix is not found. We must ignore it,
599      * it is simply a lagged message travelling
600      * upstream a SQUIT that removed the client
601      * --Run
602      * There turned out to be other reasons that
603      * a prefix is unknown, needing an upstream
604      * KILL.  Also, next to an SQUIT we better
605      * allow a KILL to pass too.
606      * --Run
607      */
608     if (!from)
609     {
610       ircstp->is_unpf++;
611       while (*ch == ' ')
612         ch++;
613       if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
614         /* Only sent a KILL for a nick change */
615       {
616         aClient *server;
617         /* Kill the unknown numeric prefix upstream if
618          * it's server still exists: */
619         if ((server = FindNServer(numeric_prefix)) && server->from == cptr)
620           sendto_one(cptr, "%s KILL %s :%s (Unknown numeric nick)",
621               NumServ(&me), numeric_prefix, me.name);
622       }
623       /*
624        * Things that must be allowed to travel
625        * upstream against an squit:
626        */
627       if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
628           (*ch == 'K' && ch[2] == 'L'))
629         from = cptr;
630       else
631         return 0;
632     }
633
634     /* Let para[0] point to the name of the sender */
635     para[0] = from->name;
636
637     if (from->from != cptr)
638     {
639       ircstp->is_wrdi++;
640       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
641           buffer, cptr->name));
642       return 0;
643     }
644   }
645
646   while (*ch == ' ')
647     ch++;
648   if (*ch == '\0')
649   {
650     ircstp->is_empt++;
651     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
652         cptr->name, from->name));
653     return (-1);
654   }
655
656   /*
657    * Extract the command code from the packet.   Point s to the end
658    * of the command code and calculate the length using pointer
659    * arithmetic.  Note: only need length for numerics and *all*
660    * numerics must have parameters and thus a space after the command
661    * code. -avalon
662    */
663   s = strchr(ch, ' ');          /* s -> End of the command code */
664   len = (s) ? (s - ch) : 0;
665   if (len == 3 && isDigit(*ch))
666   {
667     numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
668     paramcount = MAXPARA;
669     ircstp->is_num++;
670     mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
671   }
672   else
673   {
674     if (s)
675       *s++ = '\0';
676
677     /* Version      Receive         Send
678      * 2.9          Long            Long
679      * 2.10.0       Tkn/Long        Long
680      * 2.10.10      Tkn/Long        Tkn
681      * 2.10.20      Tkn             Tkn
682      *
683      * Clients/unreg servers always receive/
684      * send long commands   -record
685      */
686
687     /*
688      * This is a server. Check the token command list.
689      * -record!jegelhof@cloud9.net
690      */
691     mptr = msg_tree_parse(ch, &msg_tree_tok);
692
693 #if 1                           /* for 2.10.0/2.10.10 */
694     /*
695      * This code supports 2.9 and 2.10.0 sending long commands.
696      * It makes more calls to strCasediff() than the above
697      * so it will be somewhat slower.
698      */
699     if (!mptr)
700       mptr = msg_tree_parse(ch, &msg_tree_cmd);
701 #endif /* 1 */
702
703     if (!mptr)
704     {
705       /*
706        * Note: Give error message *only* to recognized
707        * persons. It's a nightmare situation to have
708        * two programs sending "Unknown command"'s or
709        * equivalent to each other at full blast....
710        * If it has got to person state, it at least
711        * seems to be well behaving. Perhaps this message
712        * should never be generated, though...   --msa
713        * Hm, when is the buffer empty -- if a command
714        * code has been found ?? -Armin
715        */
716 #ifdef DEBUGMODE
717       if (buffer[0] != '\0')
718       {
719         Debug((DEBUG_ERROR, "Unknown (%s) from %s",
720             ch, get_client_name(cptr, TRUE)));
721       }
722 #endif
723       ircstp->is_unco++;
724       return (-1);
725     }
726     LogMessage((cptr, mptr->msgclass));
727
728     paramcount = mptr->parameters;
729     i = bufend - ((s) ? s : ch);
730     mptr->bytes += i;
731   }
732   /*
733    * Must the following loop really be so devious? On
734    * surface it splits the message to parameters from
735    * blank spaces. But, if paramcount has been reached,
736    * the rest of the message goes into this last parameter
737    * (about same effect as ":" has...) --msa
738    */
739
740   /* Note initially true: s==NULL || *(s-1) == '\0' !! */
741
742   i = 0;
743   if (s)
744   {
745     if (paramcount > MAXPARA)
746       paramcount = MAXPARA;
747     for (;;)
748     {
749       /*
750        * Never "FRANCE " again!! ;-) Clean
751        * out *all* blanks.. --msa
752        */
753       while (*s == ' ')
754         *s++ = '\0';
755
756       if (*s == '\0')
757         break;
758       if (*s == ':')
759       {
760         /*
761          * The rest is single parameter--can
762          * include blanks also.
763          */
764         para[++i] = s + 1;
765         break;
766       }
767       para[++i] = s;
768       if (i >= paramcount)
769         break;
770       for (; *s != ' ' && *s; s++);
771     }
772   }
773   para[++i] = NULL;
774   if (numeric)
775     return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
776   mptr->count++;
777
778   return (*mptr->func) (cptr, from, i, para);
779 }