xref: /freebsd/usr.bin/mail/tty.c (revision c3dbcadca2680b8f04d8c910eae8f82868994c0d)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #ifndef lint
330c3a8314SMike Heffner #if 0
34856f23edSMike Heffner static char sccsid[] = "@(#)tty.c	8.2 (Berkeley) 6/6/93";
350c3a8314SMike Heffner #endif
369b50d902SRodney W. Grimes #endif /* not lint */
37e026a48cSDavid E. O'Brien #include <sys/cdefs.h>
38e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$");
399b50d902SRodney W. Grimes 
409b50d902SRodney W. Grimes /*
419b50d902SRodney W. Grimes  * Mail -- a mail program
429b50d902SRodney W. Grimes  *
439b50d902SRodney W. Grimes  * Generally useful tty stuff.
449b50d902SRodney W. Grimes  */
459b50d902SRodney W. Grimes 
469b50d902SRodney W. Grimes #include "rcv.h"
479b50d902SRodney W. Grimes #include "extern.h"
489b50d902SRodney W. Grimes 
49856f23edSMike Heffner static	cc_t	c_erase;		/* Current erase char */
50856f23edSMike Heffner static	cc_t	c_kill;			/* Current kill char */
519b50d902SRodney W. Grimes static	jmp_buf	rewrite;		/* Place to go when continued */
529b50d902SRodney W. Grimes static	jmp_buf	intjmp;			/* Place to go when interrupted */
539b50d902SRodney W. Grimes #ifndef TIOCSTI
549b50d902SRodney W. Grimes static	int	ttyset;			/* We must now do erase/kill */
559b50d902SRodney W. Grimes #endif
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes /*
589b50d902SRodney W. Grimes  * Read all relevant header fields.
599b50d902SRodney W. Grimes  */
609b50d902SRodney W. Grimes 
619b50d902SRodney W. Grimes int
626d8484b0SPhilippe Charnier grabh(struct header *hp, int gflags)
639b50d902SRodney W. Grimes {
64856f23edSMike Heffner 	struct termios ttybuf;
659b50d902SRodney W. Grimes 	sig_t saveint;
669b50d902SRodney W. Grimes 	sig_t savetstp;
679b50d902SRodney W. Grimes 	sig_t savettou;
689b50d902SRodney W. Grimes 	sig_t savettin;
699b50d902SRodney W. Grimes 	int errs;
70856f23edSMike Heffner #ifndef TIOCSTI
71856f23edSMike Heffner 	sig_t savequit;
72856f23edSMike Heffner #else
73856f23edSMike Heffner # ifdef TIOCEXT
74856f23edSMike Heffner 	int extproc, flag;
75856f23edSMike Heffner # endif /* TIOCEXT */
76856f23edSMike Heffner #endif /* TIOCSTI */
779b50d902SRodney W. Grimes 
789b50d902SRodney W. Grimes 	savetstp = signal(SIGTSTP, SIG_DFL);
799b50d902SRodney W. Grimes 	savettou = signal(SIGTTOU, SIG_DFL);
809b50d902SRodney W. Grimes 	savettin = signal(SIGTTIN, SIG_DFL);
819b50d902SRodney W. Grimes 	errs = 0;
829b50d902SRodney W. Grimes #ifndef TIOCSTI
839b50d902SRodney W. Grimes 	ttyset = 0;
849b50d902SRodney W. Grimes #endif
85856f23edSMike Heffner 	if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
860c3a8314SMike Heffner 		warn("tcgetattr(stdin)");
879b50d902SRodney W. Grimes 		return (-1);
889b50d902SRodney W. Grimes 	}
89856f23edSMike Heffner 	c_erase = ttybuf.c_cc[VERASE];
90856f23edSMike Heffner 	c_kill = ttybuf.c_cc[VKILL];
919b50d902SRodney W. Grimes #ifndef TIOCSTI
92856f23edSMike Heffner 	ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
93856f23edSMike Heffner 	ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
949b50d902SRodney W. Grimes 	if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
959ce73e90SMike Heffner 		(void)signal(SIGINT, SIG_DFL);
969b50d902SRodney W. Grimes 	if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
979ce73e90SMike Heffner 		(void)signal(SIGQUIT, SIG_DFL);
989b50d902SRodney W. Grimes #else
99856f23edSMike Heffner # ifdef		TIOCEXT
100856f23edSMike Heffner 	extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
101856f23edSMike Heffner 	if (extproc) {
102856f23edSMike Heffner 		flag = 0;
103856f23edSMike Heffner 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
104856f23edSMike Heffner 			warn("TIOCEXT: off");
105856f23edSMike Heffner 	}
106856f23edSMike Heffner # endif	/* TIOCEXT */
1079b50d902SRodney W. Grimes 	if (setjmp(intjmp))
1089b50d902SRodney W. Grimes 		goto out;
1099b50d902SRodney W. Grimes 	saveint = signal(SIGINT, ttyint);
1109b50d902SRodney W. Grimes #endif
1119b50d902SRodney W. Grimes 	if (gflags & GTO) {
1129b50d902SRodney W. Grimes #ifndef TIOCSTI
1139ce73e90SMike Heffner 		if (!ttyset && hp->h_to != NULL)
114856f23edSMike Heffner 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1159b50d902SRodney W. Grimes #endif
1169b50d902SRodney W. Grimes 		hp->h_to =
1179b50d902SRodney W. Grimes 			extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
1189b50d902SRodney W. Grimes 	}
1199b50d902SRodney W. Grimes 	if (gflags & GSUBJECT) {
1209b50d902SRodney W. Grimes #ifndef TIOCSTI
1219ce73e90SMike Heffner 		if (!ttyset && hp->h_subject != NULL)
122856f23edSMike Heffner 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1239b50d902SRodney W. Grimes #endif
1249b50d902SRodney W. Grimes 		hp->h_subject = readtty("Subject: ", hp->h_subject);
1259b50d902SRodney W. Grimes 	}
1269b50d902SRodney W. Grimes 	if (gflags & GCC) {
1279b50d902SRodney W. Grimes #ifndef TIOCSTI
1289ce73e90SMike Heffner 		if (!ttyset && hp->h_cc != NULL)
129856f23edSMike Heffner 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1309b50d902SRodney W. Grimes #endif
1319b50d902SRodney W. Grimes 		hp->h_cc =
1329b50d902SRodney W. Grimes 			extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
1339b50d902SRodney W. Grimes 	}
1349b50d902SRodney W. Grimes 	if (gflags & GBCC) {
1359b50d902SRodney W. Grimes #ifndef TIOCSTI
1369ce73e90SMike Heffner 		if (!ttyset && hp->h_bcc != NULL)
137856f23edSMike Heffner 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1389b50d902SRodney W. Grimes #endif
1399b50d902SRodney W. Grimes 		hp->h_bcc =
1409b50d902SRodney W. Grimes 			extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
1419b50d902SRodney W. Grimes 	}
142*c3dbcadcSEd Maste #ifdef TIOCSTI
1439b50d902SRodney W. Grimes out:
144*c3dbcadcSEd Maste #endif
1459ce73e90SMike Heffner 	(void)signal(SIGTSTP, savetstp);
1469ce73e90SMike Heffner 	(void)signal(SIGTTOU, savettou);
1479ce73e90SMike Heffner 	(void)signal(SIGTTIN, savettin);
1489b50d902SRodney W. Grimes #ifndef TIOCSTI
149856f23edSMike Heffner 	ttybuf.c_cc[VERASE] = c_erase;
150856f23edSMike Heffner 	ttybuf.c_cc[VKILL] = c_kill;
1519b50d902SRodney W. Grimes 	if (ttyset)
152856f23edSMike Heffner 		tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1539ce73e90SMike Heffner 	(void)signal(SIGQUIT, savequit);
154856f23edSMike Heffner #else
155856f23edSMike Heffner # ifdef		TIOCEXT
156856f23edSMike Heffner 	if (extproc) {
157856f23edSMike Heffner 		flag = 1;
158856f23edSMike Heffner 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
159856f23edSMike Heffner 			warn("TIOCEXT: on");
160856f23edSMike Heffner 	}
161856f23edSMike Heffner # endif	/* TIOCEXT */
1629b50d902SRodney W. Grimes #endif
1639ce73e90SMike Heffner 	(void)signal(SIGINT, saveint);
1649b50d902SRodney W. Grimes 	return (errs);
1659b50d902SRodney W. Grimes }
1669b50d902SRodney W. Grimes 
1679b50d902SRodney W. Grimes /*
1689b50d902SRodney W. Grimes  * Read up a header from standard input.
1699b50d902SRodney W. Grimes  * The source string has the preliminary contents to
1709b50d902SRodney W. Grimes  * be read.
1719b50d902SRodney W. Grimes  *
1729b50d902SRodney W. Grimes  */
1739b50d902SRodney W. Grimes 
1749b50d902SRodney W. Grimes char *
1756d8484b0SPhilippe Charnier readtty(const char *pr, char src[])
1769b50d902SRodney W. Grimes {
177*c3dbcadcSEd Maste 	char canonb[BUFSIZ];
178*c3dbcadcSEd Maste #ifdef TIOCSTI
179*c3dbcadcSEd Maste 	char ch;
180*c3dbcadcSEd Maste #endif
1819b50d902SRodney W. Grimes 	int c;
1829ce73e90SMike Heffner 	char *cp, *cp2;
1839b50d902SRodney W. Grimes 
1849b50d902SRodney W. Grimes 	fputs(pr, stdout);
1859ce73e90SMike Heffner 	(void)fflush(stdout);
1869ce73e90SMike Heffner 	if (src != NULL && strlen(src) > BUFSIZ - 2) {
1879b50d902SRodney W. Grimes 		printf("too long to edit\n");
1889b50d902SRodney W. Grimes 		return (src);
1899b50d902SRodney W. Grimes 	}
1909b50d902SRodney W. Grimes #ifndef TIOCSTI
1919ce73e90SMike Heffner 	if (src != NULL)
1920c3a8314SMike Heffner 		strlcpy(canonb, src, sizeof(canonb));
1939b50d902SRodney W. Grimes 	else
1940c3a8314SMike Heffner 		*canonb = '\0';
1959b50d902SRodney W. Grimes 	fputs(canonb, stdout);
1969ce73e90SMike Heffner 	(void)fflush(stdout);
1979b50d902SRodney W. Grimes #else
1989ce73e90SMike Heffner 	cp = src == NULL ? "" : src;
1999ce73e90SMike Heffner 	while ((c = *cp++) != '\0') {
200856f23edSMike Heffner 		if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
201856f23edSMike Heffner 		    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
2029b50d902SRodney W. Grimes 			ch = '\\';
2039b50d902SRodney W. Grimes 			ioctl(0, TIOCSTI, &ch);
2049b50d902SRodney W. Grimes 		}
2059b50d902SRodney W. Grimes 		ch = c;
2069b50d902SRodney W. Grimes 		ioctl(0, TIOCSTI, &ch);
2079b50d902SRodney W. Grimes 	}
2089b50d902SRodney W. Grimes 	cp = canonb;
2090c3a8314SMike Heffner 	*cp = '\0';
2109b50d902SRodney W. Grimes #endif
2119b50d902SRodney W. Grimes 	cp2 = cp;
2129b50d902SRodney W. Grimes 	while (cp2 < canonb + BUFSIZ)
2130c3a8314SMike Heffner 		*cp2++ = '\0';
2149b50d902SRodney W. Grimes 	cp2 = cp;
2159b50d902SRodney W. Grimes 	if (setjmp(rewrite))
2169b50d902SRodney W. Grimes 		goto redo;
2179ce73e90SMike Heffner 	(void)signal(SIGTSTP, ttystop);
2189ce73e90SMike Heffner 	(void)signal(SIGTTOU, ttystop);
2199ce73e90SMike Heffner 	(void)signal(SIGTTIN, ttystop);
2209b50d902SRodney W. Grimes 	clearerr(stdin);
2219b50d902SRodney W. Grimes 	while (cp2 < canonb + BUFSIZ) {
2229b50d902SRodney W. Grimes 		c = getc(stdin);
2239b50d902SRodney W. Grimes 		if (c == EOF || c == '\n')
2249b50d902SRodney W. Grimes 			break;
2259b50d902SRodney W. Grimes 		*cp2++ = c;
2269b50d902SRodney W. Grimes 	}
2279ce73e90SMike Heffner 	*cp2 = '\0';
2289ce73e90SMike Heffner 	(void)signal(SIGTSTP, SIG_DFL);
2299ce73e90SMike Heffner 	(void)signal(SIGTTOU, SIG_DFL);
2309ce73e90SMike Heffner 	(void)signal(SIGTTIN, SIG_DFL);
2319b50d902SRodney W. Grimes 	if (c == EOF && ferror(stdin)) {
2329b50d902SRodney W. Grimes redo:
2339ce73e90SMike Heffner 		cp = strlen(canonb) > 0 ? canonb : NULL;
2349b50d902SRodney W. Grimes 		clearerr(stdin);
2359b50d902SRodney W. Grimes 		return (readtty(pr, cp));
2369b50d902SRodney W. Grimes 	}
2379b50d902SRodney W. Grimes #ifndef TIOCSTI
2389ce73e90SMike Heffner 	if (cp == NULL || *cp == '\0')
2399b50d902SRodney W. Grimes 		return (src);
2409b50d902SRodney W. Grimes 	cp2 = cp;
2419b50d902SRodney W. Grimes 	if (!ttyset)
2429ce73e90SMike Heffner 		return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
2439b50d902SRodney W. Grimes 	while (*cp != '\0') {
2449b50d902SRodney W. Grimes 		c = *cp++;
245856f23edSMike Heffner 		if (c_erase != _POSIX_VDISABLE && c == c_erase) {
2469b50d902SRodney W. Grimes 			if (cp2 == canonb)
2479b50d902SRodney W. Grimes 				continue;
2489b50d902SRodney W. Grimes 			if (cp2[-1] == '\\') {
2499b50d902SRodney W. Grimes 				cp2[-1] = c;
2509b50d902SRodney W. Grimes 				continue;
2519b50d902SRodney W. Grimes 			}
2529b50d902SRodney W. Grimes 			cp2--;
2539b50d902SRodney W. Grimes 			continue;
2549b50d902SRodney W. Grimes 		}
255856f23edSMike Heffner 		if (c_kill != _POSIX_VDISABLE && c == c_kill) {
2569b50d902SRodney W. Grimes 			if (cp2 == canonb)
2579b50d902SRodney W. Grimes 				continue;
2589b50d902SRodney W. Grimes 			if (cp2[-1] == '\\') {
2599b50d902SRodney W. Grimes 				cp2[-1] = c;
2609b50d902SRodney W. Grimes 				continue;
2619b50d902SRodney W. Grimes 			}
2629b50d902SRodney W. Grimes 			cp2 = canonb;
2639b50d902SRodney W. Grimes 			continue;
2649b50d902SRodney W. Grimes 		}
2659b50d902SRodney W. Grimes 		*cp2++ = c;
2669b50d902SRodney W. Grimes 	}
2679b50d902SRodney W. Grimes 	*cp2 = '\0';
2689b50d902SRodney W. Grimes #endif
2699b50d902SRodney W. Grimes 	if (equal("", canonb))
2709ce73e90SMike Heffner 		return (NULL);
2719b50d902SRodney W. Grimes 	return (savestr(canonb));
2729b50d902SRodney W. Grimes }
2739b50d902SRodney W. Grimes 
2749b50d902SRodney W. Grimes /*
2759b50d902SRodney W. Grimes  * Receipt continuation.
2769b50d902SRodney W. Grimes  */
2779b50d902SRodney W. Grimes void
2786d8484b0SPhilippe Charnier ttystop(int s)
2799b50d902SRodney W. Grimes {
2809b50d902SRodney W. Grimes 	sig_t old_action = signal(s, SIG_DFL);
281856f23edSMike Heffner 	sigset_t nset;
2829b50d902SRodney W. Grimes 
283856f23edSMike Heffner 	(void)sigemptyset(&nset);
284856f23edSMike Heffner 	(void)sigaddset(&nset, s);
285856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, NULL);
286856f23edSMike Heffner 	kill(0, s);
287856f23edSMike Heffner 	(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
2889ce73e90SMike Heffner 	(void)signal(s, old_action);
2899b50d902SRodney W. Grimes 	longjmp(rewrite, 1);
2909b50d902SRodney W. Grimes }
2919b50d902SRodney W. Grimes 
2929b50d902SRodney W. Grimes void
2936d8484b0SPhilippe Charnier ttyint(int s __unused)
2949b50d902SRodney W. Grimes {
2959b50d902SRodney W. Grimes 	longjmp(intjmp, 1);
2969b50d902SRodney W. Grimes }
297