[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.20

1.20    ! okan        1: /*     $OpenBSD: tty.c,v 1.19 2009/10/27 23:59:40 deraadt 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.1       deraadt    43:
1.5       millert    44: static cc_t            c_erase;        /* Current erase char */
                     45: static cc_t            c_kill;         /* Current kill char */
1.1       deraadt    46: #ifndef TIOCSTI
1.5       millert    47: static int             ttyset;         /* We must now do erase/kill */
1.1       deraadt    48: #endif
1.13      millert    49: static volatile sig_atomic_t   ttysignal;      /* Interrupted by a signal? */
1.1       deraadt    50:
                     51: /*
                     52:  * Read all relevant header fields.
                     53:  */
                     54: int
1.14      millert    55: grabh(struct header *hp, int gflags)
1.1       deraadt    56: {
                     57:        struct termios ttybuf;
                     58: #ifndef TIOCSTI
1.13      millert    59:        struct sigaction savequit;
1.10      millert    60: #else
                     61: # ifdef        TIOCEXT
1.13      millert    62:        int extproc;
1.12      millert    63:        int flag;
                     64: # endif /* TIOCEXT */
1.1       deraadt    65: #endif
1.13      millert    66:        struct sigaction savetstp;
                     67:        struct sigaction savettou;
                     68:        struct sigaction savettin;
                     69:        struct sigaction act;
                     70:        char *s;
                     71:        int error;
                     72:
                     73:        sigemptyset(&act.sa_mask);
                     74:        act.sa_flags = SA_RESTART;
                     75:        act.sa_handler = SIG_DFL;
                     76:        (void)sigaction(SIGTSTP, &act, &savetstp);
                     77:        (void)sigaction(SIGTTOU, &act, &savettou);
                     78:        (void)sigaction(SIGTTIN, &act, &savettin);
                     79:        error = 1;
1.1       deraadt    80: #ifndef TIOCSTI
                     81:        ttyset = 0;
                     82: #endif
                     83:        if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
1.3       millert    84:                warn("tcgetattr");
1.1       deraadt    85:                return(-1);
                     86:        }
                     87:        c_erase = ttybuf.c_cc[VERASE];
                     88:        c_kill = ttybuf.c_cc[VKILL];
                     89: #ifndef TIOCSTI
                     90:        ttybuf.c_cc[VERASE] = 0;
                     91:        ttybuf.c_cc[VKILL] = 0;
1.13      millert    92:        act.sa_handler = SIG_IGN;
                     93:        if (sigaction(SIGQUIT, &act, &savequit) == 0 &&
                     94:            savequit.sa_handler == SIG_DFL)
                     95:                (void)sigaction(SIGQUIT, &savequit, NULL);
1.1       deraadt    96: #else
1.10      millert    97: # ifdef        TIOCEXT
                     98:        extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
                     99:        if (extproc) {
                    100:                flag = 0;
                    101:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    102:                        warn("TIOCEXT: off");
                    103:        }
                    104: # endif /* TIOCEXT */
1.1       deraadt   105: #endif
                    106:        if (gflags & GTO) {
                    107: #ifndef TIOCSTI
1.14      millert   108:                if (!ttyset && hp->h_to != NULL)
1.1       deraadt   109:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    110: #endif
1.13      millert   111:                s = readtty("To: ", detract(hp->h_to, 0));
                    112:                if (s == NULL)
                    113:                        goto out;
                    114:                hp->h_to = extract(s, GTO);
1.1       deraadt   115:        }
                    116:        if (gflags & GSUBJECT) {
                    117: #ifndef TIOCSTI
1.5       millert   118:                if (!ttyset && hp->h_subject != NULL)
1.1       deraadt   119:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    120: #endif
1.13      millert   121:                s = readtty("Subject: ", hp->h_subject);
                    122:                if (s == NULL)
                    123:                        goto out;
                    124:                hp->h_subject = s;
1.1       deraadt   125:        }
                    126:        if (gflags & GCC) {
                    127: #ifndef TIOCSTI
1.14      millert   128:                if (!ttyset && hp->h_cc != NULL)
1.1       deraadt   129:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    130: #endif
1.13      millert   131:                s = readtty("Cc: ", detract(hp->h_cc, 0));
                    132:                if (s == NULL)
                    133:                        goto out;
                    134:                hp->h_cc = extract(s, GCC);
1.1       deraadt   135:        }
                    136:        if (gflags & GBCC) {
                    137: #ifndef TIOCSTI
1.14      millert   138:                if (!ttyset && hp->h_bcc != NULL)
1.1       deraadt   139:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    140: #endif
1.13      millert   141:                s = readtty("Bcc: ", detract(hp->h_bcc, 0));
                    142:                if (s == NULL)
                    143:                        goto out;
                    144:                hp->h_bcc = extract(s, GBCC);
1.1       deraadt   145:        }
1.13      millert   146:        error = 0;
1.1       deraadt   147: out:
1.13      millert   148:        (void)sigaction(SIGTSTP, &savetstp, NULL);
                    149:        (void)sigaction(SIGTTOU, &savettou, NULL);
                    150:        (void)sigaction(SIGTTIN, &savettin, NULL);
1.1       deraadt   151: #ifndef TIOCSTI
                    152:        ttybuf.c_cc[VERASE] = c_erase;
                    153:        ttybuf.c_cc[VKILL] = c_kill;
                    154:        if (ttyset)
                    155:                tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1.13      millert   156:        (void)sigaction(SIGQUIT, &savequit, NULL);
1.10      millert   157: #else
                    158: # ifdef        TIOCEXT
                    159:        if (extproc) {
                    160:                flag = 1;
                    161:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    162:                        warn("TIOCEXT: on");
                    163:        }
                    164: # endif /* TIOCEXT */
1.1       deraadt   165: #endif
1.13      millert   166:        return(error);
1.1       deraadt   167: }
                    168:
                    169: /*
                    170:  * Read up a header from standard input.
                    171:  * The source string has the preliminary contents to
                    172:  * be read.
                    173:  *
                    174:  */
                    175: char *
