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