Home | History | Annotate | Line # | Download | only in mail
tty.c revision 1.8
      1 /*	$NetBSD: tty.c,v 1.8 1997/10/19 05:03:59 lukem Exp $	*/
      2 
      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. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)tty.c	8.2 (Berkeley) 6/6/93";
     40 #else
     41 __RCSID("$NetBSD: tty.c,v 1.8 1997/10/19 05:03:59 lukem Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 /*
     46  * Mail -- a mail program
     47  *
     48  * Generally useful tty stuff.
     49  */
     50 
     51 #include "rcv.h"
     52 #include "extern.h"
     53 
     54 static	cc_t	c_erase;		/* Current erase char */
     55 static	cc_t	c_kill;			/* Current kill char */
     56 static	jmp_buf	rewrite;		/* Place to go when continued */
     57 static	jmp_buf	intjmp;			/* Place to go when interrupted */
     58 #ifndef TIOCSTI
     59 static	int	ttyset;			/* We must now do erase/kill */
     60 #endif
     61 
     62 /*
     63  * Read all relevant header fields.
     64  */
     65 
     66 int
     67 grabh(hp, gflags)
     68 	struct header *hp;
     69 	int gflags;
     70 {
     71 	struct termios ttybuf;
     72 	sig_t saveint;
     73 #ifndef TIOCSTI
     74 	sig_t savequit;
     75 #else
     76 	int extproc, flag;
     77 #endif
     78 	sig_t savetstp;
     79 	sig_t savettou;
     80 	sig_t savettin;
     81 	int errs;
     82 #ifdef __GNUC__
     83 	/* Avoid longjmp clobbering */
     84 #ifdef TIOCSTI
     85 	(void) &extproc;
     86 #endif
     87 	(void) &saveint;
     88 #endif
     89 
     90 	savetstp = signal(SIGTSTP, SIG_DFL);
     91 	savettou = signal(SIGTTOU, SIG_DFL);
     92 	savettin = signal(SIGTTIN, SIG_DFL);
     93 	errs = 0;
     94 #ifndef TIOCSTI
     95 	ttyset = 0;
     96 #endif
     97 	if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
     98 		perror("tcgetattr");
     99 		return(-1);
    100 	}
    101 	c_erase = ttybuf.c_cc[VERASE];
    102 	c_kill = ttybuf.c_cc[VKILL];
    103 #ifndef TIOCSTI
    104 	ttybuf.c_cc[VERASE] = 0;
    105 	ttybuf.c_cc[VKILL] = 0;
    106 	if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
    107 		signal(SIGINT, SIG_DFL);
    108 	if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
    109 		signal(SIGQUIT, SIG_DFL);
    110 #else
    111 # ifdef		TIOCEXT
    112 	extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
    113 	if (extproc) {
    114 		flag = 0;
    115 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
    116 			perror("TIOCEXT: off");
    117 	}
    118 # endif	/* TIOCEXT */
    119 	if (setjmp(intjmp))
    120 		goto out;
    121 	saveint = signal(SIGINT, ttyint);
    122 #endif
    123 	if (gflags & GTO) {
    124 #ifndef TIOCSTI
    125 		if (!ttyset && hp->h_to != NIL)
    126 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    127 #endif
    128 		hp->h_to =
    129 			extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
    130 	}
    131 	if (gflags & GSUBJECT) {
    132 #ifndef TIOCSTI
    133 		if (!ttyset && hp->h_subject != NOSTR)
    134 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    135 #endif
    136 		hp->h_subject = readtty("Subject: ", hp->h_subject);
    137 	}
    138 	if (gflags & GCC) {
    139 #ifndef TIOCSTI
    140 		if (!ttyset && hp->h_cc != NIL)
    141 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    142 #endif
    143 		hp->h_cc =
    144 			extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
    145 	}
    146 	if (gflags & GBCC) {
    147 #ifndef TIOCSTI
    148 		if (!ttyset && hp->h_bcc != NIL)
    149 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    150 #endif
    151 		hp->h_bcc =
    152 			extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
    153 	}
    154 out:
    155 	signal(SIGTSTP, savetstp);
    156 	signal(SIGTTOU, savettou);
    157 	signal(SIGTTIN, savettin);
    158 #ifndef TIOCSTI
    159 	ttybuf.c_cc[VERASE] = c_erase;
    160 	ttybuf.c_cc[VKILL] = c_kill;
    161 	if (ttyset)
    162 		tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    163 	signal(SIGQUIT, savequit);
    164 #else
    165 # ifdef		TIOCEXT
    166 	if (extproc) {
    167 		flag = 1;
    168 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
    169 			perror("TIOCEXT: on");
    170 	}
    171 # endif	/* TIOCEXT */
    172 #endif
    173 	signal(SIGINT, saveint);
    174 	return(errs);
    175 }
    176 
    177 /*
    178  * Read up a header from standard input.
    179  * The source string has the preliminary contents to
    180  * be read.
    181  *
    182  */
    183 
    184 char *
    185 readtty(pr, src)
    186 	char pr[], src[];
    187 {
    188 	char ch, canonb[BUFSIZ];
    189 	int c;
    190 	char *cp, *cp2;
    191 #if __GNUC__
    192 	/* Avoid longjmp clobbering */
    193 	(void) &c;
    194 	(void) &cp2;
    195 #endif
    196 
    197 	fputs(pr, stdout);
    198 	fflush(stdout);
    199 	if (src != NOSTR && strlen(src) > BUFSIZ - 2) {
    200 		printf("too long to edit\n");
    201 		return(src);
    202 	}
    203 #ifndef TIOCSTI
    204 	if (src != NOSTR)
    205 		cp = copy(src, canonb);
    206 	else
    207 		cp = copy("", canonb);
    208 	fputs(canonb, stdout);
    209 	fflush(stdout);
    210 #else
    211 	cp = src == NOSTR ? "" : src;
    212 	while ((c = *cp++) != '\0') {
    213 		if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
    214 		    (c_kill != _POSIX_VDISABLE && c == c_kill)) {
    215 			ch = '\\';
    216 			ioctl(0, TIOCSTI, &ch);
    217 		}
    218 		ch = c;
    219 		ioctl(0, TIOCSTI, &ch);
    220 	}
    221 	cp = canonb;
    222 	*cp = 0;
    223 #endif
    224 	cp2 = cp;
    225 	while (cp2 < canonb + BUFSIZ)
    226 		*cp2++ = 0;
    227 	cp2 = cp;
    228 	if (setjmp(rewrite))
    229 		goto redo;
    230 	signal(SIGTSTP, ttystop);
    231 	signal(SIGTTOU, ttystop);
    232 	signal(SIGTTIN, ttystop);
    233 	clearerr(stdin);
    234 	while (cp2 < canonb + BUFSIZ) {
    235 		c = getc(stdin);
    236 		if (c == EOF || c == '\n')
    237 			break;
    238 		*cp2++ = c;
    239 	}
    240 	*cp2 = 0;
    241 	signal(SIGTSTP, SIG_DFL);
    242 	signal(SIGTTOU, SIG_DFL);
    243 	signal(SIGTTIN, SIG_DFL);
    244 	if (c == EOF && ferror(stdin)) {
    245 redo:
    246 		cp = strlen(canonb) > 0 ? canonb : NOSTR;
    247 		clearerr(stdin);
    248 		return(readtty(pr, cp));
    249 	}
    250 #ifndef TIOCSTI
    251 	if (cp == NOSTR || *cp == '\0')
    252 		return(src);
    253 	cp2 = cp;
    254 	if (!ttyset)
    255 		return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR);
    256 	while (*cp != '\0') {
    257 		c = *cp++;
    258 		if (c_erase != _POSIX_VDISABLE && c == c_erase) {
    259 			if (cp2 == canonb)
    260 				continue;
    261 			if (cp2[-1] == '\\') {
    262 				cp2[-1] = c;
    263 				continue;
    264 			}
    265 			cp2--;
    266 			continue;
    267 		}
    268 		if (c_kill != _POSIX_VDISABLE && c == c_kill) {
    269 			if (cp2 == canonb)
    270 				continue;
    271 			if (cp2[-1] == '\\') {
    272 				cp2[-1] = c;
    273 				continue;
    274 			}
    275 			cp2 = canonb;
    276 			continue;
    277 		}
    278 		*cp2++ = c;
    279 	}
    280 	*cp2 = '\0';
    281 #endif
    282 	if (equal("", canonb))
    283 		return(NOSTR);
    284 	return(savestr(canonb));
    285 }
    286 
    287 /*
    288  * Receipt continuation.
    289  */
    290 void
    291 ttystop(s)
    292 	int s;
    293 {
    294 	sig_t old_action = signal(s, SIG_DFL);
    295 	sigset_t nset;
    296 
    297 	sigemptyset(&nset);
    298 	sigaddset(&nset, s);
    299 	sigprocmask(SIG_BLOCK, &nset, NULL);
    300 	kill(0, s);
    301 	sigprocmask(SIG_UNBLOCK, &nset, NULL);
    302 	signal(s, old_action);
    303 	longjmp(rewrite, 1);
    304 }
    305 
    306 /*ARGSUSED*/
    307 void
    308 ttyint(s)
    309 	int s;
    310 {
    311 	longjmp(intjmp, 1);
    312 }
    313