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 * @(#)tty.c 8.2 (Berkeley) 6/6/93 34 * $FreeBSD: src/usr.bin/mail/tty.c,v 1.2.8.3 2003/01/06 05:46:04 mikeh Exp $ 35 * $DragonFly: src/usr.bin/mail/tty.c,v 1.2 2003/06/17 04:29:28 dillon Exp $ 36 */ 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(hp, gflags) 61 struct header *hp; 62 int gflags; 63 { 64 struct termios ttybuf; 65 sig_t saveint; 66 sig_t savetstp; 67 sig_t savettou; 68 sig_t savettin; 69 int errs; 70 #ifndef TIOCSTI 71 sig_t savequit; 72 #else 73 # ifdef TIOCEXT 74 int extproc, flag; 75 # endif /* TIOCEXT */ 76 #endif /* TIOCSTI */ 77 78 savetstp = signal(SIGTSTP, SIG_DFL); 79 savettou = signal(SIGTTOU, SIG_DFL); 80 savettin = signal(SIGTTIN, SIG_DFL); 81 errs = 0; 82 #ifndef TIOCSTI 83 ttyset = 0; 84 #endif 85 if (tcgetattr(fileno(stdin), &ttybuf) < 0) { 86 warn("tcgetattr(stdin)"); 87 return (-1); 88 } 89 c_erase = ttybuf.c_cc[VERASE]; 90 c_kill = ttybuf.c_cc[VKILL]; 91 #ifndef TIOCSTI 92 ttybuf.c_cc[VERASE] = _POSIX_VDISABLE; 93 ttybuf.c_cc[VKILL] = _POSIX_VDISABLE; 94 if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) 95 (void)signal(SIGINT, SIG_DFL); 96 if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) 97 (void)signal(SIGQUIT, SIG_DFL); 98 #else 99 # ifdef TIOCEXT 100 extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); 101 if (extproc) { 102 flag = 0; 103 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) 104 warn("TIOCEXT: off"); 105 } 106 # endif /* TIOCEXT */ 107 if (setjmp(intjmp)) 108 goto out; 109 saveint = signal(SIGINT, ttyint); 110 #endif 111 if (gflags & GTO) { 112 #ifndef TIOCSTI 113 if (!ttyset && hp->h_to != NULL) 114 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 115 #endif 116 hp->h_to = 117 extract(readtty("To: ", detract(hp->h_to, 0)), GTO); 118 } 119 if (gflags & GSUBJECT) { 120 #ifndef TIOCSTI 121 if (!ttyset && hp->h_subject != NULL) 122 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 123 #endif 124 hp->h_subject = readtty("Subject: ", hp->h_subject); 125 } 126 if (gflags & GCC) { 127 #ifndef TIOCSTI 128 if (!ttyset && hp->h_cc != NULL) 129 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 130 #endif 131 hp->h_cc = 132 extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); 133 } 134 if (gflags & GBCC) { 135 #ifndef TIOCSTI 136 if (!ttyset && hp->h_bcc != NULL) 137 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); 138 #endif 139 hp->h_bcc = 140 extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); 141 } 142 out: 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(pr, src) 174 const char *pr; 175 char src[]; 176 { 177 char ch, canonb[BUFSIZ]; 178 int c; 179 char *cp, *cp2; 180 181 fputs(pr, stdout); 182 (void)fflush(stdout); 183 if (src != NULL && strlen(src) > BUFSIZ - 2) { 184 printf("too long to edit\n"); 185 return (src); 186 } 187 #ifndef TIOCSTI 188 if (src != NULL) 189 strlcpy(canonb, src, sizeof(canonb)); 190 else 191 *canonb = '\0'; 192 fputs(canonb, stdout); 193 (void)fflush(stdout); 194 #else 195 cp = src == NULL ? "" : src; 196 while ((c = *cp++) != '\0') { 197 if ((c_erase != _POSIX_VDISABLE && c == c_erase) || 198 (c_kill != _POSIX_VDISABLE && c == c_kill)) { 199 ch = '\\'; 200 ioctl(0, TIOCSTI, &ch); 201 } 202 ch = c; 203 ioctl(0, TIOCSTI, &ch); 204 } 205 cp = canonb; 206 *cp = '\0'; 207 #endif 208 cp2 = cp; 209 while (cp2 < canonb + BUFSIZ) 210 *cp2++ = '\0'; 211 cp2 = cp; 212 if (setjmp(rewrite)) 213 goto redo; 214 (void)signal(SIGTSTP, ttystop); 215 (void)signal(SIGTTOU, ttystop); 216 (void)signal(SIGTTIN, ttystop); 217 clearerr(stdin); 218 while (cp2 < canonb + BUFSIZ) { 219 c = getc(stdin); 220 if (c == EOF || c == '\n') 221 break; 222 *cp2++ = c; 223 } 224 *cp2 = '\0'; 225 (void)signal(SIGTSTP, SIG_DFL); 226 (void)signal(SIGTTOU, SIG_DFL); 227 (void)signal(SIGTTIN, SIG_DFL); 228 if (c == EOF && ferror(stdin)) { 229 redo: 230 cp = strlen(canonb) > 0 ? canonb : NULL; 231 clearerr(stdin); 232 return (readtty(pr, cp)); 233 } 234 #ifndef TIOCSTI 235 if (cp == NULL || *cp == '\0') 236 return (src); 237 cp2 = cp; 238 if (!ttyset) 239 return (strlen(canonb) > 0 ? savestr(canonb) : NULL); 240 while (*cp != '\0') { 241 c = *cp++; 242 if (c_erase != _POSIX_VDISABLE && c == c_erase) { 243 if (cp2 == canonb) 244 continue; 245 if (cp2[-1] == '\\') { 246 cp2[-1] = c; 247 continue; 248 } 249 cp2--; 250 continue; 251 } 252 if (c_kill != _POSIX_VDISABLE && c == c_kill) { 253 if (cp2 == canonb) 254 continue; 255 if (cp2[-1] == '\\') { 256 cp2[-1] = c; 257 continue; 258 } 259 cp2 = canonb; 260 continue; 261 } 262 *cp2++ = c; 263 } 264 *cp2 = '\0'; 265 #endif 266 if (equal("", canonb)) 267 return (NULL); 268 return (savestr(canonb)); 269 } 270 271 /* 272 * Receipt continuation. 273 */ 274 void 275 ttystop(s) 276 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 /*ARGSUSED*/ 291 void 292 ttyint(s) 293 int s; 294 { 295 longjmp(intjmp, 1); 296 } 297