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