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