fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[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 /** @file
21  * @brief Parse input from IRC clients and other servers.
22  * @version $Id: parse.c 1827 2007-08-14 03:02:24Z entrope $
23  */
24 #include "config.h"
25
26 #include "parse.h"
27 #include "client.h"
28 #include "channel.h"
29 #include "handlers.h"
30 #include "hash.h"
31 #include "ircd.h"
32 #include "ircd_alloc.h"
33 #include "ircd_chattr.h"
34 #include "ircd_features.h"
35 #include "ircd_log.h"
36 #include "ircd_reply.h"
37 #include "ircd_string.h"
38 #include "msg.h"
39 #include "numeric.h"
40 #include "numnicks.h"
41 #include "opercmds.h"
42 #include "querycmds.h"
43 #include "res.h"
44 #include "s_bsd.h"
45 #include "s_conf.h"
46 #include "s_debug.h"
47 #include "s_misc.h"
48 #include "s_numeric.h"
49 #include "s_user.h"
50 #include "send.h"
51 #include "struct.h"
52 #include "sys.h"
53 #include "whocmds.h"
54 #include "whowas.h"
55
56 /* #include <assert.h> -- Now using assert in ircd_log.h */
57 #include <string.h>
58 #include <stdlib.h>
59
60 /*
61  * Message Tree stuff mostly written by orabidoo, with changes by Dianora.
62  * Adapted to Undernet, adding token support, etc by comstud 10/06/97
63  *
64  * completely rewritten June 2, 2003 - Dianora
65  *
66  * This has always just been a trie. Look at volume III of Knuth ACP
67  *
68  *
69  * ok, you start out with an array of pointers, each one corresponds
70  * to a letter at the current position in the command being examined.
71  *
72  * so roughly you have this for matching 'trie' or 'tie'
73  *
74  * 't' points -> [MessageTree *] 'r' -> [MessageTree *] -> 'i'
75  *   -> [MessageTree *] -> [MessageTree *] -> 'e' and matches
76  *
77  *                               'i' -> [MessageTree *] -> 'e' and matches
78  */
79
80 /** Number of children under a trie node. */
81 #define MAXPTRLEN       32      /* Must be a power of 2, and
82                                  * larger than 26 [a-z]|[A-Z]
83                                  * its used to allocate the set
84                                  * of pointers at each node of the tree
85                                  * There are MAXPTRLEN pointers at each node.
86                                  * Obviously, there have to be more pointers
87                                  * Than ASCII letters. 32 is a nice number
88                                  * since there is then no need to shift
89                                  * 'A'/'a' to base 0 index, at the expense
90                                  * of a few never used pointers. For a small
91                                  * parser like this, this is a good compromise
92                                  * and does make it somewhat faster.
93                                  *
94                                  * - Dianora
95                                  */
96
97 /** Node in the command lookup trie. */
98 struct MessageTree {
99   struct Message *msg; /**< Message (if any) if the string ends now. */
100   struct MessageTree *pointers[MAXPTRLEN]; /**< Child nodes for each letter. */
101 };
102
103 /** Root of command lookup trie. */
104 static struct MessageTree msg_tree;
105 static struct MessageTree tok_tree;
106
107 /** Array of all supported commands. */
108 struct Message msgtab[] = {
109   {
110     MSG_PRIVATE,
111     TOK_PRIVATE,
112     0, MAXPARA, MFLG_SLOW, 0, NULL,
113     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
114     { m_unregistered, m_privmsg, ms_privmsg, mo_privmsg, m_ignore }
115   },
116   {
117     MSG_NICK,
118     TOK_NICK,
119     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
120     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
121     { m_nick, m_nick, ms_nick, m_nick, m_ignore }
122   },
123   {
124     MSG_NOTICE,
125     TOK_NOTICE,
126     0, MAXPARA, MFLG_SLOW | MFLG_IGNORE, 0, NULL,
127     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
128     { m_ignore, m_notice, ms_notice, mo_notice, m_ignore }
129   },
130   {
131     MSG_WALLCHOPS,
132     TOK_WALLCHOPS,
133     0, MAXPARA, MFLG_SLOW, 0, NULL,
134     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
135     { m_unregistered, m_wallchops, ms_wallchops, m_wallchops, m_ignore }
136   },
137   {
138     MSG_WALLVOICES,
139     TOK_WALLVOICES,
140     0, MAXPARA, MFLG_SLOW, 0, NULL,
141     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
142     { m_unregistered, m_wallvoices, ms_wallvoices, m_wallvoices, m_ignore }
143   },
144   {
145     MSG_CPRIVMSG,
146     TOK_CPRIVMSG,
147     0, MAXPARA, MFLG_SLOW, 0, NULL,
148     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
149     { m_unregistered, m_cprivmsg, m_ignore, m_cprivmsg, m_ignore }
150   },
151   {
152     MSG_CNOTICE,
153     TOK_CNOTICE,
154     0, MAXPARA, MFLG_SLOW, 0, NULL,
155     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
156     { m_unregistered, m_cnotice, m_ignore, m_cnotice, m_ignore }
157   },
158   {
159     MSG_JOIN,
160     TOK_JOIN,
161     0, MAXPARA, MFLG_SLOW, 0, NULL,
162     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
163     { m_unregistered, m_join, ms_join, m_join, m_ignore }
164   },
165   {
166     MSG_MODE,
167     TOK_MODE,
168     0, MAXPARA, MFLG_SLOW, 0, NULL,
169     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
170     { m_unregistered, m_mode, ms_mode, m_mode, m_ignore }
171   },
172   {
173     MSG_BURST,
174     TOK_BURST,
175     0, MAXPARA, MFLG_SLOW, 0, NULL,
176     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
177     { m_ignore, m_ignore, ms_burst, m_ignore, m_ignore }
178   },
179   {
180     MSG_CREATE,
181     TOK_CREATE,
182     0, MAXPARA, MFLG_SLOW, 0, NULL,
183     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
184     { m_ignore, m_ignore, ms_create, m_ignore, m_ignore }
185   },
186   {
187     MSG_DESTRUCT,
188     TOK_DESTRUCT,
189     0, MAXPARA, MFLG_SLOW, 0, NULL,
190     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
191     { m_ignore, m_ignore, ms_destruct, m_ignore, m_ignore }
192   },
193   {
194     MSG_QUIT,
195     TOK_QUIT,
196     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
197     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
198     { m_quit, m_quit, ms_quit, m_quit, m_ignore }
199   },
200   {
201     MSG_PART,
202     TOK_PART,
203     0, MAXPARA, MFLG_SLOW, 0, NULL,
204     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
205     { m_unregistered, m_part, ms_part, m_part, m_ignore }
206   },
207   {
208     MSG_TOPIC,
209     TOK_TOPIC,
210     0, MAXPARA, MFLG_SLOW, 0, NULL,
211     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
212     { m_unregistered, m_topic, ms_topic, m_topic, m_ignore }
213   },
214   {
215     MSG_INVITE,
216     TOK_INVITE,
217     0, MAXPARA, MFLG_SLOW, 0, NULL,
218     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
219     { m_unregistered, m_invite, ms_invite, m_invite, m_ignore }
220   },
221   {
222     MSG_UNINVITE,
223     TOK_UNINVITE,
224     0, MAXPARA, MFLG_SLOW, 0, NULL,
225     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
226     { m_unregistered, m_uninvite, ms_uninvite, m_uninvite, m_ignore }
227   },
228   {
229     MSG_KICK,
230     TOK_KICK,
231     0, MAXPARA, MFLG_SLOW, 0, NULL,
232     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
233     { m_unregistered, m_kick, ms_kick, m_kick, m_ignore }
234   },
235   {
236     MSG_WALLOPS,
237     TOK_WALLOPS,
238     0, MAXPARA, MFLG_SLOW, 0, NULL,
239     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
240     { m_unregistered, m_not_oper, ms_wallops, mo_wallops, m_ignore }
241   },
242   {
243     MSG_WALLUSERS,
244     TOK_WALLUSERS,
245     0, MAXPARA, MFLG_SLOW, 0, NULL,
246     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
247     { m_unregistered, m_not_oper, ms_wallusers, mo_wallusers, m_ignore }
248   },
249   {
250     MSG_DESYNCH,
251     TOK_DESYNCH,
252     0, MAXPARA, MFLG_SLOW, 0, NULL,
253     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
254     { m_ignore, m_ignore, ms_desynch, m_ignore, m_ignore }
255   },
256   {
257     MSG_PING,
258     TOK_PING,
259     0, MAXPARA, MFLG_SLOW, 0, NULL,
260     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
261     { m_unregistered, m_ping, ms_ping, mo_ping, m_ignore }
262   },
263   {
264     MSG_PONG,
265     TOK_PONG,
266     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
267     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
268     { mr_pong, m_pong, ms_pong, m_pong, m_ignore }
269   },
270   {
271     MSG_ERROR,
272     TOK_ERROR,
273     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
274     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
275     { mr_error, m_ignore, ms_error, m_ignore, m_ignore }
276   },
277   {
278     MSG_KILL,
279     TOK_KILL,
280     0, MAXPARA, MFLG_SLOW, 0, NULL,
281     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
282     { m_unregistered, m_not_oper, ms_kill, mo_kill, m_ignore }
283   },
284   {
285     MSG_USER,
286     TOK_USER,
287     0, MAXPARA, MFLG_SLOW, 0, NULL,
288     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
289     { m_user, m_registered, m_ignore, m_registered, m_ignore }
290   },
291   {
292     MSG_AWAY,
293     TOK_AWAY,
294     0, MAXPARA, MFLG_SLOW, 0, NULL,
295     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
296     { m_unregistered, m_away, ms_away, m_away, m_ignore }
297   },
298   {
299     MSG_ISON,
300     TOK_ISON,
301     0, 1, MFLG_SLOW, 0, NULL,
302     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
303     { m_unregistered, m_ison, m_ignore, m_ison, m_ignore }
304   },
305   {
306     MSG_SERVER,
307     TOK_SERVER,
308     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
309     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
310     { mr_server, m_registered, ms_server, m_registered, m_ignore }
311   },
312   {
313     MSG_SQUIT,
314     TOK_SQUIT,
315     0, MAXPARA, MFLG_SLOW, 0, NULL,
316     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
317     { m_unregistered, m_not_oper, ms_squit, mo_squit, m_ignore }
318   },
319   {
320     MSG_WHOIS,
321     TOK_WHOIS,
322     0, MAXPARA, MFLG_SLOW, 0, NULL,
323     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
324     { m_unregistered, m_whois, ms_whois, m_whois, m_ignore }
325   },
326   {
327     MSG_WHO,
328     TOK_WHO,
329     0, MAXPARA, MFLG_SLOW, 0, NULL,
330     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
331     { m_unregistered, m_who, m_ignore, m_who, m_ignore }
332   },
333   {
334     MSG_WHOWAS,
335     TOK_WHOWAS,
336     0, MAXPARA, MFLG_SLOW, 0, NULL,
337     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
338     { m_unregistered, m_whowas, m_whowas, m_whowas, m_ignore }
339   },
340   {
341     MSG_LIST,
342     TOK_LIST,
343     0, MAXPARA, MFLG_SLOW, 0, NULL,
344     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
345     { m_unregistered, m_list, m_ignore, m_list, m_ignore }
346   },
347   {
348     MSG_NAMES,
349     TOK_NAMES,
350     0, MAXPARA, MFLG_SLOW, 0, NULL,
351     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
352     { m_unregistered, m_names, m_names, m_names, m_ignore }
353   },
354   {
355     MSG_USERHOST,
356     TOK_USERHOST,
357     0, 1, MFLG_SLOW, 0, NULL,
358     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
359     { m_unregistered, m_userhost, m_ignore, m_userhost, m_ignore }
360   },
361   {
362     MSG_USERIP,
363     TOK_USERIP,
364     0, 1, MFLG_SLOW, 0, NULL,
365     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
366     { m_unregistered, m_userip, m_ignore, m_userip, m_ignore }
367   },
368   {
369     MSG_TRACE,
370     TOK_TRACE,
371     0, MAXPARA, MFLG_SLOW, 0, NULL,
372     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
373     { m_unregistered, m_trace, ms_trace, mo_trace, m_ignore }
374   },
375   {
376     MSG_PASS,
377     TOK_PASS,
378     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
379     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
380     { mr_pass, m_registered, m_ignore, m_registered, m_ignore }
381   },
382   {
383     MSG_LUSERS,
384     TOK_LUSERS,
385     0, MAXPARA, MFLG_SLOW, 0, NULL,
386     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
387     { m_unregistered, m_lusers, ms_lusers, m_lusers, m_ignore }
388   },
389   {
390     MSG_TIME,
391     TOK_TIME,
392     0, MAXPARA, MFLG_SLOW, 0, NULL,
393     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
394     { m_unregistered, m_time, m_time, m_time, m_ignore }
395   },
396   {
397     MSG_SETTIME,
398     TOK_SETTIME,
399     0, MAXPARA, MFLG_SLOW, 0, NULL,
400     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
401     { m_unregistered, m_not_oper, ms_settime, mo_settime, m_ignore }
402   },
403   {
404     MSG_RPING,
405     TOK_RPING,
406     0, MAXPARA, MFLG_SLOW, 0, NULL,
407     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
408     { m_unregistered, m_not_oper, ms_rping, mo_rping, m_ignore }
409   },
410   {
411     MSG_RPONG,
412     TOK_RPONG,
413     0, MAXPARA, MFLG_SLOW, 0, NULL,
414     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
415     { m_unregistered, m_ignore, ms_rpong, m_ignore, m_ignore }
416   },
417   {
418     MSG_OPER,
419     TOK_OPER,
420     0, MAXPARA, MFLG_SLOW, 0, NULL,
421     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
422     { m_unregistered, m_oper, ms_oper, mo_oper, m_ignore }
423   },
424   {
425     MSG_CONNECT,
426     TOK_CONNECT,
427     0, MAXPARA, MFLG_SLOW, 0, NULL,
428     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
429     { m_unregistered, m_not_oper, ms_connect, mo_connect, m_ignore }
430   },
431   {
432     MSG_MAP,
433     TOK_MAP,
434     0, MAXPARA, MFLG_SLOW, 0, NULL,
435     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
436     { m_unregistered, m_map, m_ignore, m_map, m_ignore }
437   },
438   {
439     MSG_VERSION,
440     TOK_VERSION,
441     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
442     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
443     { m_version, m_version, ms_version, mo_version, m_ignore }
444   },
445   {
446     MSG_STATS,
447     TOK_STATS,
448     0, MAXPARA, MFLG_SLOW, 0, NULL,
449     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
450     { m_unregistered, m_stats, m_stats, m_stats, m_ignore }
451   },
452   {
453     MSG_LINKS,
454     TOK_LINKS,
455     0, MAXPARA, MFLG_SLOW, 0, NULL,
456     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
457     { m_unregistered, m_links, ms_links, m_links, m_ignore }
458   },
459   {
460     MSG_ADMIN,
461     TOK_ADMIN,
462     0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,  NULL,
463     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
464     { m_admin, m_admin, ms_admin, mo_admin, m_ignore }
465   },
466   {
467     MSG_HELP,
468     TOK_HELP,
469     0, MAXPARA, MFLG_SLOW, 0, NULL,
470     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
471     { m_unregistered, m_help, m_ignore, m_help, m_ignore }
472   },
473   {
474     MSG_INFO,
475     TOK_INFO,
476     0, MAXPARA, MFLG_SLOW, 0, NULL,
477     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
478     { m_unregistered, m_info, ms_info, mo_info, m_ignore }
479   },
480   {
481     MSG_MOTD,
482     TOK_MOTD,
483     0, MAXPARA, MFLG_SLOW, 0, NULL,
484     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
485     { m_unregistered, m_motd, m_motd, m_motd, m_ignore }
486   },
487   {
488     MSG_CLOSE,
489     TOK_CLOSE,
490     0, MAXPARA, MFLG_SLOW, 0, NULL,
491     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
492     { m_unregistered, m_not_oper, m_ignore, mo_close, m_ignore }
493   },
494   {
495     MSG_SILENCE,
496     TOK_SILENCE,
497     0, MAXPARA, MFLG_SLOW, 0, NULL,
498     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
499     { m_unregistered, m_silence, ms_silence, m_silence, m_ignore }
500   },
501   {
502     MSG_GLINE,
503     TOK_GLINE,
504     0, MAXPARA,         0, 0, NULL,
505     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
506     { m_unregistered, m_gline, ms_gline, mo_gline, m_ignore }
507   },
508   {
509     MSG_JUPE,
510     TOK_JUPE,
511     0, MAXPARA, MFLG_SLOW, 0, NULL,
512     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
513     { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore }
514   },
515   {
516     MSG_OPMODE,
517     TOK_OPMODE,
518     0, MAXPARA, MFLG_SLOW, 0, NULL,
519     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
520     { m_unregistered, mo_opmode, ms_opmode, mo_opmode, m_ignore }
521   },
522   {
523     MSG_CLEARMODE,
524     TOK_CLEARMODE,
525     0, MAXPARA, MFLG_SLOW, 0, NULL,
526     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
527     { m_unregistered, m_not_oper, ms_clearmode, mo_clearmode, m_ignore }
528   },
529   {
530     MSG_UPING,
531     TOK_UPING,
532     0, MAXPARA, MFLG_SLOW, 0, NULL,
533     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
534     { m_unregistered, m_not_oper, ms_uping, mo_uping, m_ignore }
535   },
536   {
537     MSG_END_OF_BURST,
538     TOK_END_OF_BURST,
539     0, MAXPARA, MFLG_SLOW, 0, NULL,
540     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
541     { m_ignore, m_ignore, ms_end_of_burst, m_ignore, m_ignore }
542   },
543   {
544     MSG_END_OF_BURST_ACK,
545     TOK_END_OF_BURST_ACK,
546     0, MAXPARA, MFLG_SLOW, 0, NULL,
547     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
548     { m_ignore, m_ignore, ms_end_of_burst_ack, m_ignore, m_ignore }
549   },
550   {
551     MSG_HASH,
552     TOK_HASH,
553     0, MAXPARA, MFLG_SLOW, 0, NULL,
554     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
555     { m_unregistered, m_hash, m_hash, m_hash, m_ignore }
556   },
557   {
558     MSG_REHASH,
559     TOK_REHASH,
560     0, MAXPARA, MFLG_SLOW, 0, NULL,
561     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
562     { m_unregistered, m_not_oper, ms_rehash, mo_rehash, m_ignore }
563   },
564   {
565     MSG_RESTART,
566     TOK_RESTART,
567     0, MAXPARA, MFLG_SLOW, 0, NULL,
568     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
569     { m_unregistered, m_not_oper, m_ignore, mo_restart, m_ignore }
570   },
571   {
572     MSG_DIE,
573     TOK_DIE,
574     0, MAXPARA, MFLG_SLOW, 0, NULL,
575     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
576     { m_unregistered, m_not_oper, m_ignore, mo_die, m_ignore }
577   },
578   {
579     MSG_PROTO,
580     TOK_PROTO,
581     0, MAXPARA, MFLG_SLOW, 0, NULL,
582     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
583     { m_proto, m_proto, m_proto, m_proto, m_ignore }
584   },
585   {
586     MSG_SET,
587     TOK_SET,
588     0, MAXPARA, MFLG_SLOW, 0, NULL,
589     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
590     { m_unregistered, m_not_oper, m_ignore, mo_set, m_ignore }
591   },
592   {
593     MSG_RESET,
594     TOK_RESET,
595     0, MAXPARA, MFLG_SLOW, 0, NULL,
596     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
597     { m_unregistered, m_not_oper, m_ignore, mo_reset, m_ignore }
598   },
599   {
600     MSG_GET,
601     TOK_GET,
602     0, MAXPARA, MFLG_SLOW, 0, NULL,
603     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
604     { m_unregistered, m_not_oper, m_ignore, mo_get, m_ignore }
605   },
606   {
607     MSG_PRIVS,
608     TOK_PRIVS,
609     0, MAXPARA, MFLG_SLOW, 0, NULL,
610     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
611     { m_unregistered, m_privs, ms_privs, m_privs, m_ignore }
612   },
613   {
614     MSG_ACCOUNT,
615     TOK_ACCOUNT,
616     0, MAXPARA, MFLG_SLOW, 0, NULL,
617     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
618     { m_ignore, m_ignore, ms_account, m_ignore, m_ignore }
619   },
620   {
621     MSG_ASLL,
622     TOK_ASLL,
623     0, MAXPARA, MFLG_SLOW, 0, NULL,
624     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
625     { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
626    },
627 #if WE_HAVE_A_REAL_CAPABILITY_NOW
628   {
629     MSG_CAP,
630     TOK_CAP,
631     0, MAXPARA, 0, 0, NULL,
632     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
633     { m_cap, m_cap, m_ignore, m_cap, m_ignore }
634   },
635 #endif
636   {
637     MSG_FAKEHOST,
638     TOK_FAKEHOST,
639     0, MAXPARA, MFLG_SLOW, 0, NULL,
640     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
641     { m_ignore, m_not_oper, ms_fakehost, m_fakehost, m_ignore }
642   },
643   {
644     MSG_FAKEHOST2,
645     TOK_FAKEHOST2,
646     0, MAXPARA, MFLG_SLOW, 0, NULL,
647     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
648     { m_ignore, m_ignore, ms_fakehost2, m_ignore, m_ignore }
649   },
650   {
651     MSG_FAKEHOST_OLD,
652     TOK_FAKEHOST_OLD,
653     0, MAXPARA, MFLG_SLOW, 0, NULL,
654     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
655     { m_ignore, m_not_oper, ms_fakehost_old, m_fakehost, m_ignore }
656   },
657   {
658     MSG_HIDEHOST,
659     TOK_HIDEHOST,
660     0, MAXPARA, MFLG_SLOW, 0, NULL,
661     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
662     { m_ignore, m_ignore, ms_hidehost, m_ignore, m_ignore }
663    },
664   {
665     MSG_SVSMODE,
666     TOK_SVSMODE,
667     0, MAXPARA, MFLG_SLOW, 0, NULL,
668     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
669     { m_ignore, m_ignore, ms_svsmode, m_svsmode, m_ignore }
670   },
671   {
672     MSG_SVSNICK,
673     TOK_SVSNICK,
674     0, MAXPARA, MFLG_SLOW, 0, NULL,
675     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
676     { m_ignore, m_ignore, ms_svsnick, m_svsnick, m_ignore }
677   },
678   {
679     MSG_SVSNICK_OLD,
680     TOK_SVSNICK_OLD,
681     0, MAXPARA, MFLG_SLOW, 0, NULL,
682     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
683     { m_ignore, m_ignore, ms_svsnick_old, m_svsnick, m_ignore }
684   },
685   {
686     MSG_SVSJOIN,
687     TOK_SVSJOIN,
688     0, MAXPARA, MFLG_SLOW, 0, NULL,
689     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
690     { m_ignore, m_ignore, ms_svsjoin, m_svsjoin, m_ignore }
691   },
692   {
693     MSG_SVSPART,
694     TOK_SVSPART,
695     0, MAXPARA, MFLG_SLOW, 0, NULL,
696     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
697     { m_ignore, m_ignore, ms_svspart, m_ignore, m_ignore }
698   },
699   {
700     MSG_WEBIRC,
701     TOK_WEBIRC,
702     0, MAXPARA, MFLG_SLOW, 0, NULL,
703     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
704     { m_webirc, m_registered, m_ignore, m_registered, m_ignore }
705   },
706   {
707     MSG_RELAY,
708     TOK_RELAY,
709     0, MAXPARA, MFLG_SLOW, 0, NULL,
710     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
711     { m_ignore, m_ignore, ms_relay, m_ignore, m_ignore }
712   },
713   {
714     MSG_CHECK,
715     TOK_CHECK,
716     0, MAXPARA, MFLG_SLOW, 0, NULL,
717     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
718     { m_ignore, m_not_oper, m_ignore, mo_check, m_ignore }
719   },
720   /* This command is an alias for QUIT during the unregistered part of
721    * of the server.  This is because someone jumping via a broken web
722    * proxy will send a 'POST' as their first command - which we will
723    * obviously disconnect them immediately for, stopping people abusing
724    * open gateways
725    */
726   {
727     MSG_POST,
728     TOK_POST,
729     0, MAXPARA, MFLG_SLOW, 0, NULL,
730     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
731     { m_quit, m_ignore, m_ignore, m_ignore, m_ignore }
732   },
733   { 0 }
734 };
735
736 /** Array of command parameters. */
737 static char *para[MAXPARA + 2]; /* leave room for prefix and null */
738
739
740 /** Add a message to the lookup trie.
741  * @param[in,out] mtree_p Trie node to insert under.
742  * @param[in] msg_p Message to insert.
743  * @param[in] cmd Text of command to insert.
744  */
745 void
746 add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, char *cmd)
747 {
748   struct MessageTree *ntree_p;
749
750   if (*cmd == '\0')
751   {
752     mtree_p->msg = msg_p;
753     return;
754   }
755
756   if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN-1)]) != NULL)
757   {
758     add_msg_element(ntree_p, msg_p, cmd+1);
759   }
760   else
761   {
762     ntree_p = (struct MessageTree *)MyCalloc(sizeof(struct MessageTree), 1);
763     mtree_p->pointers[*cmd & (MAXPTRLEN-1)] = ntree_p;
764     add_msg_element(ntree_p, msg_p, cmd+1);
765   }
766 }
767
768 /** Remove a message from the lookup trie.
769  * @param[in,out] mtree_p Trie node to remove command from.
770  * @param[in] cmd Text of command to remove.
771  */
772 struct MessageTree *
773 del_msg_element(struct MessageTree *mtree_p, char *cmd)
774 {
775   int slot = *cmd & (MAXPTRLEN-1);
776
777   /* Either remove leaf message or from appropriate child. */
778   if (*cmd == '\0')
779     mtree_p->msg = NULL;
780   else
781     mtree_p->pointers[slot] = del_msg_element(mtree_p->pointers[slot], cmd + 1);
782
783   /* If current message or any child still exists, keep this node. */
784   if (mtree_p->msg)
785     return mtree_p;
786   for (slot = 0; slot < MAXPTRLEN; ++slot)
787     if (mtree_p->pointers[slot])
788       return mtree_p;
789
790   /* Otherwise, if we're not a root node, free it and return null. */
791   if (mtree_p != &msg_tree && mtree_p != &tok_tree)
792     MyFree(mtree_p);
793   return NULL;
794 }
795
796 /** Initialize the message lookup trie with all known commands. */
797 void
798 initmsgtree(void)
799 {
800   int i;
801
802   memset(&msg_tree, 0, sizeof(msg_tree));
803   memset(&tok_tree, 0, sizeof(tok_tree));
804
805   for (i = 0; msgtab[i].cmd != NULL ; i++)
806   {
807     add_msg_element(&msg_tree, &msgtab[i], msgtab[i].cmd);
808     add_msg_element(&tok_tree, &msgtab[i], msgtab[i].tok);
809   }
810 }
811
812 /** Look up a command in the message trie.
813  * @param cmd Text of command to look up.
814  * @param root Root of message trie.
815  * @return Pointer to matching message, or NULL if non exists.
816  */
817 static struct Message *
818 msg_tree_parse(char *cmd, struct MessageTree *root)
819 {
820   struct MessageTree *mtree;
821
822   for (mtree = root; mtree; mtree = mtree->pointers[(*cmd++) & (MAXPTRLEN-1)]) {
823       if (*cmd == '\0' && mtree->msg)
824           return mtree->msg;
825       else if (!IsAlpha(*cmd))
826           return NULL;
827   }
828   return NULL;
829 }
830
831 /** Registers a service mapping to the pseudocommand handler.
832  * @param[in] map Service mapping to add.
833  * @return Non-zero on success; zero if a command already used the name.
834  */
835 int register_mapping(struct s_map *map)
836 {
837   struct Message *msg;
838
839   if (msg_tree_parse(map->command, &msg_tree))
840     return 0;
841
842   msg = (struct Message *)MyMalloc(sizeof(struct Message));
843   msg->cmd = map->command;
844   msg->tok = map->command;
845   msg->count = 0;
846   msg->parameters = 2;
847   msg->flags = MFLG_EXTRA;
848   if (!(map->flags & SMAP_FAST))
849     msg->flags |= MFLG_SLOW;
850   msg->bytes = 0;
851   msg->extra = map;
852
853   msg->handlers[UNREGISTERED_HANDLER] = m_ignore;
854   msg->handlers[CLIENT_HANDLER] = m_pseudo;
855   msg->handlers[SERVER_HANDLER] = m_ignore;
856   msg->handlers[OPER_HANDLER]   = m_pseudo;
857   msg->handlers[SERVICE_HANDLER] = m_ignore;
858
859   add_msg_element(&msg_tree, msg, msg->cmd);
860   map->msg = msg;
861
862   return 1;
863 }
864
865 /** Removes a service mapping.
866  * @param[in] map Service mapping to remove.
867  * @return Non-zero on success; zero if no command used the name.
868  */
869 int unregister_mapping(struct s_map *map)
870 {
871   if (!msg_tree_parse(map->command, &msg_tree))
872   {
873     /* This simply should never happen. */
874     assert(0);
875     return 0;
876   }
877
878   del_msg_element(&msg_tree, map->msg->cmd);
879
880   map->msg->extra = NULL;
881   MyFree(map->msg);
882   map->msg = NULL;
883
884   return 1;
885 }
886
887 /** Parse a line of data from a user.
888  * NOTE: parse_*() should not be called recursively by any other
889  * functions!
890  * @param[in] cptr Client that sent the data.
891  * @param[in] buffer Start of input line.
892  * @param[in] bufend End of input line.
893  * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
894  * handler returns it.
895  */
896 int
897 parse_client(struct Client *cptr, char *buffer, char *bufend)
898 {
899   struct Client*  from = cptr;
900   char*           ch;
901   char*           s;
902   int             i;
903   int             paramcount;
904   int             noprefix = 0;
905   struct Message* mptr;
906   MessageHandler  handler = 0;
907
908   Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));
909
910   if (IsDead(cptr))
911     return 0;
912
913   para[0] = cli_name(from);
914   for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
915   if (*ch == ':')               /* Is any client doing this ? */
916   {
917     for (++ch; *ch && *ch != ' '; ++ch)
918       ; /* Ignore sender prefix from client */
919     while (*ch == ' ')
920       ch++;                     /* Advance to command */
921   }
922   else
923     noprefix = 1;
924   if (*ch == '\0')
925   {
926     ServerStats->is_empt++;
927     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
928         cli_name(cptr), cli_name(from)));
929     return (-1);
930   }
931
932   if ((s = strchr(ch, ' ')))
933     *s++ = '\0';
934
935   if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL)
936   {
937     /*
938      * Note: Give error message *only* to recognized
939      * persons. It's a nightmare situation to have
940      * two programs sending "Unknown command"'s or
941      * equivalent to each other at full blast....
942      * If it has got to person state, it at least
943      * seems to be well behaving. Perhaps this message
944      * should never be generated, though...  --msa
945      * Hm, when is the buffer empty -- if a command
946      * code has been found ?? -Armin
947      */
948     if (buffer[0] != '\0')
949     {
950       if (IsUser(from)) {
951            struct Client *acptr;
952            if(feature_bool(FEAT_UNKNOWN_CMD_ENABLE) && feature_str(FEAT_UNKNOWN_CMD_TARGET) && (acptr = FindUser(feature_str(FEAT_UNKNOWN_CMD_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
953             sendcmdto_one(&me, CMD_RELAY, acptr, "%C UC %C %s :%s", acptr, from, ch, s);
954            } else {
955             send_reply(from, ERR_UNKNOWNCOMMAND, ch);
956            }
957           }
958       Debug((DEBUG_ERROR, "Unknown (%s) from %s",
959             ch, get_client_name(cptr, HIDE_IP)));
960     }
961     ServerStats->is_unco++;
962     return (-1);
963   }
964
965   paramcount = mptr->parameters;
966   i = bufend - ((s) ? s : ch);
967   mptr->bytes += i;
968   if ((mptr->flags & MFLG_SLOW) || (!IsAnOper(cptr) && !HasPriv(cptr, PRIV_FLOOD))) {
969     if(HasPriv(cptr, PRIV_HALFFLOOD))
970       cli_since(cptr) += 1;
971     else
972       cli_since(cptr) += (2 + i / 120);
973   }
974
975   /*
976    * Allow only 1 msg per 2 seconds
977    * (on average) to prevent dumping.
978    * to keep the response rate up,
979    * bursts of up to 5 msgs are allowed
980    * -SRB
981    */
982
983   /*
984    * Must the following loop really be so devious? On
985    * surface it splits the message to parameters from
986    * blank spaces. But, if paramcount has been reached,
987    * the rest of the message goes into this last parameter
988    * (about same effect as ":" has...) --msa
989    */
990
991   /* Note initially true: s==NULL || *(s-1) == '\0' !! */
992
993   if (mptr->flags & MFLG_EXTRA) {
994     /* This is a horrid kludge to avoid changing the command handler
995      * argument list. */
996     para[1] = (char*)mptr->extra;
997     i = 1;
998   } else {
999     i = 0;
1000   }
1001   if (s)
1002   {
1003     if (paramcount > MAXPARA)
1004       paramcount = MAXPARA;
1005     for (;;)
1006     {
1007       /*
1008        * Never "FRANCE " again!! ;-) Clean
1009        * out *all* blanks.. --msa
1010        */
1011       while (*s == ' ')
1012         *s++ = '\0';
1013
1014       if (*s == '\0')
1015         break;
1016       if (*s == ':')
1017       {
1018         /*
1019          * The rest is single parameter--can
1020          * include blanks also.
1021          */
1022         para[++i] = s + 1;
1023         break;
1024       }
1025       para[++i] = s;
1026       if (i >= paramcount)
1027         break;
1028       for (; *s != ' ' && *s; s++);
1029     }
1030   }
1031   para[++i] = NULL;
1032   ++mptr->count;
1033
1034   handler = mptr->handlers[cli_handler(cptr)];
1035   assert(0 != handler);
1036
1037   if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) &&
1038       handler != m_ping && handler != m_ignore)
1039     cli_user(from)->last = CurrentTime;
1040
1041   return (*handler) (cptr, from, i, para);
1042 }
1043
1044 int
1045 parse_simul_client(struct Client *cptr, char *buffer)
1046 {
1047   struct Client*  from = cptr;
1048   char*           ch;
1049   char*           s;
1050   int             i;
1051   int             paramcount;
1052   int             noprefix = 0;
1053   struct Message* mptr;
1054   MessageHandler  handler = 0;
1055
1056   Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));
1057
1058   if (IsDead(cptr))
1059     return 0;
1060
1061   para[0] = cli_name(from);
1062   for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
1063   if (*ch == ':')               /* Is any client doing this ? */
1064   {
1065     for (++ch; *ch && *ch != ' '; ++ch)
1066       ; /* Ignore sender prefix from client */
1067     while (*ch == ' ')
1068       ch++;                     /* Advance to command */
1069   }
1070   else
1071     noprefix = 1;
1072   if (*ch == '\0')
1073   {
1074     ServerStats->is_empt++;
1075     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
1076         cli_name(cptr), cli_name(from)));
1077     return (-1);
1078   }
1079
1080   if ((s = strchr(ch, ' ')))
1081     *s++ = '\0';
1082
1083   if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL)
1084   {
1085     /*
1086      * Note: Give error message *only* to recognized
1087      * persons. It's a nightmare situation to have
1088      * two programs sending "Unknown command"'s or
1089      * equivalent to each other at full blast....
1090      * If it has got to person state, it at least
1091      * seems to be well behaving. Perhaps this message
1092      * should never be generated, though...  --msa
1093      * Hm, when is the buffer empty -- if a command
1094      * code has been found ?? -Armin
1095      */
1096     if (buffer[0] != '\0')
1097     {
1098       Debug((DEBUG_ERROR, "Unknown (%s) from %s",
1099             ch, get_client_name(cptr, HIDE_IP)));
1100     }
1101     ServerStats->is_unco++;
1102     return (-1);
1103   }
1104
1105   paramcount = mptr->parameters;
1106
1107   /*
1108    * Allow only 1 msg per 2 seconds
1109    * (on average) to prevent dumping.
1110    * to keep the response rate up,
1111    * bursts of up to 5 msgs are allowed
1112    * -SRB
1113    */
1114
1115   /*
1116    * Must the following loop really be so devious? On
1117    * surface it splits the message to parameters from
1118    * blank spaces. But, if paramcount has been reached,
1119    * the rest of the message goes into this last parameter
1120    * (about same effect as ":" has...) --msa
1121    */
1122
1123   /* Note initially true: s==NULL || *(s-1) == '\0' !! */
1124
1125   if (mptr->flags & MFLG_EXTRA) {
1126     /* This is a horrid kludge to avoid changing the command handler
1127      * argument list. */
1128     para[1] = (char*)mptr->extra;
1129     i = 1;
1130   } else {
1131     i = 0;
1132   }
1133   if (s)
1134   {
1135     if (paramcount > MAXPARA)
1136       paramcount = MAXPARA;
1137     for (;;)
1138     {
1139       /*
1140        * Never "FRANCE " again!! ;-) Clean
1141        * out *all* blanks.. --msa
1142        */
1143       while (*s == ' ')
1144         *s++ = '\0';
1145
1146       if (*s == '\0')
1147         break;
1148       if (*s == ':')
1149       {
1150         /*
1151          * The rest is single parameter--can
1152          * include blanks also.
1153          */
1154         para[++i] = s + 1;
1155         break;
1156       }
1157       para[++i] = s;
1158       if (i >= paramcount)
1159         break;
1160       for (; *s != ' ' && *s; s++);
1161     }
1162   }
1163   para[++i] = NULL;
1164   ++mptr->count;
1165
1166   handler = mptr->handlers[cli_handler(cptr)];
1167   assert(0 != handler);
1168
1169   if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) &&
1170       handler != m_ping && handler != m_ignore)
1171     cli_user(from)->last = CurrentTime;
1172
1173   return (*handler) (cptr, from, i, para);
1174 }
1175
1176
1177
1178 /** Parse a line of data from a server.
1179  * @param[in] cptr Client that sent the data.
1180  * @param[in] buffer Start of input line.
1181  * @param[in] bufend End of input line.
1182  * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
1183  * handler returns it.
1184  */
1185 int parse_server(struct Client *cptr, char *buffer, char *bufend)
1186 {
1187   struct Client*  from = cptr;
1188   char*           ch = buffer;
1189   char*           s;
1190   int             len;
1191   int             i;
1192   int             numeric = 0;
1193   int             paramcount;
1194   struct Message* mptr;
1195
1196   Debug((DEBUG_DEBUG, "Server Parsing: %s", buffer));
1197
1198   if (IsDead(cptr))
1199     return 0;
1200
1201   para[0] = cli_name(from);
1202
1203   /*
1204    * A server ALWAYS sends a prefix. When it starts with a ':' it's the
1205    * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric
1206    * nick or server
1207    */
1208   if (*ch == ':')
1209   {
1210     /* Let para[0] point to the name of the sender */
1211     para[0] = ch + 1;
1212     if (!(ch = strchr(ch, ' ')))
1213       return -1;
1214     *ch++ = '\0';
1215
1216     /* And let `from' point to its client structure,
1217        opps.. a server is _also_ a client --Nem */
1218     from = FindClient(para[0]);
1219
1220     /*
1221      * If the client corresponding to the
1222      * prefix is not found. We must ignore it,
1223      * it is simply a lagged message traveling
1224      * upstream a SQUIT that removed the client
1225      * --Run
1226      */
1227     if (from == NULL)
1228     {
1229       Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
1230           para[0], buffer, cli_name(cptr)));
1231       ++ServerStats->is_unpf;
1232       while (*ch == ' ')
1233         ch++;
1234       /*
1235        * However, the only thing that MUST be
1236        * allowed to travel upstream against an
1237        * squit, is an SQUIT itself (the timestamp
1238        * protects us from being used wrong)
1239        */
1240       if (ch[1] == 'Q')
1241       {
1242         para[0] = cli_name(cptr);
1243         from = cptr;
1244       }
1245       else
1246         return 0;
1247     }
1248     else if (cli_from(from) != cptr)
1249     {
1250       ++ServerStats->is_wrdi;
1251       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
1252           buffer, cli_name(cptr)));
1253       return 0;
1254     }
1255   }
1256   else
1257   {
1258     char numeric_prefix[6];
1259     int  i;
1260     for (i = 0; i < 5; ++i)
1261     {
1262       if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
1263       {
1264         break;
1265       }
1266     }
1267     numeric_prefix[i] = '\0';
1268
1269     /*
1270      * We got a numeric nick as prefix
1271      * 1 or 2 character prefixes are from servers
1272      * 3 or 5 chars are from clients
1273      */
1274     if (0 == i)
1275     {
1276       protocol_violation(cptr,"Missing Prefix");
1277       from = cptr;
1278     }
1279     else if (' ' == ch[1] || ' ' == ch[2])
1280       from = FindNServer(numeric_prefix);
1281     else
1282       from = findNUser(numeric_prefix);
1283
1284     do
1285     {
1286       ++ch;
1287     }
1288     while (*ch != ' ' && *ch);
1289
1290     /*
1291      * If the client corresponding to the
1292      * prefix is not found. We must ignore it,
1293      * it is simply a lagged message traveling
1294      * upstream a SQUIT that removed the client
1295      * --Run
1296      * There turned out to be other reasons that
1297      * a prefix is unknown, needing an upstream
1298      * KILL.  Also, next to an SQUIT we better
1299      * allow a KILL to pass too.
1300      * --Run
1301      */
1302     if (from == NULL)
1303     {
1304       ServerStats->is_unpf++;
1305       while (*ch == ' ')
1306         ch++;
1307       if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
1308         /* Only sent a KILL for a nick change */
1309       {
1310         struct Client *server;
1311         /* Kill the unknown numeric prefix upstream if
1312          * it's server still exists: */
1313         if ((server = FindNServer(numeric_prefix)) && cli_from(server) == cptr)
1314           sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (Unknown numeric nick)",
1315                         numeric_prefix, cli_name(&me));
1316       }
1317       /*
1318        * Things that must be allowed to travel
1319        * upstream against an squit:
1320        */
1321       if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
1322           (*ch == 'K' && ch[2] == 'L'))
1323         from = cptr;
1324       else
1325         return 0;
1326     }
1327
1328     /* Let para[0] point to the name of the sender */
1329     para[0] = cli_name(from);
1330
1331     if (cli_from(from) != cptr)
1332     {
1333       ServerStats->is_wrdi++;
1334       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
1335           buffer, cli_name(cptr)));
1336       return 0;
1337     }
1338   }
1339
1340   while (*ch == ' ')
1341     ch++;
1342   if (*ch == '\0')
1343   {
1344     ServerStats->is_empt++;
1345     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
1346         cli_name(cptr), cli_name(from)));
1347     return (-1);
1348   }
1349
1350   /*
1351    * Extract the command code from the packet.   Point s to the end
1352    * of the command code and calculate the length using pointer
1353    * arithmetic.  Note: only need length for numerics and *all*
1354    * numerics must have parameters and thus a space after the command
1355    * code. -avalon
1356    */
1357   s = strchr(ch, ' ');          /* s -> End of the command code */
1358   len = (s) ? (s - ch) : 0;
1359   if (len == 3 && IsDigit(*ch))
1360   {
1361     numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
1362     paramcount = 2; /* destination, and the rest of it */
1363     ServerStats->is_num++;
1364     mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
1365   }
1366   else
1367   {
1368     if (s)
1369       *s++ = '\0';
1370
1371     /* Version      Receive         Send
1372      * 2.9          Long            Long
1373      * 2.10.0       Tkn/Long        Long
1374      * 2.10.10      Tkn/Long        Tkn
1375      * 2.10.20      Tkn             Tkn
1376      *
1377      * Clients/unreg servers always receive/
1378      * send long commands   -record
1379      *
1380      * And for the record, this trie parser really does not care. - Dianora
1381      */
1382
1383     mptr = msg_tree_parse(ch, &tok_tree);
1384
1385     if (mptr == NULL)
1386     {
1387       mptr = msg_tree_parse(ch, &msg_tree);
1388     }
1389
1390     if (mptr == NULL)
1391     {
1392       /*
1393        * Note: Give error message *only* to recognized
1394        * persons. It's a nightmare situation to have
1395        * two programs sending "Unknown command"'s or
1396        * equivalent to each other at full blast....
1397        * If it has got to person state, it at least
1398        * seems to be well behaving. Perhaps this message
1399        * should never be generated, though...   --msa
1400        * Hm, when is the buffer empty -- if a command
1401        * code has been found ?? -Armin
1402        */
1403 #ifdef DEBUGMODE
1404       if (buffer[0] != '\0')
1405       {
1406         Debug((DEBUG_ERROR, "Unknown (%s) from %s",
1407               ch, get_client_name(cptr, HIDE_IP)));
1408       }
1409 #endif
1410       ServerStats->is_unco++;
1411       return (-1);
1412     }
1413
1414     paramcount = mptr->parameters;
1415     i = bufend - ((s) ? s : ch);
1416     mptr->bytes += i;
1417   }
1418   /*
1419    * Must the following loop really be so devious? On
1420    * surface it splits the message to parameters from
1421    * blank spaces. But, if paramcount has been reached,
1422    * the rest of the message goes into this last parameter
1423    * (about same effect as ":" has...) --msa
1424    */
1425
1426   /* Note initially true: s==NULL || *(s-1) == '\0' !! */
1427
1428   i = 0;
1429   if (s)
1430   {
1431     if (paramcount > MAXPARA)
1432       paramcount = MAXPARA;
1433     for (;;)
1434     {
1435       /*
1436        * Never "FRANCE " again!! ;-) Clean
1437        * out *all* blanks.. --msa
1438        */
1439       while (*s == ' ')
1440         *s++ = '\0';
1441
1442       if (*s == '\0')
1443         break;
1444       if (*s == ':')
1445       {
1446         /*
1447          * The rest is single parameter--can
1448          * include blanks also.
1449          */
1450         if (numeric)
1451           para[++i] = s; /* preserve the colon to make do_numeric happy */
1452         else
1453           para[++i] = s + 1;
1454         break;
1455       }
1456       para[++i] = s;
1457       if (i >= paramcount)
1458         break;
1459       for (; *s != ' ' && *s; s++);
1460     }
1461   }
1462   para[++i] = NULL;
1463   if (numeric)
1464     return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
1465   mptr->count++;
1466
1467   return (*mptr->handlers[cli_handler(cptr)]) (cptr, from, i, para);
1468 }