]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mail/tty.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / usr.bin / mail / tty.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef lint
33 #if 0
34 static char sccsid[] = "@(#)tty.c       8.2 (Berkeley) 6/6/93";
35 #endif
36 #endif /* not lint */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 /*
41  * Mail -- a mail program
42  *
43  * Generally useful tty stuff.
44  */
45
46 #include "rcv.h"
47 #include "extern.h"
48
49 static  cc_t    c_erase;                /* Current erase char */
50 static  cc_t    c_kill;                 /* Current kill char */
51 static  jmp_buf rewrite;                /* Place to go when continued */
52 static  jmp_buf intjmp;                 /* Place to go when interrupted */
53 #ifndef TIOCSTI
54 static  int     ttyset;                 /* We must now do erase/kill */
55 #endif
56
57 /*
58  * Read all relevant header fields.
59  */
60
61 int
62 grabh(struct header *hp, int gflags)
63 {
64         struct termios ttybuf;
65         sig_t saveint;
66         sig_t savetstp;
67         sig_t savettou;
68         sig_t savettin;
69         int errs;
70 #ifndef TIOCSTI
71         sig_t savequit;
72 #else
73 # ifdef TIOCEXT
74         int extproc, flag;
75 # endif /* TIOCEXT */
76 #endif /* TIOCSTI */
77
78         savetstp = signal(SIGTSTP, SIG_DFL);
79         savettou = signal(SIGTTOU, SIG_DFL);
80         savettin = signal(SIGTTIN, SIG_DFL);
81         errs = 0;
82 #ifndef TIOCSTI
83         ttyset = 0;
84 #endif
85         if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
86                 warn("tcgetattr(stdin)");
87                 return (-1);
88         }
89         c_erase = ttybuf.c_cc[VERASE];
90         c_kill = ttybuf.c_cc[VKILL];
91 #ifndef TIOCSTI
92         ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
93         ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
94         if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
95                 (void)signal(SIGINT, SIG_DFL);
96         if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
97                 (void)signal(SIGQUIT, SIG_DFL);
98 #else
99 # ifdef         TIOCEXT
100         extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
101         if (extproc) {
102                 flag = 0;
103                 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
104                         warn("TIOCEXT: off");
105         }
106 # endif /* TIOCEXT */
107         if (setjmp(intjmp))
108                 goto out;
109         saveint = signal(SIGINT, ttyint);
110 #endif
111         if (gflags & GTO) {
112 #ifndef TIOCSTI
113                 if (!ttyset && hp->h_to != NULL)
114                         ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
115 #endif
116                 hp->h_to =
117                         extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
118         }
119         if (gflags & GSUBJECT) {
120 #ifndef TIOCSTI
121                 if (!ttyset && hp->h_subject != NULL)
122                         ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
123 #endif
124                 hp->h_subject = readtty("Subject: ", hp->h_subject);
125         }
126         if (gflags & GCC) {
127 #ifndef TIOCSTI
128                 if (!ttyset && hp->h_cc != NULL)
129                         ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
130 #endif
131                 hp->h_cc =
132                         extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
133         }
134         if (gflags & GBCC) {
135 #ifndef TIOCSTI
136                 if (!ttyset && hp->h_bcc != NULL)
137                         ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
138 #endif
139                 hp->h_bcc =
140                         extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
141         }
142 out:
143         (void)signal(SIGTSTP, savetstp);
144         (void)signal(SIGTTOU, savettou);
145         (void)signal(SIGTTIN, savettin);
146 #ifndef TIOCSTI
147         ttybuf.c_cc[VERASE] = c_erase;
148         ttybuf.c_cc[VKILL] = c_kill;
149         if (ttyset)
150                 tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
151         (void)signal(SIGQUIT, savequit);
152 #else
153 # ifdef         TIOCEXT
154         if (extproc) {
155                 flag = 1;
156                 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
157                         warn("TIOCEXT: on");
158         }
159 # endif /* TIOCEXT */
160 #endif
161         (void)signal(SIGINT, saveint);
162         return (errs);
163 }
164
165 /*
166  * Read up a header from standard input.
167  * The source string has the preliminary contents to
168  * be read.
169  *
170  */
171
172 char *
173 readtty(const char *pr, char src[])
174 {
175         char ch, canonb[BUFSIZ];
176         int c;
177         char *cp, *cp2;
178
179         fputs(pr, stdout);
180         (void)fflush(stdout);
181         if (src != NULL && strlen(src) > BUFSIZ - 2) {
182                 printf("too long to edit\n");
183                 return (src);
184         }
185 #ifndef TIOCSTI
186         if (src != NULL)
187                 strlcpy(canonb, src, sizeof(canonb));
188         else
189                 *canonb = '\0';
190         fputs(canonb, stdout);
191         (void)fflush(stdout);
192 #else
193         cp = src == NULL ? "" : src;
194         while ((c = *cp++) != '\0') {
195                 if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
196                     (c_kill != _POSIX_VDISABLE && c == c_kill)) {
197                         ch = '\\';
198                         ioctl(0, TIOCSTI, &ch);
199                 }
200                 ch = c;
201                 ioctl(0, TIOCSTI, &ch);
202         }
203         cp = canonb;
204         *cp = '\0';
205 #endif
206         cp2 = cp;
207         while (cp2 < canonb + BUFSIZ)
208                 *cp2++ = '\0';
209         cp2 = cp;
210         if (setjmp(rewrite))
211                 goto redo;
212         (void)signal(SIGTSTP, ttystop);
213         (void)signal(SIGTTOU, ttystop);
214         (void)signal(SIGTTIN, ttystop);
215         clearerr(stdin);
216         while (cp2 < canonb + BUFSIZ) {
217                 c = getc(stdin);
218                 if (c == EOF || c == '\n')
219                         break;
220                 *cp2++ = c;
221         }
222         *cp2 = '\0';
223         (void)signal(SIGTSTP, SIG_DFL);
224         (void)signal(SIGTTOU, SIG_DFL);
225         (void)signal(SIGTTIN, SIG_DFL);
226         if (c == EOF && ferror(stdin)) {
227 redo:
228                 cp = strlen(canonb) > 0 ? canonb : NULL;
229                 clearerr(stdin);
230                 return (readtty(pr, cp));
231         }
232 #ifndef TIOCSTI
233         if (cp == NULL || *cp == '\0')
234                 return (src);
235         cp2 = cp;
236         if (!ttyset)
237                 return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
238         while (*cp != '\0') {
239                 c = *cp++;
240                 if (c_erase != _POSIX_VDISABLE && c == c_erase) {
241                         if (cp2 == canonb)
242                                 continue;
243                         if (cp2[-1] == '\\') {
244                                 cp2[-1] = c;
245                                 continue;
246                         }
247                         cp2--;
248                         continue;
249                 }
250                 if (c_kill != _POSIX_VDISABLE && c == c_kill) {
251                         if (cp2 == canonb)
252                                 continue;
253                         if (cp2[-1] == '\\') {
254                                 cp2[-1] = c;
255                                 continue;
256                         }
257                         cp2 = canonb;
258                         continue;
259                 }
260                 *cp2++ = c;
261         }
262         *cp2 = '\0';
263 #endif
264         if (equal("", canonb))
265                 return (NULL);
266         return (savestr(canonb));
267 }
268
269 /*
270  * Receipt continuation.
271  */
272 void
273 ttystop(int s)
274 {
275         sig_t old_action = signal(s, SIG_DFL);
276         sigset_t nset;
277
278         (void)sigemptyset(&nset);
279         (void)sigaddset(&nset, s);
280         (void)sigprocmask(SIG_BLOCK, &nset, NULL);
281         kill(0, s);
282         (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
283         (void)signal(s, old_action);
284         longjmp(rewrite, 1);
285 }
286
287 void
288 ttyint(int s __unused)
289 {
290         longjmp(intjmp, 1);
291 }