]> jfr.im git - irc/rqf/shadowircd.git/blob - src/match.c
Update comment for me_svsjoin explaining the sort of morality of it.
[irc/rqf/shadowircd.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 aftype = AF_INET6;
378 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
379 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
380 }
381 else
382 #endif
383 if (!strchr(mask, ':') && !strchr(address, ':'))
384 {
385 aftype = AF_INET;
386 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
387 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
388 }
389 else
390 return 0;
391
392 rb_inet_pton(aftype, address, ipptr);
393 rb_inet_pton(aftype, mask, maskptr);
394 if (comp_with_mask(ipptr, maskptr, cidrlen))
395 return 1;
396 else
397 return 0;
398 }
399
400 /* match_cidr()
401 *
402 * Input - mask, address
403 * Ouput - 1 = Matched 0 = Did not match
404 */
405
406 int match_cidr(const char *s1, const char *s2)
407 {
408 struct rb_sockaddr_storage ipaddr, maskaddr;
409 char mask[BUFSIZE];
410 char address[NICKLEN + USERLEN + HOSTLEN + 6];
411 char *ipmask;
412 char *ip;
413 char *len;
414 void *ipptr, *maskptr;
415 int cidrlen, aftype;
416
417 strcpy(mask, s1);
418 strcpy(address, s2);
419
420 ipmask = strrchr(mask, '@');
421 if (ipmask == NULL)
422 return 0;
423
424 *ipmask++ = '\0';
425
426 ip = strrchr(address, '@');
427 if (ip == NULL)
428 return 0;
429 *ip++ = '\0';
430
431
432 len = strrchr(ipmask, '/');
433 if (len == NULL)
434 return 0;
435
436 *len++ = '\0';
437
438 cidrlen = atoi(len);
439 if (cidrlen == 0)
440 return 0;
441
442 #ifdef RB_IPV6
443 if (strchr(ip, ':') && strchr(ipmask, ':'))
444 {
445 aftype = AF_INET6;
446 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
447 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
448 }
449 else
450 #endif
451 if (!strchr(ip, ':') && !strchr(ipmask, ':'))
452 {
453 aftype = AF_INET;
454 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
455 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
456 }
457 else
458 return 0;
459
460 rb_inet_pton(aftype, ip, ipptr);
461 rb_inet_pton(aftype, ipmask, maskptr);
462 if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address))
463 return 1;
464 else
465 return 0;
466 }
467
468 /* collapse()
469 *
470 * collapses a string containing multiple *'s.
471 */
472 char *collapse(char *pattern)
473 {
474 char *p = pattern, *po = pattern;
475 char c;
476 int f = 0;
477
478 if (p == NULL)
479 return NULL;
480
481 while ((c = *p++))
482 {
483 if (c == '*')
484 {
485 if (!(f & 1))
486 *po++ = '*';
487 f |= 1;
488 }
489 else
490 {
491 *po++ = c;
492 f &= ~1;
493 }
494 }
495 *po++ = 0;
496
497 return pattern;
498 }
499
500 /* collapse_esc()
501 *
502 * The collapse() function with support for escaping characters
503 */
504 char *collapse_esc(char *pattern)
505 {
506 char *p = pattern, *po = pattern;
507 char c;
508 int f = 0;
509
510 if (p == NULL)
511 return NULL;
512
513 while ((c = *p++))
514 {
515 if (!(f & 2) && c == '*')
516 {
517 if (!(f & 1))
518 *po++ = '*';
519 f |= 1;
520 }
521 else if (!(f & 2) && c == '\\')
522 {
523 *po++ = '\\';
524 f |= 2;
525 }
526 else
527 {
528 *po++ = c;
529 f &= ~3;
530 }
531 }
532 *po++ = 0;
533 return pattern;
534 }
535
536 /*
537 * irccmp - case insensitive comparison of two 0 terminated strings.
538 *
539 * returns 0, if s1 equal to s2
540 * <0, if s1 lexicographically less than s2
541 * >0, if s1 lexicographically greater than s2
542 */
543 int irccmp(const char *s1, const char *s2)
544 {
545 const unsigned char *str1 = (const unsigned char *)s1;
546 const unsigned char *str2 = (const unsigned char *)s2;
547 int res;
548
549 s_assert(s1 != NULL);
550 s_assert(s2 != NULL);
551
552 while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
553 {
554 if (*str1 == '\0')
555 return 0;
556 str1++;
557 str2++;
558 }
559 return (res);
560 }
561
562 int ircncmp(const char *s1, const char *s2, int n)
563 {
564 const unsigned char *str1 = (const unsigned char *)s1;
565 const unsigned char *str2 = (const unsigned char *)s2;
566 int res;
567 s_assert(s1 != NULL);
568 s_assert(s2 != NULL);
569
570 while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
571 {
572 str1++;
573 str2++;
574 n--;
575 if (n == 0 || (*str1 == '\0' && *str2 == '\0'))
576 return 0;
577 }
578 return (res);
579 }
580
581 const unsigned char ToLowerTab[] = {
582 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
583 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
584 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
585 0x1e, 0x1f,
586 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
587 '*', '+', ',', '-', '.', '/',
588 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
589 ':', ';', '<', '=', '>', '?',
590 '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
591 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
592 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
593 '_',
594 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
595 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
596 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
597 0x7f,
598 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
599 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
600 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
601 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
602 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
603 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
604 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
605 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
606 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
607 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
608 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
609 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
610 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
611 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
612 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
613 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
614 };
615
616 const unsigned char ToUpperTab[] = {
617 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
618 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
619 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
620 0x1e, 0x1f,
621 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
622 '*', '+', ',', '-', '.', '/',
623 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
624 ':', ';', '<', '=', '>', '?',
625 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
626 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
627 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
628 0x5f,
629 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
630 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
631 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
632 0x7f,
633 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
634 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
635 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
636 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
637 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
638 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
639 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
640 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
641 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
642 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
643 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
644 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
645 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
646 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
647 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
648 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
649 };
650
651 /*
652 * CharAttrs table
653 *
654 * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed
655 * for channel names
656 */
657 const unsigned int CharAttrs[] = {
658 /* 0 */ CNTRL_C,
659 /* 1 */ CNTRL_C | CHAN_C | NONEOS_C,
660 /* 2 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
661 /* 3 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
662 /* 4 */ CNTRL_C | CHAN_C | NONEOS_C,
663 /* 5 */ CNTRL_C | CHAN_C | NONEOS_C,
664 /* 6 */ CNTRL_C | CHAN_C | NONEOS_C,
665 /* 7 BEL */ CNTRL_C | NONEOS_C,
666 /* 8 \b */ CNTRL_C | CHAN_C | NONEOS_C,
667 /* 9 \t */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
668 /* 10 \n */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
669 /* 11 \v */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
670 /* 12 \f */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
671 /* 13 \r */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
672 /* 14 */ CNTRL_C | CHAN_C | NONEOS_C,
673 /* 15 */ CNTRL_C | CHAN_C | NONEOS_C,
674 /* 16 */ CNTRL_C | CHAN_C | NONEOS_C,
675 /* 17 */ CNTRL_C | CHAN_C | NONEOS_C,
676 /* 18 */ CNTRL_C | CHAN_C | NONEOS_C,
677 /* 19 */ CNTRL_C | CHAN_C | NONEOS_C,
678 /* 20 */ CNTRL_C | CHAN_C | NONEOS_C,
679 /* 21 */ CNTRL_C | CHAN_C | NONEOS_C,
680 /* 22 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
681 /* 23 */ CNTRL_C | CHAN_C | NONEOS_C,
682 /* 24 */ CNTRL_C | CHAN_C | NONEOS_C,
683 /* 25 */ CNTRL_C | CHAN_C | NONEOS_C,
684 /* 26 */ CNTRL_C | CHAN_C | NONEOS_C,
685 /* 27 */ CNTRL_C | CHAN_C | NONEOS_C,
686 /* 28 */ CNTRL_C | CHAN_C | NONEOS_C,
687 /* 29 */ CNTRL_C | CHAN_C | NONEOS_C,
688 /* 30 */ CNTRL_C | CHAN_C | NONEOS_C,
689 /* 31 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
690 /* SP */ PRINT_C | SPACE_C,
691 /* ! */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C,
692 /* " */ PRINT_C | CHAN_C | NONEOS_C,
693 /* # */ PRINT_C | MWILD_C | CHANPFX_C | CHAN_C | NONEOS_C,
694 /* $ */ PRINT_C | CHAN_C | NONEOS_C | USER_C,
695 /* % */ PRINT_C | CHAN_C | NONEOS_C,
696 /* & */ PRINT_C | CHANPFX_C | CHAN_C | NONEOS_C,
697 /* ' */ PRINT_C | CHAN_C | NONEOS_C,
698 /* ( */ PRINT_C | CHAN_C | NONEOS_C,
699 /* ) */ PRINT_C | CHAN_C | NONEOS_C,
700 /* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
701 /* + */ PRINT_C | CHAN_C | NONEOS_C,
702 /* , */ PRINT_C | NONEOS_C,
703 /* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
704 /* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C,
705 /* / */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
706 /* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
707 /* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
708 /* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
709 /* 3 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
710 /* 4 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
711 /* 5 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
712 /* 6 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
713 /* 7 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
714 /* 8 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
715 /* 9 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
716 /* : */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
717 /* ; */ PRINT_C | CHAN_C | NONEOS_C,
718 /* < */ PRINT_C | CHAN_C | NONEOS_C,
719 /* = */ PRINT_C | CHAN_C | NONEOS_C,
720 /* > */ PRINT_C | CHAN_C | NONEOS_C,
721 /* ? */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
722 /* @ */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
723 /* A */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
724 /* B */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
725 /* C */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
726 /* D */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
727 /* E */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
728 /* F */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
729 /* G */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
730 /* H */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
731 /* I */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
732 /* J */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
733 /* K */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
734 /* L */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
735 /* M */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
736 /* N */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
737 /* O */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
738 /* P */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
739 /* Q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
740 /* R */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
741 /* S */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
742 /* T */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
743 /* U */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
744 /* V */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
745 /* W */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
746 /* X */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
747 /* Y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
748 /* Z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
749 /* [ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
750 /* \ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
751 /* ] */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
752 /* ^ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
753 /* _ */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
754 /* ` */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
755 /* a */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
756 /* b */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
757 /* c */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
758 /* d */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
759 /* e */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
760 /* f */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
761 /* g */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
762 /* h */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
763 /* i */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
764 /* j */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
765 /* k */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
766 /* l */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
767 /* m */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
768 /* n */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
769 /* o */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
770 /* p */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
771 /* q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
772 /* r */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
773 /* s */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
774 /* t */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
775 /* u */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
776 /* v */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
777 /* w */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
778 /* x */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
779 /* y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
780 /* z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
781 /* { */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
782 /* | */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
783 /* } */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
784 /* ~ */ PRINT_C | ALPHA_C | CHAN_C | NONEOS_C | USER_C,
785 /* del */ CHAN_C | NONEOS_C,
786 /* 0x80 */ CHAN_C | NONEOS_C,
787 /* 0x81 */ CHAN_C | NONEOS_C,
788 /* 0x82 */ CHAN_C | NONEOS_C,
789 /* 0x83 */ CHAN_C | NONEOS_C,
790 /* 0x84 */ CHAN_C | NONEOS_C,
791 /* 0x85 */ CHAN_C | NONEOS_C,
792 /* 0x86 */ CHAN_C | NONEOS_C,
793 /* 0x87 */ CHAN_C | NONEOS_C,
794 /* 0x88 */ CHAN_C | NONEOS_C,
795 /* 0x89 */ CHAN_C | NONEOS_C,
796 /* 0x8A */ CHAN_C | NONEOS_C,
797 /* 0x8B */ CHAN_C | NONEOS_C,
798 /* 0x8C */ CHAN_C | NONEOS_C,
799 /* 0x8D */ CHAN_C | NONEOS_C,
800 /* 0x8E */ CHAN_C | NONEOS_C,
801 /* 0x8F */ CHAN_C | NONEOS_C,
802 /* 0x90 */ CHAN_C | NONEOS_C,
803 /* 0x91 */ CHAN_C | NONEOS_C,
804 /* 0x92 */ CHAN_C | NONEOS_C,
805 /* 0x93 */ CHAN_C | NONEOS_C,
806 /* 0x94 */ CHAN_C | NONEOS_C,
807 /* 0x95 */ CHAN_C | NONEOS_C,
808 /* 0x96 */ CHAN_C | NONEOS_C,
809 /* 0x97 */ CHAN_C | NONEOS_C,
810 /* 0x98 */ CHAN_C | NONEOS_C,
811 /* 0x99 */ CHAN_C | NONEOS_C,
812 /* 0x9A */ CHAN_C | NONEOS_C,
813 /* 0x9B */ CHAN_C | NONEOS_C,
814 /* 0x9C */ CHAN_C | NONEOS_C,
815 /* 0x9D */ CHAN_C | NONEOS_C,
816 /* 0x9E */ CHAN_C | NONEOS_C,
817 /* 0x9F */ CHAN_C | NONEOS_C,
818 /* 0xA0 */ CHAN_C | FCHAN_C | NONEOS_C,
819 /* 0xA1 */ CHAN_C | NONEOS_C,
820 /* 0xA2 */ CHAN_C | NONEOS_C,
821 /* 0xA3 */ CHAN_C | NONEOS_C,
822 /* 0xA4 */ CHAN_C | NONEOS_C,
823 /* 0xA5 */ CHAN_C | NONEOS_C,
824 /* 0xA6 */ CHAN_C | NONEOS_C,
825 /* 0xA7 */ CHAN_C | NONEOS_C,
826 /* 0xA8 */ CHAN_C | NONEOS_C,
827 /* 0xA9 */ CHAN_C | NONEOS_C,
828 /* 0xAA */ CHAN_C | NONEOS_C,
829 /* 0xAB */ CHAN_C | NONEOS_C,
830 /* 0xAC */ CHAN_C | NONEOS_C,
831 /* 0xAD */ CHAN_C | NONEOS_C,
832 /* 0xAE */ CHAN_C | NONEOS_C,
833 /* 0xAF */ CHAN_C | NONEOS_C,
834 /* 0xB0 */ CHAN_C | NONEOS_C,
835 /* 0xB1 */ CHAN_C | NONEOS_C,
836 /* 0xB2 */ CHAN_C | NONEOS_C,
837 /* 0xB3 */ CHAN_C | NONEOS_C,
838 /* 0xB4 */ CHAN_C | NONEOS_C,
839 /* 0xB5 */ CHAN_C | NONEOS_C,
840 /* 0xB6 */ CHAN_C | NONEOS_C,
841 /* 0xB7 */ CHAN_C | NONEOS_C,
842 /* 0xB8 */ CHAN_C | NONEOS_C,
843 /* 0xB9 */ CHAN_C | NONEOS_C,
844 /* 0xBA */ CHAN_C | NONEOS_C,
845 /* 0xBB */ CHAN_C | NONEOS_C,
846 /* 0xBC */ CHAN_C | NONEOS_C,
847 /* 0xBD */ CHAN_C | NONEOS_C,
848 /* 0xBE */ CHAN_C | NONEOS_C,
849 /* 0xBF */ CHAN_C | NONEOS_C,
850 /* 0xC0 */ CHAN_C | NONEOS_C,
851 /* 0xC1 */ CHAN_C | NONEOS_C,
852 /* 0xC2 */ CHAN_C | NONEOS_C,
853 /* 0xC3 */ CHAN_C | NONEOS_C,
854 /* 0xC4 */ CHAN_C | NONEOS_C,
855 /* 0xC5 */ CHAN_C | NONEOS_C,
856 /* 0xC6 */ CHAN_C | NONEOS_C,
857 /* 0xC7 */ CHAN_C | NONEOS_C,
858 /* 0xC8 */ CHAN_C | NONEOS_C,
859 /* 0xC9 */ CHAN_C | NONEOS_C,
860 /* 0xCA */ CHAN_C | NONEOS_C,
861 /* 0xCB */ CHAN_C | NONEOS_C,
862 /* 0xCC */ CHAN_C | NONEOS_C,
863 /* 0xCD */ CHAN_C | NONEOS_C,
864 /* 0xCE */ CHAN_C | NONEOS_C,
865 /* 0xCF */ CHAN_C | NONEOS_C,
866 /* 0xD0 */ CHAN_C | NONEOS_C,
867 /* 0xD1 */ CHAN_C | NONEOS_C,
868 /* 0xD2 */ CHAN_C | NONEOS_C,
869 /* 0xD3 */ CHAN_C | NONEOS_C,
870 /* 0xD4 */ CHAN_C | NONEOS_C,
871 /* 0xD5 */ CHAN_C | NONEOS_C,
872 /* 0xD6 */ CHAN_C | NONEOS_C,
873 /* 0xD7 */ CHAN_C | NONEOS_C,
874 /* 0xD8 */ CHAN_C | NONEOS_C,
875 /* 0xD9 */ CHAN_C | NONEOS_C,
876 /* 0xDA */ CHAN_C | NONEOS_C,
877 /* 0xDB */ CHAN_C | NONEOS_C,
878 /* 0xDC */ CHAN_C | NONEOS_C,
879 /* 0xDD */ CHAN_C | NONEOS_C,
880 /* 0xDE */ CHAN_C | NONEOS_C,
881 /* 0xDF */ CHAN_C | NONEOS_C,
882 /* 0xE0 */ CHAN_C | NONEOS_C,
883 /* 0xE1 */ CHAN_C | NONEOS_C,
884 /* 0xE2 */ CHAN_C | NONEOS_C,
885 /* 0xE3 */ CHAN_C | NONEOS_C,
886 /* 0xE4 */ CHAN_C | NONEOS_C,
887 /* 0xE5 */ CHAN_C | NONEOS_C,
888 /* 0xE6 */ CHAN_C | NONEOS_C,
889 /* 0xE7 */ CHAN_C | NONEOS_C,
890 /* 0xE8 */ CHAN_C | NONEOS_C,
891 /* 0xE9 */ CHAN_C | NONEOS_C,
892 /* 0xEA */ CHAN_C | NONEOS_C,
893 /* 0xEB */ CHAN_C | NONEOS_C,
894 /* 0xEC */ CHAN_C | NONEOS_C,
895 /* 0xED */ CHAN_C | NONEOS_C,
896 /* 0xEE */ CHAN_C | NONEOS_C,
897 /* 0xEF */ CHAN_C | NONEOS_C,
898 /* 0xF0 */ CHAN_C | NONEOS_C,
899 /* 0xF1 */ CHAN_C | NONEOS_C,
900 /* 0xF2 */ CHAN_C | NONEOS_C,
901 /* 0xF3 */ CHAN_C | NONEOS_C,
902 /* 0xF4 */ CHAN_C | NONEOS_C,
903 /* 0xF5 */ CHAN_C | NONEOS_C,
904 /* 0xF6 */ CHAN_C | NONEOS_C,
905 /* 0xF7 */ CHAN_C | NONEOS_C,
906 /* 0xF8 */ CHAN_C | NONEOS_C,
907 /* 0xF9 */ CHAN_C | NONEOS_C,
908 /* 0xFA */ CHAN_C | NONEOS_C,
909 /* 0xFB */ CHAN_C | NONEOS_C,
910 /* 0xFC */ CHAN_C | NONEOS_C,
911 /* 0xFD */ CHAN_C | NONEOS_C,
912 /* 0xFE */ CHAN_C | NONEOS_C,
913 /* 0xFF */ CHAN_C | NONEOS_C
914 };