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

1.16    ! millert     1: /*     $OpenBSD: tty.c,v 1.15 2001/11/21 20:41:56 millert 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.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
1.2       deraadt    38: #if 0
1.14      millert    39: static const char sccsid[] = "@(#)tty.c        8.2 (Berkeley) 4/20/95";
1.2       deraadt    40: #else
1.16    ! millert    41: static const char rcsid[] = "$OpenBSD: tty.c,v 1.15 2001/11/21 20:41:56 millert Exp $";
1.2       deraadt    42: #endif
1.1       deraadt    43: #endif /* not lint */
                     44:
                     45: /*
                     46:  * Mail -- a mail program
                     47:  *
                     48:  * Generally useful tty stuff.
                     49:  */
                     50:
                     51: #include "rcv.h"
                     52: #include "extern.h"
1.2       deraadt    53: #include <sys/ioctl.h>
1.13      millert    54: #include <errno.h>
1.1       deraadt    55:
1.5       millert    56: static cc_t            c_erase;        /* Current erase char */
                     57: static cc_t            c_kill;         /* Current kill char */
1.1       deraadt    58: #ifndef TIOCSTI
1.5       millert    59: static int             ttyset;         /* We must now do erase/kill */
1.1       deraadt    60: #endif
1.13      millert    61: static volatile sig_atomic_t   ttysignal;      /* Interrupted by a signal? */
1.1       deraadt    62:
                     63: /*
                     64:  * Read all relevant header fields.
                     65:  */
                     66: int
1.14      millert    67: grabh(struct header *hp, int gflags)
1.1       deraadt    68: {
                     69:        struct termios ttybuf;
                     70: #ifndef TIOCSTI
1.13      millert    71:        struct sigaction savequit;
1.10      millert    72: #else
                     73: # ifdef        TIOCEXT
1.13      millert    74:        int extproc;
1.12      millert    75:        int flag;
                     76: # endif /* TIOCEXT */
1.1       deraadt    77: #endif
1.13      millert    78:        struct sigaction savetstp;
                     79:        struct sigaction savettou;
                     80:        struct sigaction savettin;
                     81:        struct sigaction act;
                     82:        char *s;
                     83:        int error;
                     84:
                     85:        sigemptyset(&act.sa_mask);
                     86:        act.sa_flags = SA_RESTART;
                     87:        act.sa_handler = SIG_DFL;
                     88:        (void)sigaction(SIGTSTP, &act, &savetstp);
                     89:        (void)sigaction(SIGTTOU, &act, &savettou);
                     90:        (void)sigaction(SIGTTIN, &act, &savettin);
                     91:        error = 1;
1.1       deraadt    92: #ifndef TIOCSTI
                     93:        ttyset = 0;
                     94: #endif
                     95:        if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
1.3       millert    96:                warn("tcgetattr");
1.1       deraadt    97:                return(-1);
                     98:        }
                     99:        c_erase = ttybuf.c_cc[VERASE];
                    100:        c_kill = ttybuf.c_cc[VKILL];
                    101: #ifndef TIOCSTI
                    102:        ttybuf.c_cc[VERASE] = 0;
                    103:        ttybuf.c_cc[VKILL] = 0;
1.13      millert   104:        act.sa_handler = SIG_IGN;
                    105:        if (sigaction(SIGQUIT, &act, &savequit) == 0 &&
                    106:            savequit.sa_handler == SIG_DFL)
                    107:                (void)sigaction(SIGQUIT, &savequit, NULL);
1.1       deraadt   108: #else
1.10      millert   109: # ifdef        TIOCEXT
                    110:        extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
                    111:        if (extproc) {
                    112:                flag = 0;
                    113:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    114:                        warn("TIOCEXT: off");
                    115:        }
                    116: # endif /* TIOCEXT */
