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