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