Annotation of src/usr.bin/mail/tty.c, Revision 1.13
1.13 ! millert 1: /* $OpenBSD: tty.c,v 1.12 2001/06/23 23:04:23 millert Exp $ */
1.3 millert 2: /* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.3 millert 39: static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 4/20/95";
1.2 deraadt 40: #else
1.13 ! millert 41: static char rcsid[] = "$OpenBSD: tty.c,v 1.12 2001/06/23 23:04:23 millert Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: /*
46: * Mail -- a mail program
47: *
48: * Generally useful tty stuff.
49: */
50:
51: #include "rcv.h"
52: #include "extern.h"
1.2 deraadt 53: #include <sys/ioctl.h>
1.13 ! millert 54: #include <errno.h>
1.1 deraadt 55:
1.5 millert 56: static cc_t c_erase; /* Current erase char */
57: static cc_t c_kill; /* Current kill char */
1.1 deraadt 58: #ifndef TIOCSTI
1.5 millert 59: static int ttyset; /* We must now do erase/kill */
1.1 deraadt 60: #endif
1.13 ! millert 61: static volatile sig_atomic_t ttysignal; /* Interrupted by a signal? */
1.1 deraadt 62:
63: /*
64: * Read all relevant header fields.
65: */
66:
67: int
68: grabh(hp, gflags)
69: struct header *hp;
70: int gflags;
71: {
72: struct termios ttybuf;
73: #ifndef TIOCSTI
1.13 ! millert 74: struct sigaction savequit;
1.10 millert 75: #else
76: # ifdef TIOCEXT
1.13 ! millert 77: int extproc;
1.12 millert 78: int flag;
79: # endif /* TIOCEXT */
1.1 deraadt 80: #endif
1.13 ! millert 81: struct sigaction savetstp;
! 82: struct sigaction savettou;
! 83: struct sigaction savettin;
! 84: struct sigaction act;
! 85: char *s;
! 86: int error;
! 87:
! 88: sigemptyset(&act.sa_mask);
! 89: act.sa_flags = SA_RESTART;
! 90: act.sa_handler = SIG_DFL;
! 91: (void)sigaction(SIGTSTP, &act, &savetstp);
! 92: (void)sigaction(SIGTTOU, &act, &savettou);
! 93: (void)sigaction(SIGTTIN, &act, &savettin);
! 94: error = 1;
1.1 deraadt 95: #ifndef TIOCSTI
96: ttyset = 0;
97: #endif
98: if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
1.3 millert 99: warn("tcgetattr");
1.1 deraadt 100: return(-1);
101: }
102: c_erase = ttybuf.c_cc[VERASE];
103: c_kill = ttybuf.c_cc[VKILL];
104: #ifndef TIOCSTI
105: ttybuf.c_cc[VERASE] = 0;
106: ttybuf.c_cc[VKILL] = 0;
1.13 ! millert 107: act.sa_handler = SIG_IGN;
! 108: if (sigaction(SIGQUIT, &act, &savequit) == 0 &&
! 109: savequit.sa_handler == SIG_DFL)
! 110: (void)sigaction(SIGQUIT, &savequit, NULL);
1.1 deraadt 111: #else
1.10 millert 112: # ifdef TIOCEXT
113: extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
114: if (extproc) {
115: flag = 0;
116: if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
117: warn("TIOCEXT: off");
118: }
119: # endif /* TIOCEXT */
1.1 deraadt 120: #endif
121: if (gflags & GTO) {
122: #ifndef TIOCSTI
123: if (!ttyset && hp->h_to != NIL)
124: ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
125: #endif
1.13 ! millert 126: s = readtty("To: ", detract(hp->h_to, 0));
! 127: if (s == NULL)
! 128: goto out;
! 129: hp->h_to = extract(s, GTO);
1.1 deraadt 130: }
131: if (gflags & GSUBJECT) {
132: #ifndef TIOCSTI
1.5 millert 133: if (!ttyset && hp->h_subject != NULL)
1.1 deraadt 134: ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
135: #endif
1.13 ! millert 136: s = readtty("Subject: ", hp->h_subject);
! 137: if (s == NULL)
! 138: goto out;
! 139: hp->h_subject = s;
1.1 deraadt 140: }
141: if (gflags & GCC) {
142: #ifndef TIOCSTI
143: if (!ttyset && hp->h_cc != NIL)
144: ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
145: #endif
1.13 ! millert 146: s = readtty("Cc: ", detract(hp->h_cc, 0));
! 147: if (s == NULL)
! 148: goto out;
! 149: hp->h_cc = extract(s, GCC);
1.1 deraadt 150: }
151: if (gflags & GBCC) {
152: #ifndef TIOCSTI
153: if (!ttyset && hp->h_bcc != NIL)
154: ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
155: #endif
1.13 ! millert 156: s = readtty("Bcc: ", detract(hp->h_bcc, 0));
! 157: if (s == NULL)
! 158: goto out;
! 159: hp->h_bcc = extract(s, GBCC);
1.1 deraadt 160: }
1.13 ! millert 161: error = 0;
1.1 deraadt 162: out:
1.13 ! millert 163: (void)sigaction(SIGTSTP, &savetstp, NULL);
! 164: (void)sigaction(SIGTTOU, &savettou, NULL);
! 165: (void)sigaction(SIGTTIN, &savettin, NULL);
1.1 deraadt 166: #ifndef TIOCSTI
167: ttybuf.c_cc[VERASE] = c_erase;
168: ttybuf.c_cc[VKILL] = c_kill;
169: if (ttyset)
170: tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1.13 ! millert 171: (void)sigaction(SIGQUIT, &savequit, NULL);
1.10 millert 172: #else
173: # ifdef TIOCEXT
174: if (extproc) {
175: flag = 1;
176: if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
177: warn("TIOCEXT: on");
178: }
179: # endif /* TIOCEXT */
1.1 deraadt 180: #endif
1.13 ! millert 181: return(error);
1.1 deraadt 182: }
183:
184: /*
185: * Read up a header from standard input.
186: * The source string has the preliminary contents to
187: * be read.
188: *
189: */
190:
191: char *
192: readtty(pr, src)
193: char pr[], src[];
194: {
1.13 ! millert 195: struct sigaction act, oact;
! 196: sigset_t oset;
1.1 deraadt 197: char ch, canonb[BUFSIZ];
1.13 ! millert 198: char *cp, *cp2;
! 199: int c;
1.1 deraadt 200:
201: fputs(pr, stdout);
202: fflush(stdout);
1.5 millert 203: if (src != NULL && strlen(src) > BUFSIZ - 2) {
1.3 millert 204: puts("too long to edit");
1.1 deraadt 205: return(src);
206: }
207: #ifndef TIOCSTI
1.5 millert 208: if (src != NULL)
1.1 deraadt 209: cp = copy(src, canonb);
210: else
211: cp = copy("", canonb);
212: fputs(canonb, stdout);
213: fflush(stdout);
214: #else
1.5 millert 215: cp = src == NULL ? "" : src;
1.2 deraadt 216: while ((c = *cp++) != '\0') {
1.1 deraadt 217: if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
218: (c_kill != _POSIX_VDISABLE && c == c_kill)) {
219: ch = '\\';
220: ioctl(0, TIOCSTI, &ch);
221: }
222: ch = c;
223: ioctl(0, TIOCSTI, &ch);
224: }
225: cp = canonb;
226: *cp = 0;
227: #endif
228: cp2 = cp;
229: while (cp2 < canonb + BUFSIZ)
230: *cp2++ = 0;
231: cp2 = cp;
1.13 ! millert 232: sigemptyset(&act.sa_mask);
! 233: act.sa_flags = 0; /* Note: will not restart syscalls */
! 234: act.sa_handler = ttyint;
! 235: (void)sigaction(SIGINT, &act, &oact);
! 236: act.sa_handler = ttystop;
! 237: (void)sigaction(SIGTSTP, &act, NULL);
! 238: (void)sigaction(SIGTTOU, &act, NULL);
! 239: (void)sigaction(SIGTTIN, &act, NULL);
! 240: (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
1.1 deraadt 241: clearerr(stdin);
242: while (cp2 < canonb + BUFSIZ) {
243: c = getc(stdin);
1.13 ! millert 244: switch (ttysignal) {
! 245: case SIGINT:
! 246: ttysignal = 0;
! 247: cp2 = NULL;
! 248: c = EOF;
! 249: /* FALLTHROUGH */
! 250: case 0:
! 251: break;
! 252: default:
! 253: ttysignal = 0;
! 254: goto redo;
! 255: }
1.1 deraadt 256: if (c == EOF || c == '\n')
257: break;
258: *cp2++ = c;
259: }
1.13 ! millert 260: act.sa_handler = SIG_DFL;
! 261: sigemptyset(&act.sa_mask);
! 262: act.sa_flags = SA_RESTART;
! 263: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
! 264: (void)sigaction(SIGTSTP, &act, NULL);
! 265: (void)sigaction(SIGTTOU, &act, NULL);
! 266: (void)sigaction(SIGTTIN, &act, NULL);
! 267: (void)sigaction(SIGTTIN, &oact, NULL);
! 268: if (cp2 == NULL)
! 269: return(NULL); /* user hit ^C */
! 270: *cp2 = '\0';
1.1 deraadt 271: if (c == EOF && ferror(stdin)) {
272: redo:
1.5 millert 273: cp = strlen(canonb) > 0 ? canonb : NULL;
1.1 deraadt 274: clearerr(stdin);
1.13 ! millert 275: /* XXX - make iterative, not recursive */
1.1 deraadt 276: return(readtty(pr, cp));
277: }
278: #ifndef TIOCSTI
1.5 millert 279: if (cp == NULL || *cp == '\0')
1.1 deraadt 280: return(src);
281: cp2 = cp;
282: if (!ttyset)
1.5 millert 283: return(strlen(canonb) > 0 ? savestr(canonb) : NULL);
1.1 deraadt 284: while (*cp != '\0') {
285: c = *cp++;
286: if (c_erase != _POSIX_VDISABLE && c == c_erase) {
287: if (cp2 == canonb)
288: continue;
289: if (cp2[-1] == '\\') {
290: cp2[-1] = c;
291: continue;
292: }
293: cp2--;
294: continue;
295: }
296: if (c_kill != _POSIX_VDISABLE && c == c_kill) {
297: if (cp2 == canonb)
298: continue;
299: if (cp2[-1] == '\\') {
300: cp2[-1] = c;
301: continue;
302: }
303: cp2 = canonb;
304: continue;
305: }
306: *cp2++ = c;
307: }
308: *cp2 = '\0';
309: #endif
310: if (equal("", canonb))
1.13 ! millert 311: return("");
1.1 deraadt 312: return(savestr(canonb));
313: }
314:
315: /*
316: * Receipt continuation.
317: */
318: void
319: ttystop(s)
320: int s;
321: {
1.13 ! millert 322: struct sigaction act, oact;
1.2 deraadt 323: sigset_t nset;
1.13 ! millert 324: int save_errno;
1.1 deraadt 325:
1.13 ! millert 326: /*
! 327: * Save old handler and set to default.
! 328: * Unblock receipt of 's' and then resend it.
! 329: */
! 330: save_errno = errno;
! 331: (void)sigemptyset(&act.sa_mask);
! 332: act.sa_flags = SA_RESTART;
! 333: act.sa_handler = SIG_DFL;
! 334: (void)sigaction(s, &act, &oact);
1.8 millert 335: (void)sigemptyset(&nset);
336: (void)sigaddset(&nset, s);
337: (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
338: (void)kill(0, s);
339: (void)sigprocmask(SIG_BLOCK, &nset, NULL);
1.13 ! millert 340: (void)sigaction(s, &oact, NULL);
! 341: ttysignal = s;
! 342: errno = save_errno;
1.1 deraadt 343: }
344:
345: /*ARGSUSED*/
346: void
347: ttyint(s)
348: int s;
349: {
1.13 ! millert 350:
! 351: ttysignal = s;
1.1 deraadt 352: }