xref: /netbsd-src/usr.bin/mail/tty.c (revision 07bae7edddbb1ce4c926b2e8db425804589074c9)
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.4 1995/05/02 01:40:17 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 #include "extern.h"
47 
48 static	cc_t	c_erase;		/* Current erase char */
49 static	cc_t	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 termios 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 (tcgetattr(fileno(stdin), &ttybuf) < 0) {
84 		perror("tcgetattr");
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;
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++, tcsetattr(fileno(stdin), TCSADRAIN, &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++, tcsetattr(fileno(stdin), TCSADRAIN, &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++, tcsetattr(fileno(stdin), TCSADRAIN, &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++, tcsetattr(fileno(stdin), TCSADRAIN, &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.c_cc[VERASE] = c_erase;
138 	ttybuf.c_cc[VKILL] = c_kill;
139 	if (ttyset)
140 		tcsetattr(fileno(stdin), TCSADRAIN, &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_erase != _POSIX_VDISABLE && c == c_erase) ||
180 		    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
181 			ch = '\\';
182 			ioctl(0, TIOCSTI, &ch);
183 		}
184 		ch = c;
185 		ioctl(0, TIOCSTI, &ch);
186 	}
187 	cp = canonb;
188 	*cp = 0;
189 #endif
190 	cp2 = cp;
191 	while (cp2 < canonb + BUFSIZ)
192 		*cp2++ = 0;
193 	cp2 = cp;
194 	if (setjmp(rewrite))
195 		goto redo;
196 	signal(SIGTSTP, ttystop);
197 	signal(SIGTTOU, ttystop);
198 	signal(SIGTTIN, ttystop);
199 	clearerr(stdin);
200 	while (cp2 < canonb + BUFSIZ) {
201 		c = getc(stdin);
202 		if (c == EOF || c == '\n')
203 			break;
204 		*cp2++ = c;
205 	}
206 	*cp2 = 0;
207 	signal(SIGTSTP, SIG_DFL);
208 	signal(SIGTTOU, SIG_DFL);
209 	signal(SIGTTIN, SIG_DFL);
210 	if (c == EOF && ferror(stdin)) {
211 redo:
212 		cp = strlen(canonb) > 0 ? canonb : NOSTR;
213 		clearerr(stdin);
214 		return(readtty(pr, cp));
215 	}
216 #ifndef TIOCSTI
217 	if (cp == NOSTR || *cp == '\0')
218 		return(src);
219 	cp2 = cp;
220 	if (!ttyset)
221 		return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR);
222 	while (*cp != '\0') {
223 		c = *cp++;
224 		if (c_erase != _POSIX_VDISABLE && c == c_erase) {
225 			if (cp2 == canonb)
226 				continue;
227 			if (cp2[-1] == '\\') {
228 				cp2[-1] = c;
229 				continue;
230 			}
231 			cp2--;
232 			continue;
233 		}
234 		if (c_kill != _POSIX_VDISABLE && c == c_kill) {
235 			if (cp2 == canonb)
236 				continue;
237 			if (cp2[-1] == '\\') {
238 				cp2[-1] = c;
239 				continue;
240 			}
241 			cp2 = canonb;
242 			continue;
243 		}
244 		*cp2++ = c;
245 	}
246 	*cp2 = '\0';
247 #endif
248 	if (equal("", canonb))
249 		return(NOSTR);
250 	return(savestr(canonb));
251 }
252 
253 /*
254  * Receipt continuation.
255  */
256 void
257 ttystop(s)
258 	int s;
259 {
260 	sig_t old_action = signal(s, SIG_DFL);
261 
262 	sigsetmask(sigblock(0) & ~sigmask(s));
263 	kill(0, s);
264 	sigblock(sigmask(s));
265 	signal(s, old_action);
266 	longjmp(rewrite, 1);
267 }
268 
269 /*ARGSUSED*/
270 void
271 ttyint(s)
272 	int s;
273 {
274 	longjmp(intjmp, 1);
275 }
276