1161754Sru/*	$OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $	*/
288276Smarkm/*	$NetBSD: cmds.c,v 1.7 1997/02/11 09:24:03 mrg Exp $	*/
388276Smarkm
47527Sjkh/*
57527Sjkh * Copyright (c) 1983, 1993
67527Sjkh *	The Regents of the University of California.  All rights reserved.
77527Sjkh *
87527Sjkh * Redistribution and use in source and binary forms, with or without
97527Sjkh * modification, are permitted provided that the following conditions
107527Sjkh * are met:
117527Sjkh * 1. Redistributions of source code must retain the above copyright
127527Sjkh *    notice, this list of conditions and the following disclaimer.
137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright
147527Sjkh *    notice, this list of conditions and the following disclaimer in the
157527Sjkh *    documentation and/or other materials provided with the distribution.
16161754Sru * 3. Neither the name of the University nor the names of its contributors
177527Sjkh *    may be used to endorse or promote products derived from this software
187527Sjkh *    without specific prior written permission.
197527Sjkh *
207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237527Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307527Sjkh * SUCH DAMAGE.
317527Sjkh */
327527Sjkh
3388276Smarkm#include <sys/cdefs.h>
3488276Smarkm__FBSDID("$FreeBSD$");
3588276Smarkm
367527Sjkh#ifndef lint
3728365Scharnier#if 0
387527Sjkhstatic char sccsid[] = "@(#)cmds.c	8.1 (Berkeley) 6/6/93";
39161754Srustatic const char rcsid[] = "$OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $";
4028365Scharnier#endif
417527Sjkh#endif /* not lint */
427527Sjkh
437527Sjkh#include "tip.h"
447527Sjkh#include "pathnames.h"
457527Sjkh
4688276Smarkm#include <vis.h>
477527Sjkh
487527Sjkh/*
497527Sjkh * tip
507527Sjkh *
517527Sjkh * miscellaneous commands
527527Sjkh */
537527Sjkh
547527Sjkhint	quant[] = { 60, 60, 24 };
557527Sjkh
567527Sjkhchar	null = '\0';
577527Sjkhchar	*sep[] = { "second", "minute", "hour" };
587527Sjkhstatic char *argv[10];		/* argument vector for take and put */
597527Sjkh
60161754Srustatic void	transfer(char *, int, char *);
61161754Srustatic void	stopsnd(int);	/* SIGINT handler during file transfers */
62161754Srustatic void	intcopy(int);	/* interrupt routine for file transfers */
63161754Srustatic void	transmit(FILE *, char *, char *);
64161754Srustatic void	send(int);
65161754Srustatic void	execute(char *);
66161754Srustatic int	args(char *, char **, int);
67161754Srustatic void	prtime(char *, time_t);
68161754Srustatic void	tandem(char *);
69161754Srustatic void	hardwareflow(char *);
70161754Sruvoid		linedisc(char *);
71161754Srustatic int	anyof(char *, char *);
7228788Seivind
737527Sjkh/*
747527Sjkh * FTP - remote ==> local
757527Sjkh *  get a file from the remote host
767527Sjkh */
7728365Scharniervoid
78161754Srugetfl(int c)
797527Sjkh{
80161754Sru	char buf[256], *cp;
81161754Sru
827527Sjkh	putchar(c);
837527Sjkh	/*
847527Sjkh	 * get the UNIX receiving file's name
857527Sjkh	 */
8628606Simp	if (prompt("Local file name? ", copyname, sizeof(copyname)))
877527Sjkh		return;
887527Sjkh	cp = expand(copyname);
897527Sjkh	if ((sfd = creat(cp, 0666)) < 0) {
907527Sjkh		printf("\r\n%s: cannot creat\r\n", copyname);
917527Sjkh		return;
927527Sjkh	}
93161754Sru
947527Sjkh	/*
957527Sjkh	 * collect parameters
967527Sjkh	 */
9728606Simp	if (prompt("List command for remote system? ", buf, sizeof(buf))) {
987527Sjkh		unlink(copyname);
997527Sjkh		return;
1007527Sjkh	}
1017527Sjkh	transfer(buf, sfd, value(EOFREAD));
1027527Sjkh}
1037527Sjkh
1047527Sjkh/*
1057527Sjkh * Cu-like take command
1067527Sjkh */
10728365Scharniervoid
108161754Srucu_take(int c)
1097527Sjkh{
1107527Sjkh	int fd, argc;
111161754Sru	char line[BUFSIZ], *cp;
1127527Sjkh
11328606Simp	if (prompt("[take] ", copyname, sizeof(copyname)))
1147527Sjkh		return;
11588276Smarkm	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
11688276Smarkm	    argc > 2) {
1177527Sjkh		printf("usage: <take> from [to]\r\n");
1187527Sjkh		return;
1197527Sjkh	}
1207527Sjkh	if (argc == 1)
1217527Sjkh		argv[1] = argv[0];
1227527Sjkh	cp = expand(argv[1]);
1237527Sjkh	if ((fd = creat(cp, 0666)) < 0) {
1247527Sjkh		printf("\r\n%s: cannot create\r\n", argv[1]);
1257527Sjkh		return;
1267527Sjkh	}
127161754Sru	(void)snprintf(line, sizeof(line), "cat %s;echo ''|tr '\\012' '\\01'", argv[0]);
12888276Smarkm	transfer(line, fd, "\01");
1297527Sjkh}
1307527Sjkh
13188276Smarkmstatic	jmp_buf intbuf;
1327527Sjkh
1337527Sjkh/*
1347527Sjkh * Bulk transfer routine --
1357527Sjkh *  used by getfl(), cu_take(), and pipefile()
1367527Sjkh */
137161754Srustatic void
138161754Srutransfer(char *buf, int fd, char *eofchars)
1397527Sjkh{
140161754Sru	int ct, eof;
14188276Smarkm	char c, buffer[BUFSIZ];
14288276Smarkm	char *p = buffer;
143161754Sru	size_t cnt;
1447527Sjkh	time_t start;
1457527Sjkh	sig_t f;
1467527Sjkh	char r;
1477527Sjkh
148161754Sru	if (number(value(FRAMESIZE)) > BUFSIZ || number(value(FRAMESIZE)) < 1) {
149161754Sru		printf("framesize must be >= 1 and <= %d\r\n", BUFSIZ);
150161754Sru		close(fd);
151161754Sru		return;
152161754Sru	}
153161754Sru
15488276Smarkm	parwrite(FD, buf, size(buf));
1557527Sjkh	quit = 0;
156161754Sru	kill(tipout_pid, SIGIOT);
1577527Sjkh	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
158161754Sru
1597527Sjkh	/*
1607527Sjkh	 * finish command
1617527Sjkh	 */
1627527Sjkh	r = '\r';
16388276Smarkm	parwrite(FD, &r, 1);
1647527Sjkh	do
165161754Sru		read(FD, &c, 1);
16688276Smarkm	while ((c&STRIP_PAR) != '\n');
16788276Smarkm	tcsetattr(0, TCSAFLUSH, &defchars);
168161754Sru
1697527Sjkh	(void) setjmp(intbuf);
1707527Sjkh	f = signal(SIGINT, intcopy);
1717527Sjkh	start = time(0);
1727527Sjkh	for (ct = 0; !quit;) {
1737527Sjkh		eof = read(FD, &c, 1) <= 0;
17488276Smarkm		c &= STRIP_PAR;
1757527Sjkh		if (quit)
1767527Sjkh			continue;
1777527Sjkh		if (eof || any(c, eofchars))
1787527Sjkh			break;
1797527Sjkh		if (c == 0)
1807527Sjkh			continue;	/* ignore nulls */
1817527Sjkh		if (c == '\r')
1827527Sjkh			continue;
18388276Smarkm		*p++ = c;
18488276Smarkm
18588276Smarkm		if (c == '\n' && boolean(value(VERBOSE)))
1867527Sjkh			printf("\r%d", ++ct);
187161781Sru		if ((cnt = (p-buffer)) == (size_t)number(value(FRAMESIZE))) {
188161781Sru			if ((size_t)write(fd, buffer, cnt) != cnt) {
18988276Smarkm				printf("\r\nwrite error\r\n");
19088276Smarkm				quit = 1;
19188276Smarkm			}
19288276Smarkm			p = buffer;
19388276Smarkm		}
1947527Sjkh	}
19588276Smarkm	if ((cnt = (p-buffer)))
196161781Sru		if ((size_t)write(fd, buffer, cnt) != cnt)
19788276Smarkm			printf("\r\nwrite error\r\n");
19888276Smarkm
19988276Smarkm	if (boolean(value(VERBOSE)))
2007527Sjkh		prtime(" lines transferred in ", time(0)-start);
20188276Smarkm	tcsetattr(0, TCSAFLUSH, &term);
2027527Sjkh	write(fildes[1], (char *)&ccc, 1);
2037527Sjkh	signal(SIGINT, f);
20488276Smarkm	close(fd);
2057527Sjkh}
2067527Sjkh
2077527Sjkh/*
2087527Sjkh * FTP - remote ==> local process
2097527Sjkh *   send remote input to local process via pipe
2107527Sjkh */
211161754Sru/*ARGSUSED*/
21228365Scharniervoid
213161754Srupipefile(int c)
2147527Sjkh{
215161754Sru	int pdes[2];
2167527Sjkh	char buf[256];
2177527Sjkh	int status, p;
218161754Sru	pid_t cpid;
2197527Sjkh
22028606Simp	if (prompt("Local command? ", buf, sizeof(buf)))
2217527Sjkh		return;
2227527Sjkh
2237527Sjkh	if (pipe(pdes)) {
2247527Sjkh		printf("can't establish pipe\r\n");
2257527Sjkh		return;
2267527Sjkh	}
2277527Sjkh
2287527Sjkh	if ((cpid = fork()) < 0) {
2297527Sjkh		printf("can't fork!\r\n");
2307527Sjkh		return;
2317527Sjkh	} else if (cpid) {
23228606Simp		if (prompt("List command for remote system? ", buf, sizeof(buf))) {
2337527Sjkh			close(pdes[0]), close(pdes[1]);
2347527Sjkh			kill (cpid, SIGKILL);
2357527Sjkh		} else {
2367527Sjkh			close(pdes[0]);
2377527Sjkh			signal(SIGPIPE, intcopy);
2387527Sjkh			transfer(buf, pdes[1], value(EOFREAD));
2397527Sjkh			signal(SIGPIPE, SIG_DFL);
2407527Sjkh			while ((p = wait(&status)) > 0 && p != cpid)
2417527Sjkh				;
2427527Sjkh		}
2437527Sjkh	} else {
24488276Smarkm		int f;
2457527Sjkh
2467527Sjkh		dup2(pdes[0], 0);
2477527Sjkh		close(pdes[0]);
2487527Sjkh		for (f = 3; f < 20; f++)
2497527Sjkh			close(f);
2507527Sjkh		execute(buf);
2517527Sjkh		printf("can't execl!\r\n");
2527527Sjkh		exit(0);
2537527Sjkh	}
2547527Sjkh}
2557527Sjkh
2567527Sjkh/*
2577527Sjkh * Interrupt service routine for FTP
2587527Sjkh */
259161754Sru/*ARGSUSED*/
260161754Srustatic void
261161754Srustopsnd(int signo)
2627527Sjkh{
2637527Sjkh	stop = 1;
2647527Sjkh	signal(SIGINT, SIG_IGN);
2657527Sjkh}
2667527Sjkh
2677527Sjkh/*
2687527Sjkh * FTP - local ==> remote
2697527Sjkh *  send local file to remote host
2707527Sjkh *  terminate transmission with pseudo EOF sequence
2717527Sjkh */
27228365Scharniervoid
273161754Srusendfile(int c)
2747527Sjkh{
275161754Sru	FILE *fp;
2767527Sjkh	char *fnamex;
2777527Sjkh
278161754Sru	putchar(c);
2797527Sjkh	/*
2807527Sjkh	 * get file name
2817527Sjkh	 */
28228606Simp	if (prompt("Local file name? ", fname, sizeof(fname)))
2837527Sjkh		return;
2847527Sjkh
2857527Sjkh	/*
2867527Sjkh	 * look up file
2877527Sjkh	 */
2887527Sjkh	fnamex = expand(fname);
289161754Sru	if ((fp = fopen(fnamex, "r")) == NULL) {
2907527Sjkh		printf("%s: cannot open\r\n", fname);
2917527Sjkh		return;
2927527Sjkh	}
293161754Sru	transmit(fp, value(EOFWRITE), NULL);
29488276Smarkm	if (!boolean(value(ECHOCHECK)))
29588276Smarkm		tcdrain(FD);
2967527Sjkh}
2977527Sjkh
2987527Sjkh/*
2997527Sjkh * Bulk transfer routine to remote host --
3007527Sjkh *   used by sendfile() and cu_put()
3017527Sjkh */
302161754Srustatic void
303161754Srutransmit(FILE *fp, char *eofchars, char *command)
3047527Sjkh{
3057527Sjkh	char *pc, lastc;
3067527Sjkh	int c, ccount, lcount;
3077527Sjkh	time_t start_t, stop_t;
3087527Sjkh	sig_t f;
3097527Sjkh
310161754Sru	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
3117527Sjkh	stop = 0;
3127527Sjkh	f = signal(SIGINT, stopsnd);
31388276Smarkm	tcsetattr(0, TCSAFLUSH, &defchars);
3147527Sjkh	read(repdes[0], (char *)&ccc, 1);
3157527Sjkh	if (command != NULL) {
3167527Sjkh		for (pc = command; *pc; pc++)
3177527Sjkh			send(*pc);
3187527Sjkh		if (boolean(value(ECHOCHECK)))
3197527Sjkh			read(FD, (char *)&c, 1);	/* trailing \n */
3207527Sjkh		else {
32188276Smarkm			tcdrain(FD);
3227527Sjkh			sleep(5); /* wait for remote stty to take effect */
3237527Sjkh		}
3247527Sjkh	}
3257527Sjkh	lcount = 0;
3267527Sjkh	lastc = '\0';
3277527Sjkh	start_t = time(0);
3287527Sjkh	while (1) {
3297527Sjkh		ccount = 0;
3307527Sjkh		do {
331161754Sru			c = getc(fp);
3327527Sjkh			if (stop)
3337527Sjkh				goto out;
3347527Sjkh			if (c == EOF)
3357527Sjkh				goto out;
3367527Sjkh			if (c == 0177 && !boolean(value(RAWFTP)))
3377527Sjkh				continue;
3387527Sjkh			lastc = c;
3397527Sjkh			if (c < 040) {
3407527Sjkh				if (c == '\n') {
3417527Sjkh					if (!boolean(value(RAWFTP)))
3427527Sjkh						c = '\r';
343161754Sru				} else if (c == '\t') {
3447527Sjkh					if (!boolean(value(RAWFTP))) {
3457527Sjkh						if (boolean(value(TABEXPAND))) {
3467527Sjkh							send(' ');
3477527Sjkh							while ((++ccount % 8) != 0)
3487527Sjkh								send(' ');
3497527Sjkh							continue;
3507527Sjkh						}
3517527Sjkh					}
3527527Sjkh				} else
3537527Sjkh					if (!boolean(value(RAWFTP)))
3547527Sjkh						continue;
3557527Sjkh			}
3567527Sjkh			send(c);
3577527Sjkh		} while (c != '\r' && !boolean(value(RAWFTP)));
3587527Sjkh		if (boolean(value(VERBOSE)))
3597527Sjkh			printf("\r%d", ++lcount);
3607527Sjkh		if (boolean(value(ECHOCHECK))) {
3617527Sjkh			timedout = 0;
362161754Sru			alarm((unsigned int)lvalue(ETIMEOUT));
3637527Sjkh			do {	/* wait for prompt */
3647527Sjkh				read(FD, (char *)&c, 1);
3657527Sjkh				if (timedout || stop) {
3667527Sjkh					if (timedout)
3677527Sjkh						printf("\r\ntimed out at eol\r\n");
3687527Sjkh					alarm(0);
3697527Sjkh					goto out;
3707527Sjkh				}
37188276Smarkm			} while ((c&STRIP_PAR) != character(value(PROMPT)));
3727527Sjkh			alarm(0);
3737527Sjkh		}
3747527Sjkh	}
3757527Sjkhout:
3767527Sjkh	if (lastc != '\n' && !boolean(value(RAWFTP)))
3777527Sjkh		send('\r');
37888276Smarkm	if (eofchars) {
37988276Smarkm		for (pc = eofchars; *pc; pc++)
38088276Smarkm			send(*pc);
38188276Smarkm	}
3827527Sjkh	stop_t = time(0);
383161754Sru	fclose(fp);
3847527Sjkh	signal(SIGINT, f);
38588276Smarkm	if (boolean(value(VERBOSE))) {
3867527Sjkh		if (boolean(value(RAWFTP)))
3877527Sjkh			prtime(" chars transferred in ", stop_t-start_t);
3887527Sjkh		else
3897527Sjkh			prtime(" lines transferred in ", stop_t-start_t);
39088276Smarkm	}
3917527Sjkh	write(fildes[1], (char *)&ccc, 1);
39288276Smarkm	tcsetattr(0, TCSAFLUSH, &term);
3937527Sjkh}
3947527Sjkh
3957527Sjkh/*
3967527Sjkh * Cu-like put command
3977527Sjkh */
398161754Sru/*ARGSUSED*/
39928365Scharniervoid
400161754Srucu_put(int c)
4017527Sjkh{
402161754Sru	FILE *fp;
4037527Sjkh	char line[BUFSIZ];
4047527Sjkh	int argc;
4057527Sjkh	char *copynamex;
4067527Sjkh
40728606Simp	if (prompt("[put] ", copyname, sizeof(copyname)))
4087527Sjkh		return;
40988276Smarkm	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
41088276Smarkm	    argc > 2) {
4117527Sjkh		printf("usage: <put> from [to]\r\n");
4127527Sjkh		return;
4137527Sjkh	}
4147527Sjkh	if (argc == 1)
4157527Sjkh		argv[1] = argv[0];
4167527Sjkh	copynamex = expand(argv[0]);
417161754Sru	if ((fp = fopen(copynamex, "r")) == NULL) {
4187527Sjkh		printf("%s: cannot open\r\n", copynamex);
4197527Sjkh		return;
4207527Sjkh	}
4217527Sjkh	if (boolean(value(ECHOCHECK)))
42288276Smarkm		(void)snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
4237527Sjkh	else
42488276Smarkm		(void)snprintf(line, sizeof(line),
42588276Smarkm		    "stty -echo;cat>%s;stty echo\r", argv[1]);
426161754Sru	transmit(fp, "\04", line);
4277527Sjkh}
4287527Sjkh
4297527Sjkh/*
4307527Sjkh * FTP - send single character
4317527Sjkh *  wait for echo & handle timeout
4327527Sjkh */
433161754Srustatic void
434161754Srusend(int c)
4357527Sjkh{
4367527Sjkh	char cc;
4377527Sjkh	int retry = 0;
4387527Sjkh
4397527Sjkh	cc = c;
44088276Smarkm	parwrite(FD, &cc, 1);
4417527Sjkh	if (number(value(CDELAY)) > 0 && c != '\r')
442161754Sru		usleep(number(value(CDELAY)));
4437527Sjkh	if (!boolean(value(ECHOCHECK))) {
4447527Sjkh		if (number(value(LDELAY)) > 0 && c == '\r')
445161754Sru			usleep(number(value(LDELAY)));
4467527Sjkh		return;
4477527Sjkh	}
4487527Sjkhtryagain:
4497527Sjkh	timedout = 0;
450161754Sru	alarm((unsigned int)lvalue(ETIMEOUT));
4517527Sjkh	read(FD, &cc, 1);
4527527Sjkh	alarm(0);
4537527Sjkh	if (timedout) {
4547527Sjkh		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
4557527Sjkh		if (retry++ > 3)
4567527Sjkh			return;
45788276Smarkm		parwrite(FD, &null, 1); /* poke it */
4587527Sjkh		goto tryagain;
4597527Sjkh	}
4607527Sjkh}
4617527Sjkh
462161754Sru/*ARGSUSED*/
4637527Sjkhvoid
464161754Srutimeout(int signo)
4657527Sjkh{
4667527Sjkh	signal(SIGALRM, timeout);
4677527Sjkh	timedout = 1;
4687527Sjkh}
4697527Sjkh
4707527Sjkh/*
4717527Sjkh * Stolen from consh() -- puts a remote file on the output of a local command.
4727527Sjkh *	Identical to consh() except for where stdout goes.
4737527Sjkh */
47428365Scharniervoid
475161754Srupipeout(int c)
4767527Sjkh{
4777527Sjkh	char buf[256];
478161754Sru	int status, p;
479161754Sru	pid_t cpid;
48088276Smarkm	time_t start = time(NULL);
4817527Sjkh
4827527Sjkh	putchar(c);
48328606Simp	if (prompt("Local command? ", buf, sizeof(buf)))
4847527Sjkh		return;
485161754Sru	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
4867527Sjkh	signal(SIGINT, SIG_IGN);
4877527Sjkh	signal(SIGQUIT, SIG_IGN);
48888276Smarkm	tcsetattr(0, TCSAFLUSH, &defchars);
4897527Sjkh	read(repdes[0], (char *)&ccc, 1);
4907527Sjkh	/*
4917527Sjkh	 * Set up file descriptors in the child and
4927527Sjkh	 *  let it go...
4937527Sjkh	 */
4947527Sjkh	if ((cpid = fork()) < 0)
4957527Sjkh		printf("can't fork!\r\n");
4967527Sjkh	else if (cpid) {
49788276Smarkm		start = time(NULL);
4987527Sjkh		while ((p = wait(&status)) > 0 && p != cpid)
4997527Sjkh			;
5007527Sjkh	} else {
50188276Smarkm		int i;
5027527Sjkh
5037527Sjkh		dup2(FD, 1);
5047527Sjkh		for (i = 3; i < 20; i++)
5057527Sjkh			close(i);
5067527Sjkh		signal(SIGINT, SIG_DFL);
5077527Sjkh		signal(SIGQUIT, SIG_DFL);
5087527Sjkh		execute(buf);
5097527Sjkh		printf("can't find `%s'\r\n", buf);
5107527Sjkh		exit(0);
5117527Sjkh	}
5127527Sjkh	if (boolean(value(VERBOSE)))
5137527Sjkh		prtime("away for ", time(0)-start);
5147527Sjkh	write(fildes[1], (char *)&ccc, 1);
51588276Smarkm	tcsetattr(0, TCSAFLUSH, &term);
5167527Sjkh	signal(SIGINT, SIG_DFL);
5177527Sjkh	signal(SIGQUIT, SIG_DFL);
5187527Sjkh}
5197527Sjkh
52088276Smarkm#ifdef CONNECT
52188276Smarkm/*
52288276Smarkm * Fork a program with:
52388276Smarkm *  0 <-> remote tty in
52488276Smarkm *  1 <-> remote tty out
525161754Sru *  2 <-> local tty stderr
52688276Smarkm */
52788276Smarkmvoid
528161754Sruconsh(int c)
5297527Sjkh{
53088276Smarkm	char buf[256];
531161754Sru	int status, p;
532161754Sru	pid_t cpid;
53388276Smarkm	time_t start = time(NULL);
5347527Sjkh
53588276Smarkm	putchar(c);
53688276Smarkm	if (prompt("Local command? ", buf, sizeof(buf)))
53788276Smarkm		return;
538161754Sru	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
53988276Smarkm	signal(SIGINT, SIG_IGN);
54088276Smarkm	signal(SIGQUIT, SIG_IGN);
54188276Smarkm	tcsetattr(0, TCSAFLUSH, &defchars);
54288276Smarkm	read(repdes[0], (char *)&ccc, 1);
5437527Sjkh	/*
5447527Sjkh	 * Set up file descriptors in the child and
5457527Sjkh	 *  let it go...
5467527Sjkh	 */
5477527Sjkh	if ((cpid = fork()) < 0)
5487527Sjkh		printf("can't fork!\r\n");
5497527Sjkh	else if (cpid) {
5507527Sjkh		start = time(0);
5517527Sjkh		while ((p = wait(&status)) > 0 && p != cpid)
5527527Sjkh			;
5537527Sjkh	} else {
55488276Smarkm		int i;
5557527Sjkh
5567527Sjkh		dup2(FD, 0);
5577527Sjkh		dup2(3, 1);
55888276Smarkm		for (i = 3; i < 20; i++)
55988276Smarkm			close(i);
5607527Sjkh		signal(SIGINT, SIG_DFL);
5617527Sjkh		signal(SIGQUIT, SIG_DFL);
56288276Smarkm		execute(buf);
56388276Smarkm		printf("can't find `%s'\r\n", buf);
5647527Sjkh		exit(0);
5657527Sjkh	}
56688276Smarkm	if (boolean(value(VERBOSE)))
5677527Sjkh		prtime("away for ", time(0)-start);
56888276Smarkm	write(fildes[1], (char *)&ccc, 1);
56988276Smarkm	tcsetattr(0, TCSAFLUSH, &term);
57088276Smarkm	signal(SIGINT, SIG_DFL);
57188276Smarkm	signal(SIGQUIT, SIG_DFL);
5727527Sjkh}
5737527Sjkh#endif
5747527Sjkh
5757527Sjkh/*
5767527Sjkh * Escape to local shell
5777527Sjkh */
578161754Sru/*ARGSUSED*/
57928365Scharniervoid
580161754Srushell(int c)
5817527Sjkh{
582161754Sru	int status;
5837527Sjkh	char *cp;
584161754Sru	pid_t shpid;
5857527Sjkh
5867527Sjkh	printf("[sh]\r\n");
5877527Sjkh	signal(SIGINT, SIG_IGN);
5887527Sjkh	signal(SIGQUIT, SIG_IGN);
5897527Sjkh	unraw();
59028365Scharnier	if ((shpid = fork())) {
5917527Sjkh		while (shpid != wait(&status));
5927527Sjkh		raw();
5937527Sjkh		printf("\r\n!\r\n");
5947527Sjkh		signal(SIGINT, SIG_DFL);
5957527Sjkh		signal(SIGQUIT, SIG_DFL);
5967527Sjkh		return;
5977527Sjkh	} else {
5987527Sjkh		signal(SIGQUIT, SIG_DFL);
5997527Sjkh		signal(SIGINT, SIG_DFL);
60088276Smarkm		if ((cp = strrchr(value(SHELL), '/')) == NULL)
6017527Sjkh			cp = value(SHELL);
6027527Sjkh		else
6037527Sjkh			cp++;
6047527Sjkh		shell_uid();
60588276Smarkm		execl(value(SHELL), cp, (char *)NULL);
6067527Sjkh		printf("\r\ncan't execl!\r\n");
6077527Sjkh		exit(1);
6087527Sjkh	}
6097527Sjkh}
6107527Sjkh
6117527Sjkh/*
6127527Sjkh * TIPIN portion of scripting
6137527Sjkh *   initiate the conversation with TIPOUT
6147527Sjkh */
61528365Scharniervoid
616161754Srusetscript(void)
6177527Sjkh{
6187527Sjkh	char c;
619161754Sru
6207527Sjkh	/*
6217527Sjkh	 * enable TIPOUT side for dialogue
6227527Sjkh	 */
623161754Sru	kill(tipout_pid, SIGEMT);
6247527Sjkh	if (boolean(value(SCRIPT)))
6257527Sjkh		write(fildes[1], value(RECORD), size(value(RECORD)));
6267527Sjkh	write(fildes[1], "\n", 1);
6277527Sjkh	/*
6287527Sjkh	 * wait for TIPOUT to finish
6297527Sjkh	 */
6307527Sjkh	read(repdes[0], &c, 1);
6317527Sjkh	if (c == 'n')
6327527Sjkh		printf("can't create %s\r\n", value(RECORD));
6337527Sjkh}
6347527Sjkh
6357527Sjkh/*
6367527Sjkh * Change current working directory of
6377527Sjkh *   local portion of tip
6387527Sjkh */
639161754Sru/*ARGSUSED*/
64028365Scharniervoid
641161754Sruchdirectory(int c)
6427527Sjkh{
64328686Simp	char dirname[PATH_MAX];
64488276Smarkm	char *cp = dirname;
6457527Sjkh
64628606Simp	if (prompt("[cd] ", dirname, sizeof(dirname))) {
6477527Sjkh		if (stoprompt)
6487527Sjkh			return;
6497527Sjkh		cp = value(HOME);
6507527Sjkh	}
6517527Sjkh	if (chdir(cp) < 0)
6527527Sjkh		printf("%s: bad directory\r\n", cp);
6537527Sjkh	printf("!\r\n");
6547527Sjkh}
6557527Sjkh
65628365Scharniervoid
657161754Srutipabort(char *msg)
6587527Sjkh{
6597527Sjkh
660161754Sru	signal(SIGTERM, SIG_IGN);
661161754Sru	kill(tipout_pid, SIGTERM);
6627527Sjkh	disconnect(msg);
6637527Sjkh	if (msg != NOSTR)
6647527Sjkh		printf("\r\n%s", msg);
6657527Sjkh	printf("\r\n[EOT]\r\n");
6667527Sjkh	daemon_uid();
6677527Sjkh	(void)uu_unlock(uucplock);
6687527Sjkh	unraw();
669178736Sbms	unexcl();
6707527Sjkh	exit(0);
6717527Sjkh}
6727527Sjkh
673161754Sru/*ARGSUSED*/
67428365Scharniervoid
675161754Srufinish(int c)
6767527Sjkh{
67788276Smarkm	char *dismsg;
6787527Sjkh
6797527Sjkh	if ((dismsg = value(DISCONNECT)) != NOSTR) {
6807527Sjkh		write(FD, dismsg, strlen(dismsg));
68188276Smarkm		sleep(5);
6827527Sjkh	}
68388276Smarkm	tipabort(NOSTR);
6847527Sjkh}
6857527Sjkh
686161754Sru/*ARGSUSED*/
687161754Srustatic void
688161754Sruintcopy(int signo)
6897527Sjkh{
6907527Sjkh	raw();
6917527Sjkh	quit = 1;
6927527Sjkh	longjmp(intbuf, 1);
6937527Sjkh}
6947527Sjkh
695161754Srustatic void
696161754Sruexecute(char *s)
6977527Sjkh{
69888276Smarkm	char *cp;
6997527Sjkh
70088276Smarkm	if ((cp = strrchr(value(SHELL), '/')) == NULL)
7017527Sjkh		cp = value(SHELL);
7027527Sjkh	else
7037527Sjkh		cp++;
7047527Sjkh	shell_uid();
70588276Smarkm	execl(value(SHELL), cp, "-c", s, (char *)NULL);
7067527Sjkh}
7077527Sjkh
708161754Srustatic int
709161754Sruargs(char *buf, char *a[], int num)
7107527Sjkh{
71188276Smarkm	char *p = buf, *start;
71288276Smarkm	char **parg = a;
71388276Smarkm	int n = 0;
7147527Sjkh
71588276Smarkm	do {
7167527Sjkh		while (*p && (*p == ' ' || *p == '\t'))
7177527Sjkh			p++;
7187527Sjkh		start = p;
7197527Sjkh		if (*p)
7207527Sjkh			*parg = p;
7217527Sjkh		while (*p && (*p != ' ' && *p != '\t'))
7227527Sjkh			p++;
7237527Sjkh		if (p != start)
7247527Sjkh			parg++, n++;
7257527Sjkh		if (*p)
7267527Sjkh			*p++ = '\0';
72788276Smarkm	} while (*p && n < num);
72888276Smarkm
7297527Sjkh	return(n);
7307527Sjkh}
7317527Sjkh
732161754Srustatic void
733161754Sruprtime(char *s, time_t a)
7347527Sjkh{
73588276Smarkm	int i;
7367527Sjkh	int nums[3];
7377527Sjkh
7387527Sjkh	for (i = 0; i < 3; i++) {
7397527Sjkh		nums[i] = (int)(a % quant[i]);
7407527Sjkh		a /= quant[i];
7417527Sjkh	}
7427527Sjkh	printf("%s", s);
7437527Sjkh	while (--i >= 0)
744161754Sru		if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
7457527Sjkh			printf("%d %s%c ", nums[i], sep[i],
7467527Sjkh				nums[i] == 1 ? '\0' : 's');
7477527Sjkh	printf("\r\n!\r\n");
7487527Sjkh}
7497527Sjkh
750161754Sru/*ARGSUSED*/
75128365Scharniervoid
752161754Sruvariable(int c)
7537527Sjkh{
7547527Sjkh	char	buf[256];
7557527Sjkh
75628606Simp	if (prompt("[set] ", buf, sizeof(buf)))
7577527Sjkh		return;
7587527Sjkh	vlex(buf);
7597527Sjkh	if (vtable[BEAUTIFY].v_access&CHANGED) {
7607527Sjkh		vtable[BEAUTIFY].v_access &= ~CHANGED;
761161754Sru		kill(tipout_pid, SIGSYS);
7627527Sjkh	}
7637527Sjkh	if (vtable[SCRIPT].v_access&CHANGED) {
7647527Sjkh		vtable[SCRIPT].v_access &= ~CHANGED;
7657527Sjkh		setscript();
7667527Sjkh		/*
7677527Sjkh		 * So that "set record=blah script" doesn't
7687527Sjkh		 *  cause two transactions to occur.
7697527Sjkh		 */
7707527Sjkh		if (vtable[RECORD].v_access&CHANGED)
7717527Sjkh			vtable[RECORD].v_access &= ~CHANGED;
7727527Sjkh	}
7737527Sjkh	if (vtable[RECORD].v_access&CHANGED) {
7747527Sjkh		vtable[RECORD].v_access &= ~CHANGED;
7757527Sjkh		if (boolean(value(SCRIPT)))
7767527Sjkh			setscript();
7777527Sjkh	}
7787527Sjkh	if (vtable[TAND].v_access&CHANGED) {
7797527Sjkh		vtable[TAND].v_access &= ~CHANGED;
7807527Sjkh		if (boolean(value(TAND)))
7817527Sjkh			tandem("on");
7827527Sjkh		else
7837527Sjkh			tandem("off");
7847527Sjkh	}
785161754Sru	if (vtable[LECHO].v_access&CHANGED) {
786161754Sru		vtable[LECHO].v_access &= ~CHANGED;
787161754Sru		HD = boolean(value(LECHO));
788161754Sru	}
7897527Sjkh	if (vtable[PARITY].v_access&CHANGED) {
7907527Sjkh		vtable[PARITY].v_access &= ~CHANGED;
79188276Smarkm		setparity(NOSTR);
7927527Sjkh	}
793161754Sru	if (vtable[HARDWAREFLOW].v_access&CHANGED) {
794161754Sru		vtable[HARDWAREFLOW].v_access &= ~CHANGED;
795161754Sru		if (boolean(value(HARDWAREFLOW)))
796161754Sru			hardwareflow("on");
797161754Sru		else
798161754Sru			hardwareflow("off");
799161754Sru	}
800161754Sru	if (vtable[LINEDISC].v_access&CHANGED) {
801161754Sru		vtable[LINEDISC].v_access &= ~CHANGED;
802161754Sru		linedisc(NOSTR);
803161754Sru	}
8047527Sjkh}
8057527Sjkh
806161754Sru/*ARGSUSED*/
80788276Smarkmvoid
808161754Srulistvariables(int c)
80988276Smarkm{
81088276Smarkm	value_t *p;
81188276Smarkm	char *buf;
81288276Smarkm	char charbuf[5];	/* for vis(3), 4 chars for encoding, plus nul */
81388276Smarkm
81488276Smarkm	puts("v\r");
81588276Smarkm	for (p = vtable; p->v_name; p++) {
81688276Smarkm		fputs(p->v_name, stdout);
81788276Smarkm		switch (p->v_type&TMASK) {
81888276Smarkm		case STRING:
81988276Smarkm			if (p->v_value) {
82088276Smarkm				buf = malloc(4*strlen(p->v_value) + 1);
82188276Smarkm				if (buf == NULL) {
82288276Smarkm					fprintf(stderr, "Unable to malloc()\n");
82388276Smarkm					abort();
82488276Smarkm				}
82588276Smarkm				strvis(buf, p->v_value, VIS_WHITE);
82688276Smarkm				printf(" %s", buf);
82788276Smarkm				free(buf);
82888276Smarkm			}
82988276Smarkm			putchar('\r');
83088276Smarkm			putchar('\n');
83188276Smarkm			break;
83288276Smarkm		case NUMBER:
83388276Smarkm			printf(" %ld\r\n", number(p->v_value));
83488276Smarkm			break;
83588276Smarkm		case BOOL:
83688276Smarkm			printf(" %s\r\n",
837161754Sru			    !boolean(p->v_value) ? "false" : "true");
83888276Smarkm			break;
83988276Smarkm		case CHAR:
84088276Smarkm			vis(charbuf, character(p->v_value), VIS_WHITE, 0);
84188276Smarkm			printf(" %s\r\n", charbuf);
84288276Smarkm			break;
84388276Smarkm		}
844161754Sru	}
84588276Smarkm}
84688276Smarkm
8477527Sjkh/*
8487527Sjkh * Turn tandem mode on or off for remote tty.
8497527Sjkh */
850161754Srustatic void
851161754Srutandem(char *option)
8527527Sjkh{
85388276Smarkm	struct termios	rmtty;
8547527Sjkh
85588276Smarkm	tcgetattr(FD, &rmtty);
85688276Smarkm	if (strcmp(option, "on") == 0) {
85788276Smarkm		rmtty.c_iflag |= IXOFF;
85888276Smarkm		term.c_iflag |= IXOFF;
8597527Sjkh	} else {
86088276Smarkm		rmtty.c_iflag &= ~IXOFF;
86188276Smarkm		term.c_iflag &= ~IXOFF;
8627527Sjkh	}
86388276Smarkm	tcsetattr(FD, TCSADRAIN, &rmtty);
86488276Smarkm	tcsetattr(0, TCSADRAIN, &term);
8657527Sjkh}
8667527Sjkh
8677527Sjkh/*
868161754Sru * Turn hardware flow control on or off for remote tty.
869161754Sru */
870161754Srustatic void
871161754Sruhardwareflow(char *option)
872161754Sru{
873161754Sru	struct termios	rmtty;
874161754Sru
875161754Sru	tcgetattr(FD, &rmtty);
876161754Sru	if (strcmp(option, "on") == 0)
877161754Sru		rmtty.c_iflag |= CRTSCTS;
878161754Sru	else
879161754Sru		rmtty.c_iflag &= ~CRTSCTS;
880161754Sru	tcsetattr(FD, TCSADRAIN, &rmtty);
881161754Sru}
882161754Sru
883161754Sru/*
884161754Sru * Change line discipline to the specified one.
885161754Sru */
886161754Sruvoid
887161754Srulinedisc(char *option)
888161754Sru{
889161781Sru	int ld = (int)(intptr_t)value(LINEDISC);
890161754Sru
891161754Sru	ioctl(FD, TIOCSETD, &ld);
892161754Sru}
893161754Sru
894161754Sru/*
8957527Sjkh * Send a break.
8967527Sjkh */
897161754Sru/*ARGSUSED*/
89828365Scharniervoid
899161754Srugenbrk(int c)
9007527Sjkh{
9017527Sjkh	ioctl(FD, TIOCSBRK, NULL);
9027527Sjkh	sleep(1);
9037527Sjkh	ioctl(FD, TIOCCBRK, NULL);
9047527Sjkh}
9057527Sjkh
9067527Sjkh/*
9077527Sjkh * Suspend tip
9087527Sjkh */
90928365Scharniervoid
910161754Srususpend(int c)
9117527Sjkh{
9127527Sjkh	unraw();
9137527Sjkh	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
9147527Sjkh	raw();
9157527Sjkh}
9167527Sjkh
9177527Sjkh/*
9187527Sjkh *	expand a file name if it includes shell meta characters
9197527Sjkh */
9207527Sjkhchar *
921161754Sruexpand(char name[])
9227527Sjkh{
9237527Sjkh	static char xname[BUFSIZ];
9247527Sjkh	char cmdbuf[BUFSIZ];
925161754Sru	int l;
92688276Smarkm	char *cp, *Shell;
92788276Smarkm	int s, pivec[2];
928161754Sru	pid_t pid;
9297527Sjkh
9307527Sjkh	if (!anyof(name, "~{[*?$`'\"\\"))
9317527Sjkh		return(name);
9327527Sjkh	/* sigint = signal(SIGINT, SIG_IGN); */
9337527Sjkh	if (pipe(pivec) < 0) {
93488276Smarkm		perror("pipe");
9357527Sjkh		/* signal(SIGINT, sigint) */
9367527Sjkh		return(name);
9377527Sjkh	}
93888276Smarkm	(void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
9397527Sjkh	if ((pid = vfork()) == 0) {
9407527Sjkh		Shell = value(SHELL);
9417527Sjkh		if (Shell == NOSTR)
9427527Sjkh			Shell = _PATH_BSHELL;
9437527Sjkh		close(pivec[0]);
9447527Sjkh		close(1);
9457527Sjkh		dup(pivec[1]);
9467527Sjkh		close(pivec[1]);
9477527Sjkh		close(2);
9487527Sjkh		shell_uid();
94988276Smarkm		execl(Shell, Shell, "-c", cmdbuf, (char *)NULL);
9507527Sjkh		_exit(1);
9517527Sjkh	}
9527527Sjkh	if (pid == -1) {
95388276Smarkm		perror("fork");
9547527Sjkh		close(pivec[0]);
9557527Sjkh		close(pivec[1]);
9567527Sjkh		return(NOSTR);
9577527Sjkh	}
9587527Sjkh	close(pivec[1]);
9597527Sjkh	l = read(pivec[0], xname, BUFSIZ);
9607527Sjkh	close(pivec[0]);
9617527Sjkh	while (wait(&s) != pid);
9627527Sjkh		;
9637527Sjkh	s &= 0377;
9647527Sjkh	if (s != 0 && s != SIGPIPE) {
9657527Sjkh		fprintf(stderr, "\"Echo\" failed\n");
9667527Sjkh		return(NOSTR);
9677527Sjkh	}
9687527Sjkh	if (l < 0) {
96988276Smarkm		perror("read");
9707527Sjkh		return(NOSTR);
9717527Sjkh	}
9727527Sjkh	if (l == 0) {
9737527Sjkh		fprintf(stderr, "\"%s\": No match\n", name);
9747527Sjkh		return(NOSTR);
9757527Sjkh	}
9767527Sjkh	if (l == BUFSIZ) {
9777527Sjkh		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
9787527Sjkh		return(NOSTR);
9797527Sjkh	}
9807527Sjkh	xname[l] = 0;
9817527Sjkh	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
9827527Sjkh		;
9837527Sjkh	*++cp = '\0';
9847527Sjkh	return(xname);
9857527Sjkh}
9867527Sjkh
9877527Sjkh/*
9887527Sjkh * Are any of the characters in the two strings the same?
9897527Sjkh */
990161754Srustatic int
991161754Sruanyof(char *s1, char *s2)
9927527Sjkh{
99388276Smarkm	int c;
9947527Sjkh
99528365Scharnier	while ((c = *s1++))
9967527Sjkh		if (any(c, s2))
9977527Sjkh			return(1);
9987527Sjkh	return(0);
9997527Sjkh}
1000