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