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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 #if 0 32 static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93"; 33 #endif 34 #endif /* not lint */ 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 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 out: 141 (void)signal(SIGTSTP, savetstp); 142 (void)signal(SIGTTOU, savettou); 143 (void)signal(SIGTTIN, savettin); 144 #ifndef TIOCSTI 145 ttybuf.c_cc[VERASE] = c_erase; 146 ttybuf.c_cc[VKILL] = c_kill; 147 if (ttyset) 148 tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 149 (void)signal(SIGQUIT, savequit); 150 #else 151 # ifdef TIOCEXT 152 if (extproc) { 153 flag = 1; 154 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 155 warn("TIOCEXT: on"); 156 } 157 # endif /* TIOCEXT */ 158 #endif 159 (void)signal(SIGINT, saveint); 160 return (errs); 161 } 162 163 /* 164 * Read up a header from standard input. 165 * The source string has the preliminary contents to 166 * be read. 167 * 168 */ 169 170 char * 171 readtty(const char *pr, char src[]) 172 { 173 char ch, canonb[BUFSIZ]; 174 int c; 175 char *cp, *cp2; 176 177 fputs(pr, stdout); 178 (void)fflush(stdout); 179 if (src != NULL && strlen(src) > BUFSIZ - 2) { 180 printf("too long to edit\n"); 181 return (src); 182 } 183 #ifndef TIOCSTI 184 if (src != NULL) 185 strlcpy(canonb, src, sizeof(canonb)); 186 else 187 *canonb = '\0'; 188 fputs(canonb, stdout); 189 (void)fflush(stdout); 190 #else 191 cp = src == NULL ? "" : src; 192 while ((c = *cp++) != '\0') { 193 if ((c_erase != _POSIX_VDISABLE && c == c_erase) || 194 (c_kill != _POSIX_VDISABLE && c == c_kill)) { 195 ch = '\\'; 196 ioctl(0, TIOCSTI, &ch); 197 } 198 ch = c; 199 ioctl(0, TIOCSTI, &ch); 200 } 201 cp = canonb; 202 *cp = '\0'; 203 #endif 204 cp2 = cp; 205 while (cp2 < canonb + BUFSIZ) 206 *cp2++ = '\0'; 207 cp2 = cp; 208 if (setjmp(rewrite)) 209 goto redo; 210 (void)signal(SIGTSTP, ttystop); 211 (void)signal(SIGTTOU, ttystop); 212 (void)signal(SIGTTIN, ttystop); 213 clearerr(stdin); 214 while (cp2 < canonb + BUFSIZ) { 215 c = getc(stdin); 216 if (c == EOF || c == '\n') 217 break; 218 *cp2++ = c; 219 } 220 *cp2 = '\0'; 221 (void)signal(SIGTSTP, SIG_DFL); 222 (void)signal(SIGTTOU, SIG_DFL); 223 (void)signal(SIGTTIN, SIG_DFL); 224 if (c == EOF && ferror(stdin)) { 225 redo: 226 cp = strlen(canonb) > 0 ? canonb : NULL; 227 clearerr(stdin); 228 return (readtty(pr, cp)); 229 } 230 #ifndef TIOCSTI 231 if (cp == NULL || *cp == '\0') 232 return (src); 233 cp2 = cp; 234 if (!ttyset) 235 return (strlen(canonb) > 0 ? savestr(canonb) : NULL); 236 while (*cp != '\0') { 237 c = *cp++; 238 if (c_erase != _POSIX_VDISABLE && c == c_erase) { 239 if (cp2 == canonb) 240 continue; 241 if (cp2[-1] == '\\') { 242 cp2[-1] = c; 243 continue; 244 } 245 cp2--; 246 continue; 247 } 248 if (c_kill != _POSIX_VDISABLE && c == c_kill) { 249 if (cp2 == canonb) 250 continue; 251 if (cp2[-1] == '\\') { 252 cp2[-1] = c; 253 continue; 254 } 255 cp2 = canonb; 256 continue; 257 } 258 *cp2++ = c; 259 } 260 *cp2 = '\0'; 261 #endif 262 if (equal("", canonb)) 263 return (NULL); 264 return (savestr(canonb)); 265 } 266 267 /* 268 * Receipt continuation. 269 */ 270 void 271 ttystop(int s) 272 { 273 sig_t old_action = signal(s, SIG_DFL); 274 sigset_t nset; 275 276 (void)sigemptyset(&nset); 277 (void)sigaddset(&nset, s); 278 (void)sigprocmask(SIG_BLOCK, &nset, NULL); 279 kill(0, s); 280 (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 281 (void)signal(s, old_action); 282 longjmp(rewrite, 1); 283 } 284 285 void 286 ttyint(int s __unused) 287 { 288 longjmp(intjmp, 1); 289 } 290