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