]>
Commit | Line | Data |
---|---|---|
189935b1 | 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,v 1.54 2005/09/27 03:54:46 entrope Exp $ | |
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_KICK, | |
223 | TOK_KICK, | |
224 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
225 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
226 | { m_unregistered, m_kick, ms_kick, m_kick, m_ignore } | |
227 | }, | |
228 | { | |
229 | MSG_WALLOPS, | |
230 | TOK_WALLOPS, | |
231 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
232 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
233 | { m_unregistered, m_not_oper, ms_wallops, mo_wallops, m_ignore } | |
234 | }, | |
235 | { | |
236 | MSG_WALLUSERS, | |
237 | TOK_WALLUSERS, | |
238 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
239 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
240 | { m_unregistered, m_not_oper, ms_wallusers, mo_wallusers, m_ignore } | |
241 | }, | |
242 | { | |
243 | MSG_DESYNCH, | |
244 | TOK_DESYNCH, | |
245 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
246 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
247 | { m_ignore, m_ignore, ms_desynch, m_ignore, m_ignore } | |
248 | }, | |
249 | { | |
250 | MSG_PING, | |
251 | TOK_PING, | |
252 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
253 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
254 | { m_unregistered, m_ping, ms_ping, mo_ping, m_ignore } | |
255 | }, | |
256 | { | |
257 | MSG_PONG, | |
258 | TOK_PONG, | |
259 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
260 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
261 | { mr_pong, m_pong, ms_pong, m_pong, m_ignore } | |
262 | }, | |
263 | { | |
264 | MSG_ERROR, | |
265 | TOK_ERROR, | |
266 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
267 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
268 | { mr_error, m_ignore, ms_error, m_ignore, m_ignore } | |
269 | }, | |
270 | { | |
271 | MSG_KILL, | |
272 | TOK_KILL, | |
273 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
274 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
275 | { m_unregistered, m_not_oper, ms_kill, mo_kill, m_ignore } | |
276 | }, | |
277 | { | |
278 | MSG_USER, | |
279 | TOK_USER, | |
280 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
281 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
282 | { m_user, m_registered, m_ignore, m_registered, m_ignore } | |
283 | }, | |
284 | { | |
285 | MSG_AWAY, | |
286 | TOK_AWAY, | |
287 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
288 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
289 | { m_unregistered, m_away, ms_away, m_away, m_ignore } | |
290 | }, | |
291 | { | |
292 | MSG_ISON, | |
293 | TOK_ISON, | |
294 | 0, 1, MFLG_SLOW, 0, NULL, | |
295 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
296 | { m_unregistered, m_ison, m_ignore, m_ison, m_ignore } | |
297 | }, | |
298 | { | |
299 | MSG_SERVER, | |
300 | TOK_SERVER, | |
301 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
302 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
303 | { mr_server, m_registered, ms_server, m_registered, m_ignore } | |
304 | }, | |
305 | { | |
306 | MSG_SQUIT, | |
307 | TOK_SQUIT, | |
308 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
309 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
310 | { m_unregistered, m_not_oper, ms_squit, mo_squit, m_ignore } | |
311 | }, | |
312 | { | |
313 | MSG_WHOIS, | |
314 | TOK_WHOIS, | |
315 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
316 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
317 | { m_unregistered, m_whois, ms_whois, m_whois, m_ignore } | |
318 | }, | |
319 | { | |
320 | MSG_WHO, | |
321 | TOK_WHO, | |
322 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
323 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
324 | { m_unregistered, m_who, m_ignore, m_who, m_ignore } | |
325 | }, | |
326 | { | |
327 | MSG_WHOWAS, | |
328 | TOK_WHOWAS, | |
329 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
330 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
331 | { m_unregistered, m_whowas, m_whowas, m_whowas, m_ignore } | |
332 | }, | |
333 | { | |
334 | MSG_LIST, | |
335 | TOK_LIST, | |
336 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
337 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
338 | { m_unregistered, m_list, m_ignore, m_list, m_ignore } | |
339 | }, | |
340 | { | |
341 | MSG_NAMES, | |
342 | TOK_NAMES, | |
343 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
344 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
345 | { m_unregistered, m_names, ms_names, m_names, m_ignore } | |
346 | }, | |
347 | { | |
348 | MSG_USERHOST, | |
349 | TOK_USERHOST, | |
350 | 0, 1, MFLG_SLOW, 0, NULL, | |
351 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
352 | { m_unregistered, m_userhost, m_ignore, m_userhost, m_ignore } | |
353 | }, | |
354 | { | |
355 | MSG_USERIP, | |
356 | TOK_USERIP, | |
357 | 0, 1, MFLG_SLOW, 0, NULL, | |
358 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
359 | { m_unregistered, m_userip, m_ignore, m_userip, m_ignore } | |
360 | }, | |
361 | { | |
362 | MSG_TRACE, | |
363 | TOK_TRACE, | |
364 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
365 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
366 | { m_unregistered, m_trace, ms_trace, mo_trace, m_ignore } | |
367 | }, | |
368 | { | |
369 | MSG_PASS, | |
370 | TOK_PASS, | |
371 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
372 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
373 | { mr_pass, m_registered, m_ignore, m_registered, m_ignore } | |
374 | }, | |
375 | { | |
376 | MSG_LUSERS, | |
377 | TOK_LUSERS, | |
378 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
379 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
380 | { m_unregistered, m_lusers, ms_lusers, m_lusers, m_ignore } | |
381 | }, | |
382 | { | |
383 | MSG_TIME, | |
384 | TOK_TIME, | |
385 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
386 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
387 | { m_unregistered, m_time, m_time, m_time, m_ignore } | |
388 | }, | |
389 | { | |
390 | MSG_SETTIME, | |
391 | TOK_SETTIME, | |
392 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
393 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
394 | { m_unregistered, m_ignore, ms_settime, mo_settime, m_ignore } | |
395 | }, | |
396 | { | |
397 | MSG_RPING, | |
398 | TOK_RPING, | |
399 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
400 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
401 | { m_unregistered, m_not_oper, ms_rping, mo_rping, m_ignore } | |
402 | }, | |
403 | { | |
404 | MSG_RPONG, | |
405 | TOK_RPONG, | |
406 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
407 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
408 | { m_unregistered, m_ignore, ms_rpong, m_ignore, m_ignore } | |
409 | }, | |
410 | { | |
411 | MSG_OPER, | |
412 | TOK_OPER, | |
413 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
414 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
415 | { m_unregistered, m_oper, ms_oper, mo_oper, m_ignore } | |
416 | }, | |
417 | { | |
418 | MSG_CONNECT, | |
419 | TOK_CONNECT, | |
420 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
421 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
422 | { m_unregistered, m_not_oper, ms_connect, mo_connect, m_ignore } | |
423 | }, | |
424 | { | |
425 | MSG_MAP, | |
426 | TOK_MAP, | |
427 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
428 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
429 | { m_unregistered, m_map, m_ignore, m_map, m_ignore } | |
430 | }, | |
431 | { | |
432 | MSG_VERSION, | |
433 | TOK_VERSION, | |
434 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
435 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
436 | { m_version, m_version, ms_version, mo_version, m_ignore } | |
437 | }, | |
438 | { | |
439 | MSG_STATS, | |
440 | TOK_STATS, | |
441 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
442 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
443 | { m_unregistered, m_stats, m_stats, m_stats, m_ignore } | |
444 | }, | |
445 | { | |
446 | MSG_LINKS, | |
447 | TOK_LINKS, | |
448 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
449 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
450 | { m_unregistered, m_links, ms_links, m_links, m_ignore } | |
451 | }, | |
452 | { | |
453 | MSG_ADMIN, | |
454 | TOK_ADMIN, | |
455 | 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL, | |
456 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
457 | { m_admin, m_admin, ms_admin, mo_admin, m_ignore } | |
458 | }, | |
459 | { | |
460 | MSG_HELP, | |
461 | TOK_HELP, | |
462 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
463 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
464 | { m_unregistered, m_help, m_ignore, m_help, m_ignore } | |
465 | }, | |
466 | { | |
467 | MSG_INFO, | |
468 | TOK_INFO, | |
469 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
470 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
471 | { m_unregistered, m_info, ms_info, mo_info, m_ignore } | |
472 | }, | |
473 | { | |
474 | MSG_MOTD, | |
475 | TOK_MOTD, | |
476 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
477 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
478 | { m_unregistered, m_motd, m_motd, m_motd, m_ignore } | |
479 | }, | |
480 | { | |
481 | MSG_CLOSE, | |
482 | TOK_CLOSE, | |
483 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
484 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
485 | { m_unregistered, m_not_oper, m_ignore, mo_close, m_ignore } | |
486 | }, | |
487 | { | |
488 | MSG_SILENCE, | |
489 | TOK_SILENCE, | |
490 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
491 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
492 | { m_unregistered, m_silence, ms_silence, m_silence, m_ignore } | |
493 | }, | |
494 | { | |
495 | MSG_GLINE, | |
496 | TOK_GLINE, | |
497 | 0, MAXPARA, 0, 0, NULL, | |
498 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
499 | { m_unregistered, m_gline, ms_gline, mo_gline, m_ignore } | |
500 | }, | |
501 | { | |
502 | MSG_JUPE, | |
503 | TOK_JUPE, | |
504 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
505 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
506 | { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore } | |
507 | }, | |
508 | { | |
509 | MSG_OPMODE, | |
510 | TOK_OPMODE, | |
511 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
512 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
513 | { m_unregistered, m_not_oper, ms_opmode, mo_opmode, m_ignore } | |
514 | }, | |
515 | { | |
516 | MSG_CLEARMODE, | |
517 | TOK_CLEARMODE, | |
518 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
519 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
520 | { m_unregistered, m_not_oper, ms_clearmode, mo_clearmode, m_ignore } | |
521 | }, | |
522 | { | |
523 | MSG_UPING, | |
524 | TOK_UPING, | |
525 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
526 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
527 | { m_unregistered, m_not_oper, ms_uping, mo_uping, m_ignore } | |
528 | }, | |
529 | { | |
530 | MSG_END_OF_BURST, | |
531 | TOK_END_OF_BURST, | |
532 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
533 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
534 | { m_ignore, m_ignore, ms_end_of_burst, m_ignore, m_ignore } | |
535 | }, | |
536 | { | |
537 | MSG_END_OF_BURST_ACK, | |
538 | TOK_END_OF_BURST_ACK, | |
539 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
540 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
541 | { m_ignore, m_ignore, ms_end_of_burst_ack, m_ignore, m_ignore } | |
542 | }, | |
543 | { | |
544 | MSG_HASH, | |
545 | TOK_HASH, | |
546 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
547 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
548 | { m_unregistered, m_hash, m_hash, m_hash, m_ignore } | |
549 | }, | |
550 | { | |
551 | MSG_REHASH, | |
552 | TOK_REHASH, | |
553 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
554 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
555 | { m_unregistered, m_not_oper, m_ignore, mo_rehash, m_ignore } | |
556 | }, | |
557 | { | |
558 | MSG_RESTART, | |
559 | TOK_RESTART, | |
560 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
561 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
562 | { m_unregistered, m_not_oper, m_ignore, mo_restart, m_ignore } | |
563 | }, | |
564 | { | |
565 | MSG_DIE, | |
566 | TOK_DIE, | |
567 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
568 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
569 | { m_unregistered, m_not_oper, m_ignore, mo_die, m_ignore } | |
570 | }, | |
571 | { | |
572 | MSG_PROTO, | |
573 | TOK_PROTO, | |
574 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
575 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
576 | { m_proto, m_proto, m_proto, m_proto, m_ignore } | |
577 | }, | |
578 | { | |
579 | MSG_SET, | |
580 | TOK_SET, | |
581 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
582 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
583 | { m_unregistered, m_not_oper, m_ignore, mo_set, m_ignore } | |
584 | }, | |
585 | { | |
586 | MSG_RESET, | |
587 | TOK_RESET, | |
588 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
589 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
590 | { m_unregistered, m_not_oper, m_ignore, mo_reset, m_ignore } | |
591 | }, | |
592 | { | |
593 | MSG_GET, | |
594 | TOK_GET, | |
595 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
596 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
597 | { m_unregistered, m_not_oper, m_ignore, mo_get, m_ignore } | |
598 | }, | |
599 | { | |
600 | MSG_PRIVS, | |
601 | TOK_PRIVS, | |
602 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
603 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
604 | { m_unregistered, m_not_oper, ms_privs, mo_privs, m_ignore } | |
605 | }, | |
606 | { | |
607 | MSG_ACCOUNT, | |
608 | TOK_ACCOUNT, | |
609 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
610 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
611 | { m_ignore, m_ignore, ms_account, m_ignore, m_ignore } | |
612 | }, | |
613 | { | |
614 | MSG_ASLL, | |
615 | TOK_ASLL, | |
616 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
617 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
618 | { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore } | |
619 | }, | |
d8e74551 | 620 | { |
621 | MSG_SETHOST, | |
622 | TOK_SETHOST, | |
623 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
624 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
625 | { m_unregistered, m_sethost, m_ignore, m_sethost, m_ignore } | |
626 | }, | |
189935b1 | 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 | |
d8e74551 | 636 | |
637 | /* | |
638 | * - ASUKA --------------------------------------------------------------------- | |
639 | * Add the command for CHECK. | |
640 | * This was adapted from Lain for use in Asuka. | |
641 | * Original code by Durzel (durzel@quakenet.org). | |
642 | * | |
643 | * qoreQ (qoreQ@quakenet.org) - 08/14/2002 | |
644 | * ----------------------------------------------------------------------------- | |
645 | */ | |
646 | { | |
647 | MSG_CHECK, | |
648 | TOK_CHECK, | |
649 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
650 | { m_unregistered, m_not_oper, m_check, m_check, m_ignore } | |
651 | }, | |
652 | ||
189935b1 | 653 | /* This command is an alias for QUIT during the unregistered part of |
654 | * of the server. This is because someone jumping via a broken web | |
655 | * proxy will send a 'POST' as their first command - which we will | |
656 | * obviously disconnect them immediately for, stopping people abusing | |
657 | * open gateways | |
658 | */ | |
659 | { | |
660 | MSG_POST, | |
661 | TOK_POST, | |
662 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
663 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
664 | { m_quit, m_ignore, m_ignore, m_ignore, m_ignore } | |
665 | }, | |
666 | { 0 } | |
667 | }; | |
668 | ||
669 | /** Array of command parameters. */ | |
670 | static char *para[MAXPARA + 2]; /* leave room for prefix and null */ | |
671 | ||
672 | ||
673 | /** Add a message to the lookup trie. | |
674 | * @param[in,out] mtree_p Trie node to insert under. | |
675 | * @param[in] msg_p Message to insert. | |
676 | * @param[in] cmd Text of command to insert. | |
677 | */ | |
678 | void | |
679 | add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, char *cmd) | |
680 | { | |
681 | struct MessageTree *ntree_p; | |
682 | ||
683 | if (*cmd == '\0') | |
684 | { | |
685 | mtree_p->msg = msg_p; | |
686 | return; | |
687 | } | |
688 | ||
689 | if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN-1)]) != NULL) | |
690 | { | |
691 | add_msg_element(ntree_p, msg_p, cmd+1); | |
692 | } | |
693 | else | |
694 | { | |
695 | ntree_p = (struct MessageTree *)MyCalloc(sizeof(struct MessageTree), 1); | |
696 | mtree_p->pointers[*cmd & (MAXPTRLEN-1)] = ntree_p; | |
697 | add_msg_element(ntree_p, msg_p, cmd+1); | |
698 | } | |
699 | } | |
700 | ||
701 | /** Remove a message from the lookup trie. | |
702 | * @param[in,out] mtree_p Trie node to remove command from. | |
703 | * @param[in] cmd Text of command to remove. | |
704 | */ | |
705 | struct MessageTree * | |
706 | del_msg_element(struct MessageTree *mtree_p, char *cmd) | |
707 | { | |
708 | int slot = *cmd & (MAXPTRLEN-1); | |
709 | ||
710 | /* Either remove leaf message or from appropriate child. */ | |
711 | if (*cmd == '\0') | |
712 | mtree_p->msg = NULL; | |
713 | else | |
714 | mtree_p->pointers[slot] = del_msg_element(mtree_p->pointers[slot], cmd + 1); | |
715 | ||
716 | /* If current message or any child still exists, keep this node. */ | |
717 | if (mtree_p->msg) | |
718 | return mtree_p; | |
719 | for (slot = 0; slot < MAXPTRLEN; ++slot) | |
720 | if (mtree_p->pointers[slot]) | |
721 | return mtree_p; | |
722 | ||
723 | /* Otherwise, if we're not a root node, free it and return null. */ | |
724 | if (mtree_p != &msg_tree && mtree_p != &tok_tree) | |
725 | MyFree(mtree_p); | |
726 | return NULL; | |
727 | } | |
728 | ||
729 | /** Initialize the message lookup trie with all known commands. */ | |
730 | void | |
731 | initmsgtree(void) | |
732 | { | |
733 | int i; | |
734 | ||
735 | memset(&msg_tree, 0, sizeof(msg_tree)); | |
736 | memset(&tok_tree, 0, sizeof(tok_tree)); | |
737 | ||
738 | for (i = 0; msgtab[i].cmd != NULL ; i++) | |
739 | { | |
740 | add_msg_element(&msg_tree, &msgtab[i], msgtab[i].cmd); | |
741 | add_msg_element(&tok_tree, &msgtab[i], msgtab[i].tok); | |
742 | } | |
743 | } | |
744 | ||
745 | /** Look up a command in the message trie. | |
746 | * @param cmd Text of command to look up. | |
747 | * @param root Root of message trie. | |
748 | * @return Pointer to matching message, or NULL if non exists. | |
749 | */ | |
750 | static struct Message * | |
751 | msg_tree_parse(char *cmd, struct MessageTree *root) | |
752 | { | |
753 | struct MessageTree *mtree; | |
754 | ||
755 | for (mtree = root; mtree; mtree = mtree->pointers[(*cmd++) & (MAXPTRLEN-1)]) { | |
756 | if (*cmd == '\0' && mtree->msg) | |
757 | return mtree->msg; | |
758 | else if (!IsAlpha(*cmd)) | |
759 | return NULL; | |
760 | } | |
761 | return NULL; | |
762 | } | |
763 | ||
764 | /** Registers a service mapping to the pseudocommand handler. | |
765 | * @param[in] map Service mapping to add. | |
766 | * @return Non-zero on success; zero if a command already used the name. | |
767 | */ | |
768 | int register_mapping(struct s_map *map) | |
769 | { | |
770 | struct Message *msg; | |
771 | ||
772 | if (msg_tree_parse(map->command, &msg_tree)) | |
773 | return 0; | |
774 | ||
775 | msg = (struct Message *)MyMalloc(sizeof(struct Message)); | |
776 | msg->cmd = map->command; | |
777 | msg->tok = map->command; | |
778 | msg->count = 0; | |
779 | msg->parameters = 2; | |
780 | msg->flags = MFLG_EXTRA; | |
781 | if (!(map->flags & SMAP_FAST)) | |
782 | msg->flags |= MFLG_SLOW; | |
783 | msg->bytes = 0; | |
784 | msg->extra = map; | |
785 | ||
786 | msg->handlers[UNREGISTERED_HANDLER] = m_ignore; | |
787 | msg->handlers[CLIENT_HANDLER] = m_pseudo; | |
788 | msg->handlers[SERVER_HANDLER] = m_ignore; | |
789 | msg->handlers[OPER_HANDLER] = m_pseudo; | |
790 | msg->handlers[SERVICE_HANDLER] = m_ignore; | |
791 | ||
792 | add_msg_element(&msg_tree, msg, msg->cmd); | |
793 | map->msg = msg; | |
794 | ||
795 | return 1; | |
796 | } | |
797 | ||
798 | /** Removes a service mapping. | |
799 | * @param[in] map Service mapping to remove. | |
800 | * @return Non-zero on success; zero if no command used the name. | |
801 | */ | |
802 | int unregister_mapping(struct s_map *map) | |
803 | { | |
804 | if (!msg_tree_parse(map->command, &msg_tree)) | |
805 | { | |
806 | /* This simply should never happen. */ | |
807 | assert(0); | |
808 | return 0; | |
809 | } | |
810 | ||
811 | del_msg_element(&msg_tree, map->msg->cmd); | |
812 | ||
813 | map->msg->extra = NULL; | |
814 | MyFree(map->msg); | |
815 | map->msg = NULL; | |
816 | ||
817 | return 1; | |
818 | } | |
819 | ||
820 | /** Parse a line of data from a user. | |
821 | * NOTE: parse_*() should not be called recursively by any other | |
822 | * functions! | |
823 | * @param[in] cptr Client that sent the data. | |
824 | * @param[in] buffer Start of input line. | |
825 | * @param[in] bufend End of input line. | |
826 | * @return 0 on success, -1 on parse error, or CPTR_KILLED if message | |
827 | * handler returns it. | |
828 | */ | |
829 | int | |
830 | parse_client(struct Client *cptr, char *buffer, char *bufend) | |
831 | { | |
832 | struct Client* from = cptr; | |
833 | char* ch; | |
834 | char* s; | |
835 | int i; | |
836 | int paramcount; | |
837 | int noprefix = 0; | |
838 | struct Message* mptr; | |
839 | MessageHandler handler = 0; | |
840 | ||
841 | Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer)); | |
842 | ||
843 | if (IsDead(cptr)) | |
844 | return 0; | |
845 | ||
846 | para[0] = cli_name(from); | |
847 | for (ch = buffer; *ch == ' '; ch++); /* Eat leading spaces */ | |
848 | if (*ch == ':') /* Is any client doing this ? */ | |
849 | { | |
850 | for (++ch; *ch && *ch != ' '; ++ch) | |
851 | ; /* Ignore sender prefix from client */ | |
852 | while (*ch == ' ') | |
853 | ch++; /* Advance to command */ | |
854 | } | |
855 | else | |
856 | noprefix = 1; | |
857 | if (*ch == '\0') | |
858 | { | |
859 | ServerStats->is_empt++; | |
860 | Debug((DEBUG_NOTICE, "Empty message from host %s:%s", | |
861 | cli_name(cptr), cli_name(from))); | |
862 | return (-1); | |
863 | } | |
864 | ||
865 | if ((s = strchr(ch, ' '))) | |
866 | *s++ = '\0'; | |
867 | ||
868 | if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL) | |
869 | { | |
870 | /* | |
871 | * Note: Give error message *only* to recognized | |
872 | * persons. It's a nightmare situation to have | |
873 | * two programs sending "Unknown command"'s or | |
874 | * equivalent to each other at full blast.... | |
875 | * If it has got to person state, it at least | |
876 | * seems to be well behaving. Perhaps this message | |
877 | * should never be generated, though... --msa | |
878 | * Hm, when is the buffer empty -- if a command | |
879 | * code has been found ?? -Armin | |
880 | */ | |
881 | if (buffer[0] != '\0') | |
882 | { | |
883 | if (IsUser(from)) | |
884 | send_reply(from, ERR_UNKNOWNCOMMAND, ch); | |
885 | Debug((DEBUG_ERROR, "Unknown (%s) from %s", | |
886 | ch, get_client_name(cptr, HIDE_IP))); | |
887 | } | |
888 | ServerStats->is_unco++; | |
889 | return (-1); | |
890 | } | |
891 | ||
892 | paramcount = mptr->parameters; | |
893 | i = bufend - ((s) ? s : ch); | |
894 | mptr->bytes += i; | |
d8e74551 | 895 | if ((mptr->flags & MFLG_SLOW) || !IsAnOper(cptr)) { |
896 | if (IsAnOper(cptr)) { | |
897 | cli_since(cptr) += 1; | |
898 | } else { | |
899 | cli_since(cptr) += (2 + i / 120); | |
900 | } | |
901 | } | |
902 | ||
189935b1 | 903 | /* |
904 | * Allow only 1 msg per 2 seconds | |
905 | * (on average) to prevent dumping. | |
906 | * to keep the response rate up, | |
907 | * bursts of up to 5 msgs are allowed | |
908 | * -SRB | |
909 | */ | |
910 | ||
911 | /* | |
912 | * Must the following loop really be so devious? On | |
913 | * surface it splits the message to parameters from | |
914 | * blank spaces. But, if paramcount has been reached, | |
915 | * the rest of the message goes into this last parameter | |
916 | * (about same effect as ":" has...) --msa | |
917 | */ | |
918 | ||
919 | /* Note initially true: s==NULL || *(s-1) == '\0' !! */ | |
920 | ||
921 | if (mptr->flags & MFLG_EXTRA) { | |
922 | /* This is a horrid kludge to avoid changing the command handler | |
923 | * argument list. */ | |
924 | para[1] = (char*)mptr->extra; | |
925 | i = 1; | |
926 | } else { | |
927 | i = 0; | |
928 | } | |
929 | if (s) | |
930 | { | |
931 | if (paramcount > MAXPARA) | |
932 | paramcount = MAXPARA; | |
933 | for (;;) | |
934 | { | |
935 | /* | |
936 | * Never "FRANCE " again!! ;-) Clean | |
937 | * out *all* blanks.. --msa | |
938 | */ | |
939 | while (*s == ' ') | |
940 | *s++ = '\0'; | |
941 | ||
942 | if (*s == '\0') | |
943 | break; | |
944 | if (*s == ':') | |
945 | { | |
946 | /* | |
947 | * The rest is single parameter--can | |
948 | * include blanks also. | |
949 | */ | |
950 | para[++i] = s + 1; | |
951 | break; | |
952 | } | |
953 | para[++i] = s; | |
954 | if (i >= paramcount) | |
955 | break; | |
956 | for (; *s != ' ' && *s; s++); | |
957 | } | |
958 | } | |
959 | para[++i] = NULL; | |
960 | ++mptr->count; | |
961 | ||
962 | handler = mptr->handlers[cli_handler(cptr)]; | |
963 | assert(0 != handler); | |
964 | ||
965 | if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) && | |
966 | handler != m_ping && handler != m_ignore) | |
967 | cli_user(from)->last = CurrentTime; | |
968 | ||
969 | return (*handler) (cptr, from, i, para); | |
970 | } | |
971 | ||
972 | /** Parse a line of data from a server. | |
973 | * @param[in] cptr Client that sent the data. | |
974 | * @param[in] buffer Start of input line. | |
975 | * @param[in] bufend End of input line. | |
976 | * @return 0 on success, -1 on parse error, or CPTR_KILLED if message | |
977 | * handler returns it. | |
978 | */ | |
979 | int parse_server(struct Client *cptr, char *buffer, char *bufend) | |
980 | { | |
981 | struct Client* from = cptr; | |
982 | char* ch = buffer; | |
983 | char* s; | |
984 | int len; | |
985 | int i; | |
986 | int numeric = 0; | |
987 | int paramcount; | |
988 | struct Message* mptr; | |
989 | ||
990 | Debug((DEBUG_DEBUG, "Server Parsing: %s", buffer)); | |
991 | ||
992 | if (IsDead(cptr)) | |
993 | return 0; | |
994 | ||
995 | para[0] = cli_name(from); | |
996 | ||
997 | /* | |
998 | * A server ALWAYS sends a prefix. When it starts with a ':' it's the | |
999 | * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric | |
1000 | * nick or server | |
1001 | */ | |
1002 | if (*ch == ':') | |
1003 | { | |
1004 | /* Let para[0] point to the name of the sender */ | |
1005 | para[0] = ch + 1; | |
1006 | if (!(ch = strchr(ch, ' '))) | |
1007 | return -1; | |
1008 | *ch++ = '\0'; | |
1009 | ||
1010 | /* And let `from' point to its client structure, | |
1011 | opps.. a server is _also_ a client --Nem */ | |
1012 | from = FindClient(para[0]); | |
1013 | ||
1014 | /* | |
1015 | * If the client corresponding to the | |
1016 | * prefix is not found. We must ignore it, | |
1017 | * it is simply a lagged message traveling | |
1018 | * upstream a SQUIT that removed the client | |
1019 | * --Run | |
1020 | */ | |
1021 | if (from == NULL) | |
1022 | { | |
1023 | Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)", | |
1024 | para[0], buffer, cli_name(cptr))); | |
1025 | ++ServerStats->is_unpf; | |
1026 | while (*ch == ' ') | |
1027 | ch++; | |
1028 | /* | |
1029 | * However, the only thing that MUST be | |
1030 | * allowed to travel upstream against an | |
1031 | * squit, is an SQUIT itself (the timestamp | |
1032 | * protects us from being used wrong) | |
1033 | */ | |
1034 | if (ch[1] == 'Q') | |
1035 | { | |
1036 | para[0] = cli_name(cptr); | |
1037 | from = cptr; | |
1038 | } | |
1039 | else | |
1040 | return 0; | |
1041 | } | |
1042 | else if (cli_from(from) != cptr) | |
1043 | { | |
1044 | ++ServerStats->is_wrdi; | |
1045 | Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)", | |
1046 | buffer, cli_name(cptr))); | |
1047 | return 0; | |
1048 | } | |
1049 | } | |
1050 | else | |
1051 | { | |
1052 | char numeric_prefix[6]; | |
1053 | int i; | |
1054 | for (i = 0; i < 5; ++i) | |
1055 | { | |
1056 | if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i])) | |
1057 | { | |
1058 | break; | |
1059 | } | |
1060 | } | |
1061 | numeric_prefix[i] = '\0'; | |
1062 | ||
1063 | /* | |
1064 | * We got a numeric nick as prefix | |
1065 | * 1 or 2 character prefixes are from servers | |
1066 | * 3 or 5 chars are from clients | |
1067 | */ | |
1068 | if (0 == i) | |
1069 | { | |
1070 | protocol_violation(cptr,"Missing Prefix"); | |
1071 | from = cptr; | |
1072 | } | |
1073 | else if (' ' == ch[1] || ' ' == ch[2]) | |
1074 | from = FindNServer(numeric_prefix); | |
1075 | else | |
1076 | from = findNUser(numeric_prefix); | |
1077 | ||
1078 | do | |
1079 | { | |
1080 | ++ch; | |
1081 | } | |
1082 | while (*ch != ' ' && *ch); | |
1083 | ||
1084 | /* | |
1085 | * If the client corresponding to the | |
1086 | * prefix is not found. We must ignore it, | |
1087 | * it is simply a lagged message traveling | |
1088 | * upstream a SQUIT that removed the client | |
1089 | * --Run | |
1090 | * There turned out to be other reasons that | |
1091 | * a prefix is unknown, needing an upstream | |
1092 | * KILL. Also, next to an SQUIT we better | |
1093 | * allow a KILL to pass too. | |
1094 | * --Run | |
1095 | */ | |
1096 | if (from == NULL) | |
1097 | { | |
1098 | ServerStats->is_unpf++; | |
1099 | while (*ch == ' ') | |
1100 | ch++; | |
1101 | if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I')) | |
1102 | /* Only sent a KILL for a nick change */ | |
1103 | { | |
1104 | struct Client *server; | |
1105 | /* Kill the unknown numeric prefix upstream if | |
1106 | * it's server still exists: */ | |
1107 | if ((server = FindNServer(numeric_prefix)) && cli_from(server) == cptr) | |
1108 | sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (Unknown numeric nick)", | |
1109 | numeric_prefix, cli_name(&me)); | |
1110 | } | |
1111 | /* | |
1112 | * Things that must be allowed to travel | |
1113 | * upstream against an squit: | |
1114 | */ | |
1115 | if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') || | |
1116 | (*ch == 'K' && ch[2] == 'L')) | |
1117 | from = cptr; | |
1118 | else | |
1119 | return 0; | |
1120 | } | |
1121 | ||
1122 | /* Let para[0] point to the name of the sender */ | |
1123 | para[0] = cli_name(from); | |
1124 | ||
1125 | if (cli_from(from) != cptr) | |
1126 | { | |
1127 | ServerStats->is_wrdi++; | |
1128 | Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)", | |
1129 | buffer, cli_name(cptr))); | |
1130 | return 0; | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | while (*ch == ' ') | |
1135 | ch++; | |
1136 | if (*ch == '\0') | |
1137 | { | |
1138 | ServerStats->is_empt++; | |
1139 | Debug((DEBUG_NOTICE, "Empty message from host %s:%s", | |
1140 | cli_name(cptr), cli_name(from))); | |
1141 | return (-1); | |
1142 | } | |
1143 | ||
1144 | /* | |
1145 | * Extract the command code from the packet. Point s to the end | |
1146 | * of the command code and calculate the length using pointer | |
1147 | * arithmetic. Note: only need length for numerics and *all* | |
1148 | * numerics must have parameters and thus a space after the command | |
1149 | * code. -avalon | |
1150 | */ | |
1151 | s = strchr(ch, ' '); /* s -> End of the command code */ | |
1152 | len = (s) ? (s - ch) : 0; | |
1153 | if (len == 3 && IsDigit(*ch)) | |
1154 | { | |
1155 | numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0'); | |
1156 | paramcount = 2; /* destination, and the rest of it */ | |
1157 | ServerStats->is_num++; | |
1158 | mptr = NULL; /* Init. to avoid stupid compiler warning :/ */ | |
1159 | } | |
1160 | else | |
1161 | { | |
1162 | if (s) | |
1163 | *s++ = '\0'; | |
1164 | ||
1165 | /* Version Receive Send | |
1166 | * 2.9 Long Long | |
1167 | * 2.10.0 Tkn/Long Long | |
1168 | * 2.10.10 Tkn/Long Tkn | |
1169 | * 2.10.20 Tkn Tkn | |
1170 | * | |
1171 | * Clients/unreg servers always receive/ | |
1172 | * send long commands -record | |
1173 | * | |
1174 | * And for the record, this trie parser really does not care. - Dianora | |
1175 | */ | |
1176 | ||
1177 | mptr = msg_tree_parse(ch, &tok_tree); | |
1178 | ||
1179 | if (mptr == NULL) | |
1180 | { | |
1181 | mptr = msg_tree_parse(ch, &msg_tree); | |
1182 | } | |
1183 | ||
1184 | if (mptr == NULL) | |
1185 | { | |
1186 | /* | |
1187 | * Note: Give error message *only* to recognized | |
1188 | * persons. It's a nightmare situation to have | |
1189 | * two programs sending "Unknown command"'s or | |
1190 | * equivalent to each other at full blast.... | |
1191 | * If it has got to person state, it at least | |
1192 | * seems to be well behaving. Perhaps this message | |
1193 | * should never be generated, though... --msa | |
1194 | * Hm, when is the buffer empty -- if a command | |
1195 | * code has been found ?? -Armin | |
1196 | */ | |
1197 | #ifdef DEBUGMODE | |
1198 | if (buffer[0] != '\0') | |
1199 | { | |
1200 | Debug((DEBUG_ERROR, "Unknown (%s) from %s", | |
1201 | ch, get_client_name(cptr, HIDE_IP))); | |
1202 | } | |
1203 | #endif | |
1204 | ServerStats->is_unco++; | |
1205 | return (-1); | |
1206 | } | |
1207 | ||
1208 | paramcount = mptr->parameters; | |
1209 | i = bufend - ((s) ? s : ch); | |
1210 | mptr->bytes += i; | |
1211 | } | |
1212 | /* | |
1213 | * Must the following loop really be so devious? On | |
1214 | * surface it splits the message to parameters from | |
1215 | * blank spaces. But, if paramcount has been reached, | |
1216 | * the rest of the message goes into this last parameter | |
1217 | * (about same effect as ":" has...) --msa | |
1218 | */ | |
1219 | ||
1220 | /* Note initially true: s==NULL || *(s-1) == '\0' !! */ | |
1221 | ||
1222 | i = 0; | |
1223 | if (s) | |
1224 | { | |
1225 | if (paramcount > MAXPARA) | |
1226 | paramcount = MAXPARA; | |
1227 | for (;;) | |
1228 | { | |
1229 | /* | |
1230 | * Never "FRANCE " again!! ;-) Clean | |
1231 | * out *all* blanks.. --msa | |
1232 | */ | |
1233 | while (*s == ' ') | |
1234 | *s++ = '\0'; | |
1235 | ||
1236 | if (*s == '\0') | |
1237 | break; | |
1238 | if (*s == ':') | |
1239 | { | |
1240 | /* | |
1241 | * The rest is single parameter--can | |
1242 | * include blanks also. | |
1243 | */ | |
1244 | if (numeric) | |
1245 | para[++i] = s; /* preserve the colon to make do_numeric happy */ | |
1246 | else | |
1247 | para[++i] = s + 1; | |
1248 | break; | |
1249 | } | |
1250 | para[++i] = s; | |
1251 | if (i >= paramcount) | |
1252 | break; | |
1253 | for (; *s != ' ' && *s; s++); | |
1254 | } | |
1255 | } | |
1256 | para[++i] = NULL; | |
1257 | if (numeric) | |
1258 | return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para)); | |
1259 | mptr->count++; | |
1260 | ||
1261 | return (*mptr->handlers[cli_handler(cptr)]) (cptr, from, i, para); | |
1262 | } |