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