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