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