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