1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if !defined(lint) && defined(DOSCCS) 35: static char sccsid[] = "@(#)tty.c 5.12 (Berkeley) 4/1/91"; 36: #endif 37: 38: /* 39: * Mail -- a mail program 40: * 41: * Generally useful tty stuff. 42: */ 43: 44: #include "rcv.h" 45: 46: static int c_erase; /* Current erase char */ 47: static int c_kill; /* Current kill char */ 48: static jmp_buf rewrite; /* Place to go when continued */ 49: static jmp_buf intjmp; /* Place to go when interrupted */ 50: #ifndef TIOCSTI 51: static int ttyset; /* We must now do erase/kill */ 52: #endif 53: 54: /* 55: * Read all relevant header fields. 56: */ 57: 58: grabh(hp, gflags) 59: struct header *hp; 60: { 61: struct sgttyb ttybuf; 62: sig_t saveint; 63: #ifndef TIOCSTI 64: sig_t savequit; 65: #endif 66: sig_t savetstp; 67: sig_t savettou; 68: sig_t savettin; 69: int errs; 70: void ttyint(); 71: 72: savetstp = signal(SIGTSTP, SIG_DFL); 73: savettou = signal(SIGTTOU, SIG_DFL); 74: savettin = signal(SIGTTIN, SIG_DFL); 75: errs = 0; 76: #ifndef TIOCSTI 77: ttyset = 0; 78: #endif 79: if (ioctl(fileno(stdin), TIOCGETP, &ttybuf) < 0) { 80: perror("gtty"); 81: return(-1); 82: } 83: c_erase = ttybuf.sg_erase; 84: c_kill = ttybuf.sg_kill; 85: #ifndef TIOCSTI 86: ttybuf.sg_erase = 0; 87: ttybuf.sg_kill = 0; 88: if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) 89: signal(SIGINT, SIG_DFL); 90: if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) 91: signal(SIGQUIT, SIG_DFL); 92: #else 93: if (setjmp(intjmp)) 94: goto out; 95: saveint = signal(SIGINT, ttyint); 96: #endif 97: if (gflags & GTO) { 98: #ifndef TIOCSTI 99: if (!ttyset && hp->h_to != NIL) 100: ttyset++, stty(fileno(stdin), &ttybuf); 101: #endif 102: hp->h_to = 103: extract(readtty("To: ", detract(hp->h_to, 0)), GTO); 104: } 105: if (gflags & GSUBJECT) { 106: #ifndef TIOCSTI 107: if (!ttyset && hp->h_subject != NOSTR) 108: ttyset++, stty(fileno(stdin), &ttybuf); 109: #endif 110: hp->h_subject = readtty("Subject: ", hp->h_subject); 111: } 112: if (gflags & GCC) { 113: #ifndef TIOCSTI 114: if (!ttyset && hp->h_cc != NIL) 115: ttyset++, stty(fileno(stdin), &ttybuf); 116: #endif 117: hp->h_cc = 118: extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); 119: } 120: if (gflags & GBCC) { 121: #ifndef TIOCSTI 122: if (!ttyset && hp->h_bcc != NIL) 123: ttyset++, stty(fileno(stdin), &ttybuf); 124: #endif 125: hp->h_bcc = 126: extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); 127: } 128: out: 129: signal(SIGTSTP, savetstp); 130: signal(SIGTTOU, savettou); 131: signal(SIGTTIN, savettin); 132: #ifndef TIOCSTI 133: ttybuf.sg_erase = c_erase; 134: ttybuf.sg_kill = c_kill; 135: if (ttyset) 136: stty(fileno(stdin), &ttybuf); 137: signal(SIGQUIT, savequit); 138: #endif 139: signal(SIGINT, saveint); 140: return(errs); 141: } 142: 143: /* 144: * Read up a header from standard input. 145: * The source string has the preliminary contents to 146: * be read. 147: * 148: */ 149: 150: char * 151: readtty(pr, src) 152: char pr[], src[]; 153: { 154: char ch, canonb[BUFSIZ]; 155: int c; 156: register char *cp, *cp2; 157: void ttystop(); 158: 159: fputs(pr, stdout); 160: fflush(stdout); 161: if (src != NOSTR && strlen(src) > BUFSIZ - 2) { 162: printf("too long to edit\n"); 163: return(src); 164: } 165: #ifndef TIOCSTI 166: if (src != NOSTR) 167: cp = copy(src, canonb); 168: else 169: cp = copy("", canonb); 170: fputs(canonb, stdout); 171: fflush(stdout); 172: #else 173: cp = src == NOSTR ? "" : src; 174: while (c = *cp++) { 175: if (c == c_erase || c == c_kill) { 176: ch = '\\'; 177: ioctl(0, TIOCSTI, &ch); 178: } 179: ch = c; 180: ioctl(0, TIOCSTI, &ch); 181: } 182: cp = canonb; 183: *cp = 0; 184: #endif 185: cp2 = cp; 186: while (cp2 < canonb + BUFSIZ) 187: *cp2++ = 0; 188: cp2 = cp; 189: if (setjmp(rewrite)) 190: goto redo; 191: signal(SIGTSTP, ttystop); 192: signal(SIGTTOU, ttystop); 193: signal(SIGTTIN, ttystop); 194: clearerr(stdin); 195: while (cp2 < canonb + BUFSIZ) { 196: c = getc(stdin); 197: if (c == EOF || c == '\n') 198: break; 199: *cp2++ = c; 200: } 201: *cp2 = 0; 202: signal(SIGTSTP, SIG_DFL); 203: signal(SIGTTOU, SIG_DFL); 204: signal(SIGTTIN, SIG_DFL); 205: if (c == EOF && ferror(stdin)) { 206: redo: 207: cp = strlen(canonb) > 0 ? canonb : NOSTR; 208: clearerr(stdin); 209: return(readtty(pr, cp)); 210: } 211: #ifndef TIOCSTI 212: if (cp == NOSTR || *cp == '\0') 213: return(src); 214: cp2 = cp; 215: if (!ttyset) 216: return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR); 217: while (*cp != '\0') { 218: c = *cp++; 219: if (c == c_erase) { 220: if (cp2 == canonb) 221: continue; 222: if (cp2[-1] == '\\') { 223: cp2[-1] = c; 224: continue; 225: } 226: cp2--; 227: continue; 228: } 229: if (c == c_kill) { 230: if (cp2 == canonb) 231: continue; 232: if (cp2[-1] == '\\') { 233: cp2[-1] = c; 234: continue; 235: } 236: cp2 = canonb; 237: continue; 238: } 239: *cp2++ = c; 240: } 241: *cp2 = '\0'; 242: #endif 243: if (equal("", canonb)) 244: return(NOSTR); 245: return(savestr(canonb)); 246: } 247: 248: /* 249: * Receipt continuation. 250: */ 251: void 252: ttystop(s) 253: { 254: sig_t old_action = signal(s, SIG_DFL); 255: 256: sigsetmask(sigblock(0L) & ~sigmask(s)); 257: kill(0, s); 258: sigblock(sigmask(s)); 259: signal(s, old_action); 260: longjmp(rewrite, 1); 261: } 262: 263: /*ARGSUSED*/ 264: void 265: ttyint(s) 266: { 267: longjmp(intjmp, 1); 268: }