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