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