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