11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3174769Smikeh#if 0
3288150Smikehstatic char sccsid[] = "@(#)tty.c	8.2 (Berkeley) 6/6/93";
3374769Smikeh#endif
341590Srgrimes#endif /* not lint */
3599112Sobrien#include <sys/cdefs.h>
3699112Sobrien__FBSDID("$FreeBSD: releng/10.3/usr.bin/mail/tty.c 216564 2010-12-19 16:25:23Z charnier $");
371590Srgrimes
381590Srgrimes/*
391590Srgrimes * Mail -- a mail program
401590Srgrimes *
411590Srgrimes * Generally useful tty stuff.
421590Srgrimes */
431590Srgrimes
441590Srgrimes#include "rcv.h"
451590Srgrimes#include "extern.h"
461590Srgrimes
4788150Smikehstatic	cc_t	c_erase;		/* Current erase char */
4888150Smikehstatic	cc_t	c_kill;			/* Current kill char */
491590Srgrimesstatic	jmp_buf	rewrite;		/* Place to go when continued */
501590Srgrimesstatic	jmp_buf	intjmp;			/* Place to go when interrupted */
511590Srgrimes#ifndef TIOCSTI
521590Srgrimesstatic	int	ttyset;			/* We must now do erase/kill */
531590Srgrimes#endif
541590Srgrimes
551590Srgrimes/*
561590Srgrimes * Read all relevant header fields.
571590Srgrimes */
581590Srgrimes
591590Srgrimesint
60216564Scharniergrabh(struct header *hp, int gflags)
611590Srgrimes{
6288150Smikeh	struct termios ttybuf;
631590Srgrimes	sig_t saveint;
641590Srgrimes	sig_t savetstp;
651590Srgrimes	sig_t savettou;
661590Srgrimes	sig_t savettin;
671590Srgrimes	int errs;
6888150Smikeh#ifndef TIOCSTI
6988150Smikeh	sig_t savequit;
7088150Smikeh#else
7188150Smikeh# ifdef TIOCEXT
7288150Smikeh	int extproc, flag;
7388150Smikeh# endif /* TIOCEXT */
7488150Smikeh#endif /* TIOCSTI */
751590Srgrimes
761590Srgrimes	savetstp = signal(SIGTSTP, SIG_DFL);
771590Srgrimes	savettou = signal(SIGTTOU, SIG_DFL);
781590Srgrimes	savettin = signal(SIGTTIN, SIG_DFL);
791590Srgrimes	errs = 0;
801590Srgrimes#ifndef TIOCSTI
811590Srgrimes	ttyset = 0;
821590Srgrimes#endif
8388150Smikeh	if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
8474769Smikeh		warn("tcgetattr(stdin)");
8577274Smikeh		return (-1);
861590Srgrimes	}
8788150Smikeh	c_erase = ttybuf.c_cc[VERASE];
8888150Smikeh	c_kill = ttybuf.c_cc[VKILL];
891590Srgrimes#ifndef TIOCSTI
9088150Smikeh	ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
9188150Smikeh	ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
921590Srgrimes	if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
9377274Smikeh		(void)signal(SIGINT, SIG_DFL);
941590Srgrimes	if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
9577274Smikeh		(void)signal(SIGQUIT, SIG_DFL);
961590Srgrimes#else
9788150Smikeh# ifdef		TIOCEXT
9888150Smikeh	extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
9988150Smikeh	if (extproc) {
10088150Smikeh		flag = 0;
10188150Smikeh		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
10288150Smikeh			warn("TIOCEXT: off");
10388150Smikeh	}
10488150Smikeh# endif	/* TIOCEXT */
1051590Srgrimes	if (setjmp(intjmp))
1061590Srgrimes		goto out;
1071590Srgrimes	saveint = signal(SIGINT, ttyint);
1081590Srgrimes#endif
1091590Srgrimes	if (gflags & GTO) {
1101590Srgrimes#ifndef TIOCSTI
11177274Smikeh		if (!ttyset && hp->h_to != NULL)
11288150Smikeh			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1131590Srgrimes#endif
1141590Srgrimes		hp->h_to =
1151590Srgrimes			extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
1161590Srgrimes	}
1171590Srgrimes	if (gflags & GSUBJECT) {
1181590Srgrimes#ifndef TIOCSTI
11977274Smikeh		if (!ttyset && hp->h_subject != NULL)
12088150Smikeh			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1211590Srgrimes#endif
1221590Srgrimes		hp->h_subject = readtty("Subject: ", hp->h_subject);
1231590Srgrimes	}
1241590Srgrimes	if (gflags & GCC) {
1251590Srgrimes#ifndef TIOCSTI
12677274Smikeh		if (!ttyset && hp->h_cc != NULL)
12788150Smikeh			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1281590Srgrimes#endif
1291590Srgrimes		hp->h_cc =
1301590Srgrimes			extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
1311590Srgrimes	}
1321590Srgrimes	if (gflags & GBCC) {
1331590Srgrimes#ifndef TIOCSTI
13477274Smikeh		if (!ttyset && hp->h_bcc != NULL)
13588150Smikeh			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
1361590Srgrimes#endif
1371590Srgrimes		hp->h_bcc =
1381590Srgrimes			extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
1391590Srgrimes	}
1401590Srgrimesout:
14177274Smikeh	(void)signal(SIGTSTP, savetstp);
14277274Smikeh	(void)signal(SIGTTOU, savettou);
14377274Smikeh	(void)signal(SIGTTIN, savettin);
1441590Srgrimes#ifndef TIOCSTI
14588150Smikeh	ttybuf.c_cc[VERASE] = c_erase;
14688150Smikeh	ttybuf.c_cc[VKILL] = c_kill;
1471590Srgrimes	if (ttyset)
14888150Smikeh		tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
14977274Smikeh	(void)signal(SIGQUIT, savequit);
15088150Smikeh#else
15188150Smikeh# ifdef		TIOCEXT
15288150Smikeh	if (extproc) {
15388150Smikeh		flag = 1;
15488150Smikeh		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
15588150Smikeh			warn("TIOCEXT: on");
15688150Smikeh	}
15788150Smikeh# endif	/* TIOCEXT */
1581590Srgrimes#endif
15977274Smikeh	(void)signal(SIGINT, saveint);
16077274Smikeh	return (errs);
1611590Srgrimes}
1621590Srgrimes
1631590Srgrimes/*
1641590Srgrimes * Read up a header from standard input.
1651590Srgrimes * The source string has the preliminary contents to
1661590Srgrimes * be read.
1671590Srgrimes *
1681590Srgrimes */
1691590Srgrimes
1701590Srgrimeschar *
171216564Scharnierreadtty(const char *pr, char src[])
1721590Srgrimes{
1731590Srgrimes	char ch, canonb[BUFSIZ];
1741590Srgrimes	int c;
17577274Smikeh	char *cp, *cp2;
1761590Srgrimes
1771590Srgrimes	fputs(pr, stdout);
17877274Smikeh	(void)fflush(stdout);
17977274Smikeh	if (src != NULL && strlen(src) > BUFSIZ - 2) {
1801590Srgrimes		printf("too long to edit\n");
18177274Smikeh		return (src);
1821590Srgrimes	}
1831590Srgrimes#ifndef TIOCSTI
18477274Smikeh	if (src != NULL)
18574769Smikeh		strlcpy(canonb, src, sizeof(canonb));
1861590Srgrimes	else
18774769Smikeh		*canonb = '\0';
1881590Srgrimes	fputs(canonb, stdout);
18977274Smikeh	(void)fflush(stdout);
1901590Srgrimes#else
19177274Smikeh	cp = src == NULL ? "" : src;
19277274Smikeh	while ((c = *cp++) != '\0') {
19388150Smikeh		if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
19488150Smikeh		    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
1951590Srgrimes			ch = '\\';
1961590Srgrimes			ioctl(0, TIOCSTI, &ch);
1971590Srgrimes		}
1981590Srgrimes		ch = c;
1991590Srgrimes		ioctl(0, TIOCSTI, &ch);
2001590Srgrimes	}
2011590Srgrimes	cp = canonb;
20274769Smikeh	*cp = '\0';
2031590Srgrimes#endif
2041590Srgrimes	cp2 = cp;
2051590Srgrimes	while (cp2 < canonb + BUFSIZ)
20674769Smikeh		*cp2++ = '\0';
2071590Srgrimes	cp2 = cp;
2081590Srgrimes	if (setjmp(rewrite))
2091590Srgrimes		goto redo;
21077274Smikeh	(void)signal(SIGTSTP, ttystop);
21177274Smikeh	(void)signal(SIGTTOU, ttystop);
21277274Smikeh	(void)signal(SIGTTIN, ttystop);
2131590Srgrimes	clearerr(stdin);
2141590Srgrimes	while (cp2 < canonb + BUFSIZ) {
2151590Srgrimes		c = getc(stdin);
2161590Srgrimes		if (c == EOF || c == '\n')
2171590Srgrimes			break;
2181590Srgrimes		*cp2++ = c;
2191590Srgrimes	}
22077274Smikeh	*cp2 = '\0';
22177274Smikeh	(void)signal(SIGTSTP, SIG_DFL);
22277274Smikeh	(void)signal(SIGTTOU, SIG_DFL);
22377274Smikeh	(void)signal(SIGTTIN, SIG_DFL);
2241590Srgrimes	if (c == EOF && ferror(stdin)) {
2251590Srgrimesredo:
22677274Smikeh		cp = strlen(canonb) > 0 ? canonb : NULL;
2271590Srgrimes		clearerr(stdin);
22877274Smikeh		return (readtty(pr, cp));
2291590Srgrimes	}
2301590Srgrimes#ifndef TIOCSTI
23177274Smikeh	if (cp == NULL || *cp == '\0')
23277274Smikeh		return (src);
2331590Srgrimes	cp2 = cp;
2341590Srgrimes	if (!ttyset)
23577274Smikeh		return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
2361590Srgrimes	while (*cp != '\0') {
2371590Srgrimes		c = *cp++;
23888150Smikeh		if (c_erase != _POSIX_VDISABLE && c == c_erase) {
2391590Srgrimes			if (cp2 == canonb)
2401590Srgrimes				continue;
2411590Srgrimes			if (cp2[-1] == '\\') {
2421590Srgrimes				cp2[-1] = c;
2431590Srgrimes				continue;
2441590Srgrimes			}
2451590Srgrimes			cp2--;
2461590Srgrimes			continue;
2471590Srgrimes		}
24888150Smikeh		if (c_kill != _POSIX_VDISABLE && c == c_kill) {
2491590Srgrimes			if (cp2 == canonb)
2501590Srgrimes				continue;
2511590Srgrimes			if (cp2[-1] == '\\') {
2521590Srgrimes				cp2[-1] = c;
2531590Srgrimes				continue;
2541590Srgrimes			}
2551590Srgrimes			cp2 = canonb;
2561590Srgrimes			continue;
2571590Srgrimes		}
2581590Srgrimes		*cp2++ = c;
2591590Srgrimes	}
2601590Srgrimes	*cp2 = '\0';
2611590Srgrimes#endif
2621590Srgrimes	if (equal("", canonb))
26377274Smikeh		return (NULL);
26477274Smikeh	return (savestr(canonb));
2651590Srgrimes}
2661590Srgrimes
2671590Srgrimes/*
2681590Srgrimes * Receipt continuation.
2691590Srgrimes */
2701590Srgrimesvoid
271216564Scharnierttystop(int s)
2721590Srgrimes{
2731590Srgrimes	sig_t old_action = signal(s, SIG_DFL);
27488150Smikeh	sigset_t nset;
2751590Srgrimes
27688150Smikeh	(void)sigemptyset(&nset);
27788150Smikeh	(void)sigaddset(&nset, s);
27888150Smikeh	(void)sigprocmask(SIG_BLOCK, &nset, NULL);
27988150Smikeh	kill(0, s);
28088150Smikeh	(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
28177274Smikeh	(void)signal(s, old_action);
2821590Srgrimes	longjmp(rewrite, 1);
2831590Srgrimes}
2841590Srgrimes
2851590Srgrimesvoid
286216564Scharnierttyint(int s __unused)
2871590Srgrimes{
2881590Srgrimes	longjmp(intjmp, 1);
2891590Srgrimes}
290