1.14      millert   176: readtty(char *pr, char *src)
1.1       deraadt   177: {
1.16      millert   178:        struct sigaction act, saveint;
1.1       deraadt   179:        char ch, canonb[BUFSIZ];
1.13      millert   180:        char *cp, *cp2;
1.14      millert   181:        sigset_t oset;
1.13      millert   182:        int c;
1.1       deraadt   183:
                    184:        fputs(pr, stdout);
                    185:        fflush(stdout);
1.18      millert   186:        if (src != NULL && strlen(src) > sizeof(canonb) - 2) {
1.3       millert   187:                puts("too long to edit");
1.1       deraadt   188:                return(src);
                    189:        }
                    190: #ifndef TIOCSTI
1.5       millert   191:        if (src != NULL)
1.15      millert   192:                cp = copy(src, canonb); /* safe, bounds checked above */
1.1       deraadt   193:        else
                    194:                cp = copy("", canonb);
                    195:        fputs(canonb, stdout);
                    196:        fflush(stdout);
                    197: #else
1.5       millert   198:        cp = src == NULL ? "" : src;
1.20    ! okan      199:        while ((c = (unsigned char)*cp++) != '\0') {
1.1       deraadt   200:                if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
                    201:                    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
                    202:                        ch = '\\';
                    203:                        ioctl(0, TIOCSTI, &ch);
                    204:                }
                    205:                ch = c;
                    206:                ioctl(0, TIOCSTI, &ch);
                    207:        }
                    208:        cp = canonb;
                    209:        *cp = 0;
                    210: #endif
1.13      millert   211:        sigemptyset(&act.sa_mask);
                    212:        act.sa_flags = 0;               /* Note: will not restart syscalls */
                    213:        act.sa_handler = ttyint;
