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