]> jfr.im git - solanum.git/blob - src/match.c
Also restrict cidrlen for testmask/masktrace (match_ips()).
[solanum.git] / src / match.c
1 /************************************************************************
2 * IRC - Internet Relay Chat, src/match.c
3 * Copyright (C) 1990 Jarkko Oikarinen
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * $Id: match.c 3532 2007-07-14 13:32:18Z jilles $
20 *
21 */
22 #include "stdinc.h"
23 #include "config.h"
24 #include "client.h"
25 #include "ircd.h"
26 #include "match.h"
27
28 /*
29 * Compare if a given string (name) matches the given
30 * mask (which can contain wild cards: '*' - match any
31 * number of chars, '?' - match any single character.
32 *
33 * return 1, if match
34 * 0, if no match
35 *
36 * Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
37 * Rewritten by Timothy Vogelsang (netski), net@astrolink.org
38 */
39
40 /** Check a string against a mask.
41 * This test checks using traditional IRC wildcards only: '*' means
42 * match zero or more characters of any type; '?' means match exactly
43 * one character of any type.
44 *
45 * @param[in] mask Wildcard-containing mask.
46 * @param[in] name String to check against \a mask.
47 * @return Zero if \a mask matches \a name, non-zero if no match.
48 */
49 int match(const char *mask, const char *name)
50 {
51 const char *m = mask, *n = name;
52 const char *m_tmp = mask, *n_tmp = name;
53 int star_p;
54
55 s_assert(mask != NULL);
56 s_assert(name != NULL);
57
58 for (;;)
59 {
60 switch (*m)
61 {
62 case '\0':
63 if (!*n)
64 return 1;
65 backtrack:
66 if (m_tmp == mask)
67 return 0;
68 m = m_tmp;
69 n = ++n_tmp;
70 break;
71 case '*':
72 case '?':
73 for (star_p = 0;; m++)
74 {
75 if (*m == '*')
76 star_p = 1;
77 else if (*m == '?')
78 {
79 if (!*n++)
80 goto backtrack;
81 }
82 else
83 break;
84 }
85 if (star_p)
86 {
87 if (!*m)
88 return 1;
89 else
90 {
91 m_tmp = m;
92 for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++);
93 }
94 }
95 /* and fall through */
96 default:
97 if (!*n)
98 return (*m != '\0' ? 0 : 1);
99 if (ToLower(*m) != ToLower(*n))
100 goto backtrack;
101 m++;
102 n++;
103 break;
104 }
105 }
106 }
107
108 /** Check a mask against a mask.
109 * This test checks using traditional IRC wildcards only: '*' means
110 * match zero or more characters of any type; '?' means match exactly
111 * one character of any type.
112 * The difference between mask_match() and match() is that in mask_match()
113 * a '?' in mask does not match a '*' in name.
114 *
115 * @param[in] mask Existing wildcard-containing mask.
116 * @param[in] name New wildcard-containing mask.
117 * @return 1 if \a name is equal to or more specific than \a mask, 0 otherwise.
118 */
119 int mask_match(const char *mask, const char *name)
120 {
121 const char *m = mask, *n = name;
122 const char *m_tmp = mask, *n_tmp = name;
123 int star_p;
124
125 s_assert(mask != NULL);
126 s_assert(name != NULL);
127
128 for (;;)
129 {
130 switch (*m)
131 {
132 case '\0':
133 if (!*n)
134 return 1;
135 backtrack:
136 if (m_tmp == mask)
137 return 0;
138 m = m_tmp;
139 n = ++n_tmp;
140 break;
141 case '*':
142 case '?':
143 for (star_p = 0;; m++)
144 {
145 if (*m == '*')
146 star_p = 1;
147 else if (*m == '?')
148 {
149 /* changed for mask_match() */
150 if (*n == '*' || !*n)
151 goto backtrack;
152 n++;
153 }
154 else
155 break;
156 }
157 if (star_p)
158 {
159 if (!*m)
160 return 1;
161 else
162 {
163 m_tmp = m;
164 for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++);
165 }
166 }
167 /* and fall through */
168 default:
169 if (!*n)
170 return (*m != '\0' ? 0 : 1);
171 if (ToLower(*m) != ToLower(*n))
172 goto backtrack;
173 m++;
174 n++;
175 break;
176 }
177 }
178 }
179
180
181 #define MATCH_MAX_CALLS 512 /* ACK! This dies when it's less that this
182 and we have long lines to parse */
183 /** Check a string against a mask.
184 * This test checks using extended wildcards: '*' means match zero
185 * or more characters of any type; '?' means match exactly one
186 * character of any type; '#' means match exactly one character that
187 * is a number; '@' means match exactly one character that is a
188 * letter; '\s' means match a space.
189 *
190 * This function supports escaping, so that a wildcard may be matched
191 * exactly.
192 *
193 * @param[in] mask Wildcard-containing mask.
194 * @param[in] name String to check against \a mask.
195 * @return Zero if \a mask matches \a name, non-zero if no match.
196 */
197 int
198 match_esc(const char *mask, const char *name)
199 {
200 const unsigned char *m = (const unsigned char *)mask;
201 const unsigned char *n = (const unsigned char *)name;
202 const unsigned char *ma = (const unsigned char *)mask;
203 const unsigned char *na = (const unsigned char *)name;
204 int wild = 0;
205 int calls = 0;
206 int quote = 0;
207 int match1 = 0;
208
209 s_assert(mask != NULL);
210 s_assert(name != NULL);
211
212 if(!mask || !name)
213 return 0;
214
215 /* if the mask is "*", it matches everything */
216 if((*m == '*') && (*(m + 1) == '\0'))
217 return 1;
218
219 while(calls++ < MATCH_MAX_CALLS)
220 {
221 if(quote)
222 quote++;
223 if(quote == 3)
224 quote = 0;
225 if(*m == '\\' && !quote)
226 {
227 m++;
228 quote = 1;
229 continue;
230 }
231 if(!quote && *m == '*')
232 {
233 /*
234 * XXX - shouldn't need to spin here, the mask should have been
235 * collapsed before match is called
236 */
237 while(*m == '*')
238 m++;
239
240 wild = 1;
241 ma = m;
242 na = n;
243
244 if(*m == '\\')
245 {
246 m++;
247 /* This means it is an invalid mask -A1kmm. */
248 if(!*m)
249 return 0;
250 quote++;
251 continue;
252 }
253 }
254
255 if(!*m)
256 {
257 if(!*n)
258 return 1;
259 if(quote)
260 return 0;
261 for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--);;
262
263 if(*m == '*' && (m > (const unsigned char *)mask))
264 return 1;
265 if(!wild)
266 return 0;
267 m = ma;
268 n = ++na;
269 }
270 else if(!*n)
271 {
272 /*
273 * XXX - shouldn't need to spin here, the mask should have been
274 * collapsed before match is called
275 */
276 if(quote)
277 return 0;
278 while(*m == '*')
279 m++;
280 return (*m == 0);
281 }
282
283 if(quote)
284 match1 = *m == 's' ? *n == ' ' : ToLower(*m) == ToLower(*n);
285 else if(*m == '?')
286 match1 = 1;
287 else if(*m == '@')
288 match1 = IsLetter(*n);
289 else if(*m == '#')
290 match1 = IsDigit(*n);
291 else
292 match1 = ToLower(*m) == ToLower(*n);
293 if(match1)
294 {
295 if(*m)
296 m++;
297 if(*n)
298 n++;
299 }
300 else
301 {
302 if(!wild)
303 return 0;
304 m = ma;
305 n = ++na;
306 }
307 }
308 return 0;
309 }
310
311 int comp_with_mask(void *addr, void *dest, u_int mask)
312 {
313 if (memcmp(addr, dest, mask / 8) == 0)
314 {
315 int n = mask / 8;
316 int m = ((-1) << (8 - (mask % 8)));
317 if (mask % 8 == 0 || (((u_char *) addr)[n] & m) == (((u_char *) dest)[n] & m))
318 {
319 return (1);
320 }
321 }
322 return (0);
323 }
324
325 int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask)
326 {
327 void *iaddr = NULL;
328 void *idest = NULL;
329
330 if (addr->sa_family == AF_INET)
331 {
332 iaddr = &((struct sockaddr_in *)addr)->sin_addr;
333 idest = &((struct sockaddr_in *)dest)->sin_addr;
334 }
335 #ifdef RB_IPV6
336 else
337 {
338 iaddr = &((struct sockaddr_in6 *)addr)->sin6_addr;
339 idest = &((struct sockaddr_in6 *)dest)->sin6_addr;
340
341 }
342 #endif
343
344 return (comp_with_mask(iaddr, idest, mask));
345 }
346
347 /*
348 * match_ips()
349 *
350 * Input - cidr ip mask, address
351 */
352 int match_ips(const char *s1, const char *s2)
353 {
354 struct rb_sockaddr_storage ipaddr, maskaddr;
355 char mask[BUFSIZE];
356 char address[HOSTLEN + 1];
357 char *len;
358 void *ipptr, *maskptr;
359 int cidrlen, aftype;
360
361 strcpy(mask, s1);
362 strcpy(address, s2);
363
364 len = strrchr(mask, '/');
365 if (len == NULL)
366 return 0;
367
368 *len++ = '\0';
369
370 cidrlen = atoi(len);
371 if (cidrlen <= 0)
372 return 0;
373
374 #ifdef RB_IPV6
375 if (strchr(mask, ':') && strchr(address, ':'))
376 {
377 if (cidrlen > 128)
378 return 0;
379
380 aftype = AF_INET6;
381 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
382 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
383 }
384 else
385 #endif
386 if (!strchr(mask, ':') && !strchr(address, ':'))
387 {
388 if (cidrlen > 32)
389 return 0;
390
391 aftype = AF_INET;
392 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
393 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
394 }
395 else
396 return 0;
397
398 rb_inet_pton(aftype, address, ipptr);
399 rb_inet_pton(aftype, mask, maskptr);
400 if (comp_with_mask(ipptr, maskptr, cidrlen))
401 return 1;
402 else
403 return 0;
404 }
405
406 /* match_cidr()
407 *
408 * Input - mask, address
409 * Ouput - 1 = Matched 0 = Did not match
410 */
411
412 int match_cidr(const char *s1, const char *s2)
413 {
414 struct rb_sockaddr_storage ipaddr, maskaddr;
415 char mask[BUFSIZE];
416 char address[NICKLEN + USERLEN + HOSTLEN + 6];
417 char *ipmask;
418 char *ip;
419 char *len;
420 void *ipptr, *maskptr;
421 int cidrlen, aftype;
422
423 strcpy(mask, s1);
424 strcpy(address, s2);
425
426 ipmask = strrchr(mask, '@');
427 if (ipmask == NULL)
428 return 0;
429
430 *ipmask++ = '\0';
431
432 ip = strrchr(address, '@');
433 if (ip == NULL)
434 return 0;
435 *ip++ = '\0';
436
437
438 len = strrchr(ipmask, '/');
439 if (len == NULL)
440 return 0;
441
442 *len++ = '\0';
443
444 cidrlen = atoi(len);
445 if (cidrlen <= 0)
446 return 0;
447
448 #ifdef RB_IPV6
449 if (strchr(ip, ':') && strchr(ipmask, ':'))
450 {
451 if (cidrlen > 128)
452 return 0;
453
454 aftype = AF_INET6;
455 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
456 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
457 }
458 else
459 #endif
460 if (!strchr(ip, ':') && !strchr(ipmask, ':'))
461 {
462 if (cidrlen > 32)
463 return 0;
464
465 aftype = AF_INET;
466 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
467 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
468 }
469 else
470 return 0;
471
472 rb_inet_pton(aftype, ip, ipptr);
473 rb_inet_pton(aftype, ipmask, maskptr);
474 if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address))
475 return 1;
476 else
477 return 0;
478 }
479
480 /* collapse()
481 *
482 * collapses a string containing multiple *'s.
483 */
484 char *collapse(char *pattern)
485 {
486 char *p = pattern, *po = pattern;
487 char c;
488 int f = 0;
489
490 if (p == NULL)
491 return NULL;
492
493 while ((c = *p++))
494 {
495 if (c == '*')
496 {
497 if (!(f & 1))
498 *po++ = '*';
499 f |= 1;
500 }
501 else
502 {
503 *po++ = c;
504 f &= ~1;
505 }
506 }
507 *po++ = 0;
508
509 return pattern;
510 }
511
512 /* collapse_esc()
513 *
514 * The collapse() function with support for escaping characters
515 */
516 char *collapse_esc(char *pattern)
517 {
518 char *p = pattern, *po = pattern;
519 char c;
520 int f = 0;
521
522 if (p == NULL)
523 return NULL;
524
525 while ((c = *p++))
526 {
527 if (!(f & 2) && c == '*')
528 {
529 if (!(f & 1))
530 *po++ = '*';
531 f |= 1;
532 }
533 else if (!(f & 2) && c == '\\')
534 {
535 *po++ = '\\';
536 f |= 2;
537 }
538 else
539 {
540 *po++ = c;
541 f &= ~3;
542 }
543 }
544 *po++ = 0;
545 return pattern;
546 }
547
548 /*
549 * irccmp - case insensitive comparison of two 0 terminated strings.
550 *
551 * returns 0, if s1 equal to s2
552 * <0, if s1 lexicographically less than s2
553 * >0, if s1 lexicographically greater than s2
554 */
555 int irccmp(const char *s1, const char *s2)
556 {
557 const unsigned char *str1 = (const unsigned char *)s1;
558 const unsigned char *str2 = (const unsigned char *)s2;
559 int res;
560
561 s_assert(s1 != NULL);
562 s_assert(s2 != NULL);
563
564 while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
565 {
566 if (*str1 == '\0')
567 return 0;
568 str1++;
569 str2++;
570 }
571 return (res);
572 }
573
574 int ircncmp(const char *s1, const char *s2, int n)
575 {
576 const unsigned char *str1 = (const unsigned char *)s1;
577 const unsigned char *str2 = (const unsigned char *)s2;
578 int res;
579 s_assert(s1 != NULL);
580 s_assert(s2 != NULL);
581
582 while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
583 {
584 str1++;
585 str2++;
586 n--;
587 if (n == 0 || (*str1 == '\0' && *str2 == '\0'))
588 return 0;
589 }
590 return (res);
591 }
592
593 const unsigned char ToLowerTab[] = {
594 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
595 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
596 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
597 0x1e, 0x1f,
598 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
599 '*', '+', ',', '-', '.', '/',
600 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
601 ':', ';', '<', '=', '>', '?',
602 '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
603 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
604 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
605 '_',
606 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
607 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
608 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
609 0x7f,
610 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
611 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
612 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
613 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
614 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
615 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
616 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
617 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
618 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
619 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
620 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
621 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
622 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
623 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
624 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
625 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
626 };
627
628 const unsigned char ToUpperTab[] = {
629 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
630 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
631 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
632 0x1e, 0x1f,
633 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
634 '*', '+', ',', '-', '.', '/',
635 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
636 ':', ';', '<', '=', '>', '?',
637 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
638 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
639 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
640 0x5f,
641 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
642 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
643 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
644 0x7f,
645 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
646 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
647 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
648 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
649 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
650 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
651 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
652 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
653 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
654 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
655 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
656 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
657 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
658 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
659 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
660 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
661 };
662
663 /*
664 * CharAttrs table
665 *
666 * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed
667 * for channel names
668 */
669 const unsigned int CharAttrs[] = {
670 /* 0 */ CNTRL_C,
671 /* 1 */ CNTRL_C | CHAN_C | NONEOS_C,
672 /* 2 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
673 /* 3 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
674 /* 4 */ CNTRL_C | CHAN_C | NONEOS_C,
675 /* 5 */ CNTRL_C | CHAN_C | NONEOS_C,
676 /* 6 */ CNTRL_C | CHAN_C | NONEOS_C,
677 /* 7 BEL */ CNTRL_C | NONEOS_C,
678 /* 8 \b */ CNTRL_C | CHAN_C | NONEOS_C,
679 /* 9 \t */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
680 /* 10 \n */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
681 /* 11 \v */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
682 /* 12 \f */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
683 /* 13 \r */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
684 /* 14 */ CNTRL_C | CHAN_C | NONEOS_C,
685 /* 15 */ CNTRL_C | CHAN_C | NONEOS_C,
686 /* 16 */ CNTRL_C | CHAN_C | NONEOS_C,
687 /* 17 */ CNTRL_C | CHAN_C | NONEOS_C,
688 /* 18 */ CNTRL_C | CHAN_C | NONEOS_C,
689 /* 19 */ CNTRL_C | CHAN_C | NONEOS_C,
690 /* 20 */ CNTRL_C | CHAN_C | NONEOS_C,
691 /* 21 */ CNTRL_C | CHAN_C | NONEOS_C,
692 /* 22 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
693 /* 23 */ CNTRL_C | CHAN_C | NONEOS_C,
694 /* 24 */ CNTRL_C | CHAN_C | NONEOS_C,
695 /* 25 */ CNTRL_C | CHAN_C | NONEOS_C,
696 /* 26 */ CNTRL_C | CHAN_C | NONEOS_C,
697 /* 27 */ CNTRL_C | CHAN_C | NONEOS_C,
698 /* 28 */ CNTRL_C | CHAN_C | NONEOS_C,
699 /* 29 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
700 /* 30 */ CNTRL_C | CHAN_C | NONEOS_C,
701 /* 31 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
702 /* SP */ PRINT_C | SPACE_C,
703 /* ! */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C,
704 /* " */ PRINT_C | CHAN_C | NONEOS_C,
705 /* # */ PRINT_C | MWILD_C | CHANPFX_C | CHAN_C | NONEOS_C,
706 /* $ */ PRINT_C | CHAN_C | NONEOS_C,
707 /* % */ PRINT_C | CHAN_C | NONEOS_C,
708 /* & */ PRINT_C | CHANPFX_C | CHAN_C | NONEOS_C,
709 /* ' */ PRINT_C | CHAN_C | NONEOS_C,
710 /* ( */ PRINT_C | CHAN_C | NONEOS_C,
711 /* ) */ PRINT_C | CHAN_C | NONEOS_C,
712 /* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
713 /* + */ PRINT_C | CHAN_C | NONEOS_C,
714 /* , */ PRINT_C | NONEOS_C,
715 /* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
716 /* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C,
717 /* / */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
718 /* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
719 /* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
720 /* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
721 /* 3 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
722 /* 4 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
723 /* 5 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
724 /* 6 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
725 /* 7 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
726 /* 8 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
727 /* 9 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
728 /* : */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
729 /* ; */ PRINT_C | CHAN_C | NONEOS_C,
730 /* < */ PRINT_C | CHAN_C | NONEOS_C,
731 /* = */ PRINT_C | CHAN_C | NONEOS_C,
732 /* > */ PRINT_C | CHAN_C | NONEOS_C,
733 /* ? */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
734 /* @ */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
735 /* A */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
736 /* B */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
737 /* C */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
738 /* D */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
739 /* E */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
740 /* F */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
741 /* G */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
742 /* H */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
743 /* I */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
744 /* J */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
745 /* K */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
746 /* L */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
747 /* M */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
748 /* N */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
749 /* O */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
750 /* P */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
751 /* Q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
752 /* R */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
753 /* S */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
754 /* T */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
755 /* U */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
756 /* V */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
757 /* W */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
758 /* X */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
759 /* Y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
760 /* Z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
761 /* [ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
762 /* \ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
763 /* ] */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
764 /* ^ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
765 /* _ */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
766 /* ` */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
767 /* a */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
768 /* b */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
769 /* c */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
770 /* d */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
771 /* e */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
772 /* f */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
773 /* g */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
774 /* h */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
775 /* i */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
776 /* j */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
777 /* k */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
778 /* l */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
779 /* m */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
780 /* n */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
781 /* o */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
782 /* p */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
783 /* q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
784 /* r */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
785 /* s */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
786 /* t */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
787 /* u */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
788 /* v */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
789 /* w */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
790 /* x */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
791 /* y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
792 /* z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
793 /* { */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
794 /* | */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
795 /* } */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
796 /* ~ */ PRINT_C | ALPHA_C | CHAN_C | NONEOS_C | USER_C,
797 /* del */ CHAN_C | NONEOS_C,
798 /* 0x80 */ CHAN_C | NONEOS_C,
799 /* 0x81 */ CHAN_C | NONEOS_C,
800 /* 0x82 */ CHAN_C | NONEOS_C,
801 /* 0x83 */ CHAN_C | NONEOS_C,
802 /* 0x84 */ CHAN_C | NONEOS_C,
803 /* 0x85 */ CHAN_C | NONEOS_C,
804 /* 0x86 */ CHAN_C | NONEOS_C,
805 /* 0x87 */ CHAN_C | NONEOS_C,
806 /* 0x88 */ CHAN_C | NONEOS_C,
807 /* 0x89 */ CHAN_C | NONEOS_C,
808 /* 0x8A */ CHAN_C | NONEOS_C,
809 /* 0x8B */ CHAN_C | NONEOS_C,
810 /* 0x8C */ CHAN_C | NONEOS_C,
811 /* 0x8D */ CHAN_C | NONEOS_C,
812 /* 0x8E */ CHAN_C | NONEOS_C,
813 /* 0x8F */ CHAN_C | NONEOS_C,
814 /* 0x90 */ CHAN_C | NONEOS_C,
815 /* 0x91 */ CHAN_C | NONEOS_C,
816 /* 0x92 */ CHAN_C | NONEOS_C,
817 /* 0x93 */ CHAN_C | NONEOS_C,
818 /* 0x94 */ CHAN_C | NONEOS_C,
819 /* 0x95 */ CHAN_C | NONEOS_C,
820 /* 0x96 */ CHAN_C | NONEOS_C,
821 /* 0x97 */ CHAN_C | NONEOS_C,
822 /* 0x98 */ CHAN_C | NONEOS_C,
823 /* 0x99 */ CHAN_C | NONEOS_C,
824 /* 0x9A */ CHAN_C | NONEOS_C,
825 /* 0x9B */ CHAN_C | NONEOS_C,
826 /* 0x9C */ CHAN_C | NONEOS_C,
827 /* 0x9D */ CHAN_C | NONEOS_C,
828 /* 0x9E */ CHAN_C | NONEOS_C,
829 /* 0x9F */ CHAN_C | NONEOS_C,
830 /* 0xA0 */ CHAN_C | FCHAN_C | NONEOS_C,
831 /* 0xA1 */ CHAN_C | NONEOS_C,
832 /* 0xA2 */ CHAN_C | NONEOS_C,
833 /* 0xA3 */ CHAN_C | NONEOS_C,
834 /* 0xA4 */ CHAN_C | NONEOS_C,
835 /* 0xA5 */ CHAN_C | NONEOS_C,
836 /* 0xA6 */ CHAN_C | NONEOS_C,
837 /* 0xA7 */ CHAN_C | NONEOS_C,
838 /* 0xA8 */ CHAN_C | NONEOS_C,
839 /* 0xA9 */ CHAN_C | NONEOS_C,
840 /* 0xAA */ CHAN_C | NONEOS_C,
841 /* 0xAB */ CHAN_C | NONEOS_C,
842 /* 0xAC */ CHAN_C | NONEOS_C,
843 /* 0xAD */ CHAN_C | NONEOS_C,
844 /* 0xAE */ CHAN_C | NONEOS_C,
845 /* 0xAF */ CHAN_C | NONEOS_C,
846 /* 0xB0 */ CHAN_C | NONEOS_C,
847 /* 0xB1 */ CHAN_C | NONEOS_C,
848 /* 0xB2 */ CHAN_C | NONEOS_C,
849 /* 0xB3 */ CHAN_C | NONEOS_C,
850 /* 0xB4 */ CHAN_C | NONEOS_C,
851 /* 0xB5 */ CHAN_C | NONEOS_C,
852 /* 0xB6 */ CHAN_C | NONEOS_C,
853 /* 0xB7 */ CHAN_C | NONEOS_C,
854 /* 0xB8 */ CHAN_C | NONEOS_C,
855 /* 0xB9 */ CHAN_C | NONEOS_C,
856 /* 0xBA */ CHAN_C | NONEOS_C,
857 /* 0xBB */ CHAN_C | NONEOS_C,
858 /* 0xBC */ CHAN_C | NONEOS_C,
859 /* 0xBD */ CHAN_C | NONEOS_C,
860 /* 0xBE */ CHAN_C | NONEOS_C,
861 /* 0xBF */ CHAN_C | NONEOS_C,
862 /* 0xC0 */ CHAN_C | NONEOS_C,
863 /* 0xC1 */ CHAN_C | NONEOS_C,
864 /* 0xC2 */ CHAN_C | NONEOS_C,
865 /* 0xC3 */ CHAN_C | NONEOS_C,
866 /* 0xC4 */ CHAN_C | NONEOS_C,
867 /* 0xC5 */ CHAN_C | NONEOS_C,
868 /* 0xC6 */ CHAN_C | NONEOS_C,
869 /* 0xC7 */ CHAN_C | NONEOS_C,
870 /* 0xC8 */ CHAN_C | NONEOS_C,
871 /* 0xC9 */ CHAN_C | NONEOS_C,
872 /* 0xCA */ CHAN_C | NONEOS_C,
873 /* 0xCB */ CHAN_C | NONEOS_C,
874 /* 0xCC */ CHAN_C | NONEOS_C,
875 /* 0xCD */ CHAN_C | NONEOS_C,
876 /* 0xCE */ CHAN_C | NONEOS_C,
877 /* 0xCF */ CHAN_C | NONEOS_C,
878 /* 0xD0 */ CHAN_C | NONEOS_C,
879 /* 0xD1 */ CHAN_C | NONEOS_C,
880 /* 0xD2 */ CHAN_C | NONEOS_C,
881 /* 0xD3 */ CHAN_C | NONEOS_C,
882 /* 0xD4 */ CHAN_C | NONEOS_C,
883 /* 0xD5 */ CHAN_C | NONEOS_C,
884 /* 0xD6 */ CHAN_C | NONEOS_C,
885 /* 0xD7 */ CHAN_C | NONEOS_C,
886 /* 0xD8 */ CHAN_C | NONEOS_C,
887 /* 0xD9 */ CHAN_C | NONEOS_C,
888 /* 0xDA */ CHAN_C | NONEOS_C,
889 /* 0xDB */ CHAN_C | NONEOS_C,
890 /* 0xDC */ CHAN_C | NONEOS_C,
891 /* 0xDD */ CHAN_C | NONEOS_C,
892 /* 0xDE */ CHAN_C | NONEOS_C,
893 /* 0xDF */ CHAN_C | NONEOS_C,
894 /* 0xE0 */ CHAN_C | NONEOS_C,
895 /* 0xE1 */ CHAN_C | NONEOS_C,
896 /* 0xE2 */ CHAN_C | NONEOS_C,
897 /* 0xE3 */ CHAN_C | NONEOS_C,
898 /* 0xE4 */ CHAN_C | NONEOS_C,
899 /* 0xE5 */ CHAN_C | NONEOS_C,
900 /* 0xE6 */ CHAN_C | NONEOS_C,
901 /* 0xE7 */ CHAN_C | NONEOS_C,
902 /* 0xE8 */ CHAN_C | NONEOS_C,
903 /* 0xE9 */ CHAN_C | NONEOS_C,
904 /* 0xEA */ CHAN_C | NONEOS_C,
905 /* 0xEB */ CHAN_C | NONEOS_C,
906 /* 0xEC */ CHAN_C | NONEOS_C,
907 /* 0xED */ CHAN_C | NONEOS_C,
908 /* 0xEE */ CHAN_C | NONEOS_C,
909 /* 0xEF */ CHAN_C | NONEOS_C,
910 /* 0xF0 */ CHAN_C | NONEOS_C,
911 /* 0xF1 */ CHAN_C | NONEOS_C,
912 /* 0xF2 */ CHAN_C | NONEOS_C,
913 /* 0xF3 */ CHAN_C | NONEOS_C,
914 /* 0xF4 */ CHAN_C | NONEOS_C,
915 /* 0xF5 */ CHAN_C | NONEOS_C,
916 /* 0xF6 */ CHAN_C | NONEOS_C,
917 /* 0xF7 */ CHAN_C | NONEOS_C,
918 /* 0xF8 */ CHAN_C | NONEOS_C,
919 /* 0xF9 */ CHAN_C | NONEOS_C,
920 /* 0xFA */ CHAN_C | NONEOS_C,
921 /* 0xFB */ CHAN_C | NONEOS_C,
922 /* 0xFC */ CHAN_C | NONEOS_C,
923 /* 0xFD */ CHAN_C | NONEOS_C,
924 /* 0xFE */ CHAN_C | NONEOS_C,
925 /* 0xFF */ CHAN_C | NONEOS_C
926 };