Home | History | Annotate | Line # | Download | only in mail
tty.c revision 1.15
      1 /*	$NetBSD: tty.c,v 1.15 2002/03/05 21:18:15 wiz 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.15 2002/03/05 21:18:15 wiz 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(struct header *hp, int gflags)
     68 {
     69 	struct termios ttybuf;
     70 	sig_t saveint;
     71 	sig_t savetstp;
     72 	sig_t savettou;
     73 	sig_t savettin;
     74 	int errs;
     75 #ifndef TIOCSTI
     76 	sig_t savequit;
     77 #else
     78 # ifdef TIOCEXT
     79 	int extproc, flag;
     80 # endif /* TIOCEXT */
     81 #endif /* TIOCSTI */
     82 
     83 #ifdef __GNUC__
     84 	/* Avoid longjmp clobbering */
     85 # if defined(TIOCSTI) && defined(TIOCEXT)
     86 	(void)&extproc;
     87 # endif
     88 	(void)&saveint;
     89 #endif /* __GNUC__ */
     90 
     91 	savetstp = signal(SIGTSTP, SIG_DFL);
     92 	savettou = signal(SIGTTOU, SIG_DFL);
     93 	savettin = signal(SIGTTIN, SIG_DFL);
     94 	errs = 0;
     95 #ifndef TIOCSTI
     96 	ttyset = 0;
     97 #endif
     98 	if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
     99 		perror("tcgetattr");
    100 		return(-1);
    101 	}
    102 	c_erase = ttybuf.c_cc[VERASE];
    103 	c_kill = ttybuf.c_cc[VKILL];
    104 #ifndef TIOCSTI
    105 	ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
    106 	ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
    107 	if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
    108 		signal(SIGINT, SIG_DFL);
    109 	if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
    110 		signal(SIGQUIT, SIG_DFL);
    111 #else
    112 # ifdef		TIOCEXT
    113 	extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
    114 	if (extproc) {
    115 		flag = 0;
    116 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
    117 			perror("TIOCEXT: off");
    118 	}
    119 # endif	/* TIOCEXT */
    120 	if (setjmp(intjmp))
    121 		goto out;
    122 	saveint = signal(SIGINT, ttyint);
    123 #endif
    124 	if (gflags & GTO) {
    125 #ifndef TIOCSTI
    126 		if (!ttyset && hp->h_to != NULL)
    127 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    128 #endif
    129 		hp->h_to =
    130 			extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
    131 	}
    132 	if (gflags & GSUBJECT) {
    133 #ifndef TIOCSTI
    134 		if (!ttyset && hp->h_subject != NULL)
    135 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    136 #endif
    137 		hp->h_subject = readtty("Subject: ", hp->h_subject);
    138 	}
    139 	if (gflags & GCC) {
    140 #ifndef TIOCSTI
    141 		if (!ttyset && hp->h_cc != NULL)
    142 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    143 #endif
    144 		hp->h_cc =
    145 			extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
    146 	}
    147 	if (gflags & GBCC) {
    148 #ifndef TIOCSTI
    149 		if (!ttyset && hp->h_bcc != NULL)
    150 			ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    151 #endif
    152 		hp->h_bcc =
    153 			extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
    154 	}
    155 out:
    156 	signal(SIGTSTP, savetstp);
    157 	signal(SIGTTOU, savettou);
    158 	signal(SIGTTIN, savettin);
    159 #ifndef TIOCSTI
    160 	ttybuf.c_cc[VERASE] = c_erase;
    161 	ttybuf.c_cc[VKILL] = c_kill;
    162 	if (ttyset)
    163 		tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
    164 	signal(SIGQUIT, savequit);
    165 #else
    166 # ifdef		TIOCEXT
    167 	if (extproc) {
    168 		flag = 1;
    169 		if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
    170 			perror("TIOCEXT: on");
    171 	}
    172 # endif	/* TIOCEXT */
    173 #endif
    174 	signal(SIGINT, saveint);
    175 	return(errs);
    176 }
    177 
    178 /*
    179  * Read up a header from standard input.
    180  * The source string has the preliminary contents to
    181  * be read.
    182  *
    183  */
    184 
    185 char *
    186 readtty(char pr[], char 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 != NULL && strlen(src) > BUFSIZ - 2) {
    200 		printf("too long to edit\n");
    201 		return(src);
    202 	}
    203 #ifndef TIOCSTI
    204 	if (src != NULL)
    205 		cp = copy(src, canonb);
    206 	else
    207 		cp = copy("", canonb);
    208 	fputs(canonb, stdout);
    209 	fflush(stdout);
    210 #else
    211 	cp = src == NULL ? "" : 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 : NULL;
    247 		clearerr(stdin);
    248 		return(readtty(pr, cp));
    249 	}
    250 #ifndef TIOCSTI
    251 	if (cp == NULL || *cp == '\0')
    252 		return(src);
    253 	cp2 = cp;
    254 	if (!ttyset)
    255 		return(strlen(canonb) > 0 ? savestr(canonb) : NULL);
    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(NULL);
    284 	return(savestr(canonb));
    285 }
    286 
    287 /*
    288  * Receipt continuation.
    289  */
    290 void
    291 ttystop(int s)
    292 {
    293 	sig_t old_action = signal(s, SIG_DFL);
    294 	sigset_t nset;
    295 
    296 	sigemptyset(&nset);
    297 	sigaddset(&nset, s);
    298 	sigprocmask(SIG_BLOCK, &nset, NULL);
    299 	kill(0, s);
    300 	sigprocmask(SIG_UNBLOCK, &nset, NULL);
    301 	signal(s, old_action);
    302 	longjmp(rewrite, 1);
    303 }
    304 
    305 /*ARGSUSED*/
    306 void
    307 ttyint(int s)
    308 {
    309 	longjmp(intjmp, 1);
    310 }
    311