1.1       deraadt   117: #endif
                    118:        if (gflags & GTO) {
                    119: #ifndef TIOCSTI
1.14      millert   120:                if (!ttyset && hp->h_to != NULL)
1.1       deraadt   121:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    122: #endif
1.13      millert   123:                s = readtty("To: ", detract(hp->h_to, 0));
                    124:                if (s == NULL)
                    125:                        goto out;
                    126:                hp->h_to = extract(s, GTO);
1.1       deraadt   127:        }
                    128:        if (gflags & GSUBJECT) {
                    129: #ifndef TIOCSTI
1.5       millert   130:                if (!ttyset && hp->h_subject != NULL)
1.1       deraadt   131:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    132: #endif
1.13      millert   133:                s = readtty("Subject: ", hp->h_subject);
                    134:                if (s == NULL)
                    135:                        goto out;
                    136:                hp->h_subject = s;
1.1       deraadt   137:        }
                    138:        if (gflags & GCC) {
                    139: #ifndef TIOCSTI
1.14      millert   140:                if (!ttyset && hp->h_cc != NULL)
1.1       deraadt   141:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    142: #endif
1.13      millert   143:                s = readtty("Cc: ", detract(hp->h_cc, 0));
                    144:                if (s == NULL)
                    145:                        goto out;
                    146:                hp->h_cc = extract(s, GCC);
1.1       deraadt   147:        }
                    148:        if (gflags & GBCC) {
                    149: #ifndef TIOCSTI
1.14      millert   150:                if (!ttyset && hp->h_bcc != NULL)
1.1       deraadt   151:                        ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
                    152: #endif
1.13      millert   153:                s = readtty("Bcc: ", detract(hp->h_bcc, 0));
                    154:                if (s == NULL)
                    155:                        goto out;
                    156:                hp->h_bcc = extract(s, GBCC);
1.1       deraadt   157:        }
1.13      millert   158:        error = 0;
1.1       deraadt   159: out:
1.13      millert   160:        (void)sigaction(SIGTSTP, &savetstp, NULL);
                    161:        (void)sigaction(SIGTTOU, &savettou, NULL);
                    162:        (void)sigaction(SIGTTIN, &savettin, NULL);
1.1       deraadt   163: #ifndef TIOCSTI
                    164:        ttybuf.c_cc[VERASE] = c_erase;
                    165:        ttybuf.c_cc[VKILL] = c_kill;
                    166:        if (ttyset)
                    167:                tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1.13      millert   168:        (void)sigaction(SIGQUIT, &savequit, NULL);
1.10      millert   169: #else
                    170: # ifdef        TIOCEXT
                    171:        if (extproc) {
                    172:                flag = 1;
                    173:                if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                    174:                        warn("TIOCEXT: on");
                    175:        }
                    176: # endif /* TIOCEXT */
1.1       deraadt   177: #endif
1.13      millert   178:        return(error);
1.1       deraadt   179: }
                    180:
                    181: /*
                    182:  * Read up a header from standard input.
                    183:  * The source string has the preliminary contents to
                    184:  * be read.
                    185:  *
                    186:  */
                    187: char *
1.14      millert   188: readtty(char *pr, char *src)
1.1       deraadt   189: {
1.16    ! millert   190:        struct sigaction act, saveint;
1.1       deraadt   191:        char ch, canonb[BUFSIZ];
1.13      millert   192:        char *cp, *cp2;
1.14      millert   193:        sigset_t oset;
1.13      millert   194:        int c;
1.1       deraadt   195:
                    196:        fputs(pr, stdout);
                    197:        fflush(stdout);
1.5       millert   198:        if (src != NULL && strlen(src) > BUFSIZ - 2) {
1.3       millert   199:                puts("too long to edit");
1.1       deraadt   200:                return(src);
                    201:        }
                    202: #ifndef TIOCSTI
1.5       millert   203:        if (src != NULL)
1.15      millert   204:                cp = copy(src, canonb); /* safe, bounds checked above */
1.1       deraadt   205:        else
                    206:                cp = copy("", canonb);
                    207:        fputs(canonb, stdout);
                    208:        fflush(stdout);
                    209: #else
1.5       millert   210:        cp = src == NULL ? "" : src;
1.2       deraadt   211:        while ((c = *cp++) != '\0') {
1.1       deraadt   212:                if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
                    213:                    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
                    214:                        ch = '\\';
                    215:                        ioctl(0, TIOCSTI, &ch);
                    216:                }
                    217:                ch = c;
                    218:                ioctl(0, TIOCSTI, &ch);
                    219:        }
                    220:        cp = canonb;
                    221:        *cp = 0;
                    222: #endif
                    223:        cp2 = cp;
                    224:        while (cp2 < canonb + BUFSIZ)
                    225:                *cp2++ = 0;
                    226:        cp2 = cp;
1.13      millert   227:        sigemptyset(&act.sa_mask);
                    228:        act.sa_flags = 0;               /* Note: will not restart syscalls */
                    229:        act.sa_handler = ttyint;
