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.1 (Berkeley) 6/6/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 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 int c_erase; /* Current erase char */ 52 static int 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 tio; 69 sig_t saveint; 70 #ifndef TIOCSTI 71 sig_t savequit; 72 #endif 73 sig_t savetstp; 74 sig_t savettou; 75 sig_t savettin; 76 int errs; 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), &tio) < 0) { 86 warn("tcgetattr(stdin)"); 87 return (-1); 88 } 89 c_erase = tio.c_cc[VERASE]; 90 c_kill = tio.c_cc[VKILL]; 91 #ifndef TIOCSTI 92 tio.c_cc[VERASE] = 0; 93 tio.c_cc[VKILL] = 0; 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 if (setjmp(intjmp)) 100 goto out; 101 saveint = signal(SIGINT, ttyint); 102 #endif 103 if (gflags & GTO) { 104 #ifndef TIOCSTI 105 if (!ttyset && hp->h_to != NULL) 106 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio); 107 #endif 108 hp->h_to = 109 extract(readtty("To: ", detract(hp->h_to, 0)), GTO); 110 } 111 if (gflags & GSUBJECT) { 112 #ifndef TIOCSTI 113 if (!ttyset && hp->h_subject != NULL) 114 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio); 115 #endif 116 hp->h_subject = readtty("Subject: ", hp->h_subject); 117 } 118 if (gflags & GCC) { 119 #ifndef TIOCSTI 120 if (!ttyset && hp->h_cc != NULL) 121 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio); 122 #endif 123 hp->h_cc = 124 extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); 125 } 126 if (gflags & GBCC) { 127 #ifndef TIOCSTI 128 if (!ttyset && hp->h_bcc != NULL) 129 ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio); 130 #endif 131 hp->h_bcc = 132 extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); 133 } 134 out: 135 (void)signal(SIGTSTP, savetstp); 136 (void)signal(SIGTTOU, savettou); 137 (void)signal(SIGTTIN, savettin); 138 #ifndef TIOCSTI 139 tio.c_cc[VERASE] = c_erase; 140 tio.c_cc[VKILL] = c_kill; 141 if (ttyset) 142 tcsetattr(fileno(stdin), TCSADRAIN, &tio); 143 (void)signal(SIGQUIT, savequit); 144 #endif 145 (void)signal(SIGINT, saveint); 146 return (errs); 147 } 148 149 /* 150 * Read up a header from standard input. 151 * The source string has the preliminary contents to 152 * be read. 153 * 154 */ 155 156 char * 157 readtty(pr, src) 158 const char *pr; 159 char src[]; 160 { 161 char ch, canonb[BUFSIZ]; 162 int c; 163 char *cp, *cp2; 164 165 fputs(pr, stdout); 166 (void)fflush(stdout); 167 if (src != NULL && strlen(src) > BUFSIZ - 2) { 168 printf("too long to edit\n"); 169 return (src); 170 } 171 #ifndef TIOCSTI 172 if (src != NULL) 173 strlcpy(canonb, src, sizeof(canonb)); 174 else 175 *canonb = '\0'; 176 fputs(canonb, stdout); 177 (void)fflush(stdout); 178 #else 179 cp = src == NULL ? "" : src; 180 while ((c = *cp++) != '\0') { 181 if (c == c_erase || c == c_kill) { 182 ch = '\\'; 183 ioctl(0, TIOCSTI, &ch); 184 } 185 ch = c; 186 ioctl(0, TIOCSTI, &ch); 187 } 188 cp = canonb; 189 *cp = '\0'; 190 #endif 191 cp2 = cp; 192 while (cp2 < canonb + BUFSIZ) 193 *cp2++ = '\0'; 194 cp2 = cp; 195 if (setjmp(rewrite)) 196 goto redo; 197 (void)signal(SIGTSTP, ttystop); 198 (void)signal(SIGTTOU, ttystop); 199 (void)signal(SIGTTIN, ttystop); 200 clearerr(stdin); 201 while (cp2 < canonb + BUFSIZ) { 202 c = getc(stdin); 203 if (c == EOF || c == '\n') 204 break; 205 *cp2++ = c; 206 } 207 *cp2 = '\0'; 208 (void)signal(SIGTSTP, SIG_DFL); 209 (void)signal(SIGTTOU, SIG_DFL); 210 (void)signal(SIGTTIN, SIG_DFL); 211 if (c == EOF && ferror(stdin)) { 212 redo: 213 cp = strlen(canonb) > 0 ? canonb : NULL; 214 clearerr(stdin); 215 return (readtty(pr, cp)); 216 } 217 #ifndef TIOCSTI 218 if (cp == NULL || *cp == '\0') 219 return (src); 220 cp2 = cp; 221 if (!ttyset) 222 return (strlen(canonb) > 0 ? savestr(canonb) : NULL); 223 while (*cp != '\0') { 224 c = *cp++; 225 if (c == c_erase) { 226 if (cp2 == canonb) 227 continue; 228 if (cp2[-1] == '\\') { 229 cp2[-1] = c; 230 continue; 231 } 232 cp2--; 233 continue; 234 } 235 if (c == c_kill) { 236 if (cp2 == canonb) 237 continue; 238 if (cp2[-1] == '\\') { 239 cp2[-1] = c; 240 continue; 241 } 242 cp2 = canonb; 243 continue; 244 } 245 *cp2++ = c; 246 } 247 *cp2 = '\0'; 248 #endif 249 if (equal("", canonb)) 250 return (NULL); 251 return (savestr(canonb)); 252 } 253 254 /* 255 * Receipt continuation. 256 */ 257 void 258 ttystop(s) 259 int s; 260 { 261 sig_t old_action = signal(s, SIG_DFL); 262 263 (void)sigsetmask(sigblock(0) & ~sigmask(s)); 264 (void)kill(0, s); 265 (void)sigblock(sigmask(s)); 266 (void)signal(s, old_action); 267 longjmp(rewrite, 1); 268 } 269 270 /*ARGSUSED*/ 271 void 272 ttyint(s) 273 int s; 274 { 275 longjmp(intjmp, 1); 276 } 277