1.16      millert   214:        (void)sigaction(SIGINT, &act, &saveint);
1.13      millert   215:        act.sa_handler = ttystop;
                    216:        (void)sigaction(SIGTSTP, &act, NULL);
                    217:        (void)sigaction(SIGTTOU, &act, NULL);
                    218:        (void)sigaction(SIGTTIN, &act, NULL);
                    219:        (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
1.1       deraadt   220:        clearerr(stdin);
1.18      millert   221:        memset(cp, 0, canonb + sizeof(canonb) - cp);
                    222:        for (cp2 = cp; cp2 < canonb + sizeof(canonb) - 1; ) {
1.1       deraadt   223:                c = getc(stdin);
1.13      millert   224:                switch (ttysignal) {
                    225:                        case SIGINT:
                    226:                                ttysignal = 0;
                    227:                                cp2 = NULL;
                    228:                                c = EOF;
                    229:                                /* FALLTHROUGH */
                    230:                        case 0:
                    231:                                break;
                    232:                        default:
                    233:                                ttysignal = 0;
                    234:                                goto redo;
                    235:                }
1.1       deraadt   236:                if (c == EOF || c == '\n')
                    237:                        break;
                    238:                *cp2++ = c;
                    239:        }
1.13      millert   240:        act.sa_handler = SIG_DFL;
                    241:        sigemptyset(&act.sa_mask);
                    242:        act.sa_flags = SA_RESTART;
                    243:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    244:        (void)sigaction(SIGTSTP, &act, NULL);
                    245:        (void)sigaction(SIGTTOU, &act, NULL);
                    246:        (void)sigaction(SIGTTIN, &act, NULL);
1.16      millert   247:        (void)sigaction(SIGINT, &saveint, NULL);
1.13      millert   248:        if (cp2 == NULL)
                    249:                return(NULL);                   /* user hit ^C */
                    250:        *cp2 = '\0';
1.1       deraadt   251:        if (c == EOF && ferror(stdin)) {
                    252: redo:
1.5       millert   253:                cp = strlen(canonb) > 0 ? canonb : NULL;
1.1       deraadt   254:                clearerr(stdin);
1.13      millert   255:                /* XXX - make iterative, not recursive */
1.1       deraadt   256:                return(readtty(pr, cp));
                    257:        }
                    258: #ifndef TIOCSTI
1.5       millert   259:        if (cp == NULL || *cp == '\0')
1.1       deraadt   260:                return(src);
                    261:        cp2 = cp;
                    262:        if (!ttyset)
1.5       millert   263:                return(strlen(canonb) > 0 ? savestr(canonb) : NULL);
1.1       deraadt   264:        while (*cp != '\0') {
1.20    ! okan      265:                c = (unsigned char)*cp++;
1.1       deraadt   266:                if (c_erase != _POSIX_VDISABLE && c == c_erase) {
                    267:                        if (cp2 == canonb)
                    268:                                continue;
                    269:                        if (cp2[-1] == '\\') {
                    270:                                cp2[-1] = c;
                    271:                                continue;
                    272:                        }
                    273:                        cp2--;
                    274:                        continue;
                    275:                }
                    276:                if (c_kill != _POSIX_VDISABLE && c == c_kill) {
                    277:                        if (cp2 == canonb)
                    278:                                continue;
                    279:                        if (cp2[-1] == '\\') {
                    280:                                cp2[-1] = c;
                    281:                                continue;
                    282:                        }
                    283:                        cp2 = canonb;
                    284:                        continue;
                    285:                }
                    286:                *cp2++ = c;
                    287:        }
                    288:        *cp2 = '\0';
                    289: #endif
                    290:        if (equal("", canonb))
1.13      millert   291:                return("");
1.1       deraadt   292:        return(savestr(canonb));
                    293: }
                    294:
                    295: /*
                    296:  * Receipt continuation.
                    297:  */
                    298: void
1.14      millert   299: ttystop(int s)
1.1       deraadt   300: {
1.13      millert   301:        struct sigaction act, oact;
1.2       deraadt   302:        sigset_t nset;
1.13      millert   303:        int save_errno;
1.1       deraadt   304:
1.13      millert   305:        /*
                    306:         * Save old handler and set to default.
                    307:         * Unblock receipt of 's' and then resend it.
                    308:         */
                    309:        save_errno = errno;
                    310:        (void)sigemptyset(&act.sa_mask);
                    311:        act.sa_flags = SA_RESTART;
                    312:        act.sa_handler = SIG_DFL;
                    313:        (void)sigaction(s, &act, &oact);
1.8       millert   314:        (void)sigemptyset(&nset);
                    315:        (void)sigaddset(&nset, s);
                    316:        (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
                    317:        (void)kill(0, s);
                    318:        (void)sigprocmask(SIG_BLOCK, &nset, NULL);
1.13      millert   319:        (void)sigaction(s, &oact, NULL);
                    320:        ttysignal = s;
                    321:        errno = save_errno;
1.1       deraadt   322: }
                    323:
                    324: /*ARGSUSED*/
                    325: void
1.14      millert   326: ttyint(int s)
1.1       deraadt   327: {
1.13      millert   328:
                    329:        ttysignal = s;
1.1       deraadt   330: }