2 * S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 #endif /* HAVE_WCTYPE_H */
52 #endif /* HAVE_WCWIDTH */
66 * Mail -- a mail program
68 * Auxiliary functions.
72 * Return a pointer to a dynamic copy of the argument.
75 savestr(const char *str
)
78 int size
= strlen(str
) + 1;
80 if ((new = salloc(size
)) != NULL
)
81 memcpy(new, str
, size
);
86 * Return new string copy of a non-terminated argument.
89 savestrbuf(const char *sbuf
, size_t sbuf_len
)
93 if ((news
= salloc(sbuf_len
+ 1)) != NULL
) {
94 memcpy(news
, sbuf
, sbuf_len
);
101 * Make a copy of new argument incorporating old one.
104 save2str(const char *str
, const char *old
)
107 int newsize
= strlen(str
) + 1;
108 int oldsize
= old
? strlen(old
) + 1 : 0;
110 if ((new = salloc(newsize
+ oldsize
)) != NULL
) {
112 memcpy(new, old
, oldsize
);
113 new[oldsize
- 1] = ' ';
115 memcpy(new + oldsize
, str
, newsize
);
121 savecat(const char *s1
, const char *s2
)
126 np
= ns
= salloc(strlen(s1
) + strlen(s2
) + 1);
127 for (cp
= s1
; *cp
; cp
++)
129 for (cp
= s2
; *cp
; cp
++)
137 #ifndef HAVE_SNPRINTF
139 * Lazy vsprintf wrapper.
142 snprintf(char *str
, size_t size
, const char *format
, ...)
147 va_start(ap
, format
);
148 ret
= vsprintf(str
, format
, ap
);
152 #endif /* !HAVE_SNPRINTF */
155 * Announce a fatal error and die.
158 panic(const char *format
, ...)
162 va_start(ap
, format
);
163 fprintf(stderr
, catgets(catd
, CATSET
, 1, "panic: "));
164 vfprintf(stderr
, format
, ap
);
166 fprintf(stderr
, catgets(catd
, CATSET
, 2, "\n"));
177 sigaddset(&set
, SIGINT
);
178 sigprocmask(SIG_BLOCK
, &set
, NULL
);
187 sigaddset(&set
, SIGINT
);
188 sigprocmask(SIG_UNBLOCK
, &set
, NULL
);
192 * Touch the named message by setting its MTOUCH flag.
193 * Touched messages have the effect of not being sent
194 * back to the system mailbox on exit.
197 touch(struct message
*mp
)
200 mp
->m_flag
|= MTOUCH
;
201 if ((mp
->m_flag
& MREAD
) == 0)
202 mp
->m_flag
|= MREAD
|MSTATUS
;
206 * Test to see if the passed file name is a directory.
207 * Return true if it is.
214 if (stat(name
, &sbuf
) < 0)
216 return(S_ISDIR(sbuf
.st_mode
));
220 * Count the number of arguments in the given string raw list.
223 argcount(char **argv
)
227 for (ap
= argv
; *ap
++ != NULL
;)
229 return ap
- argv
- 1;
233 * Copy a string, lowercasing it as we go.
236 i_strcpy(char *dest
, const char *src
, int size
)
242 *dest
++ = lowerconv(*src
& 0377);
249 i_strdup(const char *src
)
254 sz
= strlen(src
) + 1;
256 i_strcpy(dest
, src
, sz
);
261 * Convert a string to lowercase, in-place and with multibyte-aware.
266 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
267 if (mb_cur_max
> 1) {
273 len
= mbtowc(&wc
, cp
, mb_cur_max
);
278 if (wctomb(tp
, wc
) == len
)
279 tp
+= len
, cp
+= len
;
285 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
288 *cp
= tolower(*cp
& 0377);
294 substr(const char *str
, const char *sub
)
296 const char *cp
, *backup
;
300 while (*str
&& *cp
) {
301 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
302 if (mb_cur_max
> 1) {
306 if ((sz
= mbtowc(&c
, cp
, mb_cur_max
)) < 0)
309 if ((sz
= mbtowc(&c2
, str
, mb_cur_max
)) < 0)
315 if ((sz
= mbtowc(&c
, backup
, mb_cur_max
)) > 0) {
323 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
327 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
329 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
346 colalign(const char *cp
, int col
, int fill
)
351 np
= nb
= salloc(mb_cur_max
* strlen(cp
) + col
+ 1);
353 #if defined (HAVE_MBTOWC) && defined (HAVE_WCWIDTH)
354 if (mb_cur_max
> 1) {
357 if ((sz
= mbtowc(&wc
, cp
, mb_cur_max
)) < 0) {
360 if ((n
= wcwidth(wc
)) < 0)
364 #endif /* HAVE_MBTOWC && HAVE_WCWIDTH */
371 if (sz
== 1 && spacechar(*cp
&0377)) {
394 while ((c
= getc(fp
)) != EOF
)
398 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
&&
399 lines
> (*cp
? atol(cp
) : scrnheight
))
400 run_command(get_pager(), 0, fileno(fp
), -1, NULL
, NULL
, NULL
);
402 while ((c
= getc(fp
)) != EOF
)
407 * The following code deals with input stacking to do source
408 * commands. All but the current file pointer are saved on
412 static int ssp
; /* Top of file stack */
414 FILE *s_file
; /* File we were in. */
415 enum condition s_cond
; /* Saved state of conditionals */
416 int s_loading
; /* Loading .mailrc, etc. */
421 * Pushdown current input file and switch to a new one.
422 * Set the global flag "sourcing" so that others will realize
423 * that they are no longer reading from a tty (in all probability).
432 if ((cp
= expand(*arglist
)) == NULL
)
434 if ((fi
= Fopen(cp
, "r")) == NULL
) {
438 if (ssp
>= SSTACK
- 1) {
439 printf(catgets(catd
, CATSET
, 3,
440 "Too much \"sourcing\" going on.\n"));
444 sstack
[ssp
].s_file
= input
;
445 sstack
[ssp
].s_cond
= cond
;
446 sstack
[ssp
].s_loading
= loading
;
456 * Pop the current input back to the previous level.
457 * Update the "sourcing" flag as appropriate.
463 printf(catgets(catd
, CATSET
, 4,
464 "\"Source\" stack over-pop.\n"));
470 printf(catgets(catd
, CATSET
, 5, "Unmatched \"if\"\n"));
472 cond
= sstack
[ssp
].s_cond
;
473 loading
= sstack
[ssp
].s_loading
;
474 input
= sstack
[ssp
].s_file
;
481 * Touch the indicated file.
482 * This is nifty for the shell.
492 utb
.actime
= time((time_t *)0) + 1;
493 utb
.modtime
= sb
.st_mtime
;
498 * Examine the passed line buffer and
499 * return true if it is all blanks and tabs.
502 blankline(char *linebuf
)
506 for (cp
= linebuf
; *cp
; cp
++)
507 if (!blankchar(*cp
& 0377))
513 * Are any of the characters in the two strings the same?
516 anyof(char *s1
, char *s2
)
520 if (strchr(s2
, *s1
++))
526 * Determine if as1 is a valid prefix of as2.
527 * Return true if yep.
530 is_prefix(const char *as1
, const char *as2
)
539 return(*--s1
== '\0');
543 last_at_before_slash(const char *sp
)
547 for (cp
= sp
; *cp
; cp
++)
550 while (cp
> sp
&& *--cp
!= '@');
551 return *cp
== '@' ? (char *)cp
: NULL
;
555 which_protocol(const char *name
)
557 register const char *cp
;
563 if (name
[0] == '%' && name
[1] == ':')
565 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
566 if (!alnumchar(*cp
&0377))
568 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
569 if (strncmp(name
, "pop3://", 7) == 0)
573 fprintf(stderr
, catgets(catd
, CATSET
, 216,
574 "No POP3 support compiled in.\n"));
576 if (strncmp(name
, "pop3s://", 8) == 0)
580 fprintf(stderr
, catgets(catd
, CATSET
, 225,
581 "No SSL support compiled in.\n"));
582 #endif /* !USE_SSL */
583 if (strncmp(name
, "imap://", 7) == 0)
587 fprintf(stderr
, catgets(catd
, CATSET
, 269,
588 "No IMAP support compiled in.\n"));
590 if (strncmp(name
, "imaps://", 8) == 0)
594 fprintf(stderr
, catgets(catd
, CATSET
, 225,
595 "No SSL support compiled in.\n"));
596 #endif /* !USE_SSL */
597 return PROTO_UNKNOWN
;
599 file
: p
= PROTO_FILE
;
600 np
= ac_alloc((sz
= strlen(name
)) + 5);
602 if (stat(name
, &st
) == 0) {
603 if (S_ISDIR(st
.st_mode
)) {
604 strcpy(&np
[sz
], "/tmp");
605 if (stat(np
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
606 strcpy(&np
[sz
], "/new");
607 if (stat(np
, &st
) == 0 &&
608 S_ISDIR(st
.st_mode
)) {
609 strcpy(&np
[sz
], "/cur");
610 if (stat(np
, &st
) == 0 &&
617 strcpy(&np
[sz
], ".gz");
618 if (stat(np
, &st
) < 0) {
619 strcpy(&np
[sz
], ".bz2");
620 if (stat(np
, &st
) < 0) {
621 if ((cp
= value("newfolders")) != 0 &&
622 strcmp(cp
, "maildir") == 0)
633 protfile(const char *xcp
)
635 const char *cp
= xcp
;
639 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
643 if (cp
[0] == '/' && state
== 1)
653 protbase(const char *cp
)
655 char *n
= salloc(strlen(cp
) + 1);
659 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
663 } else if (cp
[0] == '/')
673 disconnected(const char *file
)
678 if (value("disconnected"))
681 if (strncmp(cp
, "imap://", 7) == 0)
683 else if (strncmp(cp
, "imaps://", 8) == 0)
687 if ((cq
= strchr(cp
, ':')) != NULL
)
689 vp
= ac_alloc(vs
= strlen(cp
) + 14);
690 snprintf(vp
, vs
, "disconnected-%s", cp
);
691 r
= value(vp
) != NULL
;
703 h
= (h
<< 4 & 0xffffffff) + (*cp
&0377);
704 if ((g
= h
& 0xf0000000) != 0) {
715 const long primes
[] = {
716 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
717 131071, 262139, 524287, 1048573, 2097143, 4194301,
718 8388593, 16777213, 33554393, 67108859, 134217689,
719 268435399, 536870909, 1073741789, 2147483647
724 for (i
= 0; i
< sizeof primes
/ sizeof *primes
; i
++)
725 if ((mprime
= primes
[i
]) >= (n
< 65536 ? n
*4 :
726 n
< 262144 ? n
*2 : n
))
728 if (i
== sizeof primes
/ sizeof *primes
)
729 mprime
= n
; /* not so prime, but better than failure */
733 #define Hexchar(n) ((n)>9 ? (n)-10+'A' : (n)+'0')
734 #define hexchar(n) ((n)>9 ? (n)-10+'a' : (n)+'0')
737 strenc(const char *cp
)
741 np
= n
= salloc(strlen(cp
) * 3 + 1);
743 if (alnumchar(*cp
&0377) || *cp
== '_' || *cp
== '@' ||
744 (np
> n
&& (*cp
== '.' || *cp
== '-' ||
749 *np
++ = Hexchar((*cp
&0xf0) >> 4);
750 *np
++ = Hexchar(*cp
&0x0f);
759 strdec(const char *cp
)
763 np
= n
= salloc(strlen(cp
) + 1);
765 if (cp
[0] == '%' && cp
[1] && cp
[2]) {
766 *np
= (int)(cp
[1]>'9'?cp
[1]-'A'+10:cp
[1]-'0') << 4;
767 *np
++ |= cp
[2]>'9'?cp
[2]-'A'+10:cp
[2]-'0';
778 md5tohex(const void *vp
)
785 for (i
= 0; i
< 16; i
++) {
786 hex
[2*i
] = hexchar((cp
[i
]&0xf0) >> 4);
787 hex
[2*i
+1] = hexchar(cp
[i
]&0x0f);
794 cram_md5_string(const char *user
, const char *pass
, const char *b64
)
797 char digest
[16], *cp
, *sp
, *rp
, *xp
;
802 mime_fromb64(&in
, &out
, 0);
803 hmac_md5((unsigned char *)out
.s
, out
.l
,
804 (unsigned char *)pass
, strlen(pass
),
807 xp
= md5tohex(digest
);
808 sp
= ac_alloc(ss
= strlen(user
) + strlen(xp
) + 2);
809 snprintf(sp
, ss
, "%s %s", user
, xp
);
812 rp
= salloc(rs
= strlen(cp
) + 3);
813 snprintf(rp
, rs
, "%s\r\n", cp
);
822 char *line
= NULL
, *user
;
826 fputs("User: ", stdout
);
829 if (readline(stdin
, &line
, &linesize
) == 0) {
834 user
= savestr(line
);
840 getpassword(struct termios
*otio
, int *reset_tio
, const char *query
)
843 char *line
= NULL
, *pass
;
848 fputs(query
? query
: "Password:", stdout
);
852 tio
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
854 tcsetattr(0, TCSAFLUSH
, &tio
);
856 i
= readline(stdin
, &line
, &linesize
);
859 tcsetattr(0, TCSADRAIN
, otio
);
867 pass
= savestr(line
);
873 transflags(struct message
*omessage
, long omsgCount
, int transparent
)
875 struct message
*omp
, *nmp
, *newdot
, *newprevdot
;
882 while (omp
< &omessage
[omsgCount
] &&
883 nmp
< &message
[msgCount
]) {
884 if (dot
&& nmp
->m_uid
== dot
->m_uid
)
886 if (prevdot
&& nmp
->m_uid
== prevdot
->m_uid
)
888 if (omp
->m_uid
== nmp
->m_uid
) {
889 hf
= nmp
->m_flag
& MHIDDEN
;
890 if (transparent
&& mb
.mb_type
== MB_IMAP
)
891 omp
->m_flag
&= ~MHIDDEN
;
893 if (transparent
&& mb
.mb_type
== MB_CACHE
)
894 nmp
[-1].m_flag
|= hf
;
895 } else if (omp
->m_uid
< nmp
->m_uid
)
902 prevdot
= newprevdot
;
907 getrandstring(size_t length
)
909 static unsigned char nodedigest
[16];
921 data
= salloc(length
);
922 if ((fd
= open("/dev/urandom", O_RDONLY
)) < 0 ||
923 length
!= (size_t)read(fd
, data
, length
)) {
930 MD5Update(&ctx
, (unsigned char *)cp
, strlen(cp
));
931 MD5Final(nodedigest
, &ctx
);
933 /* In that case it's only used for boundaries and
934 * Message-Id:s so that srand(3) should suffice */
936 for (i
= 0; i
< sizeof(nodedigest
); ++i
)
937 nodedigest
[i
] = (unsigned char)(
941 for (i
= 0; i
< length
; i
++)
943 ((int)(255 * (rand() / (RAND_MAX
+ 1.0))) ^
944 nodedigest
[i
% sizeof nodedigest
]);
948 cp
= memtob64(data
, length
);
949 rp
= salloc(length
+1);
950 strncpy(rp
, cp
, length
)[length
] = '\0';
968 if ((p
= malloc(s
)) == NULL
)
974 srealloc(void *v
, size_t s
)
982 if ((r
= realloc(v
, s
)) == NULL
)
988 scalloc(size_t nmemb
, size_t size
)
994 if ((vp
= calloc(nmemb
, size
)) == NULL
)
1000 sstpcpy(char *dst
, const char *src
)
1002 while ((*dst
= *src
++) != '\0')
1008 sstrdup(const char *cp
)
1013 dp
= smalloc(strlen(cp
) + 1);
1021 makedir(const char *name
)
1026 if (mkdir(name
, 0700) < 0) {
1028 if ((e
== EEXIST
|| e
== ENOSYS
) &&
1029 stat(name
, &st
) == 0 &&
1030 (st
.st_mode
&S_IFMT
) == S_IFDIR
)
1039 cwget(struct cw
*cw
)
1041 if ((cw
->cw_fd
= open(".", O_RDONLY
)) < 0)
1043 if (fchdir(cw
->cw_fd
) < 0) {
1051 cwret(struct cw
*cw
)
1053 if (fchdir(cw
->cw_fd
) < 0)
1059 cwrelse(struct cw
*cw
)
1063 #else /* !HAVE_FCHDIR */
1065 cwget(struct cw
*cw
)
1067 if (getcwd(cw
->cw_wd
, sizeof cw
->cw_wd
) == NULL
|| chdir(cw
->cw_wd
) < 0)
1073 cwret(struct cw
*cw
)
1075 if (chdir(cw
->cw_wd
) < 0)
1082 cwrelse(struct cw
*cw
)
1085 #endif /* !HAVE_FCHDIR */
1088 makeprint(struct str
*in
, struct str
*out
)
1090 static int print_all_chars
= -1;
1094 out
->s
= smalloc(msz
= in
->l
+ 1);
1095 if (print_all_chars
== -1)
1096 print_all_chars
= value("print-all-chars") != NULL
;
1097 if (print_all_chars
) {
1098 memcpy(out
->s
, in
->s
, in
->l
);
1100 out
->s
[out
->l
] = '\0';
1105 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1106 if (mb_cur_max
> 1) {
1108 char mb
[MB_LEN_MAX
+1];
1111 while (inp
< &in
->s
[in
->l
]) {
1113 n
= mbtowc(&wc
, inp
, &in
->s
[in
->l
] - inp
);
1119 mbtowc(&wc
, NULL
, mb_cur_max
);
1120 wc
= utf8
? 0xFFFD : '?';
1125 if (!iswprint(wc
) && wc
!= '\n' && wc
!= '\r' &&
1126 wc
!= '\b' && wc
!= '\t') {
1127 if ((wc
& ~(wchar_t)037) == 0)
1128 wc
= utf8
? 0x2400 | wc
: '?';
1129 else if (wc
== 0177)
1130 wc
= utf8
? 0x2421 : '?';
1132 wc
= utf8
? 0x2426 : '?';
1134 if ((n
= wctomb(mb
, wc
)) <= 0)
1137 if (out
->l
>= msz
- 1) {
1138 dist
= outp
- out
->s
;
1139 out
->s
= srealloc(out
->s
, msz
+= 32);
1140 outp
= &out
->s
[dist
];
1142 for (i
= 0; i
< n
; i
++)
1146 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1149 while (inp
< &in
->s
[in
->l
]) {
1151 if (!isprint(c
) && c
!= '\n' && c
!= '\r' &&
1152 c
!= '\b' && c
!= '\t')
1158 out
->s
[out
->l
] = '\0';
1162 prstr(const char *s
)
1169 makeprint(&in
, &out
);
1170 rp
= salloc(out
.l
+ 1);
1171 memcpy(rp
, out
.s
, out
.l
);
1178 prout(const char *s
, size_t sz
, FILE *fp
)
1185 makeprint(&in
, &out
);
1186 n
= fwrite(out
.s
, 1, out
.l
, fp
);
1192 * Print out a Unicode character or a substitute for it.
1195 putuc(int u
, int c
, FILE *fp
)
1197 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1198 if (utf8
&& u
& ~(wchar_t)0177) {
1199 char mb
[MB_LEN_MAX
];
1201 if ((n
= wctomb(mb
, u
)) > 0) {
1202 for (i
= 0; i
< n
; i
++)
1203 r
+= putc(mb
[i
] & 0377, fp
) != EOF
;
1206 return putc('\0', fp
) != EOF
;
1210 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1211 return putc(c
, fp
) != EOF
;
1215 * Locale-independent character class functions.
1218 asccasecmp(const char *s1
, const char *s2
)
1223 if ((cmp
= lowerconv(*s1
& 0377) - lowerconv(*s2
& 0377)) != 0)
1225 while (*s1
++ != '\0' && *s2
++ != '\0');
1230 ascncasecmp(const char *s1
, const char *s2
, size_t sz
)
1238 if ((cmp
= lowerconv(*s1
& 0377) - lowerconv(*s2
& 0377)) != 0)
1240 while (i
++ < sz
&& *s1
++ != '\0' && *s2
++ != '\0');
1245 asccasestr(const char *haystack
, const char *xneedle
)
1247 char *needle
, *NEEDLE
;
1250 sz
= strlen(xneedle
);
1252 return (char *)haystack
;
1253 needle
= ac_alloc(sz
);
1254 NEEDLE
= ac_alloc(sz
);
1255 for (i
= 0; i
< sz
; i
++) {
1256 needle
[i
] = lowerconv(xneedle
[i
]&0377);
1257 NEEDLE
[i
] = upperconv(xneedle
[i
]&0377);
1260 if (*haystack
== *needle
|| *haystack
== *NEEDLE
) {
1261 for (i
= 1; i
< sz
; i
++)
1262 if (haystack
[i
] != needle
[i
] &&
1263 haystack
[i
] != NEEDLE
[i
])
1266 return (char *)haystack
;
1273 const unsigned char class_char
[] = {
1274 /* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
1275 C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,
1276 /* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
1277 C_CNTRL
,C_BLANK
,C_WHITE
,C_SPACE
,C_SPACE
,C_SPACE
,C_CNTRL
,C_CNTRL
,
1278 /* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
1279 C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,
1280 /* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
1281 C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,C_CNTRL
,
1282 /* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
1283 C_BLANK
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,
1284 /* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
1285 C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,
1286 /* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
1287 C_OCTAL
,C_OCTAL
,C_OCTAL
,C_OCTAL
,C_OCTAL
,C_OCTAL
,C_OCTAL
,C_OCTAL
,
1288 /* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
1289 C_DIGIT
,C_DIGIT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,
1290 /* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
1291 C_PUNCT
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,
1292 /* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
1293 C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,
1294 /* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
1295 C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,C_UPPER
,
1296 /* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
1297 C_UPPER
,C_UPPER
,C_UPPER
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,
1298 /* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
1299 C_PUNCT
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,
1300 /* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
1301 C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,
1302 /* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
1303 C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,C_LOWER
,
1304 /* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
1305 C_LOWER
,C_LOWER
,C_LOWER
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_PUNCT
,C_CNTRL