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