[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Annotation of src/usr.bin/mail/tty.c, Revision 1.21

1.21    ! anton       1: /*     $OpenBSD: tty.c,v 1.20 2014/01/17 18:42:30 okan Exp $   */
1.3       millert     2: /*     $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $    */
1.2       deraadt     3:
1.1       deraadt     4: /*
                      5:  * Copyright (c) 1980, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.17      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Mail -- a mail program
                     35:  *
                     36:  * Generally useful tty stuff.
                     37:  */
                     38:
                     39: #include "rcv.h"
                     40: #include "extern.h"
1.2       deraadt    41: #include <sys/ioctl.h>
1.13      millert    42: #include <errno.h>
1.21    ! anton      43: #include <fcntl.h>
1.1       deraadt    44:
1.21    ! anton      45: #define        TABWIDTH        8
        !            46:
        !            47: struct tty {
        !            48:        int      fdin;
        !            49:        int      fdout;
        !            50:        int      flags;
        !            51: #define        TTY_ALTWERASE   0x1
        !            52: #define        TTY_ERR         0x2
        !            53:        cc_t    *keys;
        !            54:        char    *buf;
        !            55:        size_t   size;
        !            56:        size_t   len;
        !            57:        size_t   cursor;
        !            58: };
        !            59:
        !            60: static void    tty_flush(struct tty *);
        !            61: static int     tty_getc(struct tty *);
        !            62: static int     tty_insert(struct tty *, int, int);
        !            63: static void    tty_putc(struct tty *, int);
        !            64: static void    tty_reset(struct tty *);
        !            65: static void    tty_visc(struct tty *, int);
        !            66:
        !            67: static struct tty              tty;
1.13      millert    68: static volatile sig_atomic_t   ttysignal;      /* Interrupted by a signal? */
1.1       deraadt    69:
                     70: /*
                     71:  * Read all relevant header fields.
                     72:  */
                     73: int
1.14      millert    74: grabh(struct header *hp, int gflags)
1.1       deraadt    75: {
1.21    ! anton      76:        struct termios newtio, oldtio;
        !            77: #ifdef TIOCEXT
1.13      millert    78:        int extproc;
1.12      millert    79:        int flag;
1.1       deraadt    80: #endif
1.13      millert    81:        struct sigaction savetstp;
                     82:        struct sigaction savettou;
                     83:        struct sigaction savettin;
                     84:        struct sigaction act;
                     85:        char *s;
                     86:        int error;
                     87:
                     88:        sigemptyset(&act.sa_mask);
                     89:        act.sa_flags = SA_RESTART;
                     90:        act.sa_handler = SIG_DFL;
                     91:        (void)sigaction(SIGTSTP, &act, &savetstp);
                     92:        (void)sigaction(SIGTTOU, &act, &savettou);
                     93:        (void)sigaction(SIGTTIN, &act, &savettin);
                     94:        error = 1;
1.21    ! anton      95:        memset(&tty, 0, sizeof(tty));
        !            96:        tty.fdin = fileno(stdin);
        !            97:        tty.fdout = fileno(stdout);
        !            98:        if (tcgetattr(tty.fdin, &oldtio) < 0) {
1.3       millert    99:                warn("tcgetattr");
1.1       deraadt   100:                return(-1);
                    101:        }
1.21    ! anton     102:        tty.keys = oldtio.c_cc;
        !           103:        if (oldtio.c_lflag & ALTWERASE)
        !           104:                tty.flags |= TTY_ALTWERASE;
        !           105:
        !           106:        newtio = oldtio;
        !           107:        newtio.c_lflag &= ~(ECHO | ICANON);
        !           108:        newtio.c_cc[VMIN] = 1;
        !           109:        newtio.c_cc[VTIME] = 0;
        !           110:        if (tcsetattr(tty.fdin, TCSADRAIN, &newtio) < 0) {
        !           111:                warn("tcsetattr");
        !           112:                return(-1);
        !           113:        }
        !           114:
        !           115: #ifdef TIOCEXT
        !           116:        extproc = ((oldtio.c_lflag & EXTPROC) ? 1 : 0);
1.10      millert   117:        if (extproc) {
                    118:                flag = 0;
                    119:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    120:                        warn("TIOCEXT: off");
                    121:        }
1.1       deraadt   122: #endif
                    123:        if (gflags & GTO) {
1.13      millert   124:                s = readtty("To: ", detract(hp->h_to, 0));
                    125:                if (s == NULL)
                    126:                        goto out;
                    127:                hp->h_to = extract(s, GTO);
1.1       deraadt   128:        }
                    129:        if (gflags & GSUBJECT) {
1.13      millert   130:                s = readtty("Subject: ", hp->h_subject);
                    131:                if (s == NULL)
                    132:                        goto out;
                    133:                hp->h_subject = s;
1.1       deraadt   134:        }
                    135:        if (gflags & GCC) {
1.13      millert   136:                s = readtty("Cc: ", detract(hp->h_cc, 0));
                    137:                if (s == NULL)
                    138:                        goto out;
                    139:                hp->h_cc = extract(s, GCC);
1.1       deraadt   140:        }
                    141:        if (gflags & GBCC) {
1.13      millert   142:                s = readtty("Bcc: ", detract(hp->h_bcc, 0));
                    143:                if (s == NULL)
                    144:                        goto out;
                    145:                hp->h_bcc = extract(s, GBCC);
1.1       deraadt   146:        }
1.13      millert   147:        error = 0;
1.1       deraadt   148: out:
1.13      millert   149:        (void)sigaction(SIGTSTP, &savetstp, NULL);
                    150:        (void)sigaction(SIGTTOU, &savettou, NULL);
                    151:        (void)sigaction(SIGTTIN, &savettin, NULL);
1.21    ! anton     152: #ifdef TIOCEXT
1.10      millert   153:        if (extproc) {
                    154:                flag = 1;
                    155:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    156:                        warn("TIOCEXT: on");
                    157:        }
1.1       deraadt   158: #endif
1.21    ! anton     159:        if (tcsetattr(tty.fdin, TCSADRAIN, &oldtio) < 0)
        !           160:                warn("tcsetattr");
1.13      millert   161:        return(error);
1.1       deraadt   162: }
                    163:
                    164: /*
                    165:  * Read up a header from standard input.
                    166:  * The source string has the preliminary contents to
                    167:  * be read.
                    168:  *
                    169:  */
                    170: char *
1.14      millert   171: readtty(char *pr, char *src)
1.1       deraadt   172: {
1.16      millert   173:        struct sigaction act, saveint;
1.21    ! anton     174:        unsigned char canonb[BUFSIZ];
        !           175:        char *cp;
1.14      millert   176:        sigset_t oset;
1.21    ! anton     177:        int c, done;
        !           178:
        !           179:        memset(canonb, 0, sizeof(canonb));
        !           180:        tty.buf = canonb;
        !           181:        tty.size = sizeof(canonb) - 1;
        !           182:
        !           183:        for (cp = pr; *cp != '\0'; cp++)
        !           184:                tty_insert(&tty, *cp, 1);
        !           185:        tty_flush(&tty);
        !           186:        tty_reset(&tty);
1.1       deraadt   187:
1.18      millert   188:        if (src != NULL && strlen(src) > sizeof(canonb) - 2) {
1.3       millert   189:                puts("too long to edit");
1.1       deraadt   190:                return(src);
                    191:        }
1.21    ! anton     192:        if (src != NULL) {
        !           193:                for (cp = src; *cp != '\0'; cp++)
        !           194:                        tty_insert(&tty, *cp, 1);
        !           195:                tty_flush(&tty);
1.1       deraadt   196:        }
1.21    ! anton     197:
1.13      millert   198:        sigemptyset(&act.sa_mask);
                    199:        act.sa_flags = 0;               /* Note: will not restart syscalls */
                    200:        act.sa_handler = ttyint;
1.16      millert   201:        (void)sigaction(SIGINT, &act, &saveint);
1.13      millert   202:        act.sa_handler = ttystop;
                    203:        (void)sigaction(SIGTSTP, &act, NULL);
                    204:        (void)sigaction(SIGTTOU, &act, NULL);
                    205:        (void)sigaction(SIGTTIN, &act, NULL);
                    206:        (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
1.21    ! anton     207:        for (;;) {
        !           208:                c = tty_getc(&tty);
1.13      millert   209:                switch (ttysignal) {
                    210:                        case SIGINT:
1.21    ! anton     211:                                tty_visc(&tty, '\003'); /* output ^C */
1.13      millert   212:                                /* FALLTHROUGH */
                    213:                        case 0:
                    214:                                break;
                    215:                        default:
                    216:                                ttysignal = 0;
                    217:                                goto redo;
                    218:                }
1.21    ! anton     219:                if (c == 0) {
        !           220:                        done = 1;
        !           221:                } else if (c == '\n') {
        !           222:                        tty_putc(&tty, c);
        !           223:                        done = 1;
        !           224:                } else {
        !           225:                        done = tty_insert(&tty, c, 0);
        !           226:                        tty_flush(&tty);
        !           227:                }
        !           228:                if (done)
1.1       deraadt   229:                        break;
                    230:        }
1.13      millert   231:        act.sa_handler = SIG_DFL;
                    232:        sigemptyset(&act.sa_mask);
                    233:        act.sa_flags = SA_RESTART;
                    234:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    235:        (void)sigaction(SIGTSTP, &act, NULL);
                    236:        (void)sigaction(SIGTTOU, &act, NULL);
                    237:        (void)sigaction(SIGTTIN, &act, NULL);
1.16      millert   238:        (void)sigaction(SIGINT, &saveint, NULL);
1.21    ! anton     239:        if (tty.flags & TTY_ERR) {
        !           240:                if (ttysignal == SIGINT) {
        !           241:                        ttysignal = 0;
        !           242:                        return(NULL);   /* user hit ^C */
        !           243:                }
        !           244:
1.1       deraadt   245: redo:
1.5       millert   246:                cp = strlen(canonb) > 0 ? canonb : NULL;
1.13      millert   247:                /* XXX - make iterative, not recursive */
1.1       deraadt   248:                return(readtty(pr, cp));
                    249:        }
                    250:        if (equal("", canonb))
1.13      millert   251:                return("");
1.1       deraadt   252:        return(savestr(canonb));
                    253: }
                    254:
                    255: /*
                    256:  * Receipt continuation.
                    257:  */
                    258: void
1.14      millert   259: ttystop(int s)
1.1       deraadt   260: {
1.13      millert   261:        struct sigaction act, oact;
1.2       deraadt   262:        sigset_t nset;
1.13      millert   263:        int save_errno;
1.1       deraadt   264:
1.13      millert   265:        /*
                    266:         * Save old handler and set to default.
                    267:         * Unblock receipt of 's' and then resend it.
                    268:         */
                    269:        save_errno = errno;
                    270:        (void)sigemptyset(&act.sa_mask);
                    271:        act.sa_flags = SA_RESTART;
                    272:        act.sa_handler = SIG_DFL;
                    273:        (void)sigaction(s, &act, &oact);
1.8       millert   274:        (void)sigemptyset(&nset);
                    275:        (void)sigaddset(&nset, s);
                    276:        (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
                    277:        (void)kill(0, s);
                    278:        (void)sigprocmask(SIG_BLOCK, &nset, NULL);
1.13      millert   279:        (void)sigaction(s, &oact, NULL);
                    280:        ttysignal = s;
                    281:        errno = save_errno;
1.1       deraadt   282: }
                    283:
                    284: /*ARGSUSED*/
                    285: void
1.14      millert   286: ttyint(int s)
1.1       deraadt   287: {
1.13      millert   288:
                    289:        ttysignal = s;
1.21    ! anton     290: }
        !           291:
        !           292: static void
        !           293: tty_flush(struct tty *t)
        !           294: {
        !           295:        size_t  i, len;
        !           296:        int     c;
        !           297:
        !           298:        if (t->cursor < t->len) {
        !           299:                for (; t->cursor < t->len; t->cursor++)
        !           300:                        tty_visc(t, t->buf[t->cursor]);
        !           301:        } else if (t->cursor > t->len) {
        !           302:                len = t->cursor - t->len;
        !           303:                for (i = len; i > 0; i--) {
        !           304:                        c = t->buf[--t->cursor];
        !           305:                        if (c == '\t')
        !           306:                                len += TABWIDTH - 1;
        !           307:                        else if (iscntrl(c))
        !           308:                                len++;  /* account for leading ^ */
        !           309:                }
        !           310:                for (i = 0; i < len; i++)
        !           311:                        tty_putc(t, '\b');
        !           312:                for (i = 0; i < len; i++)
        !           313:                        tty_putc(t, ' ');
        !           314:                for (i = 0; i < len; i++)
        !           315:                        tty_putc(t, '\b');
        !           316:                t->cursor = t->len;
        !           317:        }
        !           318:
        !           319:        t->buf[t->len] = '\0';
        !           320: }
        !           321:
        !           322: static int
        !           323: tty_getc(struct tty *t)
        !           324: {
        !           325:        ssize_t         n;
        !           326:        unsigned char   c;
        !           327:
        !           328:        n = read(t->fdin, &c, 1);
        !           329:        switch (n) {
        !           330:        case -1:
        !           331:                t->flags |= TTY_ERR;
        !           332:                /* FALLTHROUGH */
        !           333:        case 0:
        !           334:                return 0;
        !           335:        default:
        !           336:                return c & 0x7f;
        !           337:        }
        !           338: }
        !           339:
        !           340: static int
        !           341: tty_insert(struct tty *t, int c, int nocntrl)
        !           342: {
        !           343:        const unsigned char     *ws = " \t";
        !           344:
        !           345:        if (CCEQ(t->keys[VERASE], c)) {
        !           346:                if (nocntrl)
        !           347:                        return 0;
        !           348:                if (t->len > 0)
        !           349:                        t->len--;
        !           350:        } else if (CCEQ(t->keys[VWERASE], c)) {
        !           351:                if (nocntrl)
        !           352:                        return 0;
        !           353:                for (; t->len > 0; t->len--)
        !           354:                        if (strchr(ws, t->buf[t->len - 1]) == NULL
        !           355:                            && ((t->flags & TTY_ALTWERASE) == 0
        !           356:                                    || isalpha(t->buf[t->len - 1])))
        !           357:                                break;
        !           358:                for (; t->len > 0; t->len--)
        !           359:                        if (strchr(ws, t->buf[t->len - 1]) != NULL
        !           360:                            || ((t->flags & TTY_ALTWERASE)
        !           361:                                    && !isalpha(t->buf[t->len - 1])))
        !           362:                                break;
        !           363:        } else if (CCEQ(t->keys[VKILL], c)) {
        !           364:                if (nocntrl)
        !           365:                        return 0;
        !           366:                t->len = 0;
        !           367:        } else {
        !           368:                if (t->len == t->size)
        !           369:                        return 1;
        !           370:                t->buf[t->len++] = c;
        !           371:        }
        !           372:
        !           373:        return 0;
        !           374: }
        !           375:
        !           376: static void
        !           377: tty_putc(struct tty *t, int c)
        !           378: {
        !           379:        unsigned char   cc = c;
        !           380:
        !           381:        write(t->fdout, &cc, 1);
        !           382: }
        !           383:
        !           384: static void
        !           385: tty_reset(struct tty *t)
        !           386: {
        !           387:        memset(t->buf, 0, t->len);
        !           388:        t->len = t->cursor = 0;
        !           389: }
        !           390:
        !           391: static void
        !           392: tty_visc(struct tty *t, int c)
        !           393: {
        !           394:        int     i;
        !           395:
        !           396:        if (c == '\t') {
        !           397:                for (i = 0; i < TABWIDTH; i++)
        !           398:                        tty_putc(t, ' ');
        !           399:        } else if (iscntrl(c)) {
        !           400:                tty_putc(t, '^');
        !           401:                if (c == 0x7F)
        !           402:                        tty_putc(t, '?');
        !           403:                else
        !           404:                        tty_putc(t, (c | 0x40));
        !           405:        } else {
        !           406:                tty_putc(t, c);
        !           407:        }
1.1       deraadt   408: }