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