1.16    ! millert   230:        (void)sigaction(SIGINT, &act, &saveint);
1.13      millert   231:        act.sa_handler = ttystop;
                    232:        (void)sigaction(SIGTSTP, &act, NULL);
                    233:        (void)sigaction(SIGTTOU, &act, NULL);
                    234:        (void)sigaction(SIGTTIN, &act, NULL);
                    235:        (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
1.1       deraadt   236:        clearerr(stdin);
                    237:        while (cp2 < canonb + BUFSIZ) {
                    238:                c = getc(stdin);
1.13      millert   239:                switch (ttysignal) {
                    240:                        case SIGINT:
                    241:                                ttysignal = 0;
                    242:                                cp2 = NULL;
                    243:                                c = EOF;
                    244:                                /* FALLTHROUGH */
                    245:                        case 0:
                    246:                                break;
                    247:                        default:
                    248:                                ttysignal = 0;
                    249:                                goto redo;
                    250:                }
1.1       deraadt   251:                if (c == EOF || c == '\n')
                    252:                        break;
                    253:                *cp2++ = c;
                    254:        }
1.13      millert   255:        act.sa_handler = SIG_DFL;
                    256:        sigemptyset(&act.sa_mask);
                    257:        act.sa_flags = SA_RESTART;
                    258:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    259:        (void)sigaction(SIGTSTP, &act, NULL);
                    260:        (void)sigaction(SIGTTOU, &act, NULL);
                    261:        (void)sigaction(SIGTTIN, &act, NULL);
1.16    ! millert   262:        (void)sigaction(SIGINT, &saveint, NULL);
1.13      millert   263:        if (cp2 == NULL)
                    264:                return(NULL);                   /* user hit ^C */
                    265:        *cp2 = '\0';
1.1       deraadt   266:        if (c == EOF && ferror(stdin)) {
                    267: redo:
1.5       millert   268:                cp = strlen(canonb) > 0 ? canonb : NULL;
1.1       deraadt   269:                clearerr(stdin);
1.13      millert   270:                /* XXX - make iterative, not recursive */
1.1       deraadt   271:                return(readtty(pr, cp));
                    272:        }
                    273: #ifndef TIOCSTI
1.5       millert   274:        if (cp == NULL || *cp == '\0')
1.1       deraadt   275:                return(src);
                    276:        cp2 = cp;
                    277:        if (!ttyset)
1.5       millert   278:                return(strlen(canonb) > 0 ? savestr(canonb) : NULL);
1.1       deraadt   279:        while (*cp != '\0') {
                    280:                c = *cp++;
                    281:                if (c_erase != _POSIX_VDISABLE && c == c_erase) {
                    282:                        if (cp2 == canonb)
                    283:                                continue;
                    284:                        if (cp2[-1] == '\\') {
                    285:                                cp2[-1] = c;
                    286:                                continue;
                    287:                        }
                    288:                        cp2--;
                    289:                        continue;
                    290:                }
                    291:                if (c_kill != _POSIX_VDISABLE && c == c_kill) {
                    292:                        if (cp2 == canonb)
                    293:                                continue;
                    294:                        if (cp2[-1] == '\\') {
                    295:                                cp2[-1] = c;
                    296:                                continue;
                    297:                        }
                    298:                        cp2 = canonb;
                    299:                        continue;
                    300:                }
                    301:                *cp2++ = c;
                    302:        }
                    303:        *cp2 = '\0';
                    304: #endif
                    305:        if (equal("", canonb))
1.13      millert   306:                return("");
1.1       deraadt   307:        return(savestr(canonb));
                    308: }
                    309:
                    310: /*
                    311:  * Receipt continuation.
                    312:  */
                    313: void
1.14      millert   314: ttystop(int s)
1.1       deraadt   315: {
1.13      millert   316:        struct sigaction act, oact;
1.2       deraadt   317:        sigset_t nset;
1.13      millert   318:        int save_errno;
1.1       deraadt   319:
1.13      millert   320:        /*
                    321:         * Save old handler and set to default.
                    322:         * Unblock receipt of 's' and then resend it.
                    323:         */
                    324:        save_errno = errno;
                    325:        (void)sigemptyset(&act.sa_mask);
                    326:        act.sa_flags = SA_RESTART;
                    327:        act.sa_handler = SIG_DFL;
                    328:        (void)sigaction(s, &act, &oact);
1.8       millert   329:        (void)sigemptyset(&nset);
                    330:        (void)sigaddset(&nset, s);
                    331:        (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
                    332:        (void)kill(0, s);
                    333:        (void)sigprocmask(SIG_BLOCK, &nset, NULL);
1.13      millert   334:        (void)sigaction(s, &oact, NULL);
                    335:        ttysignal = s;
                    336:        errno = save_errno;
1.1       deraadt   337: }
                    338:
                    339: /*ARGSUSED*/
                    340: void
1.14      millert   341: ttyint(int s)
1.1       deraadt   342: {
1.13      millert   343:
                    344:        ttysignal = s;
1.1       deraadt   345: }