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