diff --git a/tip/GNUmakefile b/tip/GNUmakefile
new file mode 100644
index 0000000000000000000000000000000000000000..55e40bf22492f954bf5d318536356589c8d18410
--- /dev/null
+++ b/tip/GNUmakefile
@@ -0,0 +1,27 @@
+CC = gcc -g
+
+# for BSD
+#CFLAGS = -O
+#LIBS= -lutil
+
+# for Linux
+CFLAGS = -O -DLINUX
+LIBS= -ldb
+
+OBJS = acu.o acutab.o cmds.o cmdtab.o cu.o hunt.o log.o partab.o \
+       remote.o tip.o tipout.o value.o vars.o getcap.o
+DESTDIR = /usr/site
+
+all: tip
+
+tip: $(OBJS)
+	$(CC) -o tip $(OBJS) $(LIBS)
+
+tip.static: $(OBJS)
+	$(CC) -static -o tip.static $(OBJS) $(LIBS)
+
+install:
+	install -s -c tip $(DESTDIR)/bin/tip
+
+clean:
+	rm -f $(OBJS) tip tip.static
diff --git a/tip/acu.c b/tip/acu.c
new file mode 100644
index 0000000000000000000000000000000000000000..865b6fad8403a0da484aab9d4a9789c590dbfd51
--- /dev/null
+++ b/tip/acu.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)acu.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: acu.c,v 1.1 2000-12-22 18:48:46 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+#if UNIDIALER
+acu_t* unidialer_getmodem (const char *modem_name);
+#endif
+
+static acu_t *acu = NOACU;
+static int conflag;
+static void acuabort();
+static acu_t *acutype();
+static jmp_buf jmpbuf;
+/*
+ * Establish connection for tip
+ *
+ * If DU is true, we should dial an ACU whose type is AT.
+ * The phone numbers are in PN, and the call unit is in CU.
+ *
+ * If the PN is an '@', then we consult the PHONES file for
+ *   the phone numbers.  This file is /etc/phones, unless overriden
+ *   by an exported shell variable.
+ *
+ * The data base files must be in the format:
+ *	host-name[ \t]*phone-number
+ *   with the possibility of multiple phone numbers
+ *   for a single host acting as a rotary (in the order
+ *   found in the file).
+ */
+char *
+connect()
+{
+	register char *cp = PN;
+	char *phnum, string[256];
+	FILE *fd;
+	int tried = 0;
+
+	if (!DU) {		/* regular connect message */
+		if (CM != NOSTR)
+			xpwrite(FD, CM, size(CM));
+		logent(value(HOST), "", DV, "call completed");
+		return (NOSTR);
+	}
+	/*
+	 * @ =>'s use data base in PHONES environment variable
+	 *        otherwise, use /etc/phones
+	 */
+	signal(SIGINT, acuabort);
+	signal(SIGQUIT, acuabort);
+	if (setjmp(jmpbuf)) {
+		signal(SIGINT, SIG_IGN);
+		signal(SIGQUIT, SIG_IGN);
+		printf("\ncall aborted\n");
+		logent(value(HOST), "", "", "call aborted");
+		if (acu != NOACU) {
+			boolean(value(VERBOSE)) = FALSE;
+			if (conflag)
+				disconnect(NOSTR);
+			else
+				(*acu->acu_abort)();
+		}
+		return ("interrupt");
+	}
+	if ((acu = acutype(AT)) == NOACU)
+		return ("unknown ACU type");
+	if (*cp != '@') {
+		while (*cp) {
+			for (phnum = cp; *cp && *cp != ','; cp++)
+				;
+			if (*cp)
+				*cp++ = '\0';
+
+			if ((conflag = (*acu->acu_dialer)(phnum, CU))) {
+				if (CM != NOSTR)
+					xpwrite(FD, CM, size(CM));
+				logent(value(HOST), phnum, acu->acu_name,
+					"call completed");
+				return (NOSTR);
+			} else
+				logent(value(HOST), phnum, acu->acu_name,
+					"call failed");
+			tried++;
+		}
+	} else {
+		if ((fd = fopen(PH, "r")) == NOFILE) {
+			printf("%s: ", PH);
+			return ("can't open phone number file");
+		}
+		while (fgets(string, sizeof(string), fd) != NOSTR) {
+			for (cp = string; !any(*cp, " \t\n"); cp++)
+				;
+			if (*cp == '\n') {
+				fclose(fd);
+				return ("unrecognizable host name");
+			}
+			*cp++ = '\0';
+			if (strcmp(string, value(HOST)))
+				continue;
+			while (any(*cp, " \t"))
+				cp++;
+			if (*cp == '\n') {
+				fclose(fd);
+				return ("missing phone number");
+			}
+			for (phnum = cp; *cp && *cp != ',' && *cp != '\n'; cp++)
+				;
+			if (*cp)
+				*cp++ = '\0';
+
+			if ((conflag = (*acu->acu_dialer)(phnum, CU))) {
+				fclose(fd);
+				if (CM != NOSTR)
+					xpwrite(FD, CM, size(CM));
+				logent(value(HOST), phnum, acu->acu_name,
+					"call completed");
+				return (NOSTR);
+			} else
+				logent(value(HOST), phnum, acu->acu_name,
+					"call failed");
+			tried++;
+		}
+		fclose(fd);
+	}
+	if (!tried)
+		logent(value(HOST), "", acu->acu_name, "missing phone number");
+	else
+		(*acu->acu_abort)();
+	return (tried ? "call failed" : "missing phone number");
+}
+
+void
+disconnect(reason)
+	char *reason;
+{
+	if (!conflag) {
+		logent(value(HOST), "", DV, "call terminated");
+		return;
+	}
+	if (reason == NOSTR) {
+		logent(value(HOST), "", acu->acu_name, "call terminated");
+		if (boolean(value(VERBOSE)))
+			printf("\r\ndisconnecting...");
+	} else
+		logent(value(HOST), "", acu->acu_name, reason);
+	(*acu->acu_disconnect)();
+}
+
+static void
+acuabort(s)
+{
+	signal(s, SIG_IGN);
+	longjmp(jmpbuf, 1);
+}
+
+static acu_t *
+acutype(s)
+	register char *s;
+{
+	register acu_t *p;
+	extern acu_t acutable[];
+
+	for (p = acutable; p->acu_name != '\0'; p++)
+		if (!strcmp(s, p->acu_name))
+			return (p);
+
+	#if UNIDIALER
+	return unidialer_getmodem (s);
+	#else
+	return (NOACU);
+	#endif
+}
diff --git a/tip/acutab.c b/tip/acutab.c
new file mode 100644
index 0000000000000000000000000000000000000000..0c1c41af72f1dead212643226ff45c8c2af2143d
--- /dev/null
+++ b/tip/acutab.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)acutab.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: acutab.c,v 1.1 2000-12-22 18:48:46 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+extern int df02_dialer(), df03_dialer(),
+	   biz31f_dialer(),
+	   biz31w_dialer(),
+	   biz22f_dialer(),
+	   biz22w_dialer(),
+	   ven_dialer(),
+	   hay_dialer(),
+	   cour_dialer(),
+	   multitech_dialer(),
+	   t3000_dialer(),
+	   v3451_dialer(),
+	   v831_dialer(),
+	   dn_dialer();
+
+extern void df_disconnect(), df_abort(),
+	   biz31_disconnect(), biz31_abort(),
+	   biz22_disconnect(), biz22_abort(),
+	   ven_disconnect(), ven_abort(),
+	   hay_disconnect(), hay_abort(),
+	   cour_disconnect(), cour_abort(),
+	   multitech_disconnect(), multitech_abort(),
+	   t3000_disconnect(), t3000_abort(),
+	   v3451_disconnect(), v3451_abort(),
+	   v831_disconnect(), v831_abort(),
+	   dn_disconnect(), dn_abort();
+
+acu_t acutable[] = {
+#if BIZ1031
+	"biz31f", biz31f_dialer, biz31_disconnect,	biz31_abort,
+	"biz31w", biz31w_dialer, biz31_disconnect,	biz31_abort,
+#endif
+#if BIZ1022
+	"biz22f", biz22f_dialer, biz22_disconnect,	biz22_abort,
+	"biz22w", biz22w_dialer, biz22_disconnect,	biz22_abort,
+#endif
+#if DF02
+	"df02",	df02_dialer,	df_disconnect,		df_abort,
+#endif
+#if DF03
+	"df03",	df03_dialer,	df_disconnect,		df_abort,
+#endif
+#if DN11
+	"dn11",	dn_dialer,	dn_disconnect,		dn_abort,
+#endif
+#if VENTEL
+	"ventel",ven_dialer,	ven_disconnect,		ven_abort,
+#endif
+#if HAYES
+	"hayes",hay_dialer,	hay_disconnect,		hay_abort,
+#endif
+#if COURIER
+	"courier",cour_dialer,	cour_disconnect,	cour_abort,
+#endif
+#if MULTITECH
+	"multitech",multitech_dialer,	multitech_disconnect,	multitech_abort,
+#endif
+#if T3000
+	"t3000",t3000_dialer,	t3000_disconnect,	t3000_abort,
+#endif
+#if V3451
+#if !V831
+	"vadic",v3451_dialer,	v3451_disconnect,	v3451_abort,
+#endif
+	"v3451",v3451_dialer,	v3451_disconnect,	v3451_abort,
+#endif
+#if V831
+#if !V3451
+	"vadic",v831_dialer,	v831_disconnect,	v831_abort,
+#endif
+	"v831",v831_dialer,	v831_disconnect,	v831_abort,
+#endif
+	0,	0,		0,			0
+};
+
diff --git a/tip/cmds.c b/tip/cmds.c
new file mode 100644
index 0000000000000000000000000000000000000000..2ad298b1ab183bd45e3c701c10a5a3c3c24c031b
--- /dev/null
+++ b/tip/cmds.c
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmds.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: cmds.c,v 1.1 2000-12-22 18:48:46 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <err.h>
+#ifndef LINUX
+#include <libutil.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ * tip
+ *
+ * miscellaneous commands
+ */
+
+int	quant[] = { 60, 60, 24 };
+
+char	null = '\0';
+char	*sep[] = { "second", "minute", "hour" };
+static char *argv[10];		/* argument vector for take and put */
+
+void	timeout();		/* timeout function called on alarm */
+static void	stopsnd();		/* SIGINT handler during file transfers */
+static void	intcopy();		/* interrupt routine for file transfers */
+
+void suspend __P((char));
+void genbrk __P((void));
+void variable __P((void));
+void finish __P((void));
+void tipabort __P((char *));
+void chdirectory __P((void));
+void shell __P((void));
+void cu_put __P((char));
+void sendfile __P((char));
+void pipefile __P((void));
+void cu_take __P((char));
+void getfl __P((char));
+
+static int anyof __P((char *, char *));
+static void tandem __P((char *));
+static void prtime __P((char *, time_t));
+static int args __P((char *, char **, int));
+static void execute __P((char *));
+static void send __P((char));
+static void transmit __P((FILE *, char *, char *));
+static void transfer __P((char *, int, char *));
+static void xfer __P((char *, int, char *));
+
+void
+usedefchars ()
+{
+#if HAVE_TERMIOS
+	int cnt;
+	struct termios ttermios;
+	ttermios = ctermios;
+	for (cnt = 0; cnt < NCCS; cnt++)
+		ttermios.c_cc [cnt] = otermios.c_cc [cnt];
+	tcsetattr (0, TCSANOW, &ttermios);
+#else
+	ioctl(0, TIOCSETC, &defchars);
+#endif
+}
+
+void
+usetchars ()
+{
+#if HAVE_TERMIOS
+	tcsetattr (0, TCSANOW, &ctermios);
+#else
+	ioctl(0, TIOCSETC, &tchars);
+#endif
+}
+
+void
+flush_remote ()
+{
+#ifdef TIOCFLUSH
+	int cmd = 0;
+	ioctl (FD, TIOCFLUSH, &cmd);
+#else
+#if HAVE_TERMIOS
+	tcflush (FD, TCIOFLUSH);
+#else
+	struct sgttyb buf;
+	ioctl (FD, TIOCGETP, &buf);	/* this does a */
+	ioctl (FD, TIOCSETP, &buf);	/*   wflushtty */
+#endif
+#endif
+}
+
+/*
+ * FTP - remote ==> local
+ *  get a file from the remote host
+ */
+void
+getfl(c)
+	char c;
+{
+	char buf[256], *cp, *expand();
+
+	putchar(c);
+	/*
+	 * get the UNIX receiving file's name
+	 */
+	if (prompt("Local file name? ", copyname, sizeof(copyname)))
+		return;
+	cp = expand(copyname);
+	if ((sfd = creat(cp, 0666)) < 0) {
+		printf("\r\n%s: cannot creat\r\n", copyname);
+		return;
+	}
+
+	/*
+	 * collect parameters
+	 */
+	if (prompt("List command for remote system? ", buf, sizeof(buf))) {
+		unlink(copyname);
+		return;
+	}
+	transfer(buf, sfd, value(EOFREAD));
+}
+
+/*
+ * Cu-like take command
+ */
+void
+cu_take(cc)
+	char cc;
+{
+	int fd, argc;
+	char line[BUFSIZ], *expand(), *cp;
+
+	if (prompt("[take] ", copyname, sizeof(copyname)))
+		return;
+	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
+		printf("usage: <take> from [to]\r\n");
+		return;
+	}
+	if (argc == 1)
+		argv[1] = argv[0];
+	cp = expand(argv[1]);
+	if ((fd = creat(cp, 0666)) < 0) {
+		printf("\r\n%s: cannot create\r\n", argv[1]);
+		return;
+	}
+	(void)snprintf(line, sizeof(line), "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
+	xfer(line, fd, "\n___tip_end_of_file_marker___\n");
+}
+
+static jmp_buf intbuf;
+
+static void
+xfer(buf, fd, eofchars)
+	char *buf, *eofchars;
+{
+	int ct;
+	char c, *match;
+	int cnt, eof, v;
+	time_t start;
+	sig_t f;
+	char r;
+	FILE *ff;
+
+	v = boolean(value(VERBOSE));
+
+	if ((ff = fdopen (fd, "w")) == NULL) {
+		warn("file open");
+		return;
+	}
+	if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
+		if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
+			warn("file allocation");
+			(void)fclose(ff);
+			return;
+		}
+
+	xpwrite(FD, buf, size(buf));
+	quit = 0;
+	kill(pid, SIGIOT);
+	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
+
+	/*
+	 * finish command
+	 */
+	r = '\r';
+	xpwrite(FD, &r, 1);
+	do
+		read(FD, &c, 1);
+	while ((c&0177) != '\n');
+
+	usedefchars ();
+
+	(void) setjmp(intbuf);
+	f = signal(SIGINT, intcopy);
+	start = time(0);
+	match = eofchars;
+	for (ct = 0; !quit;) {
+		eof = read(FD, &c, 1) <= 0;
+		c &= 0177;
+		if (quit)
+			continue;
+		if (eof)
+			break;
+		if (c == 0)
+			continue;	/* ignore nulls */
+		if (c == '\r')
+			continue;
+		if (c != *match && match > eofchars) {
+			register char *p = eofchars;
+			while (p < match) {
+				if (*p == '\n'&& v)
+					(void)printf("\r%d", ++ct);
+				fputc(*p++, ff);
+			}
+			match = eofchars;
+		}
+		if (c == *match) {
+			if (*++match == '\0')
+				break;
+		} else {
+			if (c == '\n' && v)
+				(void)printf("\r%d", ++ct);
+			fputc(c, ff);
+		}
+	}
+	if (v)
+		prtime(" lines transferred in ", time(0)-start);
+	usetchars ();
+	write(fildes[1], (char *)&ccc, 1);
+	signal(SIGINT, f);
+	(void)fclose(ff);
+}
+
+/*
+ * Bulk transfer routine --
+ *  used by getfl(), cu_take(), and pipefile()
+ */
+static void
+transfer(buf, fd, eofchars)
+	char *buf, *eofchars;
+{
+	register int ct;
+	char c;
+	register int cnt, eof, v;
+	time_t start;
+	sig_t f;
+	char r;
+	FILE *ff;
+
+	v = boolean(value(VERBOSE));
+
+	if ((ff = fdopen (fd, "w")) == NULL) {
+		warn("file open");
+		return;
+	}
+	if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
+		if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
+			warn("file allocation");
+			(void)fclose(ff);
+			return;
+		}
+
+	xpwrite(FD, buf, size(buf));
+	quit = 0;
+	kill(pid, SIGIOT);
+	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
+
+	/*
+	 * finish command
+	 */
+	r = '\r';
+	xpwrite(FD, &r, 1);
+	do
+		read(FD, &c, 1);
+	while ((c&0177) != '\n');
+	usedefchars ();
+	(void) setjmp(intbuf);
+	f = signal(SIGINT, intcopy);
+	start = time(0);
+	for (ct = 0; !quit;) {
+		eof = read(FD, &c, 1) <= 0;
+		c &= 0177;
+		if (quit)
+			continue;
+		if (eof || any(c, eofchars))
+			break;
+		if (c == 0)
+			continue;	/* ignore nulls */
+		if (c == '\r')
+			continue;
+		if (c == '\n' && v)
+			printf("\r%d", ++ct);
+		fputc(c, ff);
+	}
+	if (v)
+		prtime(" lines transferred in ", time(0)-start);
+	usetchars ();
+	write(fildes[1], (char *)&ccc, 1);
+	signal(SIGINT, f);
+	(void)fclose(ff);
+}
+
+/*
+ * FTP - remote ==> local process
+ *   send remote input to local process via pipe
+ */
+void
+pipefile()
+{
+	int cpid, pdes[2];
+	char buf[256];
+	int status, p;
+
+	if (prompt("Local command? ", buf, sizeof(buf)))
+		return;
+
+	if (pipe(pdes)) {
+		printf("can't establish pipe\r\n");
+		return;
+	}
+
+	if ((cpid = fork()) < 0) {
+		printf("can't fork!\r\n");
+		return;
+	} else if (cpid) {
+		if (prompt("List command for remote system? ", buf, sizeof(buf))) {
+			close(pdes[0]), close(pdes[1]);
+			kill (cpid, SIGKILL);
+		} else {
+			close(pdes[0]);
+			signal(SIGPIPE, intcopy);
+			transfer(buf, pdes[1], value(EOFREAD));
+			signal(SIGPIPE, SIG_DFL);
+			while ((p = wait(&status)) > 0 && p != cpid)
+				;
+		}
+	} else {
+		register int f;
+
+		dup2(pdes[0], 0);
+		close(pdes[0]);
+		for (f = 3; f < 20; f++)
+			close(f);
+		execute(buf);
+		printf("can't execl!\r\n");
+		exit(0);
+	}
+}
+
+/*
+ * Interrupt service routine for FTP
+ */
+void
+stopsnd()
+{
+
+	stop = 1;
+	signal(SIGINT, SIG_IGN);
+}
+
+/*
+ * FTP - local ==> remote
+ *  send local file to remote host
+ *  terminate transmission with pseudo EOF sequence
+ */
+void
+sendfile(cc)
+	char cc;
+{
+	FILE *fd;
+	char *fnamex;
+	char *expand();
+
+	putchar(cc);
+	/*
+	 * get file name
+	 */
+	if (prompt("Local file name? ", fname, sizeof(fname)))
+		return;
+
+	/*
+	 * look up file
+	 */
+	fnamex = expand(fname);
+	if ((fd = fopen(fnamex, "r")) == NULL) {
+		printf("%s: cannot open\r\n", fname);
+		return;
+	}
+	transmit(fd, value(EOFWRITE), NULL);
+	if (!boolean(value(ECHOCHECK))) {
+		flush_remote ();
+	}
+}
+
+/*
+ * Bulk transfer routine to remote host --
+ *   used by sendfile() and cu_put()
+ */
+static void
+transmit(fd, eofchars, command)
+	FILE *fd;
+	char *eofchars, *command;
+{
+	char *pc, lastc;
+	int c, ccount, lcount;
+	time_t start_t, stop_t;
+	sig_t f;
+
+	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
+	stop = 0;
+	f = signal(SIGINT, stopsnd);
+	usedefchars ();
+	read(repdes[0], (char *)&ccc, 1);
+	if (command != NULL) {
+		for (pc = command; *pc; pc++)
+			send(*pc);
+		if (boolean(value(ECHOCHECK)))
+			read(FD, (char *)&c, 1);	/* trailing \n */
+		else {
+			flush_remote ();
+			sleep(5); /* wait for remote stty to take effect */
+		}
+	}
+	lcount = 0;
+	lastc = '\0';
+	start_t = time(0);
+	while (1) {
+		ccount = 0;
+		do {
+			c = getc(fd);
+			if (stop)
+				goto out;
+			if (c == EOF)
+				goto out;
+			if (c == 0177 && !boolean(value(RAWFTP)))
+				continue;
+			lastc = c;
+			if (c < 040) {
+				if (c == '\n') {
+					if (!boolean(value(RAWFTP)))
+						c = '\r';
+				}
+				else if (c == '\t') {
+					if (!boolean(value(RAWFTP))) {
+						if (boolean(value(TABEXPAND))) {
+							send(' ');
+							while ((++ccount % 8) != 0)
+								send(' ');
+							continue;
+						}
+					}
+				} else
+					if (!boolean(value(RAWFTP)))
+						continue;
+			}
+			send(c);
+		} while (c != '\r' && !boolean(value(RAWFTP)));
+		if (boolean(value(VERBOSE)))
+			printf("\r%d", ++lcount);
+		if (boolean(value(ECHOCHECK))) {
+			timedout = 0;
+			alarm(number(value(ETIMEOUT)));
+			do {	/* wait for prompt */
+				read(FD, (char *)&c, 1);
+				if (timedout || stop) {
+					if (timedout)
+						printf("\r\ntimed out at eol\r\n");
+					alarm(0);
+					goto out;
+				}
+			} while ((c&0177) != character(value(PROMPT)));
+			alarm(0);
+		}
+	}
+out:
+	if (lastc != '\n' && !boolean(value(RAWFTP)))
+		send('\r');
+	for (pc = eofchars; pc && *pc; pc++)
+		send(*pc);
+	stop_t = time(0);
+	fclose(fd);
+	signal(SIGINT, f);
+	if (boolean(value(VERBOSE)))
+		if (boolean(value(RAWFTP)))
+			prtime(" chars transferred in ", stop_t-start_t);
+		else
+			prtime(" lines transferred in ", stop_t-start_t);
+	write(fildes[1], (char *)&ccc, 1);
+	usetchars ();
+}
+
+/*
+ * Cu-like put command
+ */
+void
+cu_put(cc)
+	char cc;
+{
+	FILE *fd;
+	char line[BUFSIZ];
+	int argc;
+	char *expand();
+	char *copynamex;
+
+	if (prompt("[put] ", copyname, sizeof(copyname)))
+		return;
+	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
+		printf("usage: <put> from [to]\r\n");
+		return;
+	}
+	if (argc == 1)
+		argv[1] = argv[0];
+	copynamex = expand(argv[0]);
+	if ((fd = fopen(copynamex, "r")) == NULL) {
+		printf("%s: cannot open\r\n", copynamex);
+		return;
+	}
+	if (boolean(value(ECHOCHECK)))
+		snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
+	else
+		snprintf(line, sizeof(line), "stty -echo;cat>%s;stty echo\r", argv[1]);
+	transmit(fd, "\04", line);
+}
+
+
+static void
+nap(msec)
+	int msec; /* milliseconds */
+{
+	usleep(msec*1000);
+}
+
+
+/*
+ * FTP - send single character
+ *  wait for echo & handle timeout
+ */
+static void
+send(c)
+	char c;
+{
+	char cc;
+	int retry = 0;
+
+	cc = c;
+	xpwrite(FD, &cc, 1);
+	if (number(value(CDELAY)) > 0 && c != '\r')
+		nap(number(value(CDELAY)));
+	if (!boolean(value(ECHOCHECK))) {
+		if (number(value(LDELAY)) > 0 && c == '\r')
+			nap(number(value(LDELAY)));
+		return;
+	}
+tryagain:
+	timedout = 0;
+	alarm(number(value(ETIMEOUT)));
+	read(FD, &cc, 1);
+	alarm(0);
+	if (timedout) {
+		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
+		if (retry++ > 3)
+			return;
+		xpwrite(FD, &null, 1); /* poke it */
+		goto tryagain;
+	}
+}
+
+void
+timeout()
+{
+	signal(SIGALRM, timeout);
+	timedout = 1;
+}
+
+/*
+ * Stolen from consh() -- puts a remote file on the output of a local command.
+ *	Identical to consh() except for where stdout goes.
+ */
+void
+pipeout(c)
+{
+	char buf[256];
+	int cpid, status, p;
+	time_t start;
+
+	putchar(c);
+	if (prompt("Local command? ", buf, sizeof(buf)))
+		return;
+	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
+	signal(SIGINT, SIG_IGN);
+	signal(SIGQUIT, SIG_IGN);
+	usedefchars ();
+	read(repdes[0], (char *)&ccc, 1);
+	/*
+	 * Set up file descriptors in the child and
+	 *  let it go...
+	 */
+	if ((cpid = fork()) < 0)
+		printf("can't fork!\r\n");
+	else if (cpid) {
+		start = time(0);
+		while ((p = wait(&status)) > 0 && p != cpid)
+			;
+	} else {
+		register int i;
+
+		dup2(FD, 1);
+		for (i = 3; i < 20; i++)
+			close(i);
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+		execute(buf);
+		printf("can't find `%s'\r\n", buf);
+		exit(0);
+	}
+	if (boolean(value(VERBOSE)))
+		prtime("away for ", time(0)-start);
+	write(fildes[1], (char *)&ccc, 1);
+	usetchars ();
+	signal(SIGINT, SIG_DFL);
+	signal(SIGQUIT, SIG_DFL);
+}
+
+#if CONNECT
+
+int
+tiplink (char *cmd, unsigned int flags)
+{
+	int cpid, status, p;
+	time_t start;
+
+	if (flags & TL_SIGNAL_TIPOUT) {
+		kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
+		signal(SIGINT, SIG_IGN);
+		signal(SIGQUIT, SIG_IGN);
+		usedefchars ();
+		read(repdes[0], (char *)&ccc, 1);
+	}
+
+	/*
+	 * Set up file descriptors in the child and
+	 *  let it go...
+	 */
+	if ((cpid = fork()) < 0)
+		printf("can't fork!\r\n");
+	else if (cpid) {
+		start = time(0);
+		while ((p = wait(&status)) > 0 && p != cpid)
+			;
+	} else {
+		register int fd;
+
+		dup2(FD, 0);
+		dup2(3, 1);
+		for (fd = 3; fd < 20; fd++)
+			close (fd);
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+		execute (cmd);
+		printf("can't find `%s'\r\n", cmd);
+		exit(0);
+	}
+
+	if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
+		prtime("away for ", time(0)-start);
+
+	if (flags & TL_SIGNAL_TIPOUT) {
+		write(fildes[1], (char *)&ccc, 1);
+		usetchars ();
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+	}
+
+	return 0;
+}
+
+/*
+ * Fork a program with:
+ *  0 <-> remote tty in
+ *  1 <-> remote tty out
+ *  2 <-> local tty out
+ */
+int
+consh(c)
+{
+	char buf[256];
+	putchar(c);
+	if (prompt("Local command? ", buf, sizeof(buf)))
+		return;
+	tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
+	return 0;
+}
+#endif
+
+/*
+ * Escape to local shell
+ */
+void
+shell()
+{
+	int shpid, status;
+	char *cp;
+
+	printf("[sh]\r\n");
+	signal(SIGINT, SIG_IGN);
+	signal(SIGQUIT, SIG_IGN);
+	unraw();
+	if ((shpid = fork())) {
+		while (shpid != wait(&status));
+		raw();
+		printf("\r\n!\r\n");
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+		return;
+	} else {
+		signal(SIGQUIT, SIG_DFL);
+		signal(SIGINT, SIG_DFL);
+		if ((cp = rindex(value(SHELL), '/')) == NULL)
+			cp = value(SHELL);
+		else
+			cp++;
+		shell_uid();
+		execl(value(SHELL), cp, 0);
+		printf("\r\ncan't execl!\r\n");
+		exit(1);
+	}
+}
+
+/*
+ * TIPIN portion of scripting
+ *   initiate the conversation with TIPOUT
+ */
+void
+setscript()
+{
+	char c;
+	/*
+	 * enable TIPOUT side for dialogue
+	 */
+	kill(pid, SIGEMT);
+	if (boolean(value(SCRIPT)))
+		write(fildes[1], value(RECORD), size(value(RECORD)));
+	write(fildes[1], "\n", 1);
+	/*
+	 * wait for TIPOUT to finish
+	 */
+	read(repdes[0], &c, 1);
+	if (c == 'n')
+		printf("can't create %s\r\n", value(RECORD));
+}
+
+/*
+ * Change current working directory of
+ *   local portion of tip
+ */
+void
+chdirectory()
+{
+	char dirname[PATH_MAX];
+	register char *cp = dirname;
+
+	if (prompt("[cd] ", dirname, sizeof(dirname))) {
+		if (stoprompt)
+			return;
+		cp = value(HOME);
+	}
+	if (chdir(cp) < 0)
+		printf("%s: bad directory\r\n", cp);
+	printf("!\r\n");
+}
+
+void
+tipabort(msg)
+	char *msg;
+{
+
+	kill(pid, SIGTERM);
+	disconnect(msg);
+	if (msg != NOSTR)
+		printf("\r\n%s", msg);
+	printf("\r\n[EOT]\r\n");
+	daemon_uid();
+	(void)uu_unlock(uucplock);
+	unraw();
+	exit(0);
+}
+
+void
+finish()
+{
+	char *abortmsg = NOSTR, *dismsg;
+
+	if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
+		abortmsg = "logout failed";
+	}
+
+	if ((dismsg = value(DISCONNECT)) != NOSTR) {
+		write(FD, dismsg, strlen(dismsg));
+		sleep (2);
+	}
+	tipabort(abortmsg);
+}
+
+void
+intcopy()
+{
+	raw();
+	quit = 1;
+	longjmp(intbuf, 1);
+}
+
+static void
+execute(s)
+	char *s;
+{
+	register char *cp;
+
+	if ((cp = rindex(value(SHELL), '/')) == NULL)
+		cp = value(SHELL);
+	else
+		cp++;
+	shell_uid();
+	execl(value(SHELL), cp, "-c", s, 0);
+}
+
+static int
+args(buf, a, num)
+	char *buf, *a[];
+	int num;
+{
+	register char *p = buf, *start;
+	register char **parg = a;
+	register int n = 0;
+
+	while (*p && n < num) {
+		while (*p && (*p == ' ' || *p == '\t'))
+			p++;
+		start = p;
+		if (*p)
+			*parg = p;
+		while (*p && (*p != ' ' && *p != '\t'))
+			p++;
+		if (p != start)
+			parg++, n++;
+		if (*p)
+			*p++ = '\0';
+	}
+	return(n);
+}
+
+static void
+prtime(s, a)
+	char *s;
+	time_t a;
+{
+	register i;
+	int nums[3];
+
+	for (i = 0; i < 3; i++) {
+		nums[i] = (int)(a % quant[i]);
+		a /= quant[i];
+	}
+	printf("%s", s);
+	while (--i >= 0)
+		if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
+			printf("%d %s%c ", nums[i], sep[i],
+				nums[i] == 1 ? '\0' : 's');
+	printf("\r\n!\r\n");
+}
+
+void
+variable()
+{
+	char	buf[256];
+
+	if (prompt("[set] ", buf, sizeof(buf)))
+		return;
+	vlex(buf);
+	if (vtable[BEAUTIFY].v_access&CHANGED) {
+		vtable[BEAUTIFY].v_access &= ~CHANGED;
+		kill(pid, SIGSYS);
+	}
+	if (vtable[SCRIPT].v_access&CHANGED) {
+		vtable[SCRIPT].v_access &= ~CHANGED;
+		setscript();
+		/*
+		 * So that "set record=blah script" doesn't
+		 *  cause two transactions to occur.
+		 */
+		if (vtable[RECORD].v_access&CHANGED)
+			vtable[RECORD].v_access &= ~CHANGED;
+	}
+	if (vtable[RECORD].v_access&CHANGED) {
+		vtable[RECORD].v_access &= ~CHANGED;
+		if (boolean(value(SCRIPT)))
+			setscript();
+	}
+	if (vtable[TAND].v_access&CHANGED) {
+		vtable[TAND].v_access &= ~CHANGED;
+		if (boolean(value(TAND)))
+			tandem("on");
+		else
+			tandem("off");
+	}
+ 	if (vtable[LECHO].v_access&CHANGED) {
+ 		vtable[LECHO].v_access &= ~CHANGED;
+ 		HD = boolean(value(LECHO));
+ 	}
+	if (vtable[PARITY].v_access&CHANGED) {
+		vtable[PARITY].v_access &= ~CHANGED;
+		setparity(value(PARITY));
+	}
+}
+
+/*
+ * Turn tandem mode on or off for remote tty.
+ */
+static void
+tandem(option)
+	char *option;
+{
+#if HAVE_TERMIOS
+	struct termios ttermios;
+	tcgetattr (FD, &ttermios);
+	if (strcmp(option,"on") == 0) {
+		ttermios.c_iflag |= IXOFF;
+		ctermios.c_iflag |= IXOFF;
+	}
+	else {
+		ttermios.c_iflag &= ~IXOFF;
+		ctermios.c_iflag &= ~IXOFF;
+	}
+	tcsetattr (FD, TCSANOW, &ttermios);
+	tcsetattr (0, TCSANOW, &ctermios);
+#else /* HAVE_TERMIOS */
+	struct sgttyb rmtty;
+
+	ioctl(FD, TIOCGETP, &rmtty);
+	if (strcmp(option,"on") == 0) {
+		rmtty.sg_flags |= TANDEM;
+		arg.sg_flags |= TANDEM;
+	} else {
+		rmtty.sg_flags &= ~TANDEM;
+		arg.sg_flags &= ~TANDEM;
+	}
+	ioctl(FD, TIOCSETP, &rmtty);
+	ioctl(0,  TIOCSETP, &arg);
+#endif /* HAVE_TERMIOS */
+}
+
+/*
+ * Send a break.
+ */
+void
+genbrk()
+{
+
+	ioctl(FD, TIOCSBRK, NULL);
+	sleep(1);
+	ioctl(FD, TIOCCBRK, NULL);
+}
+
+/*
+ * Suspend tip
+ */
+void
+suspend(c)
+	char c;
+{
+
+	unraw();
+	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
+	raw();
+}
+
+/*
+ *	expand a file name if it includes shell meta characters
+ */
+
+char *
+expand(name)
+	char name[];
+{
+	static char xname[BUFSIZ];
+	char cmdbuf[BUFSIZ];
+	register int pid, l;
+	register char *cp, *Shell;
+	int s, pivec[2] /*, (*sigint)()*/;
+
+	if (!anyof(name, "~{[*?$`'\"\\"))
+		return(name);
+	/* sigint = signal(SIGINT, SIG_IGN); */
+	if (pipe(pivec) < 0) {
+		warn("pipe");
+		/* signal(SIGINT, sigint) */
+		return(name);
+	}
+	snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
+	if ((pid = vfork()) == 0) {
+		Shell = value(SHELL);
+		if (Shell == NOSTR)
+			Shell = _PATH_BSHELL;
+		close(pivec[0]);
+		close(1);
+		dup(pivec[1]);
+		close(pivec[1]);
+		close(2);
+		shell_uid();
+		execl(Shell, Shell, "-c", cmdbuf, 0);
+		_exit(1);
+	}
+	if (pid == -1) {
+		warn("fork");
+		close(pivec[0]);
+		close(pivec[1]);
+		return(NOSTR);
+	}
+	close(pivec[1]);
+	l = read(pivec[0], xname, BUFSIZ);
+	close(pivec[0]);
+	while (wait(&s) != pid);
+		;
+	s &= 0377;
+	if (s != 0 && s != SIGPIPE) {
+		fprintf(stderr, "\"Echo\" failed\n");
+		return(NOSTR);
+	}
+	if (l < 0) {
+		warn("read");
+		return(NOSTR);
+	}
+	if (l == 0) {
+		fprintf(stderr, "\"%s\": No match\n", name);
+		return(NOSTR);
+	}
+	if (l == BUFSIZ) {
+		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
+		return(NOSTR);
+	}
+	xname[l] = 0;
+	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+		;
+	*++cp = '\0';
+	return(xname);
+}
+
+/*
+ * Are any of the characters in the two strings the same?
+ */
+
+static int
+anyof(s1, s2)
+	register char *s1, *s2;
+{
+	register int c;
+
+	while ((c = *s1++))
+		if (any(c, s2))
+			return(1);
+	return(0);
+}
diff --git a/tip/cmdtab.c b/tip/cmdtab.c
new file mode 100644
index 0000000000000000000000000000000000000000..5997ffffd426471ef3a63b369f56b6dfe786a4ea
--- /dev/null
+++ b/tip/cmdtab.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmdtab.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: cmdtab.c,v 1.1 2000-12-22 18:48:47 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+extern	int shell(), getfl(), sendfile(), chdirectory();
+extern	int finish(), help(), pipefile(), pipeout(), variable();
+extern	int cu_take(), cu_put(), dollar(), genbrk(), suspend();
+
+esctable_t etable[] = {
+	{ '!',	NORM,	"shell",			 shell },
+	{ '<',	NORM,	"receive file from remote host", getfl },
+	{ '>',	NORM,	"send file to remote host",	 sendfile },
+	{ 't',	NORM,	"take file from remote UNIX",	 cu_take },
+	{ 'p',	NORM,	"put file to remote UNIX",	 cu_put },
+	{ '|',	NORM,	"pipe remote file",		 pipefile },
+	{ '$',	NORM,	"pipe local command to remote host", pipeout },
+#if CONNECT
+	{ 'C',  NORM,	"connect program to remote host",consh },
+#endif
+	{ 'c',	NORM,	"change directory",		 chdirectory },
+	{ '.',	NORM,	"exit from tip",		 finish },
+	{CTRL('d'),NORM,"exit from tip",		 finish },
+	{CTRL('y'),NORM,"suspend tip (local+remote)",	 suspend },
+	{CTRL('z'),NORM,"suspend tip (local only)",	 suspend },
+	{ 's',	NORM,	"set variable",			 variable },
+	{ '?',	NORM,	"get this summary",		 help },
+	{ '#',	NORM,	"send break",			 genbrk },
+	{ 0, 0, 0 }
+};
diff --git a/tip/cu.c b/tip/cu.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc6c1637d9f21155c2782c640f48e82281de7fbc
--- /dev/null
+++ b/tip/cu.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cu.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: cu.c,v 1.1 2000-12-22 18:48:47 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+void	cleanup();
+
+#if INCLUDE_CU_INTERFACE
+
+/*
+ * Botch the interface to look like cu's
+ */
+cumain(argc, argv)
+	char *argv[];
+{
+	register int i;
+	static char sbuf[12];
+
+	if (argc < 2) {
+		printf("usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n");
+		exit(8);
+	}
+	CU = DV = NOSTR;
+	BR = DEFBR;
+	for (; argc > 1; argv++, argc--) {
+		if (argv[1][0] != '-')
+			PN = argv[1];
+		else switch (argv[1][1]) {
+
+		case 't':
+			HW = 1, DU = -1;
+			--argc;
+			continue;
+
+		case 'a':
+			CU = argv[2]; ++argv; --argc;
+			break;
+
+		case 's':
+			if (argc < 3 || speed(atoi(argv[2])) == 0) {
+				fprintf(stderr, "cu: unsupported speed %s\n",
+					argv[2]);
+				exit(3);
+			}
+			BR = atoi(argv[2]); ++argv; --argc;
+			break;
+
+		case 'l':
+			DV = argv[2]; ++argv; --argc;
+			break;
+
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			if (CU)
+				CU[strlen(CU)-1] = argv[1][1];
+			if (DV)
+				DV[strlen(DV)-1] = argv[1][1];
+			break;
+
+		default:
+			printf("Bad flag %s", argv[1]);
+			break;
+		}
+	}
+	signal(SIGINT, cleanup);
+	signal(SIGQUIT, cleanup);
+	signal(SIGHUP, cleanup);
+	signal(SIGTERM, cleanup);
+
+	/*
+	 * The "cu" host name is used to define the
+	 * attributes of the generic dialer.
+	 */
+	(void)snprintf(sbuf, sizeof(sbuf), "cu%d", BR);
+	if ((i = hunt(sbuf)) == 0) {
+		printf("all ports busy\n");
+		exit(3);
+	}
+	if (i == -1) {
+		printf("link down\n");
+		(void)uu_unlock(uucplock);
+		exit(3);
+	}
+	setbuf(stdout, NULL);
+	loginit();
+	user_uid();
+	vinit();
+	setparity("none");
+	boolean(value(VERBOSE)) = 0;
+	if (HW)
+		ttysetup(speed(BR));
+	if (connect()) {
+		printf("Connect failed\n");
+		daemon_uid();
+		(void)uu_unlock(uucplock);
+		exit(1);
+	}
+	if (!HW)
+		ttysetup(speed(BR));
+}
+#endif /* INCLUDE_CU_INTERFACE */
diff --git a/tip/getcap.c b/tip/getcap.c
new file mode 100644
index 0000000000000000000000000000000000000000..dda084fb2e76a238fdc22ffc8f377578ac4590f5
--- /dev/null
+++ b/tip/getcap.c
@@ -0,0 +1,1079 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Casey Leedom of Lawrence Livermore National Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#ifdef LINUX
+#define dbopen(a1,a2,a3,a4,a5)	NULL
+#endif
+
+
+#define	BFRAG		1024
+#define	BSIZE		1024
+#define	ESC		('[' & 037)	/* ASCII ESC */
+#define	MAX_RECURSION	32		/* maximum getent recursion */
+#define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
+
+#define RECOK	(char)0
+#define TCERR	(char)1
+#define	SHADOW	(char)2
+
+static size_t	 topreclen;	/* toprec length */
+static char	*toprec;	/* Additional record specified by cgetset() */
+static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
+
+static int	cdbget __P((DB *, char **, char *));
+static int 	getent __P((char **, u_int *, char **, int, char *, int, char *));
+static int	nfcmp __P((char *, char *));
+
+#ifdef LINUX
+char *
+fgetln(FILE *stream, size_t *len)
+{
+	static char buf[1024];
+
+	fgets(buf, sizeof buf, stream);
+	*len = strlen(buf);
+	return buf;
+}
+#endif
+
+/*
+ * Cgetset() allows the addition of a user specified buffer to be added
+ * to the database array, in effect "pushing" the buffer on top of the
+ * virtual database. 0 is returned on success, -1 on failure.
+ */
+int
+cgetset(ent)
+	char *ent;
+{
+	if (ent == NULL) {
+		if (toprec)
+			free(toprec);
+                toprec = NULL;
+                topreclen = 0;
+                return (0);
+        }
+        topreclen = strlen(ent);
+        if ((toprec = malloc (topreclen + 1)) == NULL) {
+		errno = ENOMEM;
+                return (-1);
+	}
+	gottoprec = 0;
+        (void)strcpy(toprec, ent);
+        return (0);
+}
+
+/*
+ * Cgetcap searches the capability record buf for the capability cap with
+ * type `type'.  A pointer to the value of cap is returned on success, NULL
+ * if the requested capability couldn't be found.
+ *
+ * Specifying a type of ':' means that nothing should follow cap (:cap:).
+ * In this case a pointer to the terminating ':' or NUL will be returned if
+ * cap is found.
+ *
+ * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
+ * return NULL.
+ */
+char *
+cgetcap(buf, cap, type)
+	char *buf, *cap;
+	int type;
+{
+	register char *bp, *cp;
+
+	bp = buf;
+	for (;;) {
+		/*
+		 * Skip past the current capability field - it's either the
+		 * name field if this is the first time through the loop, or
+		 * the remainder of a field whose name failed to match cap.
+		 */
+		for (;;)
+			if (*bp == '\0')
+				return (NULL);
+			else
+				if (*bp++ == ':')
+					break;
+
+		/*
+		 * Try to match (cap, type) in buf.
+		 */
+		for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
+			continue;
+		if (*cp != '\0')
+			continue;
+		if (*bp == '@')
+			return (NULL);
+		if (type == ':') {
+			if (*bp != '\0' && *bp != ':')
+				continue;
+			return(bp);
+		}
+		if (*bp != type)
+			continue;
+		bp++;
+		return (*bp == '@' ? NULL : bp);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Cgetent extracts the capability record name from the NULL terminated file
+ * array db_array and returns a pointer to a malloc'd copy of it in buf.
+ * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
+ * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success,
+ * -1 if the requested record couldn't be found, -2 if a system error was
+ * encountered (couldn't open/read a file, etc.), and -3 if a potential
+ * reference loop is detected.
+ */
+int
+cgetent(buf, db_array, name)
+	char **buf, **db_array, *name;
+{
+	u_int dummy;
+
+	return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
+}
+
+/*
+ * Getent implements the functions of cgetent.  If fd is non-negative,
+ * *db_array has already been opened and fd is the open file descriptor.  We
+ * do this to save time and avoid using up file descriptors for tc=
+ * recursions.
+ *
+ * Getent returns the same success/failure codes as cgetent.  On success, a
+ * pointer to a malloc'ed capability record with all tc= capabilities fully
+ * expanded and its length (not including trailing ASCII NUL) are left in
+ * *cap and *len.
+ *
+ * Basic algorithm:
+ *	+ Allocate memory incrementally as needed in chunks of size BFRAG
+ *	  for capability buffer.
+ *	+ Recurse for each tc=name and interpolate result.  Stop when all
+ *	  names interpolated, a name can't be found, or depth exceeds
+ *	  MAX_RECURSION.
+ */
+static int
+getent(cap, len, db_array, fd, name, depth, nfield)
+	char **cap, **db_array, *name, *nfield;
+	u_int *len;
+	int fd, depth;
+{
+	DB *capdbp;
+	register char *r_end, *rp, **db_p;
+	int myfd, eof, foundit, retval, clen;
+	char *record, *cbuf;
+	int tc_not_resolved;
+	char pbuf[_POSIX_PATH_MAX];
+
+	/*
+	 * Return with ``loop detected'' error if we've recursed more than
+	 * MAX_RECURSION times.
+	 */
+	if (depth > MAX_RECURSION)
+		return (-3);
+
+	/*
+	 * Check if we have a top record from cgetset().
+         */
+	if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
+		if ((record = malloc (topreclen + BFRAG)) == NULL) {
+			errno = ENOMEM;
+			return (-2);
+		}
+		(void)strcpy(record, toprec);
+		myfd = 0;
+		db_p = db_array;
+		rp = record + topreclen + 1;
+		r_end = rp + BFRAG;
+		goto tc_exp;
+	}
+	/*
+	 * Allocate first chunk of memory.
+	 */
+	if ((record = malloc(BFRAG)) == NULL) {
+		errno = ENOMEM;
+		return (-2);
+	}
+	r_end = record + BFRAG;
+	foundit = 0;
+	/*
+	 * Loop through database array until finding the record.
+	 */
+
+	for (db_p = db_array; *db_p != NULL; db_p++) {
+		eof = 0;
+
+		/*
+		 * Open database if not already open.
+		 */
+
+		if (fd >= 0) {
+			(void)lseek(fd, (off_t)0, SEEK_SET);
+			myfd = 0;
+		} else {
+			(void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
+			if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
+			     != NULL) {
+				free(record);
+				retval = cdbget(capdbp, &record, name);
+				if (retval < 0) {
+					/* no record available */
+#ifndef LINUX
+					(void)capdbp->close(capdbp);
+#else
+					(void)capdbp->close(capdbp, 0);
+#endif
+					return (retval);
+				}
+				/* save the data; close frees it */
+				clen = strlen(record);
+				cbuf = malloc(clen + 1);
+				memcpy(cbuf, record, clen + 1);
+#ifndef LINUX
+				if (capdbp->close(capdbp) < 0) {
+#else
+				if (capdbp->close(capdbp, 0) < 0) {
+#endif
+					free(cbuf);
+					return (-2);
+				}
+				*len = clen;
+				*cap = cbuf;
+				return (retval);
+			} else {
+				fd = open(*db_p, O_RDONLY, 0);
+				if (fd < 0) {
+					/* No error on unfound file. */
+					if (errno == ENOENT)
+						continue;
+					free(record);
+					return (-2);
+				}
+				myfd = 1;
+			}
+		}
+		/*
+		 * Find the requested capability record ...
+		 */
+		{
+		char buf[BUFSIZ];
+		register char *b_end, *bp;
+		register int c;
+
+		/*
+		 * Loop invariants:
+		 *	There is always room for one more character in record.
+		 *	R_end always points just past end of record.
+		 *	Rp always points just past last character in record.
+		 *	B_end always points just past last character in buf.
+		 *	Bp always points at next character in buf.
+		 */
+		b_end = buf;
+		bp = buf;
+		for (;;) {
+
+			/*
+			 * Read in a line implementing (\, newline)
+			 * line continuation.
+			 */
+			rp = record;
+			for (;;) {
+				if (bp >= b_end) {
+					int n;
+
+					n = read(fd, buf, sizeof(buf));
+					if (n <= 0) {
+						if (myfd)
+							(void)close(fd);
+						if (n < 0) {
+							free(record);
+							return (-2);
+						} else {
+							fd = -1;
+							eof = 1;
+							break;
+						}
+					}
+					b_end = buf+n;
+					bp = buf;
+				}
+
+				c = *bp++;
+				if (c == '\n') {
+					if (rp > record && *(rp-1) == '\\') {
+						rp--;
+						continue;
+					} else
+						break;
+				}
+				*rp++ = c;
+
+				/*
+				 * Enforce loop invariant: if no room
+				 * left in record buffer, try to get
+				 * some more.
+				 */
+				if (rp >= r_end) {
+					u_int pos;
+					size_t newsize;
+
+					pos = rp - record;
+					newsize = r_end - record + BFRAG;
+					record = realloc(record, newsize);
+					if (record == NULL) {
+						errno = ENOMEM;
+						if (myfd)
+							(void)close(fd);
+						return (-2);
+					}
+					r_end = record + newsize;
+					rp = record + pos;
+				}
+			}
+				/* loop invariant let's us do this */
+			*rp++ = '\0';
+
+			/*
+			 * If encountered eof check next file.
+			 */
+			if (eof)
+				break;
+
+			/*
+			 * Toss blank lines and comments.
+			 */
+			if (*record == '\0' || *record == '#')
+				continue;
+
+			/*
+			 * See if this is the record we want ...
+			 */
+			if (cgetmatch(record, name) == 0) {
+				if (nfield == NULL || !nfcmp(nfield, record)) {
+					foundit = 1;
+					break;	/* found it! */
+				}
+			}
+		}
+	}
+		if (foundit)
+			break;
+	}
+
+	if (!foundit)
+		return (-1);
+
+	/*
+	 * Got the capability record, but now we have to expand all tc=name
+	 * references in it ...
+	 */
+tc_exp:	{
+		register char *newicap, *s;
+		register int newilen;
+		u_int ilen;
+		int diff, iret, tclen;
+		char *icap, *scan, *tc, *tcstart, *tcend;
+
+		/*
+		 * Loop invariants:
+		 *	There is room for one more character in record.
+		 *	R_end points just past end of record.
+		 *	Rp points just past last character in record.
+		 *	Scan points at remainder of record that needs to be
+		 *	scanned for tc=name constructs.
+		 */
+		scan = record;
+		tc_not_resolved = 0;
+		for (;;) {
+			if ((tc = cgetcap(scan, "tc", '=')) == NULL)
+				break;
+
+			/*
+			 * Find end of tc=name and stomp on the trailing `:'
+			 * (if present) so we can use it to call ourselves.
+			 */
+			s = tc;
+			for (;;)
+				if (*s == '\0')
+					break;
+				else
+					if (*s++ == ':') {
+						*(s - 1) = '\0';
+						break;
+					}
+			tcstart = tc - 3;
+			tclen = s - tcstart;
+			tcend = s;
+
+			iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
+				      NULL);
+			newicap = icap;		/* Put into a register. */
+			newilen = ilen;
+			if (iret != 0) {
+				/* an error */
+				if (iret < -1) {
+					if (myfd)
+						(void)close(fd);
+					free(record);
+					return (iret);
+				}
+				if (iret == 1)
+					tc_not_resolved = 1;
+				/* couldn't resolve tc */
+				if (iret == -1) {
+					*(s - 1) = ':';
+					scan = s - 1;
+					tc_not_resolved = 1;
+					continue;
+
+				}
+			}
+			/* not interested in name field of tc'ed record */
+			s = newicap;
+			for (;;)
+				if (*s == '\0')
+					break;
+				else
+					if (*s++ == ':')
+						break;
+			newilen -= s - newicap;
+			newicap = s;
+
+			/* make sure interpolated record is `:'-terminated */
+			s += newilen;
+			if (*(s-1) != ':') {
+				*s = ':';	/* overwrite NUL with : */
+				newilen++;
+			}
+
+			/*
+			 * Make sure there's enough room to insert the
+			 * new record.
+			 */
+			diff = newilen - tclen;
+			if (diff >= r_end - rp) {
+				u_int pos, tcpos, tcposend;
+				size_t newsize;
+
+				pos = rp - record;
+				newsize = r_end - record + diff + BFRAG;
+				tcpos = tcstart - record;
+				tcposend = tcend - record;
+				record = realloc(record, newsize);
+				if (record == NULL) {
+					errno = ENOMEM;
+					if (myfd)
+						(void)close(fd);
+					free(icap);
+					return (-2);
+				}
+				r_end = record + newsize;
+				rp = record + pos;
+				tcstart = record + tcpos;
+				tcend = record + tcposend;
+			}
+
+			/*
+			 * Insert tc'ed record into our record.
+			 */
+			s = tcstart + newilen;
+			bcopy(tcend, s, rp - tcend);
+			bcopy(newicap, tcstart, newilen);
+			rp += diff;
+			free(icap);
+
+			/*
+			 * Start scan on `:' so next cgetcap works properly
+			 * (cgetcap always skips first field).
+			 */
+			scan = s-1;
+		}
+
+	}
+	/*
+	 * Close file (if we opened it), give back any extra memory, and
+	 * return capability, length and success.
+	 */
+	if (myfd)
+		(void)close(fd);
+	*len = rp - record - 1;	/* don't count NUL */
+	if (r_end > rp)
+		if ((record =
+		     realloc(record, (size_t)(rp - record))) == NULL) {
+			errno = ENOMEM;
+			return (-2);
+		}
+
+	*cap = record;
+	if (tc_not_resolved)
+		return (1);
+	return (0);
+}
+
+static int
+cdbget(capdbp, bp, name)
+	DB *capdbp;
+	char **bp, *name;
+{
+	DBT key, data;
+
+	key.data = name;
+	key.size = strlen(name);
+
+	for (;;) {
+		/* Get the reference. */
+#ifndef LINUX
+		switch(capdbp->get(capdbp, &key, &data, 0)) {
+#else
+		switch(capdbp->get(capdbp, 0, &key, &data, 0)) {
+#endif
+		case -1:
+			return (-2);
+		case 1:
+			return (-1);
+		}
+
+		/* If not an index to another record, leave. */
+		if (((char *)data.data)[0] != SHADOW)
+			break;
+
+		key.data = (char *)data.data + 1;
+		key.size = data.size - 1;
+	}
+
+	*bp = (char *)data.data + 1;
+	return (((char *)(data.data))[0] == TCERR ? 1 : 0);
+}
+
+/*
+ * Cgetmatch will return 0 if name is one of the names of the capability
+ * record buf, -1 if not.
+ */
+int
+cgetmatch(buf, name)
+	char *buf, *name;
+{
+	register char *np, *bp;
+
+	/*
+	 * Start search at beginning of record.
+	 */
+	bp = buf;
+	for (;;) {
+		/*
+		 * Try to match a record name.
+		 */
+		np = name;
+		for (;;)
+			if (*np == '\0')
+				if (*bp == '|' || *bp == ':' || *bp == '\0')
+					return (0);
+				else
+					break;
+			else
+				if (*bp++ != *np++)
+					break;
+
+		/*
+		 * Match failed, skip to next name in record.
+		 */
+		bp--;	/* a '|' or ':' may have stopped the match */
+		for (;;)
+			if (*bp == '\0' || *bp == ':')
+				return (-1);	/* match failed totally */
+			else
+				if (*bp++ == '|')
+					break;	/* found next name */
+	}
+}
+
+
+
+
+
+int
+cgetfirst(buf, db_array)
+	char **buf, **db_array;
+{
+	(void)cgetclose();
+	return (cgetnext(buf, db_array));
+}
+
+static FILE *pfp;
+static int slash;
+static char **dbp;
+
+int
+cgetclose()
+{
+	if (pfp != NULL) {
+		(void)fclose(pfp);
+		pfp = NULL;
+	}
+	dbp = NULL;
+	gottoprec = 0;
+	slash = 0;
+	return(0);
+}
+
+/*
+ * Cgetnext() gets either the first or next entry in the logical database
+ * specified by db_array.  It returns 0 upon completion of the database, 1
+ * upon returning an entry with more remaining, and -1 if an error occurs.
+ */
+int
+cgetnext(bp, db_array)
+        register char **bp;
+	char **db_array;
+{
+	size_t len;
+	int status, i, done;
+	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
+	u_int dummy;
+
+	if (dbp == NULL)
+		dbp = db_array;
+
+	if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
+		(void)cgetclose();
+		return (-1);
+	}
+	for(;;) {
+		if (toprec && !gottoprec) {
+			gottoprec = 1;
+			line = toprec;
+		} else {
+			line = fgetln(pfp, &len);
+			if (line == NULL && pfp) {
+				(void)fclose(pfp);
+				if (ferror(pfp)) {
+					(void)cgetclose();
+					return (-1);
+				} else {
+					if (*++dbp == NULL) {
+						(void)cgetclose();
+						return (0);
+					} else if ((pfp =
+					    fopen(*dbp, "r")) == NULL) {
+						(void)cgetclose();
+						return (-1);
+					} else
+						continue;
+				}
+			} else
+				line[len - 1] = '\0';
+			if (len == 1) {
+				slash = 0;
+				continue;
+			}
+			if (isspace(*line) ||
+			    *line == ':' || *line == '#' || slash) {
+				if (line[len - 2] == '\\')
+					slash = 1;
+				else
+					slash = 0;
+				continue;
+			}
+			if (line[len - 2] == '\\')
+				slash = 1;
+			else
+				slash = 0;
+		}
+
+
+		/*
+		 * Line points to a name line.
+		 */
+		i = 0;
+		done = 0;
+		np = nbuf;
+		for (;;) {
+			for (cp = line; *cp != '\0'; cp++) {
+				if (*cp == ':') {
+					*np++ = ':';
+					done = 1;
+					break;
+				}
+				if (*cp == '\\')
+					break;
+				*np++ = *cp;
+			}
+			if (done) {
+				*np = '\0';
+				break;
+			} else { /* name field extends beyond the line */
+				line = fgetln(pfp, &len);
+				if (line == NULL && pfp) {
+					(void)fclose(pfp);
+					if (ferror(pfp)) {
+						(void)cgetclose();
+						return (-1);
+					}
+				} else
+					line[len - 1] = '\0';
+			}
+		}
+		rp = buf;
+		for(cp = nbuf; *cp != '\0'; cp++)
+			if (*cp == '|' || *cp == ':')
+				break;
+			else
+				*rp++ = *cp;
+
+		*rp = '\0';
+		/*
+		 * XXX
+		 * Last argument of getent here should be nbuf if we want true
+		 * sequential access in the case of duplicates.
+		 * With NULL, getent will return the first entry found
+		 * rather than the duplicate entry record.  This is a
+		 * matter of semantics that should be resolved.
+		 */
+		status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
+		if (status == -2 || status == -3)
+			(void)cgetclose();
+
+		return (status + 1);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Cgetstr retrieves the value of the string capability cap from the
+ * capability record pointed to by buf.  A pointer to a decoded, NUL
+ * terminated, malloc'd copy of the string is returned in the char *
+ * pointed to by str.  The length of the string not including the trailing
+ * NUL is returned on success, -1 if the requested string capability
+ * couldn't be found, -2 if a system error was encountered (storage
+ * allocation failure).
+ */
+int
+cgetstr(buf, cap, str)
+	char *buf, *cap;
+	char **str;
+{
+	register u_int m_room;
+	register char *bp, *mp;
+	int len;
+	char *mem;
+
+	/*
+	 * Find string capability cap
+	 */
+	bp = cgetcap(buf, cap, '=');
+	if (bp == NULL)
+		return (-1);
+
+	/*
+	 * Conversion / storage allocation loop ...  Allocate memory in
+	 * chunks SFRAG in size.
+	 */
+	if ((mem = malloc(SFRAG)) == NULL) {
+		errno = ENOMEM;
+		return (-2);	/* couldn't even allocate the first fragment */
+	}
+	m_room = SFRAG;
+	mp = mem;
+
+	while (*bp != ':' && *bp != '\0') {
+		/*
+		 * Loop invariants:
+		 *	There is always room for one more character in mem.
+		 *	Mp always points just past last character in mem.
+		 *	Bp always points at next character in buf.
+		 */
+		if (*bp == '^') {
+			bp++;
+			if (*bp == ':' || *bp == '\0')
+				break;	/* drop unfinished escape */
+			if (*bp == '?') {
+				*mp++ = '\177';
+				bp++;
+			} else
+				*mp++ = *bp++ & 037;
+		} else if (*bp == '\\') {
+			bp++;
+			if (*bp == ':' || *bp == '\0')
+				break;	/* drop unfinished escape */
+			if ('0' <= *bp && *bp <= '7') {
+				register int n, i;
+
+				n = 0;
+				i = 3;	/* maximum of three octal digits */
+				do {
+					n = n * 8 + (*bp++ - '0');
+				} while (--i && '0' <= *bp && *bp <= '7');
+				*mp++ = n;
+			}
+			else switch (*bp++) {
+				case 'b': case 'B':
+					*mp++ = '\b';
+					break;
+				case 't': case 'T':
+					*mp++ = '\t';
+					break;
+				case 'n': case 'N':
+					*mp++ = '\n';
+					break;
+				case 'f': case 'F':
+					*mp++ = '\f';
+					break;
+				case 'r': case 'R':
+					*mp++ = '\r';
+					break;
+				case 'e': case 'E':
+					*mp++ = ESC;
+					break;
+				case 'c': case 'C':
+					*mp++ = ':';
+					break;
+				default:
+					/*
+					 * Catches '\', '^', and
+					 *  everything else.
+					 */
+					*mp++ = *(bp-1);
+					break;
+			}
+		} else
+			*mp++ = *bp++;
+		m_room--;
+
+		/*
+		 * Enforce loop invariant: if no room left in current
+		 * buffer, try to get some more.
+		 */
+		if (m_room == 0) {
+			size_t size = mp - mem;
+
+			if ((mem = realloc(mem, size + SFRAG)) == NULL)
+				return (-2);
+			m_room = SFRAG;
+			mp = mem + size;
+		}
+	}
+	*mp++ = '\0';	/* loop invariant let's us do this */
+	m_room--;
+	len = mp - mem - 1;
+
+	/*
+	 * Give back any extra memory and return value and success.
+	 */
+	if (m_room != 0)
+		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
+			return (-2);
+	*str = mem;
+	return (len);
+}
+
+/*
+ * Cgetustr retrieves the value of the string capability cap from the
+ * capability record pointed to by buf.  The difference between cgetustr()
+ * and cgetstr() is that cgetustr does not decode escapes but rather treats
+ * all characters literally.  A pointer to a  NUL terminated malloc'd
+ * copy of the string is returned in the char pointed to by str.  The
+ * length of the string not including the trailing NUL is returned on success,
+ * -1 if the requested string capability couldn't be found, -2 if a system
+ * error was encountered (storage allocation failure).
+ */
+int
+cgetustr(buf, cap, str)
+	char *buf, *cap, **str;
+{
+	register u_int m_room;
+	register char *bp, *mp;
+	int len;
+	char *mem;
+
+	/*
+	 * Find string capability cap
+	 */
+	if ((bp = cgetcap(buf, cap, '=')) == NULL)
+		return (-1);
+
+	/*
+	 * Conversion / storage allocation loop ...  Allocate memory in
+	 * chunks SFRAG in size.
+	 */
+	if ((mem = malloc(SFRAG)) == NULL) {
+		errno = ENOMEM;
+		return (-2);	/* couldn't even allocate the first fragment */
+	}
+	m_room = SFRAG;
+	mp = mem;
+
+	while (*bp != ':' && *bp != '\0') {
+		/*
+		 * Loop invariants:
+		 *	There is always room for one more character in mem.
+		 *	Mp always points just past last character in mem.
+		 *	Bp always points at next character in buf.
+		 */
+		*mp++ = *bp++;
+		m_room--;
+
+		/*
+		 * Enforce loop invariant: if no room left in current
+		 * buffer, try to get some more.
+		 */
+		if (m_room == 0) {
+			size_t size = mp - mem;
+
+			if ((mem = realloc(mem, size + SFRAG)) == NULL)
+				return (-2);
+			m_room = SFRAG;
+			mp = mem + size;
+		}
+	}
+	*mp++ = '\0';	/* loop invariant let's us do this */
+	m_room--;
+	len = mp - mem - 1;
+
+	/*
+	 * Give back any extra memory and return value and success.
+	 */
+	if (m_room != 0)
+		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
+			return (-2);
+	*str = mem;
+	return (len);
+}
+
+/*
+ * Cgetnum retrieves the value of the numeric capability cap from the
+ * capability record pointed to by buf.  The numeric value is returned in
+ * the long pointed to by num.  0 is returned on success, -1 if the requested
+ * numeric capability couldn't be found.
+ */
+int
+cgetnum(buf, cap, num)
+	char *buf, *cap;
+	long *num;
+{
+	register long n;
+	register int base, digit;
+	register char *bp;
+
+	/*
+	 * Find numeric capability cap
+	 */
+	bp = cgetcap(buf, cap, '#');
+	if (bp == NULL)
+		return (-1);
+
+	/*
+	 * Look at value and determine numeric base:
+	 *	0x... or 0X...	hexadecimal,
+	 * else	0...		octal,
+	 * else			decimal.
+	 */
+	if (*bp == '0') {
+		bp++;
+		if (*bp == 'x' || *bp == 'X') {
+			bp++;
+			base = 16;
+		} else
+			base = 8;
+	} else
+		base = 10;
+
+	/*
+	 * Conversion loop ...
+	 */
+	n = 0;
+	for (;;) {
+		if ('0' <= *bp && *bp <= '9')
+			digit = *bp - '0';
+		else if ('a' <= *bp && *bp <= 'f')
+			digit = 10 + *bp - 'a';
+		else if ('A' <= *bp && *bp <= 'F')
+			digit = 10 + *bp - 'A';
+		else
+			break;
+
+		if (digit >= base)
+			break;
+
+		n = n * base + digit;
+		bp++;
+	}
+
+	/*
+	 * Return value and success.
+	 */
+	*num = n;
+	return (0);
+}
+
+
+/*
+ * Compare name field of record.
+ */
+static int
+nfcmp(nf, rec)
+	char *nf, *rec;
+{
+	char *cp, tmp;
+	int ret;
+
+	for (cp = rec; *cp != ':'; cp++)
+		;
+
+	tmp = *(cp + 1);
+	*(cp + 1) = '\0';
+	ret = strcmp(nf, rec);
+	*(cp + 1) = tmp;
+
+	return (ret);
+}
diff --git a/tip/hunt.c b/tip/hunt.c
new file mode 100644
index 0000000000000000000000000000000000000000..df2a1c12fc05003278d17a8b3fce0f92cc050240
--- /dev/null
+++ b/tip/hunt.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)hunt.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: hunt.c,v 1.1 2000-12-22 18:48:47 mike Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <err.h>
+#ifndef LINUX
+#include <libutil.h>
+#endif
+#include "tipconf.h"
+#include "tip.h"
+
+extern char *getremote();
+extern char *rindex();
+
+static	jmp_buf deadline;
+static	int deadfl;
+
+void
+dead()
+{
+	deadfl = 1;
+	longjmp(deadline, 1);
+}
+
+int
+hunt(name)
+	char *name;
+{
+	register char *cp;
+	sig_t f;
+	int res;
+
+	f = signal(SIGALRM, dead);
+	while ((cp = getremote(name))) {
+		deadfl = 0;
+		uucplock = rindex(cp, '/')+1;
+		if ((res = uu_lock(uucplock)) != UU_LOCK_OK) {
+			if (res != UU_LOCK_INUSE)
+				fprintf(stderr, "uu_lock: %s\n", uu_lockerr(res));
+			continue;
+		}
+		/*
+		 * Straight through call units, such as the BIZCOMP,
+		 * VADIC and the DF, must indicate they're hardwired in
+		 *  order to get an open file descriptor placed in FD.
+		 * Otherwise, as for a DN-11, the open will have to
+		 *  be done in the "open" routine.
+		 */
+		if (!HW)
+			break;
+		if (setjmp(deadline) == 0) {
+			alarm(10);
+			FD = open(cp, O_RDWR);
+		}
+		alarm(0);
+		if (FD < 0) {
+			warn("%s", cp);
+			deadfl = 1;
+		}
+		if (!deadfl) {
+			ioctl(FD, TIOCEXCL, 0);
+#if HAVE_TERMIOS
+			{
+				struct termios t;
+				if (tcgetattr(FD, &t) == 0) {
+					t.c_cflag |= HUPCL;
+					(void)tcsetattr(FD, TCSANOW, &t);
+				}
+			}
+#else /* HAVE_TERMIOS */
+#ifdef TIOCHPCL
+			ioctl(FD, TIOCHPCL, 0);
+#endif
+#endif /* HAVE_TERMIOS */
+			signal(SIGALRM, SIG_DFL);
+			return ((int)cp);
+		}
+		(void)uu_unlock(uucplock);
+	}
+	signal(SIGALRM, f);
+	return (deadfl ? -1 : (int)cp);
+}
diff --git a/tip/log.c b/tip/log.c
new file mode 100644
index 0000000000000000000000000000000000000000..65b25ceb336fc678bec3899e3d199974eccf5dc8
--- /dev/null
+++ b/tip/log.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)log.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: log.c,v 1.1 2000-12-22 18:48:48 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+#include <err.h>
+
+#if ACULOG
+static	FILE *flog = NULL;
+
+/*
+ * Log file maintenance routines
+ */
+
+void
+logent(group, num, acu, message)
+	char *group, *num, *acu, *message;
+{
+	char *user, *timestamp;
+	struct passwd *pwd;
+	time_t t;
+
+	if (flog == NULL)
+		return;
+	if (flock(fileno(flog), LOCK_EX) < 0) {
+		warn("flock");
+		return;
+	}
+	if ((user = getlogin()) == NOSTR)
+		if ((pwd = getpwuid(getuid())) == NOPWD)
+			user = "???";
+		else
+			user = pwd->pw_name;
+	t = time(0);
+	timestamp = ctime(&t);
+	timestamp[24] = '\0';
+	fprintf(flog, "%s (%s) <%s, %s, %s> %s\n",
+		user, timestamp, group,
+#if PRISTINE
+		"",
+#else
+		num,
+#endif
+		acu, message);
+	(void) fflush(flog);
+	(void) flock(fileno(flog), LOCK_UN);
+}
+
+void
+loginit()
+{
+	flog = fopen(value(LOG), "a");
+	if (flog == NULL)
+		fprintf(stderr, "can't open log file %s.\r\n", value(LOG));
+}
+#endif
diff --git a/tip/modems.5 b/tip/modems.5
new file mode 100644
index 0000000000000000000000000000000000000000..7fd347433cc02bba62881d7981a0f30dc6c3ead7
--- /dev/null
+++ b/tip/modems.5
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)modems.5	3/24/95
+.\"
+.Dd March 24, 1995
+.Dt MODEMS 5
+.Os BSD 4.4
+.Sh NAME
+.Nm modems
+.Nd modem configuration data base
+.Sh DESCRIPTION
+The modems known by
+.Xr tip 1
+and their attributes are stored in an
+.Tn ASCII
+file which
+is structured somewhat like the
+.Xr termcap 5
+file.  Each line in the file provides a description for a single
+.Em modem .
+Fields are separated by a colon (``:'').
+Lines ending in a \e character with an immediately following newline are
+continued on the next line.
+.Pp
+The first entry is the name(s) of the modem.  If there is more
+than one name for a modem, the names are separated by vertical bars.
+After the name of the modem comes the fields of the description.  A
+field name followed by an `=' sign indicates a string value follows.  A field
+name followed by a `#' sign indicates a following numeric value.
+.Pp
+When
+.Xr tip 1
+is invoked, an entry for a remote system is looked up in the
+.Pa /etc/remote
+database. 
+If the entry includes an "ACU" type capability (abbreviated at), 
+.Xr tip 1
+looks up the specified modem in 
+.Pa /etc/modems.
+If a modem entry is found,
+the corresponding capabilities determine how 
+.Xr tip 1
+programs the modem when connecting to and disconnecting from the
+remote system.
+.Sh CAPABILITIES
+Capabilities are either strings (str), numbers (num), or boolean
+flags (bool).  A string capability is specified by 
+.Em capability Ns Ar = Ns Em value ;
+for example, ``reset_command=ATZ\\r''.  A numeric capability is specified by
+.Em capability Ns Ar # Ns Em value ;
+for example, ``intercharacter_delay#50''.  A boolean capability is specified 
+by simply listing the capability.
+.Bl -tag -width intercharacter_delay indent
+.It Cm \&dial_command
+(str)
+AT command used to dial remote system (typically, "ATDT")
+.It Cm \&echo_off_command
+(str)
+AT command to turn off command echo.
+.It Cm \&escape_guard_time
+(num)
+The delay, expressed in milliseconds, used to frame return-to-command
+escape sequences.
+.It Cm \&escape_sequence
+(str)
+The return-to-command escape sequence.
+.It Cm \&hangup_command
+(str)
+AT command used to hangup modem.
+.It Cm \&hw_flow_control
+(bool)
+Enable hardware (RTS/CTS) flow control between computer and modem (DTE/DCE).
+.It Cm \&init_string
+(str)
+AT command used to initialize modem before dialing.
+.It Cm \&intercharacter_delay
+(num)
+Delay value, expressed in milliseconds, between characters when sending commands
+to the modem.
+.It Cm \&intercommand_delay
+(num)
+Minimum delay value, expressed in milliseconds, to impose between commands
+issued to the modem.
+.It Cm \&lock_baud
+(bool)
+Use a fixed bit rate between the computer and the modem (DTE / DCE). The
+bit rate is specified in 
+.Pa /etc/remote.
+.It Cm \&reset_command
+(str)
+AT command to reset the modem.
+.It Cm \&reset_delay
+(num)
+The time, expressed in milliseconds, required by the modem to complete
+a reset and return to a ready condition.
+.Sh FILES
+.Bl -tag -width /etc/modems -compact
+.It Pa /etc/modems
+The
+.Nm modems
+configuration database file
+resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr tip 1 ,
+.Xr remote 5
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.4 .
diff --git a/tip/partab.c b/tip/partab.c
new file mode 100644
index 0000000000000000000000000000000000000000..577d2fca875f9c2df14cf7e09de2b2c45650f1b6
--- /dev/null
+++ b/tip/partab.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)partab.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: partab.c,v 1.1 2000-12-22 18:48:48 mike Exp $";
+#endif /* not lint */
+
+/*
+ * Even parity table for 0-0177
+ */
+char evenpartab[] = {
+	0000,0201,0202,0003,0204,0005,0006,0207,
+	0210,0011,0012,0213,0014,0215,0216,0017,
+	0220,0021,0022,0223,0024,0225,0226,0027,
+	0030,0231,0232,0033,0234,0035,0036,0237,
+	0240,0041,0042,0243,0044,0245,0246,0047,
+	0050,0251,0252,0053,0254,0055,0056,0257,
+	0060,0261,0262,0063,0264,0065,0066,0267,
+	0270,0071,0072,0273,0074,0275,0276,0077,
+	0300,0101,0102,0303,0104,0305,0306,0107,
+	0110,0311,0312,0113,0314,0115,0116,0317,
+	0120,0321,0322,0123,0324,0125,0126,0327,
+	0330,0131,0132,0333,0134,0335,0336,0137,
+	0140,0341,0342,0143,0344,0145,0146,0347,
+	0350,0151,0152,0353,0154,0355,0356,0157,
+	0360,0161,0162,0363,0164,0365,0366,0167,
+	0170,0371,0372,0173,0374,0175,0176,0377,
+};
diff --git a/tip/pathnames.h b/tip/pathnames.h
new file mode 100644
index 0000000000000000000000000000000000000000..0f9a15b1fa0f0ba6593d89d3d48a4daffd843d0f
--- /dev/null
+++ b/tip/pathnames.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+/*
+	Specify path to ACU (modem) log
+*/
+#define	_PATH_ACULOG		"/var/log/aculog"
+
+/*
+	Specify path and format of lock files
+*/
+/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/etc/locks/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/usr/spool/locks/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK/LCK..%s" */
+#define _PATH_LOCKDIRNAME _PATH_UUCPLOCK "LCK..%s"
+
+/*
+	Specify location for system wide databases
+*/
+#define	_PATH_MODEMS		"/etc/modems"
+#define	_PATH_PHONES		"/etc/phones"
+#define	_PATH_REMOTE		"/etc/remote"
+
diff --git a/tip/remcap.c b/tip/remcap.c
new file mode 100644
index 0000000000000000000000000000000000000000..7a7e0c2732ca6469cd27cbab536162db4be01e18
--- /dev/null
+++ b/tip/remcap.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remcap.c	8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define	BUFSIZ		1024
+#endif
+#define MAXHOP		32		/* max number of tc= indirections */
+
+#define	tgetent		rgetent
+#define	tnchktc		rnchktc
+#define	tnamatch	rnamatch
+#define	tgetnum		rgetnum
+#define	tgetflag	rgetflag
+#define	tgetstr		rgetstr
+#define	E_TERMCAP	RM = _PATH_REMOTE
+#define V_TERMCAP	"REMOTE"
+#define V_TERM		"HOST"
+
+char	*RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG:		Should use a "last" pointer in tbuf, so that searching
+ *		for capabilities alphabetically would not be a n**2/2
+ *		process when large numbers of capabilities are given.
+ * Note:	If we add a last pointer now we will screw up the
+ *		tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities.  We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static	char *tbuf;
+static	int hopcount;	/* detect infinite loops in termcap, init 0 */
+static	char *tskip();
+char	*tgetstr();
+static	char *tdecode();
+static	char *remotefile;
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file.  Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name)
+	char *bp, *name;
+{
+	char lbuf[BUFSIZ], *cp, *p;
+	int rc1, rc2;
+
+	remotefile = cp = getenv(V_TERMCAP);
+	if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) {
+		remotefile = cp = _PATH_REMOTE;
+		return (getent(bp, name, cp));
+	} else {
+		if ((rc1 = getent(bp, name, cp)) != 1)
+			*bp = '\0';
+		remotefile = cp = _PATH_REMOTE;
+		rc2 = getent(lbuf, name, cp);
+		if (rc1 != 1 && rc2 != 1)
+			return (rc2);
+		if (rc2 == 1) {
+			p = lbuf;
+			if (rc1 == 1)
+				while (*p++ != ':')
+					;
+			if (strlen(bp) + strlen(p) > BUFSIZ) {
+				write(2, "Remcap entry too long\n", 23);
+				return (-1);
+			}
+			strcat(bp, p);
+		}
+		tbuf = bp;
+		return (1);
+	}
+}
+
+getent(bp, name, cp)
+	char *bp, *name, *cp;
+{
+	register int c;
+	register int i = 0, cnt = 0;
+	char ibuf[BUFSIZ], *cp2;
+	int tf;
+
+	tbuf = bp;
+	tf = 0;
+	/*
+	 * TERMCAP can have one of two things in it. It can be the
+	 * name of a file to use instead of /etc/termcap. In this
+	 * case it better start with a "/". Or it can be an entry to
+	 * use so we don't have to read the file. In this case it
+	 * has to already have the newlines crunched out.
+	 */
+	if (cp && *cp) {
+		if (*cp!='/') {
+			cp2 = getenv(V_TERM);
+			if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
+				strcpy(bp,cp);
+				return (tnchktc());
+			} else
+				tf = open(E_TERMCAP, O_RDONLY);
+		} else
+			tf = open(RM = cp, O_RDONLY);
+	}
+	if (tf == 0)
+		tf = open(E_TERMCAP, O_RDONLY);
+	if (tf < 0)
+		return (-1);
+	for (;;) {
+		cp = bp;
+		for (;;) {
+			if (i == cnt) {
+				cnt = read(tf, ibuf, BUFSIZ);
+				if (cnt <= 0) {
+					close(tf);
+					return (0);
+				}
+				i = 0;
+			}
+			c = ibuf[i++];
+			if (c == '\n') {
+				if (cp > bp && cp[-1] == '\\') {
+					cp--;
+					continue;
+				}
+				break;
+			}
+			if (cp >= bp+BUFSIZ) {
+				write(2,"Remcap entry too long\n", 23);
+				break;
+			} else
+				*cp++ = c;
+		}
+		*cp = 0;
+
+		/*
+		 * The real work for the match.
+		 */
+		if (tnamatch(name)) {
+			close(tf);
+			return (tnchktc());
+		}
+	}
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+	register char *p, *q;
+	char tcname[16];	/* name of similar terminal */
+	char tcbuf[BUFSIZ];
+	char *holdtbuf = tbuf;
+	int l;
+	char *cp;
+
+	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
+	while (*--p != ':')
+		if (p<tbuf) {
+			write(2, "Bad remcap entry\n", 18);
+			return (0);
+		}
+	p++;
+	/* p now points to beginning of last field */
+	if (p[0] != 't' || p[1] != 'c')
+		return (1);
+	strcpy(tcname, p+3);
+	q = tcname;
+	while (*q && *q != ':')
+		q++;
+	*q = 0;
+	if (++hopcount > MAXHOP) {
+		write(2, "Infinite tc= loop\n", 18);
+		return (0);
+	}
+	if (getent(tcbuf, tcname, remotefile) != 1) {
+		if (strcmp(remotefile, _PATH_REMOTE) == 0)
+			return (0);
+		else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1)
+			return (0);
+	}
+	for (q = tcbuf; *q++ != ':'; )
+		;
+	l = p - holdtbuf + strlen(q);
+	if (l > BUFSIZ) {
+		write(2, "Remcap entry too long\n", 23);
+		q[BUFSIZ - (p-holdtbuf)] = 0;
+	}
+	strcpy(p, q);
+	tbuf = holdtbuf;
+	return (1);
+}
+
+/*
+ * Tnamatch deals with name matching.  The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name.  The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+	char *np;
+{
+	register char *Np, *Bp;
+
+	Bp = tbuf;
+	if (*Bp == '#')
+		return (0);
+	for (;;) {
+		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+			continue;
+		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+			return (1);
+		while (*Bp && *Bp != ':' && *Bp != '|')
+			Bp++;
+		if (*Bp == 0 || *Bp == ':')
+			return (0);
+		Bp++;
+	}
+}
+
+/*
+ * Skip to the next field.  Notice that this is very dumb, not
+ * knowing about \: escapes or any such.  If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+	register char *bp;
+{
+
+	while (*bp && *bp != ':')
+		bp++;
+	if (*bp == ':')
+		bp++;
+	return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ *	li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character.  If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+	char *id;
+{
+	register int i, base;
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = tskip(bp);
+		if (*bp == 0)
+			return (-1);
+		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+			continue;
+		if (*bp == '@')
+			return (-1);
+		if (*bp != '#')
+			continue;
+		bp++;
+		base = 10;
+		if (*bp == '0')
+			base = 8;
+		i = 0;
+		while (isdigit(*bp))
+			i *= base, i += *bp++ - '0';
+		return (i);
+	}
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer.  Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+	char *id;
+{
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = tskip(bp);
+		if (!*bp)
+			return (0);
+		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+			if (!*bp || *bp == ':')
+				return (1);
+			else if (*bp == '@')
+				return (0);
+		}
+	}
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ *	cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+	char *id, **area;
+{
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = tskip(bp);
+		if (!*bp)
+			return (0);
+		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+			continue;
+		if (*bp == '@')
+			return (0);
+		if (*bp != '=')
+			continue;
+		bp++;
+		return (tdecode(bp, area));
+	}
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+	register char *str;
+	char **area;
+{
+	register char *cp;
+	register int c;
+	register char *dp;
+	int i;
+
+	cp = *area;
+	while ((c = *str++) && c != ':') {
+		switch (c) {
+
+		case '^':
+			c = *str++ & 037;
+			break;
+
+		case '\\':
+			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+			c = *str++;
+nextc:
+			if (*dp++ == c) {
+				c = *dp++;
+				break;
+			}
+			dp++;
+			if (*dp)
+				goto nextc;
+			if (isdigit(c)) {
+				c -= '0', i = 2;
+				do
+					c <<= 3, c |= *str++ - '0';
+				while (--i && isdigit(*str));
+			}
+			break;
+		}
+		*cp++ = c;
+	}
+	*cp++ = 0;
+	str = *area;
+	*area = cp;
+	return (str);
+}
diff --git a/tip/remote.c b/tip/remote.c
new file mode 100644
index 0000000000000000000000000000000000000000..0eba8545252bcb78f016113207d41c0cad011052
--- /dev/null
+++ b/tip/remote.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)remote.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: remote.c,v 1.1 2000-12-22 18:48:48 mike Exp $";
+#endif /* not lint */
+
+#ifndef LINUX
+#include <sys/syslimits.h>
+#endif
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+/*
+ * Attributes to be gleened from remote host description
+ *   data base.
+ */
+static char **caps[] = {
+	&AT, &DV, &CM, &CU, &EL, &IE, &OE, &PN, &PR, &DI,
+	&ES, &EX, &FO, &RC, &RE, &PA, &LI, &LO
+};
+
+static char *capstrings[] = {
+	"at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr",
+	"di", "es", "ex", "fo", "rc", "re", "pa", "li", "lo", 0
+};
+
+static char	*db_array[3] = { _PATH_REMOTE, 0, 0 };
+
+char *cgetcap __P((char *, char *, int));
+
+#define cgetflag(f)	(cgetcap(bp, f, ':') != NULL)
+
+static void getremcap __P((char *));
+
+/*
+	Expand the start tilde sequence at the start of the
+	specified path. Optionally, free space allocated to
+	path before reinitializing it.
+*/
+static int
+expand_tilde (char **path, void (*free) (char *p))
+{
+	int rc = 0;
+	char buffer [PATH_MAX];
+	char *tailp;
+	if ((tailp = strchr (*path + 1, '/')) != NULL)
+	{
+		struct passwd *pwd;
+		*tailp++ = '\0';
+		if (*(*path + 1) == '\0')
+			strcpy (buffer, getlogin ());
+		else
+			strcpy (buffer, *path + 1);
+		if ((pwd = getpwnam (buffer)) != NULL)
+		{
+			strcpy (buffer, pwd->pw_dir);
+			strcat (buffer, "/");
+			strcat (buffer, tailp);
+			if (free)
+				free (*path);
+			*path = strdup (buffer);
+			rc++;
+		}
+		return rc;
+	}
+	return (-1);
+}
+
+static void
+getremcap(host)
+	register char *host;
+{
+	register char **p, ***q;
+	char *bp;
+	char *rempath;
+	int   stat;
+
+	rempath = getenv("REMOTE");
+	if (rempath != NULL)
+		if (*rempath != '/')
+			/* we have an entry */
+			cgetset(rempath);
+		else {	/* we have a path */
+			db_array[1] = rempath;
+			db_array[2] = _PATH_REMOTE;
+		}
+
+	if ((stat = cgetent(&bp, db_array, host)) < 0) {
+		if (DV ||
+		    (host[0] == '/' && access(DV = host, R_OK | W_OK) == 0)) {
+			CU = DV;
+			HO = host;
+			HW = 1;
+			DU = 0;
+			if (!BR)
+				BR = DEFBR;
+			FS = DEFFS;
+			return;
+		}
+		switch(stat) {
+		case -1:
+			warnx("unknown host %s", host);
+			break;
+		case -2:
+			warnx("can't open host description file");
+			break;
+		case -3:
+			warnx("possible reference loop in host description file");
+			break;
+		}
+		exit(3);
+	}
+
+	for (p = capstrings, q = caps; *p != NULL; p++, q++)
+		if (**q == NULL)
+			cgetstr(bp, *p, *q);
+	if (!BR && (cgetnum(bp, "br", &BR) == -1))
+		BR = DEFBR;
+	if (cgetnum(bp, "fs", &FS) == -1)
+		FS = DEFFS;
+	if (DU < 0)
+		DU = 0;
+	else
+		DU = cgetflag("du");
+	if (DV == NOSTR) {
+		fprintf(stderr, "%s: missing device spec\n", host);
+		exit(3);
+	}
+	if (DU && CU == NOSTR)
+		CU = DV;
+	if (DU && PN == NOSTR) {
+		fprintf(stderr, "%s: missing phone number\n", host);
+		exit(3);
+	}
+
+	HD = cgetflag("hd");
+
+	/*
+	 * This effectively eliminates the "hw" attribute
+	 *   from the description file
+	 */
+	if (!HW)
+		HW = (CU == NOSTR) || (DU && equal(DV, CU));
+	HO = host;
+
+	/*
+		If login script, verify access
+	*/
+	if (LI != NOSTR) {
+		if (*LI == '~')
+			(void) expand_tilde (&LI, NULL);
+		if (access (LI, F_OK | X_OK) != 0) {
+			printf("tip (warning): can't open login script \"%s\"\n", LI);
+			LI = NOSTR;
+		}
+	}
+
+	/*
+		If logout script, verify access
+	*/
+	if (LO != NOSTR) {
+		if (*LO == '~')
+			(void) expand_tilde (&LO, NULL);
+		if (access (LO, F_OK | X_OK) != 0) {
+			printf("tip (warning): can't open logout script \"%s\"\n", LO);
+			LO = NOSTR;
+		}
+	}
+
+	/*
+	 * see if uppercase mode should be turned on initially
+	 */
+	if (cgetflag("ra"))
+		boolean(value(RAISE)) = 1;
+	if (cgetflag("ec"))
+		boolean(value(ECHOCHECK)) = 1;
+	if (cgetflag("be"))
+		boolean(value(BEAUTIFY)) = 1;
+	if (cgetflag("nb"))
+		boolean(value(BEAUTIFY)) = 0;
+	if (cgetflag("sc"))
+		boolean(value(SCRIPT)) = 1;
+	if (cgetflag("tb"))
+		boolean(value(TABEXPAND)) = 1;
+	if (cgetflag("vb"))
+		boolean(value(VERBOSE)) = 1;
+	if (cgetflag("nv"))
+		boolean(value(VERBOSE)) = 0;
+	if (cgetflag("ta"))
+		boolean(value(TAND)) = 1;
+	if (cgetflag("nt"))
+		boolean(value(TAND)) = 0;
+	if (cgetflag("rw"))
+		boolean(value(RAWFTP)) = 1;
+	if (cgetflag("hd"))
+		boolean(value(HALFDUPLEX)) = 1;
+	if (RE == NOSTR)
+		RE = (char *)"tip.record";
+	if (EX == NOSTR)
+		EX = (char *)"\t\n\b\f";
+	if (ES != NOSTR)
+		vstring("es", ES);
+	if (FO != NOSTR)
+		vstring("fo", FO);
+	if (PR != NOSTR)
+		vstring("pr", PR);
+	if (RC != NOSTR)
+		vstring("rc", RC);
+	if (cgetnum(bp, "dl", &DL) == -1)
+		DL = 0;
+	if (cgetnum(bp, "cl", &CL) == -1)
+		CL = 0;
+	if (cgetnum(bp, "et", &ET) == -1)
+		ET = 10;
+}
+
+char *
+getremote(host)
+	char *host;
+{
+	register char *cp;
+	static char *next;
+	static int lookedup = 0;
+
+	if (!lookedup) {
+		if (host == NOSTR && (host = getenv("HOST")) == NOSTR)
+			errx(3, "no host specified");
+		getremcap(host);
+		next = DV;
+		lookedup++;
+	}
+	/*
+	 * We return a new device each time we're called (to allow
+	 *   a rotary action to be simulated)
+	 */
+	if (next == NOSTR)
+		return (NOSTR);
+	if ((cp = index(next, ',')) == NULL) {
+		DV = next;
+		next = NOSTR;
+	} else {
+		*cp++ = '\0';
+		DV = next;
+		next = cp;
+	}
+	return (DV);
+}
diff --git a/tip/tip.1 b/tip/tip.1
new file mode 100644
index 0000000000000000000000000000000000000000..687fda9886670f9238b6764e7605eb0b9c10a925
--- /dev/null
+++ b/tip/tip.1
@@ -0,0 +1,442 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)tip.1	8.4 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt TIP 1
+.Os BSD 4
+.Sh NAME
+.Nm tip
+.Nd connect to a remote system
+.Sh SYNOPSIS
+.Nm tip
+.Op Fl v
+.Fl Ns Ns Ar speed 
+.Ar system\-name
+.Nm tip
+.Op Fl v
+.Fl Ns Ns Ar speed 
+.Ar phone\-number
+.Sh DESCRIPTION
+.Nm Tip
+establish a full-duplex connection to another machine,
+giving the appearance of being logged in directly on the
+remote cpu.  It goes without saying that you must have a login
+on the machine (or equivalent) to which you wish to connect.
+.Pp
+Available Option:
+.Bl -tag -width indent
+.It Fl v
+Set verbose mode.
+.El
+.Pp
+Typed characters are normally transmitted directly to the remote
+machine (which does the echoing as well).  A tilde (`~') appearing
+as the first character of a line is an escape signal; the following
+are recognized:
+.Bl -tag -width flag
+.It Ic \&~^D No or Ic \&~ .
+Drop the connection and exit
+(you may still be logged in on the
+remote machine).
+.It Ic \&~c Op Ar name 
+Change directory to
+.Ar name
+(no argument
+implies change to your home directory).
+.It Ic \&~!
+Escape to a shell (exiting the shell will
+return you to tip).
+.It Ic \&~>
+Copy file from local to remote.
+.Nm Tip
+prompts for the name of a local file to transmit.
+.It Ic \&~<
+Copy file from remote to local.
+.Nm Tip
+prompts first for the name of the file to be sent, then for
+a command to be executed on the remote machine.
+.It Ic \&~p Ar from Op Ar to 
+Send a file to a remote
+.Ux
+host.  The put command causes the remote
+.Ux
+system to run the command string ``cat > 'to''', while
+.Nm tip
+sends it the ``from''
+file.  If the ``to'' file isn't specified the ``from'' file name is used.
+This command is actually a
+.Ux
+specific version of the ``~>'' command.
+.It Ic \&~t Ar from Op Ar to 
+Take a file from a remote
+.Ux
+host.
+As in the put command the ``to'' file
+defaults to the ``from'' file name if it isn't specified.
+The remote host
+executes the command string ``cat 'from';echo ^A'' to send the file to
+.Nm tip  .
+.It Ic \&~|
+Pipe the output from a remote command to a local
+.Ux
+process.
+The command string sent to the local
+.Ux
+system is processed by the shell.
+.It Ic \&~$
+Pipe the output from a local
+.Ux
+process to the remote host.
+The command string sent to the local
+.Ux
+system is processed by the shell.
+.It Ic \&~C
+Fork a child process on the local system to perform special protocols
+such as \s-1XMODEM\s+1.  The child program will be run with the following
+somewhat unusual arrangement of file descriptors:
+.nf
+.in +1i
+0 <-> local tty in
+1 <-> local tty out
+2 <-> local tty out
+3 <-> remote tty in
+4 <-> remote tty out
+.in -1i
+.fi
+.It Ic \&~#
+Send a
+.Dv BREAK
+to the remote system.
+For systems which don't support the
+necessary
+.Ar ioctl
+call the break is simulated by a sequence of line speed changes
+and
+.Dv DEL
+characters.
+.It Ic \&~s
+Set a variable (see the discussion below).
+.It Ic \&~^Z
+Stop
+.Nm tip
+(only available with job control).
+.It Ic \&~^Y
+Stop only the ``local side'' of
+.Nm tip
+(only available with job control);
+the ``remote side'' of
+.Nm tip  ,
+the side that displays output from the remote host, is left running.
+.It Ic \&~?
+Get a summary of the tilde escapes
+.El
+.Pp
+.Nm Tip
+uses the file
+.Pa /etc/remote
+to find how to reach a particular
+system and to find out how it should operate while talking
+to the system;
+refer to
+.Xr remote  5
+for a full description.
+Each system has a default baud rate with which to
+establish a connection.  If this value is not suitable, the baud rate
+to be used may be specified on the command line, e.g.
+.Ql "tip -300 mds" .
+.Pp
+When
+.Nm tip
+establishes a connection it sends out a
+connection message to the remote system; the default value, if any,
+is defined in
+.Pa /etc/remote
+(see
+.Xr remote 5 ) .
+.Pp
+When
+.Nm tip
+prompts for an argument (e.g. during setup of
+a file transfer) the line typed may be edited with the standard
+erase and kill characters.  A null line in response to a prompt,
+or an interrupt, will abort the dialogue and return you to the
+remote machine.
+.Pp
+.Nm Tip
+guards against multiple users connecting to a remote system
+by opening modems and terminal lines with exclusive access,
+and by honoring the locking protocol used by
+.Xr uucico 8 .
+.Pp
+During file transfers
+.Nm tip
+provides a running count of the number of lines transferred.
+When using the ~> and ~< commands, the ``eofread'' and ``eofwrite''
+variables are used to recognize end-of-file when reading, and
+specify end-of-file when writing (see below).  File transfers
+normally depend on tandem mode for flow control.  If the remote
+system does not support tandem mode, ``echocheck'' may be set
+to indicate
+.Nm tip
+should synchronize with the remote system on the echo of each
+transmitted character.
+.Pp
+When
+.Nm tip
+must dial a phone number to connect to a system it will print
+various messages indicating its actions.
+.Nm Tip
+supports modems that use the AT command set. 
+.Nm Tip
+uses the file
+.Pa /etc/modems
+to find out how to operate with a particular
+modem; refer to
+.Xr modems  5
+for a full description.
+.Ss VARIABLES
+.Nm Tip
+maintains a set of
+.Ar variables
+which control its operation.
+Some of these variables are read-only to normal users (root is allowed
+to change anything of interest).  Variables may be displayed
+and set through the ``s'' escape.  The syntax for variables is patterned
+after
+.Xr vi  1
+and
+.Xr Mail  1  .
+Supplying ``all''
+as an argument to the set command displays all variables readable by
+the user.  Alternatively, the user may request display of a particular
+variable by attaching a `?' to the end.  For example ``escape?''
+displays the current escape character.
+.Pp
+Variables are numeric, string, character, or boolean values.  Boolean
+variables are set merely by specifying their name; they may be reset
+by prepending a `!' to the name.  Other variable types are set by
+concatenating an `=' and the value.  The entire assignment must not
+have any blanks in it.  A single set command may be used to interrogate
+as well as set a number of variables.
+Variables may be initialized at run time by placing set commands
+(without the ``~s'' prefix in a file
+.Pa .tiprc
+in one's home directory).  The
+.Fl v
+option causes
+.Nm tip
+to display the sets as they are made.
+Certain common variables have abbreviations.
+The following is a list of common variables,
+their abbreviations, and their default values.
+.Bl -tag -width Ar
+.It Ar beautify
+(bool) Discard unprintable characters when a session is being scripted;
+abbreviated
+.Ar be  .
+.It Ar baudrate
+(num) The baud rate at which the connection was established;
+abbreviated
+.Ar ba  .
+.It Ar dialtimeout
+(num) When dialing a phone number, the time (in seconds)
+to wait for a connection to be established; abbreviated
+.Ar dial  .
+.It Ar echocheck
+(bool) Synchronize with the remote host during file transfer by
+waiting for the echo of the last character transmitted; default is
+.Ar off  .
+.It Ar eofread
+(str) The set of characters which signify an end-of-transmission
+during a ~< file transfer command; abbreviated
+.Ar eofr  .
+.It Ar eofwrite
+(str) The string sent to indicate end-of-transmission during
+a ~> file transfer command; abbreviated
+.Ar eofw  .
+.It Ar eol
+(str) The set of characters which indicate an end-of-line.
+.Nm Tip
+will recognize escape characters only after an end-of-line.
+.It Ar escape
+(char) The command prefix (escape) character; abbreviated
+.Ar es  ;
+default value is `~'.
+.It Ar exceptions
+(str) The set of characters which should not be discarded
+due to the beautification switch; abbreviated
+.Ar ex  ;
+default value is ``\et\en\ef\eb''.
+.It Ar force
+(char) The character used to force literal data transmission;
+abbreviated
+.Ar fo  ;
+default value is `^P'.
+.It Ar framesize
+(num) The amount of data (in bytes) to buffer between file system
+writes when receiving files; abbreviated
+.Ar fr  .
+.It Ar host
+(str) The name of the host to which you are connected; abbreviated
+.Ar ho  .
+.It Ar login
+(str) Pathname of a login shell script to run once connected; standard input
+and output are redirected to the remote host. Leading tildes in the pathname
+are expanded expansion; abbreviated
+.Ar li  .
+.It Ar logout
+(str) Pathname of a shell script to run before disconnecting; standard input
+and output are redirected to the remote host. Leading tildes in the pathname
+are expanded expansion; abbreviated
+.Ar lo  .
+.It Ar prompt
+(char) The character which indicates an end-of-line on the remote
+host; abbreviated
+.Ar pr  ;
+default value is `\en'.  This value is used to synchronize during
+data transfers.  The count of lines transferred during a file transfer
+command is based on receipt of this character.
+.It Ar raise
+(bool) Upper case mapping mode; abbreviated
+.Ar ra  ;
+default value is
+.Ar off  .
+When this mode is enabled, all lower case letters will be mapped to
+upper case by
+.Nm tip
+for transmission to the remote machine.
+.It Ar raisechar
+(char) The input character used to toggle upper case mapping mode;
+abbreviated
+.Ar rc  ;
+default value is `^A'.
+.It Ar record
+(str) The name of the file in which a session script is recorded;
+abbreviated
+.Ar rec  ;
+default value is ``tip.record''.
+.It Ar script
+(bool) Session scripting mode; abbreviated
+.Ar sc  ;
+default is
+.Ar off  .
+When
+.Ar script
+is
+.Li true  ,
+.Nm tip
+will record everything transmitted by the remote machine in
+the script record file specified in
+.Ar record  .
+If the
+.Ar beautify
+switch is on, only printable
+.Tn ASCII
+characters will be included in
+the script file (those characters between 040 and 0177).  The
+variable
+.Ar exceptions
+is used to indicate characters which are an exception to the normal
+beautification rules.
+.It Ar tabexpand
+(bool) Expand tabs to spaces during file transfers; abbreviated
+.Ar tab  ;
+default value is
+.Ar false  .
+Each tab is expanded to 8 spaces.
+.It Ar verbose
+(bool) Verbose mode; abbreviated
+.Ar verb  ;
+default is
+.Ar true  .
+When verbose mode is enabled,
+.Nm tip
+prints messages while dialing, shows the current number
+of lines transferred during a file transfer operations,
+and more.
+.El
+.Sh ENVIRONMENT
+.Nm Tip
+uses the following environment variables:
+.Bl -tag -width Fl
+.It Ev SHELL
+(str) The name of the shell to use for the ~! command; default
+value is ``/bin/sh'', or taken from the environment.
+.It Ev HOME
+(str) The home directory to use for the ~c command; default
+value is taken from the environment.
+.It Ev HOST
+Check for a default host if none specified.
+.El
+.Pp
+The variables
+.Ev ${REMOTE}
+and
+.Ev ${PHONES}
+are also exported.
+.Sh FILES
+.Bl -tag -width /var/spool/lock/LCK..* -compact
+.It Pa /etc/modems
+Global modem configuration data base.
+.It Pa /etc/remote
+Global system descriptions.
+.It Pa /etc/phones
+Global phone number data base.
+.It ${REMOTE}
+Private system descriptions.
+.It ${PHONES}
+Private phone numbers.
+.It ~/.tiprc
+Initialization file.
+.It Pa tip.record
+Record file.
+.It /var/log/aculog
+Line access log.
+.It Pa /var/spool/lock/LCK..*
+Lock file to avoid conflicts with
+.Xr uucp .
+.El
+.Sh DIAGNOSTICS
+Diagnostics are, hopefully, self explanatory.
+.Sh SEE ALSO
+.Xr cu 1 ,
+.Xr phones 5 ,
+.Xr remote 5
+.Sh HISTORY
+The
+.Nm tip
+appeared command in
+.Bx 4.2 .
+.Sh BUGS
+The full set of variables is undocumented and should, probably, be
+pared down.
diff --git a/tip/tip.c b/tip/tip.c
new file mode 100644
index 0000000000000000000000000000000000000000..00bc079b7e9633ca38394ff9f26681b92c583bb2
--- /dev/null
+++ b/tip/tip.c
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tip.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: tip.c,v 1.1 2000-12-22 18:48:49 mike Exp $";
+#endif /* not lint */
+
+/*
+	Forward declarations
+*/
+void ttysetup (int speed);
+
+/*
+ * tip - UNIX link to other systems
+ *  tip [-v] [-speed] system-name
+ * or
+ *  cu phone-number [-s speed] [-l line] [-a acu]
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifndef LINUX
+#include <libutil.h>
+#endif
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+/*
+ * Baud rate mapping table
+ */
+#ifndef LINUX
+#if !HAVE_TERMIOS
+CONST int bauds[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600,
+	1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1
+};
+#endif
+#else
+struct baudmap {
+	CONST int BR;
+	CONST int bval;
+} baudmap[] = {
+	{ 0,		B0 },
+	{ 50,		B50 },
+	{ 75,		B75 },
+	{ 110,		B110 },
+	{ 134,		B134 },
+	{ 150,		B150 },
+	{ 200,		B200 },
+	{ 300,		B300 },
+	{ 600,		B600 },
+	{ 1200,		B1200 },
+	{ 1800,		B1800 },
+	{ 2400,		B2400 },
+	{ 4800,		B4800 },
+	{ 9600,		B9600 },
+	{ 19200,	B19200 },
+	{ 38400,	B38400 },
+	{ 57600,	B57600 },
+	{ 115200,	B115200 },
+	{ -1,		0 }
+};
+#endif
+
+#if !HAVE_TERMIOS
+int	disc = OTTYDISC;		/* tip normally runs this way */
+#endif
+
+void	intprompt();
+void	timeout();
+void	cleanup();
+void	tipdone();
+char	*sname();
+char	PNbuf[256];			/* This limits the size of a number */
+
+static void usage __P((void));
+void setparity __P((char *));
+void xpwrite __P((int, char *, int));
+char escape __P((void));
+void tipin __P((void));
+int prompt __P((char *, char *, size_t));
+void unraw __P((void));
+void shell_uid __P((void));
+void daemon_uid __P((void));
+void user_uid __P((void));
+int speed __P((int));
+
+int
+main(argc, argv)
+	char *argv[];
+{
+	char *system = NOSTR;
+	register int i;
+	register char *p;
+	char sbuf[12];
+
+	gid = getgid();
+	egid = getegid();
+	uid = getuid();
+	euid = geteuid();
+
+#if INCLUDE_CU_INTERFACE
+	if (equal(sname(argv[0]), "cu")) {
+		cumode = 1;
+		cumain(argc, argv);
+		goto cucommon;
+	}
+#endif /* INCLUDE_CU_INTERFACE */
+
+	if (argc > 4)
+		usage();
+	if (!isatty(0))
+		errx(1, "must be interactive");
+
+	for (; argc > 1; argv++, argc--) {
+		if (argv[1][0] != '-')
+			system = argv[1];
+		else switch (argv[1][1]) {
+
+		case 'v':
+			vflag++;
+			break;
+
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			BR = atoi(&argv[1][1]);
+			break;
+
+		default:
+			warnx("%s, unknown option", argv[1]);
+			break;
+		}
+	}
+
+	if (system == NOSTR)
+		goto notnumber;
+	if (isalpha(*system))
+		goto notnumber;
+	/*
+	 * System name is really a phone number...
+	 * Copy the number then stomp on the original (in case the number
+	 *	is private, we don't want 'ps' or 'w' to find it).
+	 */
+	if (strlen(system) > sizeof(PNbuf) - 1)
+		errx(1, "phone number too long (max = %d bytes)", sizeof PNbuf - 1);
+	strncpy(PNbuf, system, sizeof(PNbuf) - 1);
+	for (p = system; *p; p++)
+		*p = '\0';
+	PN = PNbuf;
+	(void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
+	system = sbuf;
+
+notnumber:
+	(void)signal(SIGINT, cleanup);
+	(void)signal(SIGQUIT, cleanup);
+	(void)signal(SIGHUP, cleanup);
+	(void)signal(SIGTERM, cleanup);
+	(void)signal(SIGUSR1, tipdone);
+
+	if ((i = hunt(system)) == 0) {
+		printf("all ports busy\n");
+		exit(3);
+	}
+	if (i == -1) {
+		printf("link down\n");
+		(void)uu_unlock(uucplock);
+		exit(3);
+	}
+	setbuf(stdout, NULL);
+	loginit();
+
+	/*
+	 * Kludge, their's no easy way to get the initialization
+	 *   in the right order, so force it here
+	 */
+	if ((PH = getenv("PHONES")) == NOSTR)
+		PH = _PATH_PHONES;
+	vinit();				/* init variables */
+	setparity("even");			/* set the parity table */
+	if ((i = speed(number(value(BAUDRATE)))) == 0) {
+		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
+		(void)uu_unlock(uucplock);
+		exit(3);
+	}
+
+	/*
+	 * Now that we have the logfile and the ACU open
+	 *  return to the real uid and gid.  These things will
+	 *  be closed on exit.  Swap real and effective uid's
+	 *  so we can get the original permissions back
+	 *  for removing the uucp lock.
+	 */
+	user_uid();
+
+	/*
+	 * Hardwired connections require the
+	 *  line speed set before they make any transmissions
+	 *  (this is particularly true of things like a DF03-AC)
+	 */
+	if (HW)
+		ttysetup(i);
+	if ((p = connect())) {
+		printf("\07%s\n[EOT]\n", p);
+		daemon_uid();
+		(void)uu_unlock(uucplock);
+		exit(1);
+	}
+	if (!HW)
+		ttysetup(i);
+/* cucommon:*/
+	/*
+	 * From here down the code is shared with
+	 * the "cu" version of tip.
+	 */
+
+#if HAVE_TERMIOS
+	tcgetattr (0, &otermios);
+	ctermios = otermios;
+#ifndef _POSIX_SOURCE
+	ctermios.c_iflag = (IMAXBEL|IXANY|ISTRIP|IXON|BRKINT);
+	ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOCTL|ECHOE|ECHOKE);
+#else
+	ctermios.c_iflag = (ISTRIP|IXON|BRKINT);
+	ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOE);
+#endif
+	ctermios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
+	ctermios.c_cc[VINTR] = 	ctermios.c_cc[VQUIT] = -1;
+	ctermios.c_cc[VSUSP] = ctermios.c_cc[VDISCARD] =
+		ctermios.c_cc[VLNEXT] = -1;
+#ifdef VDSUSP
+	ctermios.c_cc[VDSUSP] = -1;
+#endif
+#else /* HAVE_TERMIOS */
+	ioctl(0, TIOCGETP, (char *)&defarg);
+	ioctl(0, TIOCGETC, (char *)&defchars);
+	ioctl(0, TIOCGLTC, (char *)&deflchars);
+	ioctl(0, TIOCGETD, (char *)&odisc);
+	arg = defarg;
+	arg.sg_flags = ANYP | CBREAK;
+	tchars = defchars;
+	tchars.t_intrc = tchars.t_quitc = -1;
+	ltchars = deflchars;
+	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
+		= ltchars.t_lnextc = -1;
+#endif /* HAVE_TERMIOS */
+	raw();
+
+	pipe(fildes); pipe(repdes);
+	(void)signal(SIGALRM, timeout);
+
+	/*
+	 * Everything's set up now:
+	 *	connection established (hardwired or dialup)
+	 *	line conditioned (baud rate, mode, etc.)
+	 *	internal data structures (variables)
+	 * so, fork one process for local side and one for remote.
+	 */
+	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
+
+	if (LI != NOSTR && tiplink (LI, 0) != 0) {
+		tipabort ("login failed");
+	}
+
+	if ((pid = fork()))
+		tipin();
+	else
+		tipout();
+	/*NOTREACHED*/
+}
+
+static void
+usage()
+{
+	fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
+	exit(1);
+}
+
+void
+cleanup()
+{
+
+	daemon_uid();
+	(void)uu_unlock(uucplock);
+#if !HAVE_TERMIOS
+	if (odisc)
+		ioctl(0, TIOCSETD, (char *)&odisc);
+#endif
+	exit(0);
+}
+
+void
+tipdone()
+{
+	tipabort("Hangup.");
+}
+/*
+ * Muck with user ID's.  We are setuid to the owner of the lock
+ * directory when we start.  user_uid() reverses real and effective
+ * ID's after startup, to run with the user's permissions.
+ * daemon_uid() switches back to the privileged uid for unlocking.
+ * Finally, to avoid running a shell with the wrong real uid,
+ * shell_uid() sets real and effective uid's to the user's real ID.
+ */
+static int uidswapped;
+
+void
+user_uid()
+{
+	if (uidswapped == 0) {
+		seteuid(uid);
+		uidswapped = 1;
+	}
+}
+
+void
+daemon_uid()
+{
+	if (uidswapped) {
+		seteuid(euid);
+		uidswapped = 0;
+	}
+}
+
+void
+shell_uid()
+{
+	setegid(gid);
+	seteuid(uid);
+}
+
+/*
+ * put the controlling keyboard into raw mode
+ */
+void
+raw ()
+{
+#if HAVE_TERMIOS
+	tcsetattr (0, TCSANOW, &ctermios);
+#else /* HAVE_TERMIOS */
+
+	ioctl(0, TIOCSETP, &arg);
+	ioctl(0, TIOCSETC, &tchars);
+	ioctl(0, TIOCSLTC, &ltchars);
+	ioctl(0, TIOCSETD, (char *)&disc);
+#endif /* HAVE_TERMIOS */
+}
+
+
+/*
+ * return keyboard to normal mode
+ */
+void
+unraw()
+{
+#if HAVE_TERMIOS
+	tcsetattr (0, TCSANOW, &otermios);
+#else /* HAVE_TERMIOS */
+
+	ioctl(0, TIOCSETD, (char *)&odisc);
+	ioctl(0, TIOCSETP, (char *)&defarg);
+	ioctl(0, TIOCSETC, (char *)&defchars);
+	ioctl(0, TIOCSLTC, (char *)&deflchars);
+#endif /* HAVE_TERMIOS */
+}
+
+static	jmp_buf promptbuf;
+
+/*
+ * Print string ``s'', then read a string
+ *  in from the terminal.  Handles signals & allows use of
+ *  normal erase and kill characters.
+ */
+int
+prompt(s, p, sz)
+	char *s;
+	register char *p;
+	size_t sz;
+{
+	register char *b = p;
+	sig_t oint, oquit;
+
+	stoprompt = 0;
+	oint = signal(SIGINT, intprompt);
+	oquit = signal(SIGQUIT, SIG_IGN);
+	unraw();
+	printf("%s", s);
+	if (setjmp(promptbuf) == 0)
+		while ((*p = getchar()) != EOF && *p != '\n' && --sz > 0)
+			p++;
+	*p = '\0';
+
+	raw();
+	(void)signal(SIGINT, oint);
+	(void)signal(SIGQUIT, oquit);
+	return (stoprompt || p == b);
+}
+
+/*
+ * Interrupt service routine during prompting
+ */
+void
+intprompt()
+{
+
+	(void)signal(SIGINT, SIG_IGN);
+	stoprompt = 1;
+	printf("\r\n");
+	longjmp(promptbuf, 1);
+}
+
+/*
+ * ****TIPIN   TIPIN****
+ */
+void
+tipin()
+{
+	int i;
+	char gch, bol = 1;
+
+	/*
+	 * Kinda klugey here...
+	 *   check for scripting being turned on from the .tiprc file,
+	 *   but be careful about just using setscript(), as we may
+	 *   send a SIGEMT before tipout has a chance to set up catching
+	 *   it; so wait a second, then setscript()
+	 */
+	if (boolean(value(SCRIPT))) {
+		sleep(1);
+		setscript();
+	}
+
+	while (1) {
+		i = tipgetchar();
+		if (i == EOF)
+			break;
+		gch = i&0177;
+		if ((gch == character(value(ESCAPE))) && bol) {
+			if (!(gch = escape()))
+				continue;
+		} else if (!cumode && gch == character(value(RAISECHAR))) {
+			boolean(value(RAISE)) = !boolean(value(RAISE));
+			continue;
+		} else if (gch == '\r') {
+			bol = 1;
+			xpwrite(FD, &gch, 1);
+			if (boolean(value(HALFDUPLEX)))
+				printf("\r\n");
+			continue;
+		} else if (!cumode && gch == character(value(FORCE))) {
+			i = tipgetchar();
+			if (i == EOF)
+				break;
+			gch = i & 0177;
+		}
+		bol = any(gch, value(EOL));
+		if (boolean(value(RAISE)) && islower(gch))
+			gch = toupper(gch);
+		xpwrite(FD, &gch, 1);
+		if (boolean(value(HALFDUPLEX)))
+			printf("%c", gch);
+	}
+}
+
+extern esctable_t etable[];
+
+/*
+ * Escape handler --
+ *  called on recognition of ``escapec'' at the beginning of a line
+ */
+char
+escape()
+{
+	register char gch;
+	register esctable_t *p;
+	char c = character(value(ESCAPE));
+	int i;
+
+	i = tipgetchar();
+	if (i == EOF)
+		return 0;
+	gch = (i&0177);
+	for (p = etable; p->e_char; p++)
+		if (p->e_char == gch) {
+			if ((p->e_flags&PRIV) && uid)
+				continue;
+			printf("%s", ctrl(c));
+			(*p->e_func)(gch);
+			return (0);
+		}
+	/* ESCAPE ESCAPE forces ESCAPE */
+	if (c != gch)
+		xpwrite(FD, &c, 1);
+	return (gch);
+}
+
+int
+speed(n)
+	int n;
+{
+#ifndef LINUX
+#if HAVE_TERMIOS
+	return (n);
+#else
+	register CONST int *p;
+
+	for (p = bauds; *p != -1;  p++)
+		if (*p == n)
+			return (p - bauds);
+	return (0);
+#endif
+#else
+	struct baudmap *p;
+
+	for (p = baudmap; p->BR != -1;  p++)
+		if (p->BR == n)
+			return (p->bval);
+	return (0);
+#endif
+}
+
+int
+any(c, p)
+	register char c, *p;
+{
+	while (p && *p)
+		if (*p++ == c)
+			return (1);
+	return (0);
+}
+
+int
+size(s)
+	register char	*s;
+{
+	register int i = 0;
+
+	while (s && *s++)
+		i++;
+	return (i);
+}
+
+char *
+interp(s)
+	register char *s;
+{
+	static char buf[256];
+	register char *p = buf, c, *q;
+
+	while ((c = *s++)) {
+		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
+			if (*q++ == c) {
+				*p++ = '\\'; *p++ = *q;
+				goto next;
+			}
+		if (c < 040) {
+			*p++ = '^'; *p++ = c + 'A'-1;
+		} else if (c == 0177) {
+			*p++ = '^'; *p++ = '?';
+		} else
+			*p++ = c;
+	next:
+		;
+	}
+	*p = '\0';
+	return (buf);
+}
+
+char *
+ctrl(c)
+	char c;
+{
+	static char s[3];
+
+	if (c < 040 || c == 0177) {
+		s[0] = '^';
+		s[1] = c == 0177 ? '?' : c+'A'-1;
+		s[2] = '\0';
+	} else {
+		s[0] = c;
+		s[1] = '\0';
+	}
+	return (s);
+}
+
+/*
+ * Help command
+ */
+void
+help(c)
+	char c;
+{
+	register esctable_t *p;
+
+	printf("%c\r\n", c);
+	for (p = etable; p->e_char; p++) {
+		if ((p->e_flags&PRIV) && uid)
+			continue;
+		printf("%2s", ctrl(character(value(ESCAPE))));
+		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
+			p->e_flags&EXP ? '*': ' ', p->e_help);
+	}
+}
+
+/*
+ * Set up the "remote" tty's state
+ */
+void
+ttysetup (int speed)
+{
+#if HAVE_TERMIOS
+	struct termios termios;
+	tcgetattr (FD, &termios);
+	if (boolean(value(TAND)))
+		termios.c_iflag = IXOFF;
+	else
+		termios.c_iflag = 0;
+#ifndef _POSIX_SOURCE
+	termios.c_lflag = (PENDIN|ECHOKE|ECHOE);
+#else
+	termios.c_lflag = (PENDIN|ECHOE);
+#endif
+	termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
+	cfsetispeed(&termios, speed);
+	cfsetospeed(&termios, speed);
+	tcsetattr (FD, TCSANOW, &termios);
+#else /* HAVE_TERMIOS */
+	unsigned bits = LDECCTQ;
+
+	arg.sg_ispeed = arg.sg_ospeed = speed;
+	arg.sg_flags = RAW;
+	if (boolean(value(TAND)))
+		arg.sg_flags |= TANDEM;
+	ioctl(FD, TIOCSETP, (char *)&arg);
+	ioctl(FD, TIOCLBIS, (char *)&bits);
+#endif /* HAVE_TERMIOS */
+}
+
+/*
+ * Return "simple" name from a file name,
+ * strip leading directories.
+ */
+char *
+sname(s)
+	register char *s;
+{
+	register char *p = s;
+
+	while (*s)
+		if (*s++ == '/')
+			p = s;
+	return (p);
+}
+
+static char partab[0200];
+static int bits8;
+
+/*
+ * Do a write to the remote machine with the correct parity.
+ * We are doing 8 bit wide output, so we just generate a character
+ * with the right parity and output it.
+ */
+void
+xpwrite(fd, buf, n)
+	int fd;
+	char *buf;
+	register int n;
+{
+	register int i;
+	register char *bp;
+
+	bp = buf;
+	if (bits8 == 0)
+		for (i = 0; i < n; i++) {
+			*bp = partab[(*bp) & 0177];
+			bp++;
+		}
+	if (write(fd, buf, n) < 0) {
+		if (errno == EIO)
+			tipabort("Lost carrier.");
+		if (errno == ENODEV)
+			tipabort("tty not available.");
+		tipabort("Something wrong...");
+	}
+}
+
+/*
+ * Build a parity table with appropriate high-order bit.
+ */
+void
+setparity(defparity)
+	char *defparity;
+{
+	register int i, flip, clr, set;
+	char *parity;
+	extern char evenpartab[];
+
+	if (value(PARITY) == NOSTR)
+		value(PARITY) = defparity;
+	parity = value(PARITY);
+	if (equal(parity, "none")) {
+		bits8 = 1;
+		return;
+	}
+	bits8 = 0;
+	flip = 0;
+	clr = 0377;
+	set = 0;
+	if (equal(parity, "odd"))
+		flip = 0200;			/* reverse bit 7 */
+	else if (equal(parity, "zero"))
+		clr = 0177;			/* turn off bit 7 */
+	else if (equal(parity, "one"))
+		set = 0200;			/* turn on bit 7 */
+	else if (!equal(parity, "even")) {
+		(void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
+		(void) fflush(stderr);
+	}
+	for (i = 0; i < 0200; i++)
+		partab[i] = (evenpartab[i] ^ flip) | (set & clr);
+}
+
+
+/*
+ * getchar with EOF check
+ */
+tipgetchar()
+{
+	char gch;
+
+	gch = getchar();
+	if (gch == EOF && feof(stdin))
+		finish();
+	return gch;
+}
+
diff --git a/tip/tip.h b/tip/tip.h
new file mode 100644
index 0000000000000000000000000000000000000000..67f539426efbef1d869e8a734495abb56162c196
--- /dev/null
+++ b/tip/tip.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)tip.h	8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * tip - terminal interface program
+ */
+
+#ifdef LINUX
+/* signals */
+#define	SIGEMT	SIGUSR1
+#define	SIGSYS	SIGUSR2
+
+/* uucp stuff */
+#define uu_lock(x)	(0)
+#define uu_unlock(x)	(0)
+#define UU_LOCK_OK	0
+#define UU_LOCK_INUSE	1
+
+#define HAVE_TERMIOS	1	/* XXX */
+#endif
+
+#include <sys/types.h>
+#ifndef LINUX
+#include <machine/endian.h>
+#else
+#define BYTE_ORDER      __BYTE_ORDER
+#endif
+#include <sys/file.h>
+#include <sys/time.h>
+#include <limits.h>
+
+#if HAVE_TERMIOS
+#include <sys/ioctl.h>         /* for TIOCHPCL */
+#ifndef LINUX
+#include <sys/filio.h>    /* for FIONREAD */
+#endif
+#include <sys/termios.h>
+#else
+#include <sgtty.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * Remote host attributes
+ */
+char	*DV;			/* UNIX device(s) to open */
+char	*EL;			/* chars marking an EOL */
+char	*CM;			/* initial connection message */
+char	*IE;			/* EOT to expect on input */
+char	*OE;			/* EOT to send to complete FT */
+char	*CU;			/* call unit if making a phone call */
+char	*AT;			/* acu type */
+char	*PN;			/* phone number(s) */
+char	*DI;			/* disconnect string */
+char	*PA;			/* parity to be generated */
+
+char	*PH;			/* phone number file */
+char	*RM;			/* remote file name */
+char	*HO;			/* host name */
+
+char	*LI;			/* login script */
+char	*LO;			/* logout script */
+
+long	BR;			/* line speed for conversation */
+long	FS;			/* frame size for transfers */
+
+char	DU;			/* this host is dialed up */
+char	HW;			/* this device is hardwired, see hunt.c */
+char	*ES;			/* escape character */
+char	*EX;			/* exceptions */
+char	*FO;			/* force (literal next) char*/
+char	*RC;			/* raise character */
+char	*RE;			/* script record file */
+char	*PR;			/* remote prompt */
+long	DL;			/* line delay for file transfers to remote */
+long	CL;			/* char delay for file transfers to remote */
+long	ET;			/* echocheck timeout */
+char	HD;			/* this host is half duplex - do local echo */
+
+/*
+ * String value table
+ */
+typedef
+	struct {
+		char	*v_name;	/* whose name is it */
+		char	v_type;		/* for interpreting set's */
+		char	v_access;	/* protection of touchy ones */
+		char	*v_abrev;	/* possible abreviation */
+		char	*v_value;	/* casted to a union later */
+	}
+	value_t;
+
+#define STRING	01		/* string valued */
+#define BOOL	02		/* true-false value */
+#define NUMBER	04		/* numeric value */
+#define CHAR	010		/* character value */
+
+#define WRITE	01		/* write access to variable */
+#define	READ	02		/* read access */
+
+#define CHANGED	01		/* low bit is used to show modification */
+#define PUBLIC	1		/* public access rights */
+#define PRIVATE	03		/* private to definer */
+#define ROOT	05		/* root defined */
+
+#define	TRUE	1
+#define FALSE	0
+
+#define ENVIRON	020		/* initialize out of the environment */
+#define IREMOTE	040		/* initialize out of remote structure */
+#define INIT	0100		/* static data space used for initialization */
+#define TMASK	017
+
+/*
+ * Definition of ACU line description
+ */
+typedef
+	struct {
+		char	*acu_name;
+		int	(*acu_dialer)();
+		void	(*acu_disconnect)();
+		void	(*acu_abort)();
+	}
+	acu_t;
+
+#define	equal(a, b)	(strcmp(a,b)==0)/* A nice function to string compare */
+
+/*
+ * variable manipulation stuff --
+ *   if we defined the value entry in value_t, then we couldn't
+ *   initialize it in vars.c, so we cast it as needed to keep lint
+ *   happy.
+ */
+typedef
+	union {
+		int	zz_number;
+		short	zz_boolean[2];
+		char	zz_character[4];
+		int	*zz_address;
+	}
+	zzhack;
+
+#define value(v)	vtable[v].v_value
+
+#define number(v)	((((zzhack *)(&(v))))->zz_number)
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define boolean(v)	((((zzhack *)(&(v))))->zz_boolean[0])
+#define character(v)	((((zzhack *)(&(v))))->zz_character[0])
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define boolean(v)	((((zzhack *)(&(v))))->zz_boolean[1])
+#define character(v)	((((zzhack *)(&(v))))->zz_character[3])
+#endif
+
+#define address(v)	((((zzhack *)(&(v))))->zz_address)
+
+/*
+ * Escape command table definitions --
+ *   lookup in this table is performed when ``escapec'' is recognized
+ *   at the begining of a line (as defined by the eolmarks variable).
+*/
+
+typedef
+	struct {
+		char	e_char;		/* char to match on */
+		char	e_flags;	/* experimental, priviledged */
+		char	*e_help;	/* help string */
+		int 	(*e_func)();	/* command */
+	}
+	esctable_t;
+
+#define NORM	00		/* normal protection, execute anyone */
+#define EXP	01		/* experimental, mark it with a `*' on help */
+#define PRIV	02		/* priviledged, root execute only */
+
+extern int	vflag;		/* verbose during reading of .tiprc file */
+extern value_t	vtable[];	/* variable table */
+
+#if !ACULOG
+#define logent(a, b, c, d)
+#define loginit()
+#else
+void logent __P((char *, char *, char *, char*));
+#endif
+
+/*
+ * Definition of indices into variable table so
+ *  value(DEFINE) turns into a static address.
+ */
+
+/*
+'a,.!awk '{ printf("\%s \%s \%d\n", $1, $2, NR - 1); }'
+*/
+
+#define BEAUTIFY 0
+#define BAUDRATE 1
+#define DIALTIMEOUT 2
+#define EOFREAD 3
+#define EOFWRITE 4
+#define EOL 5
+#define ESCAPE 6
+#define EXCEPTIONS 7
+#define FORCE 8
+#define FRAMESIZE 9
+#define HOST 10
+#define LOG 11
+#define LOGIN 12
+#define LOGOUT 13
+#define PHONES 14
+#define PROMPT 15
+#define RAISE 16
+#define RAISECHAR 17
+#define RECORD 18
+#define REMOTE 19
+#define SCRIPT 20
+#define TABEXPAND 21
+#define VERBOSE 22
+#define SHELL 23
+#define HOME 24
+#define ECHOCHECK 25
+#define DISCONNECT 26
+#define TAND 27
+#define LDELAY 28
+#define CDELAY 29
+#define ETIMEOUT 30
+#define RAWFTP 31
+#define HALFDUPLEX 32
+#define LECHO 33
+#define PARITY 34
+#define NOVAL	((value_t *)NULL)
+#define NOACU	((acu_t *)NULL)
+#define NOSTR	((char *)NULL)
+#ifdef NOFILE
+#undef NOFILE
+#endif
+#define NOFILE	((FILE *)NULL)
+#define NOPWD	((struct passwd *)0)
+
+#if HAVE_TERMIOS
+struct termios otermios;
+struct termios ctermios;
+#else /* HAVE_TERMIOS */
+struct sgttyb	arg;		/* current mode of local terminal */
+struct sgttyb	defarg;		/* initial mode of local terminal */
+struct tchars	tchars;		/* current state of terminal */
+struct tchars	defchars;	/* initial state of terminal */
+struct ltchars	ltchars;	/* current local characters of terminal */
+struct ltchars	deflchars;	/* initial local characters of terminal */
+#endif /* HAVE_TERMIOS */
+
+FILE	*fscript;		/* FILE for scripting */
+
+int	fildes[2];		/* file transfer synchronization channel */
+int	repdes[2];		/* read process sychronization channel */
+int	FD;			/* open file descriptor to remote host */
+int	AC;			/* open file descriptor to dialer (v831 only) */
+int	vflag;			/* print .tiprc initialization sequence */
+int	sfd;			/* for ~< operation */
+int	pid;			/* pid of tipout */
+uid_t	uid, euid;		/* real and effective user id's */
+gid_t	gid, egid;		/* real and effective group id's */
+int	stop;			/* stop transfer session flag */
+int	quit;			/* same; but on other end */
+int	intflag;		/* recognized interrupt */
+int	stoprompt;		/* for interrupting a prompt session */
+int	timedout;		/* ~> transfer timedout */
+int	cumode;			/* simulating the "cu" program */
+
+char	fname[PATH_MAX];	/* file name buffer for ~< */
+char	copyname[PATH_MAX];	/* file name buffer for ~> */
+char	ccc;			/* synchronization character */
+char	ch;			/* for tipout */
+char	*uucplock;		/* name of lock file for uucp's */
+
+int	odisc;				/* initial tty line discipline */
+extern	int disc;			/* current tty discpline */
+
+extern	char *ctrl();
+extern	char *vinterp();
+extern	char *connect();
+extern	int   size __P((char *));
+extern	int   any __P((char, char *));
+extern	void  setscript __P((void));
+extern	void  tipout __P((void));
+extern	void  vinit __P((void));
+extern	void  loginit __P((void));
+extern	int   hunt __P((char *));
+extern	int vstring __P((char *, char *));
+extern	void setparity __P((char *));
+extern	void vlex __P((char *));
+extern	void daemon_uid __P((void));
+extern	void disconnect __P((char *));
+extern	void shell_uid __P((void));
+extern	void unraw __P((void));
+extern	void xpwrite __P((int, char *, int));
+extern	int prompt __P((char *, char *, size_t));
+extern	int consh __P((int));
+extern	void tipabort __P((char *));
+
+#define TL_VERBOSE       0x00000001
+#define TL_SIGNAL_TIPOUT 0x00000002
+
+int tiplink (char *cmd, unsigned int flags);
+void raw ();
+
+/* end of tip.h */
diff --git a/tip/tipconf.h b/tip/tipconf.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0890b8f71f6c79b318662abccad635baf9d1b40
--- /dev/null
+++ b/tip/tipconf.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tipconf.h	8.1 (Berkeley) 3/25/95
+ */
+
+#ifndef tipconf_h_included
+#define tipconf_h_included
+
+/*
+	Define constness
+*/
+#define CONST const
+
+/*
+	Specify default bit rate for connections
+*/
+#define DEFBR 1200
+
+/*
+	Default frame size for file transfer buffering of writes
+	on local side
+*/
+#ifndef BUFSIZ
+#define DEFFS 1024
+#else
+#define DEFFS BUFSIZ
+#endif
+
+/*
+	Enable logging of ACU use
+*/
+#define ACULOG             1
+
+/*
+	Strip phone #s from ACU log file
+*/
+#define PRISTINE           1
+
+/*
+	Enable command to "connect" remote with local process
+*/
+#define CONNECT            1
+
+/*
+	Specify style of UUCP lock files
+*/
+#define HAVE_V2_LOCKFILES  0
+#define HAVE_HDB_LOCKFILES 1
+
+/*
+	System has a millisecond based sleep function
+*/
+#define HAVE_USLEEP        0
+
+/*
+	System has select
+*/
+#define HAVE_SELECT        1
+
+/*
+	System has termios tty interface
+*/
+#define HAVE_TERMIOS       1
+
+/*
+	Include configurable modem driver
+*/
+#define UNIDIALER          0
+
+/*
+	Specify builtin modem drivers to include
+*/
+#define BIZ1031            0
+#define BIZ1022            0
+#define COURIER            0
+#define DF02               0
+#define DF03               0
+#define DN11               0
+#define HAYES              0
+#define MULTITECH          0
+#define T3000              0
+#define V3451              0
+#define V831               0
+#define VENTEL             0
+
+/*
+	Include cu interface so that, when tip is linked to cu and then
+	invoked as cu, it behaves like cu.
+*/
+#define INCLUDE_CU_INTERFACE 0
+
+#endif
+
+/* end of tipconf.h */
diff --git a/tip/tipout.c b/tip/tipout.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a77903250ec27c41833e5481d16e5482650ebdb
--- /dev/null
+++ b/tip/tipout.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tipout.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: tipout.c,v 1.1 2000-12-22 18:48:49 mike Exp $";
+#endif /* not lint */
+
+#include "tip.h"
+#include <errno.h>
+/*
+ * tip
+ *
+ * lower fork of tip -- handles passive side
+ *  reading from the remote host
+ */
+
+static	jmp_buf sigbuf;
+
+/*
+ * TIPOUT wait state routine --
+ *   sent by TIPIN when it wants to posses the remote host
+ */
+void
+intIOT()
+{
+
+	write(repdes[1],&ccc,1);
+	read(fildes[0], &ccc,1);
+	longjmp(sigbuf, 1);
+}
+
+/*
+ * Scripting command interpreter --
+ *  accepts script file name over the pipe and acts accordingly
+ */
+void
+intEMT()
+{
+	char c, line[256];
+	register char *pline = line;
+	char reply;
+
+	read(fildes[0], &c, 1);
+	while (c != '\n' && pline - line < sizeof(line)) {
+		*pline++ = c;
+		read(fildes[0], &c, 1);
+	}
+	*pline = '\0';
+	if (boolean(value(SCRIPT)) && fscript != NULL)
+		fclose(fscript);
+	if (pline == line) {
+		boolean(value(SCRIPT)) = FALSE;
+		reply = 'y';
+	} else {
+		if ((fscript = fopen(line, "a")) == NULL)
+			reply = 'n';
+		else {
+			reply = 'y';
+			boolean(value(SCRIPT)) = TRUE;
+		}
+	}
+	write(repdes[1], &reply, 1);
+	longjmp(sigbuf, 1);
+}
+
+void
+intTERM()
+{
+
+	if (boolean(value(SCRIPT)) && fscript != NULL)
+		fclose(fscript);
+	exit(0);
+}
+
+void
+intSYS()
+{
+
+	boolean(value(BEAUTIFY)) = !boolean(value(BEAUTIFY));
+	longjmp(sigbuf, 1);
+}
+
+/*
+ * ****TIPOUT   TIPOUT****
+ */
+void
+tipout()
+{
+	char buf[BUFSIZ];
+	register char *cp;
+	register int cnt;
+	int omask;
+
+	signal(SIGINT, SIG_IGN);
+	signal(SIGQUIT, SIG_IGN);
+	signal(SIGEMT, intEMT);		/* attention from TIPIN */
+	signal(SIGTERM, intTERM);	/* time to go signal */
+	signal(SIGIOT, intIOT);		/* scripting going on signal */
+	signal(SIGHUP, intTERM);	/* for dial-ups */
+	signal(SIGSYS, intSYS);		/* beautify toggle */
+	(void) setjmp(sigbuf);
+	for (omask = 0;; sigsetmask(omask)) {
+		cnt = read(FD, buf, BUFSIZ);
+		if (cnt <= 0) {
+			/* lost carrier */
+			if (cnt < 0 && errno == EIO) {
+				sigblock(sigmask(SIGTERM));
+				intTERM();
+				/*NOTREACHED*/
+			} else if (cnt == 0 && errno == ENOENT) {
+				if (getppid() != 1)
+					kill(getppid(),SIGUSR1);
+				sigblock(sigmask(SIGTERM));
+				intTERM();
+				/*NOTREACHED*/
+			} else if (cnt < 0) {
+				if (getppid() != 1)
+					kill(getppid(),SIGUSR1);
+				sigblock(sigmask(SIGTERM));
+				intTERM();
+				/*NOTREACHED*/
+			}
+			continue;
+		}
+#define	ALLSIGS	sigmask(SIGEMT)|sigmask(SIGTERM)|sigmask(SIGIOT)|sigmask(SIGSYS)
+		omask = sigblock(ALLSIGS);
+		for (cp = buf; cp < buf + cnt; cp++)
+			*cp &= 0177;
+		write(1, buf, cnt);
+		if (boolean(value(SCRIPT)) && fscript != NULL) {
+			if (!boolean(value(BEAUTIFY))) {
+				fwrite(buf, 1, cnt, fscript);
+				continue;
+			}
+			for (cp = buf; cp < buf + cnt; cp++)
+				if ((*cp >= ' ' && *cp <= '~') ||
+				    any(*cp, value(EXCEPTIONS)))
+					putc(*cp, fscript);
+		}
+	}
+}
diff --git a/tip/value.c b/tip/value.c
new file mode 100644
index 0000000000000000000000000000000000000000..7faa1039d88ddf52aac42f6b38a557deec05ce75
--- /dev/null
+++ b/tip/value.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)value.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: value.c,v 1.1 2000-12-22 18:48:50 mike Exp $";
+#endif /* not lint */
+
+#include "tip.h"
+
+#define MIDDLE	35
+
+static value_t *vlookup();
+int vstring __P((char *, char *));
+void vlex __P((char *));
+void vassign __P((value_t *, char *));
+
+static int col = 0;
+
+/*
+ * Variable manipulation
+ */
+void
+vinit()
+{
+	register value_t *p;
+	register char *cp;
+	FILE *f;
+	char file[256];
+
+	for (p = vtable; p->v_name != NULL; p++) {
+		if (p->v_type&ENVIRON)
+			if ((cp = getenv(p->v_name)))
+				p->v_value = cp;
+		if (p->v_type&IREMOTE)
+			if (p->v_type&STRING)
+				p->v_value = *(char **) address(p->v_value);
+			else
+				number(p->v_value) = *address(p->v_value);
+	}
+	/*
+	 * Read the .tiprc file in the HOME directory
+	 *  for sets
+	 */
+	strcpy(file, value(HOME));
+	strcat(file, "/.tiprc");
+	if ((f = fopen(file, "r")) != NULL) {
+		register char *tp;
+
+		while (fgets(file, sizeof(file)-1, f) != NULL) {
+			if (vflag)
+				printf("set %s", file);
+			if ((tp = rindex(file, '\n')))
+				*tp = '\0';
+			vlex(file);
+		}
+		fclose(f);
+	}
+	/*
+	 * To allow definition of exception prior to fork
+	 */
+	vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
+}
+
+static int vaccess();
+
+/*VARARGS1*/
+void
+vassign(p, v)
+	register value_t *p;
+	char *v;
+{
+
+	if (!vaccess(p->v_access, WRITE)) {
+		printf("access denied\r\n");
+		return;
+	}
+	switch (p->v_type&TMASK) {
+
+	case STRING:
+		if (p->v_value && equal(p->v_value, v))
+			return;
+		if (!(p->v_type&(ENVIRON|INIT)))
+			free(p->v_value);
+		if ((p->v_value = malloc(size(v)+1)) == NOSTR) {
+			printf("out of core\r\n");
+			return;
+		}
+		p->v_type &= ~(ENVIRON|INIT);
+		strcpy(p->v_value, v);
+		break;
+
+	case NUMBER:
+		if (number(p->v_value) == number(v))
+			return;
+		number(p->v_value) = number(v);
+		break;
+
+	case BOOL:
+		if (boolean(p->v_value) == (*v != '!'))
+			return;
+		boolean(p->v_value) = (*v != '!');
+		break;
+
+	case CHAR:
+		if (character(p->v_value) == *v)
+			return;
+		character(p->v_value) = *v;
+	}
+	p->v_access |= CHANGED;
+}
+
+static void vprint();
+
+void
+vlex(s)
+	register char *s;
+{
+	register value_t *p;
+	static void vtoken();
+
+	if (equal(s, "all")) {
+		for (p = vtable; p->v_name; p++)
+			if (vaccess(p->v_access, READ))
+				vprint(p);
+	} else {
+		register char *cp;
+
+		do {
+			if ((cp = vinterp(s, ' ')))
+				cp++;
+			vtoken(s);
+			s = cp;
+		} while (s);
+	}
+	if (col > 0) {
+		printf("\r\n");
+		col = 0;
+	}
+}
+
+static void
+vtoken(s)
+	register char *s;
+{
+	register value_t *p;
+	register char *cp;
+	char *expand();
+
+	if ((cp = index(s, '='))) {
+		*cp = '\0';
+		if ((p = vlookup(s))) {
+			cp++;
+			if (p->v_type&NUMBER)
+				vassign(p, (char *) atoi(cp));
+			else {
+				if (strcmp(s, "record") == 0)
+					cp = expand(cp);
+				vassign(p, cp);
+			}
+			return;
+		}
+	} else if ((cp = index(s, '?'))) {
+		*cp = '\0';
+		if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
+			vprint(p);
+			return;
+		}
+	} else {
+		if (*s != '!')
+			p = vlookup(s);
+		else
+			p = vlookup(s+1);
+		if (p != NOVAL) {
+			vassign(p, s);
+			return;
+		}
+	}
+	printf("%s: unknown variable\r\n", s);
+}
+
+static void
+vprint(p)
+	register value_t *p;
+{
+	register char *cp;
+	extern char *interp(), *ctrl();
+
+	if (col > 0 && col < MIDDLE)
+		while (col++ < MIDDLE)
+			putchar(' ');
+	col += size(p->v_name);
+	switch (p->v_type&TMASK) {
+
+	case BOOL:
+		if (boolean(p->v_value) == FALSE) {
+			col++;
+			putchar('!');
+		}
+		printf("%s", p->v_name);
+		break;
+
+	case STRING:
+		printf("%s=", p->v_name);
+		col++;
+		if (p->v_value) {
+			cp = interp(p->v_value, NULL);
+			col += size(cp);
+			printf("%s", cp);
+		}
+		break;
+
+	case NUMBER:
+		col += 6;
+		printf("%s=%-5d", p->v_name, number(p->v_value));
+		break;
+
+	case CHAR:
+		printf("%s=", p->v_name);
+		col++;
+		if (p->v_value) {
+			cp = ctrl(character(p->v_value));
+			col += size(cp);
+			printf("%s", cp);
+		}
+		break;
+	}
+	if (col >= MIDDLE) {
+		col = 0;
+		printf("\r\n");
+		return;
+	}
+}
+
+
+static int
+vaccess(mode, rw)
+	register unsigned mode, rw;
+{
+	if (mode & (rw<<PUBLIC))
+		return (1);
+	if (mode & (rw<<PRIVATE))
+		return (1);
+	return ((mode & (rw<<ROOT)) && getuid() == 0);
+}
+
+static value_t *
+vlookup(s)
+	register char *s;
+{
+	register value_t *p;
+
+	for (p = vtable; p->v_name; p++)
+		if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
+			return (p);
+	return (NULL);
+}
+
+char *
+vinterp(s, stop)
+	register char *s;
+	char stop;
+{
+	register char *p = s, c;
+	int num;
+
+	while ((c = *s++) && c != stop)
+		switch (c) {
+
+		case '^':
+			if (*s)
+				*p++ = *s++ - 0100;
+			else
+				*p++ = c;
+			break;
+
+		case '\\':
+			num = 0;
+			c = *s++;
+			if (c >= '0' && c <= '7')
+				num = (num<<3)+(c-'0');
+			else {
+				register char *q = "n\nr\rt\tb\bf\f";
+
+				for (; *q; q++)
+					if (c == *q++) {
+						*p++ = *q;
+						goto cont;
+					}
+				*p++ = c;
+			cont:
+				break;
+			}
+			if ((c = *s++) >= '0' && c <= '7') {
+				num = (num<<3)+(c-'0');
+				if ((c = *s++) >= '0' && c <= '7')
+					num = (num<<3)+(c-'0');
+				else
+					s--;
+			} else
+				s--;
+			*p++ = num;
+			break;
+
+		default:
+			*p++ = c;
+		}
+	*p = '\0';
+	return (c == stop ? s-1 : NULL);
+}
+
+/*
+ * assign variable s with value v (for NUMBER or STRING or CHAR types)
+ */
+
+int
+vstring(s,v)
+	register char *s;
+	register char *v;
+{
+	register value_t *p;
+	char *expand();
+
+	p = vlookup(s);
+	if (p == 0)
+		return (1);
+	if (p->v_type&NUMBER)
+		vassign(p, (char *) atoi(v));
+	else {
+		if (strcmp(s, "record") == 0)
+			v = expand(v);
+		vassign(p, v);
+	}
+	return (0);
+}
diff --git a/tip/vars.c b/tip/vars.c
new file mode 100644
index 0000000000000000000000000000000000000000..e07459f7a7bcd039e25c88e79dca34bd90324f8f
--- /dev/null
+++ b/tip/vars.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)vars.c	8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+	"$Id: vars.c,v 1.2 2000-12-27 00:49:36 mike Exp $";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+/*
+ * Definition of variables
+ */
+value_t vtable[] = {
+	{ "beautify",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "be",		(char *)TRUE },
+	{ "baudrate",	NUMBER|IREMOTE|INIT,	(READ<<PUBLIC)|(WRITE<<ROOT),
+	  "ba",		(char *)&BR },
+	{ "dialtimeout",NUMBER,			(READ<<PUBLIC)|(WRITE<<ROOT),
+	  "dial",	(char *)60 },
+	{ "eofread",	STRING|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "eofr",	(char *)&IE },
+	{ "eofwrite",	STRING|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "eofw",	(char *)&OE },
+	{ "eol",	STRING|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  NOSTR,	(char *)&EL },
+	{ "escape",	CHAR,			(READ|WRITE)<<PUBLIC,
+	  "es",		(char *)'~' },
+	{ "exceptions",	STRING|INIT|IREMOTE,	(READ|WRITE)<<PUBLIC,
+	  "ex",		(char *)&EX },
+	{ "force",	CHAR,			(READ|WRITE)<<PUBLIC,
+	  "fo",		(char *)CTRL('p') },
+	{ "framesize",	NUMBER|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "fr",		(char *)&FS },
+	{ "host",	STRING|IREMOTE|INIT,	READ<<PUBLIC,
+	  "ho",		(char *)&HO },
+	{ "log",	STRING|INIT,		(READ|WRITE)<<ROOT,
+	  NOSTR,	_PATH_ACULOG },
+	{ "login",	STRING|IREMOTE|INIT,		(READ|WRITE)<<PUBLIC,
+	  "li",	(char *)&LI },
+	{ "logout",	STRING|IREMOTE|INIT,		(READ|WRITE)<<PUBLIC,
+	  "lo",	(char *)&LO },
+	{ "phones",	STRING|INIT|IREMOTE,	READ<<PUBLIC,
+	  NOSTR,	(char *)&PH },
+	{ "prompt",	CHAR,			(READ|WRITE)<<PUBLIC,
+	  "pr",		(char *)'\n' },
+	{ "raise",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "ra",		(char *)FALSE },
+	{ "raisechar",	CHAR,			(READ|WRITE)<<PUBLIC,
+	  "rc",		(char *)CTRL('a') },
+	{ "record",	STRING|INIT|IREMOTE,	(READ|WRITE)<<PUBLIC,
+	  "rec",	(char *)&RE },
+	{ "remote",	STRING|INIT|IREMOTE,	READ<<PUBLIC,
+	  NOSTR,	(char *)&RM },
+	{ "script",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "sc",		(char *)FALSE },
+	{ "tabexpand",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "tab",	(char *)FALSE },
+	{ "verbose",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "verb",	(char *)TRUE },
+	{ "SHELL",	STRING|ENVIRON|INIT,	(READ|WRITE)<<PUBLIC,
+	  NULL,		_PATH_BSHELL },
+	{ "HOME",	STRING|ENVIRON,		(READ|WRITE)<<PUBLIC,
+	  NOSTR,	NOSTR },
+	{ "echocheck",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "ec",		(char *)FALSE },
+	{ "disconnect",	STRING|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "di",		(char *)&DI },
+	{ "tandem",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "ta",		(char *)TRUE },
+	{ "linedelay",	NUMBER|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "ldelay",	(char *)&DL },
+	{ "chardelay",	NUMBER|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "cdelay",	(char *)&CL },
+	{ "etimeout",	NUMBER|IREMOTE|INIT,	(READ|WRITE)<<PUBLIC,
+	  "et",		(char *)&ET },
+	{ "rawftp",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "raw",	(char *)FALSE },
+	{ "halfduplex",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "hdx",	(char *)FALSE },
+	{ "localecho",	BOOL,			(READ|WRITE)<<PUBLIC,
+	  "le",		(char *)FALSE },
+	{ "parity",	STRING|INIT|IREMOTE,	(READ|WRITE)<<PUBLIC,
+	  "par",	(char *)&PA },
+	{ NOSTR, 0, 0, NOSTR, NOSTR }
+};