1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. 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 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93"; 37 #endif 38 #endif /* not lint */ 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 /* 43 * Mail -- a mail program 44 * 45 * Generally useful tty stuff. 46 */ 47 48 #include "rcv.h" 49 #include "extern.h" 50 51 static cc_t c_erase; /* Current erase char */ 52 static cc_t c_kill; /* Current kill char */ 53 static jmp_buf rewrite; /* Place to go when continued */ 54 static jmp_buf intjmp; /* Place to go when interrupted */ 55 #ifndef TIOCSTI 56 static int ttyset; /* We must now do erase/kill */ 57 #endif 58 59 /* 60 * Read all relevant header fields. 61 */ 62 63 int 64 grabh(hp, gflags) 65 struct header *hp; 66 int gflags; 67 { 68 struct termios ttybuf; 69 sig_t saveint; 70 sig_t savetstp; 71 sig_t savettou; 72 sig_t savettin; 73 int errs; 74 #ifndef TIOCSTI 75 sig_t savequit; 76 #else 77 # ifdef TIOCEXT 78 int extproc, flag; 79 # endif /* TIOCEXT */ 80 #endif /* TIOCSTI */ 81 82 savetstp = signal(SIGTSTP, SIG_DFL); 83 savettou = signal(SIGTTOU, SIG_DFL); 84 savettin = signal(SIGTTIN, SIG_DFL); 85 errs = 0; 86 #ifndef TIOCSTI 87 ttyset = 0; 88 #endif 89 if (tcgetattr(fileno(stdin), &ttybuf) < 0) { 90 warn("tcgetattr(stdin)"); 91 return (-1); 92 } 93 c_erase = ttybuf.c_cc[VERASE]; 94 c_kill = ttybuf.c_cc[VKILL]; 95 #ifndef TIOCSTI 96 ttybuf.c_cc[VERASE] = _POSIX_VDISABLE; 97 ttybuf.c_cc[VKILL] = _POSIX_VDISABLE; 98 if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) 99 (void)signal(SIGINT, SIG_DFL); 100 if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) 101 (void)signal(SIGQUIT, SIG_DFL); 102 #else 103 # ifdef TIOCEXT 104 extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); 105 if (extproc) { 106 flag = 0; 107 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 108 warn("TIOCEXT: off"); 109 } 110 # endif /* TIOCEXT */ 111 if (setjmp(intjmp)) 112 goto out; 113 saveint = signal(SIGINT, ttyint); 114 #endif 115 if (gflags & GTO) { 116 #ifndef TIOCSTI 117 if (!ttyset && hp->h_to != NULL) 118 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 119 #endif 120 hp->h_to = 121 extract(readtty("To: ", detract(hp->h_to, 0)), GTO); 122 } 123 if (gflags & GSUBJECT) { 124 #ifndef TIOCSTI 125 if (!ttyset && hp->h_subject != NULL) 126 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 127 #endif 128 hp->h_subject = readtty("Subject: ", hp->h_subject); 129 } 130 if (gflags & GCC) { 131 #ifndef TIOCSTI 132 if (!ttyset && hp->h_cc != NULL) 133 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 134 #endif 135 hp->h_cc = 136 extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); 137 } 138 if (gflags & GBCC) { 139 #ifndef TIOCSTI 140 if (!ttyset && hp->h_bcc != NULL) 141 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 142 #endif 143 hp->h_bcc = 144 extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); 145 } 146 out: 147 (void)signal(SIGTSTP, savetstp); 148 (void)signal(SIGTTOU, savettou); 149 (void)signal(SIGTTIN, savettin); 150 #ifndef TIOCSTI 151 ttybuf.c_cc[VERASE] = c_erase; 152 ttybuf.c_cc[VKILL] = c_kill; 153 if (ttyset) 154 tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 155 (void)signal(SIGQUIT, savequit); 156 #else 157 # ifdef TIOCEXT 158 if (extproc) { 159 flag = 1; 160 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 161 warn("TIOCEXT: on"); 162 } 163 # endif /* TIOCEXT */ 164 #endif 165 (void)signal(SIGINT, saveint); 166 return (errs); 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 176 char * 177 readtty(pr, src) 178 const char *pr; 179 char src[]; 180 { 181 char ch, canonb[BUFSIZ]; 182 int c; 183 char *cp, *cp2; 184 185 fputs(pr, stdout); 186 (void)fflush(stdout); 187 if (src != NULL && strlen(src) > BUFSIZ - 2) { 188 printf("too long to edit\n"); 189 return (src); 190 } 191 #ifndef TIOCSTI 192 if (src != NULL) 193 strlcpy(canonb, src, sizeof(canonb)); 194 else 195 *canonb = '\0'; 196 fputs(canonb, stdout); 197 (void)fflush(stdout); 198 #else 199 cp = src == NULL ? "" : src; 200 while ((c = *cp++) != '\0') { 201 if ((c_erase != _POSIX_VDISABLE && c == c_erase) || 202 (c_kill != _POSIX_VDISABLE && c == c_kill)) { 203 ch = '\\'; 204 ioctl(0, TIOCSTI, &ch); 205 } 206 ch = c; 207 ioctl(0, TIOCSTI, &ch); 208 } 209 cp = canonb; 210 *cp = '\0'; 211 #endif 212 cp2 = cp; 213 while (cp2 < canonb + BUFSIZ) 214 *cp2++ = '\0'; 215 cp2 = cp; 216 if (setjmp(rewrite)) 217 goto redo; 218 (void)signal(SIGTSTP, ttystop); 219 (void)signal(SIGTTOU, ttystop); 220 (void)signal(SIGTTIN, ttystop); 221 clearerr(stdin); 222 while (cp2 < canonb + BUFSIZ) { 223 c = getc(stdin); 224 if (c == EOF || c == '\n') 225 break; 226 *cp2++ = c; 227 } 228 *cp2 = '\0'; 229 (void)signal(SIGTSTP, SIG_DFL); 230 (void)signal(SIGTTOU, SIG_DFL); 231 (void)signal(SIGTTIN, SIG_DFL); 232 if (c == EOF && ferror(stdin)) { 233 redo: 234 cp = strlen(canonb) > 0 ? canonb : NULL; 235 clearerr(stdin); 236 return (readtty(pr, cp)); 237 } 238 #ifndef TIOCSTI 239 if (cp == NULL || *cp == '\0') 240 return (src); 241 cp2 = cp; 242 if (!ttyset) 243 return (strlen(canonb) > 0 ? savestr(canonb) : NULL); 244 while (*cp != '\0') { 245 c = *cp++; 246 if (c_erase != _POSIX_VDISABLE && c == c_erase) { 247 if (cp2 == canonb) 248 continue; 249 if (cp2[-1] == '\\') { 250 cp2[-1] = c; 251 continue; 252 } 253 cp2--; 254 continue; 255 } 256 if (c_kill != _POSIX_VDISABLE && c == c_kill) { 257 if (cp2 == canonb) 258 continue; 259 if (cp2[-1] == '\\') { 260 cp2[-1] = c; 261 continue; 262 } 263 cp2 = canonb; 264 continue; 265 } 266 *cp2++ = c; 267 } 268 *cp2 = '\0'; 269 #endif 270 if (equal("", canonb)) 271 return (NULL); 272 return (savestr(canonb)); 273 } 274 275 /* 276 * Receipt continuation. 277 */ 278 void 279 ttystop(s) 280 int s; 281 { 282 sig_t old_action = signal(s, SIG_DFL); 283 sigset_t nset; 284 285 (void)sigemptyset(&nset); 286 (void)sigaddset(&nset, s); 287 (void)sigprocmask(SIG_BLOCK, &nset, NULL); 288 kill(0, s); 289 (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 290 (void)signal(s, old_action); 291 longjmp(rewrite, 1); 292 } 293 294 /*ARGSUSED*/ 295 void 296 ttyint(s) 297 int s; 298 { 299 longjmp(intjmp, 1); 300 } 301