tty.c revision 1.8
1/* $OpenBSD: tty.c,v 1.8 1997/07/30 06:32:41 millert Exp $ */ 2/* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */ 3 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 38#if 0 39static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 4/20/95"; 40#else 41static char rcsid[] = "$OpenBSD: tty.c,v 1.8 1997/07/30 06:32:41 millert Exp $"; 42#endif 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" 53#include <sys/ioctl.h> 54 55static cc_t c_erase; /* Current erase char */ 56static cc_t c_kill; /* Current kill char */ 57static sigjmp_buf rewrite; /* Place to go when continued */ 58static sigjmp_buf intjmp; /* Place to go when interrupted */ 59#ifndef TIOCSTI 60static int ttyset; /* We must now do erase/kill */ 61#endif 62 63/* 64 * Read all relevant header fields. 65 */ 66 67int 68grabh(hp, gflags) 69 struct header *hp; 70 int gflags; 71{ 72 struct termios ttybuf; 73 sig_t saveint; 74#ifndef TIOCSTI 75 sig_t savequit; 76#else 77 int extproc, flag; 78#endif 79 sig_t savetstp; 80 sig_t savettou; 81 sig_t savettin; 82 int errs = 0; 83#ifdef __GNUC__ 84 /* Avoid siglongjmp clobbering */ 85#ifdef TIOCSTI 86 (void)&extproc; 87#endif 88 (void)&saveint; 89 (void)&errs; 90#endif 91 92 savetstp = signal(SIGTSTP, SIG_DFL); 93 savettou = signal(SIGTTOU, SIG_DFL); 94 savettin = signal(SIGTTIN, SIG_DFL); 95 errs = 0; 96#ifndef TIOCSTI 97 ttyset = 0; 98#endif 99 if (tcgetattr(fileno(stdin), &ttybuf) < 0) { 100 warn("tcgetattr"); 101 return(-1); 102 } 103 c_erase = ttybuf.c_cc[VERASE]; 104 c_kill = ttybuf.c_cc[VKILL]; 105#ifndef TIOCSTI 106 ttybuf.c_cc[VERASE] = 0; 107 ttybuf.c_cc[VKILL] = 0; 108 if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) 109 (void)signal(SIGINT, SIG_DFL); 110 if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) 111 (void)signal(SIGQUIT, SIG_DFL); 112#else 113# ifdef TIOCEXT 114 extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); 115 if (extproc) { 116 flag = 0; 117 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 118 warn("TIOCEXT: off"); 119 } 120# endif /* TIOCEXT */ 121 if (sigsetjmp(intjmp, 1)) { 122 errs = SIGINT; 123 goto out; 124 } 125 saveint = signal(SIGINT, ttyint); 126#endif 127 if (gflags & GTO) { 128#ifndef TIOCSTI 129 if (!ttyset && hp->h_to != NIL) 130 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 131#endif 132 hp->h_to = 133 extract(readtty("To: ", detract(hp->h_to, 0)), GTO); 134 } 135 if (gflags & GSUBJECT) { 136#ifndef TIOCSTI 137 if (!ttyset && hp->h_subject != NULL) 138 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 139#endif 140 hp->h_subject = readtty("Subject: ", hp->h_subject); 141 } 142 if (gflags & GCC) { 143#ifndef TIOCSTI 144 if (!ttyset && hp->h_cc != NIL) 145 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 146#endif 147 hp->h_cc = 148 extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); 149 } 150 if (gflags & GBCC) { 151#ifndef TIOCSTI 152 if (!ttyset && hp->h_bcc != NIL) 153 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 154#endif 155 hp->h_bcc = 156 extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); 157 } 158out: 159 (void)signal(SIGTSTP, savetstp); 160 (void)signal(SIGTTOU, savettou); 161 (void)signal(SIGTTIN, savettin); 162#ifndef TIOCSTI 163 ttybuf.c_cc[VERASE] = c_erase; 164 ttybuf.c_cc[VKILL] = c_kill; 165 if (ttyset) 166 tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 167 (void)signal(SIGQUIT, savequit); 168#else 169# ifdef TIOCEXT 170 if (extproc) { 171 flag = 1; 172 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 173 warn("TIOCEXT: on"); 174 } 175# endif /* TIOCEXT */ 176#endif 177 (void)signal(SIGINT, saveint); 178 return(errs); 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 188char * 189readtty(pr, src) 190 char pr[], src[]; 191{ 192 char ch, canonb[BUFSIZ]; 193 int c; 194 char *cp, *cp2; 195#if __GNUC__ 196 /* Avoid siglongjmp clobbering */ 197 (void)&c; 198 (void)&cp2; 199#endif 200 201 fputs(pr, stdout); 202 fflush(stdout); 203 if (src != NULL && strlen(src) > BUFSIZ - 2) { 204 puts("too long to edit"); 205 return(src); 206 } 207#ifndef TIOCSTI 208 if (src != NULL) 209 cp = copy(src, canonb); 210 else 211 cp = copy("", canonb); 212 fputs(canonb, stdout); 213 fflush(stdout); 214#else 215 cp = src == NULL ? "" : src; 216 while ((c = *cp++) != '\0') { 217 if ((c_erase != _POSIX_VDISABLE && c == c_erase) || 218 (c_kill != _POSIX_VDISABLE && c == c_kill)) { 219 ch = '\\'; 220 ioctl(0, TIOCSTI, &ch); 221 } 222 ch = c; 223 ioctl(0, TIOCSTI, &ch); 224 } 225 cp = canonb; 226 *cp = 0; 227#endif 228 cp2 = cp; 229 while (cp2 < canonb + BUFSIZ) 230 *cp2++ = 0; 231 cp2 = cp; 232 if (sigsetjmp(rewrite, 1)) 233 goto redo; 234 (void)signal(SIGTSTP, ttystop); 235 (void)signal(SIGTTOU, ttystop); 236 (void)signal(SIGTTIN, ttystop); 237 clearerr(stdin); 238 while (cp2 < canonb + BUFSIZ) { 239 c = getc(stdin); 240 if (c == EOF || c == '\n') 241 break; 242 *cp2++ = c; 243 } 244 *cp2 = 0; 245 (void)signal(SIGTSTP, SIG_DFL); 246 (void)signal(SIGTTOU, SIG_DFL); 247 (void)signal(SIGTTIN, SIG_DFL); 248 if (c == EOF && ferror(stdin)) { 249redo: 250 cp = strlen(canonb) > 0 ? canonb : NULL; 251 clearerr(stdin); 252 return(readtty(pr, cp)); 253 } 254#ifndef TIOCSTI 255 if (cp == NULL || *cp == '\0') 256 return(src); 257 cp2 = cp; 258 if (!ttyset) 259 return(strlen(canonb) > 0 ? savestr(canonb) : NULL); 260 while (*cp != '\0') { 261 c = *cp++; 262 if (c_erase != _POSIX_VDISABLE && c == c_erase) { 263 if (cp2 == canonb) 264 continue; 265 if (cp2[-1] == '\\') { 266 cp2[-1] = c; 267 continue; 268 } 269 cp2--; 270 continue; 271 } 272 if (c_kill != _POSIX_VDISABLE && c == c_kill) { 273 if (cp2 == canonb) 274 continue; 275 if (cp2[-1] == '\\') { 276 cp2[-1] = c; 277 continue; 278 } 279 cp2 = canonb; 280 continue; 281 } 282 *cp2++ = c; 283 } 284 *cp2 = '\0'; 285#endif 286 if (equal("", canonb)) 287 return(NULL); 288 return(savestr(canonb)); 289} 290 291/* 292 * Receipt continuation. 293 */ 294void 295ttystop(s) 296 int s; 297{ 298 sig_t old_action = signal(s, SIG_DFL); 299 sigset_t nset; 300 301 (void)sigemptyset(&nset); 302 (void)sigaddset(&nset, s); 303 (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 304 (void)kill(0, s); 305 (void)sigprocmask(SIG_BLOCK, &nset, NULL); 306 (void)signal(s, old_action); 307 siglongjmp(rewrite, 1); 308} 309 310/*ARGSUSED*/ 311void 312ttyint(s) 313 int s; 314{ 315 siglongjmp(intjmp, 1); 316} 317