]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mail/tty.c
Merge llvm-project release/16.x llvmorg-16.0.1-0-gcd89023f7979
[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 #ifdef TIOCSTI
143 out:
144 #endif
145         (void)signal(SIGTSTP, savetstp);
146         (void)signal(SIGTTOU, savettou);
147         (void)signal(SIGTTIN, savettin);
148 #ifndef TIOCSTI
149         ttybuf.c_cc[VERASE] = c_erase;
150         ttybuf.c_cc[VKILL] = c_kill;
151         if (ttyset)
152                 tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
153         (void)signal(SIGQUIT, savequit);
154 #else
155 # ifdef         TIOCEXT
156         if (extproc) {
157                 flag = 1;
158                 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
159                         warn("TIOCEXT: on");
160         }
161 # endif /* TIOCEXT */
162 #endif
163         (void)signal(SIGINT, saveint);
164         return (errs);
165 }
166
167 /*
168  * Read up a header from standard input.
169  * The source string has the preliminary contents to
170  * be read.
171  *
172  */
173
174 char *
175 readtty(const char *pr, char src[])
176 {
177         char canonb[BUFSIZ];
178 #ifdef TIOCSTI
179         char ch;
180 #endif
181         int c;
182         char *cp, *cp2;
183
184         fputs(pr, stdout);
185         (void)fflush(stdout);
186         if (src != NULL && strlen(src) > BUFSIZ - 2) {
187                 printf("too long to edit\n");
188                 return (src);
189         }
190 #ifndef TIOCSTI
191         if (src != NULL)
192                 strlcpy(canonb, src, sizeof(canonb));
193         else
194                 *canonb = '\0';
195         fputs(canonb, stdout);
196         (void)fflush(stdout);
197 #else
198         cp = src == NULL ? "" : src;
199         while ((c = *cp++) != '\0') {
200                 if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
201                     (c_kill != _POSIX_VDISABLE && c == c_kill)) {
202                         ch = '\\';
203                         ioctl(0, TIOCSTI, &ch);
204                 }
205                 ch = c;
206                 ioctl(0, TIOCSTI, &ch);
207         }
208         cp = canonb;
209         *cp = '\0';
210 #endif
211         cp2 = cp;
212         while (cp2 < canonb + BUFSIZ)
213                 *cp2++ = '\0';
214         cp2 = cp;
215         if (setjmp(rewrite))
216                 goto redo;
217         (void)signal(SIGTSTP, ttystop);
218         (void)signal(SIGTTOU, ttystop);
219         (void)signal(SIGTTIN, ttystop);
220         clearerr(stdin);
221         while (cp2 < canonb + BUFSIZ) {
222                 c = getc(stdin);
223                 if (c == EOF || c == '\n')
224                         break;
225                 *cp2++ = c;
226         }
227         *cp2 = '\0';
228         (void)signal(SIGTSTP, SIG_DFL);
229         (void)signal(SIGTTOU, SIG_DFL);
230         (void)signal(SIGTTIN, SIG_DFL);
231         if (c == EOF && ferror(stdin)) {
232 redo:
233                 cp = strlen(canonb) > 0 ? canonb : NULL;
234                 clearerr(stdin);
235                 return (readtty(pr, cp));
236         }
237 #ifndef TIOCSTI
238         if (cp == NULL || *cp == '\0')
239                 return (src);
240         cp2 = cp;
241         if (!ttyset)
242                 return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
243         while (*cp != '\0') {
244                 c = *cp++;
245                 if (c_erase != _POSIX_VDISABLE && c == c_erase) {
246                         if (cp2 == canonb)
247                                 continue;
248                         if (cp2[-1] == '\\') {
249                                 cp2[-1] = c;
250                                 continue;
251                         }
252                         cp2--;
253                         continue;
254                 }
255                 if (c_kill != _POSIX_VDISABLE && c == c_kill) {
256                         if (cp2 == canonb)
257                                 continue;
258                         if (cp2[-1] == '\\') {
259                                 cp2[-1] = c;
260                                 continue;
261                         }
262                         cp2 = canonb;
263                         continue;
264                 }
265                 *cp2++ = c;
266         }
267         *cp2 = '\0';
268 #endif
269         if (equal("", canonb))
270                 return (NULL);
271         return (savestr(canonb));
272 }
273
274 /*
275  * Receipt continuation.
276  */
277 void
278 ttystop(int s)
279 {
280         sig_t old_action = signal(s, SIG_DFL);
281         sigset_t nset;
282
283         (void)sigemptyset(&nset);
284         (void)sigaddset(&nset, s);
285         (void)sigprocmask(SIG_BLOCK, &nset, NULL);
286         kill(0, s);
287         (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
288         (void)signal(s, old_action);
289         longjmp(rewrite, 1);
290 }
291
292 void
293 ttyint(int s __unused)
294 {
295         longjmp(intjmp, 1);
296 }