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
grabh(hp,gflags)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 *
readtty(pr,src)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
ttystop(s)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
ttyint(s)261 ttyint(s)
262 int s;
263 {
264 longjmp(intjmp, 1);
265 }
266