diff usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,1258 @@
+/*
+ * Copyright 1994-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)utilities.c	1.19	05/06/12 SMI"
+
+/*
+ * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c
+ */
+
+/*
+ * Copyright (c) 1988, 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[] = "@(#)utilities.c	8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#define	TELOPTS
+#ifdef	lint
+static char *telcmds[] = {0};
+static char *slc_names[] = {0};
+static char *encrypt_names[] = {0};
+static char *enctype_names[] = {0};
+#else	/* lint */
+#define	TELCMDS
+#define	SLC_NAMES
+#endif	/* lint */
+#include <arpa/telnet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <ctype.h>
+
+#include "general.h"
+
+#include "ring.h"
+
+#include "defines.h"
+
+#include "externs.h"
+
+FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
+int	prettydump;
+
+/*
+ * upcase()
+ *
+ *	Upcase (in place) the argument.
+ */
+
+    void
+upcase(argument)
+	register char *argument;
+{
+	register int c;
+
+	while ((c = *argument) != 0) {
+		if (islower(c)) {
+			*argument = toupper(c);
+		}
+	argument++;
+	}
+}
+
+/*
+ * SetSockOpt()
+ *
+ * Compensate for differences in 4.2 and 4.3 systems.
+ */
+
+    int
+SetSockOpt(fd, level, option, yesno)
+    int fd, level, option, yesno;
+{
+	return (setsockopt(fd, level, option, &yesno, sizeof (yesno)));
+}
+
+/*
+ * The following are routines used to print out debugging information.
+ */
+
+unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)";
+
+    void
+SetNetTrace(file)
+    register char *file;
+{
+	if (NetTrace && NetTrace != stdout)
+		(void) fclose(NetTrace);
+	if (file && (strcmp(file, "-") != 0)) {
+		NetTrace = fopen(file, "w");
+		if (NetTrace) {
+			(void) strcpy((char *)NetTraceFile, file);
+			return;
+		}
+		(void) fprintf(stderr, "Cannot open %s.\n", file);
+	}
+	NetTrace = stdout;
+	(void) strcpy((char *)NetTraceFile, "(standard output)");
+}
+
+    void
+Dump(direction, buffer, length)
+    char direction;
+    unsigned char *buffer;
+    int length;
+{
+#define	BYTES_PER_LINE	32
+#define	min(x, y)	((x < y) ? x:y)
+	unsigned char *pThis;
+	int offset;
+
+	offset = 0;
+
+	while (length) {
+		/* print one line */
+		(void) fprintf(NetTrace, "%c 0x%x\t", direction, offset);
+		pThis = buffer;
+		if (prettydump) {
+			buffer = buffer + min(length, BYTES_PER_LINE/2);
+			while (pThis < buffer) {
+				(void) fprintf(NetTrace, "%c%.2x",
+				    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
+				    (*pThis)&0xff);
+				pThis++;
+			}
+			length -= BYTES_PER_LINE/2;
+			offset += BYTES_PER_LINE/2;
+		} else {
+			buffer = buffer + min(length, BYTES_PER_LINE);
+			while (pThis < buffer) {
+				(void) fprintf(NetTrace, "%.2x", (*pThis)&0xff);
+				pThis++;
+			}
+			length -= BYTES_PER_LINE;
+			offset += BYTES_PER_LINE;
+		}
+		if (NetTrace == stdout) {
+			(void) fprintf(NetTrace, "\r\n");
+		} else {
+			(void) fprintf(NetTrace, "\n");
+		}
+		if (length < 0) {
+			(void) fflush(NetTrace);
+			return;
+		}
+		/* find next unique line */
+	}
+	(void) fflush(NetTrace);
+}
+
+
+	void
+printoption(direction, cmd, option)
+	char *direction;
+	int cmd, option;
+{
+	if (!showoptions)
+		return;
+	if (cmd == IAC) {
+		if (TELCMD_OK(option))
+			(void) fprintf(NetTrace, "%s IAC %s", direction,
+			    TELCMD(option));
+		else
+			(void) fprintf(NetTrace, "%s IAC %d", direction,
+				option);
+	} else {
+		register char *fmt;
+		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
+			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+		if (fmt) {
+		    (void) fprintf(NetTrace, "%s %s ", direction, fmt);
+		    if (TELOPT_OK(option))
+			(void) fprintf(NetTrace, "%s", TELOPT(option));
+		    else if (option == TELOPT_EXOPL)
+			(void) fprintf(NetTrace, "EXOPL");
+		    else
+			(void) fprintf(NetTrace, "%d", option);
+		} else
+			(void) fprintf(NetTrace, "%s %d %d", direction, cmd,
+			    option);
+	}
+	if (NetTrace == stdout) {
+	    (void) fprintf(NetTrace, "\r\n");
+	    (void) fflush(NetTrace);
+	} else {
+	    (void) fprintf(NetTrace, "\n");
+	}
+}
+
+    void
+optionstatus()
+{
+	register int i;
+	extern char will_wont_resp[], do_dont_resp[];
+
+	for (i = 0; i < SUBBUFSIZE; i++) {
+		if (do_dont_resp[i]) {
+			if (TELOPT_OK(i))
+				(void) printf("resp DO_DONT %s: %d\n",
+				    TELOPT(i), do_dont_resp[i]);
+			else if (TELCMD_OK(i))
+				(void) printf("resp DO_DONT %s: %d\n",
+				    TELCMD(i), do_dont_resp[i]);
+			else
+				(void) printf("resp DO_DONT %d: %d\n", i,
+				    do_dont_resp[i]);
+			if (my_want_state_is_do(i)) {
+				if (TELOPT_OK(i))
+					(void) printf("want DO   %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("want DO   %s\n",
+						TELCMD(i));
+				else
+					(void) printf("want DO   %d\n", i);
+			} else {
+				if (TELOPT_OK(i))
+					(void) printf("want DONT %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("want DONT %s\n",
+					    TELCMD(i));
+				else
+					(void) printf("want DONT %d\n", i);
+			}
+		} else {
+			if (my_state_is_do(i)) {
+				if (TELOPT_OK(i))
+					(void) printf("     DO   %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("     DO   %s\n",
+					    TELCMD(i));
+				else
+					(void) printf("     DO   %d\n", i);
+			}
+		}
+		if (will_wont_resp[i]) {
+			if (TELOPT_OK(i))
+				(void) printf("resp WILL_WONT %s: %d\n",
+				    TELOPT(i), will_wont_resp[i]);
+			else if (TELCMD_OK(i))
+				(void) printf("resp WILL_WONT %s: %d\n",
+				    TELCMD(i), will_wont_resp[i]);
+			else
+				(void) printf("resp WILL_WONT %d: %d\n",
+				    i, will_wont_resp[i]);
+			if (my_want_state_is_will(i)) {
+				if (TELOPT_OK(i))
+					(void) printf("want WILL %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("want WILL %s\n",
+					    TELCMD(i));
+				else
+					(void) printf("want WILL %d\n", i);
+			} else {
+				if (TELOPT_OK(i))
+					(void) printf("want WONT %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("want WONT %s\n",
+					    TELCMD(i));
+				else
+					(void) printf("want WONT %d\n", i);
+			}
+		} else {
+			if (my_state_is_will(i)) {
+				if (TELOPT_OK(i))
+					(void) printf("     WILL %s\n",
+					    TELOPT(i));
+				else if (TELCMD_OK(i))
+					(void) printf("     WILL %s\n",
+					    TELCMD(i));
+				else
+					(void) printf("     WILL %d\n", i);
+			}
+		}
+	}
+
+}
+
+    void
+printsub(direction, pointer, length)
+	char direction;	/* '<' or '>' */
+	unsigned char *pointer;	/* where suboption data sits */
+	int	  length;	/* length of suboption data */
+{
+	register int i;
+	char buf[512];
+	extern int want_status_response;
+
+	if (showoptions || direction == 0 ||
+	    (want_status_response && (pointer[0] == TELOPT_STATUS))) {
+		if (direction) {
+			(void) fprintf(NetTrace, "%s IAC SB ",
+				(direction == '<')? "RCVD":"SENT");
+			if (length >= 3) {
+				register int j;
+
+				i = pointer[length-2];
+				j = pointer[length-1];
+
+				if (i != IAC || j != SE) {
+					(void) fprintf(NetTrace,
+					    "(terminated by ");
+					if (TELOPT_OK(i))
+						(void) fprintf(NetTrace, "%s ",
+						    TELOPT(i));
+					else if (TELCMD_OK(i))
+						(void) fprintf(NetTrace, "%s ",
+						    TELCMD(i));
+					else
+						(void) fprintf(NetTrace, "%d ",
+						    i);
+					if (TELOPT_OK(j))
+						(void) fprintf(NetTrace, "%s",
+						    TELOPT(j));
+					else if (TELCMD_OK(j))
+						(void) fprintf(NetTrace, "%s",
+						    TELCMD(j));
+					else
+						(void) fprintf(NetTrace, "%d",
+						    j);
+					(void) fprintf(NetTrace,
+					    ", not IAC SE!) ");
+				}
+			}
+			length -= 2;
+		}
+		if (length < 1) {
+			(void) fprintf(NetTrace, "(Empty suboption??\?)");
+			if (NetTrace == stdout)
+				(void) fflush(NetTrace);
+			return;
+		}
+		switch (pointer[0]) {
+		case TELOPT_TTYPE:
+			(void) fprintf(NetTrace, "TERMINAL-TYPE ");
+			switch (pointer[1]) {
+			case TELQUAL_IS:
+				(void) fprintf(NetTrace, "IS \"%.*s\"",
+				    length-2,
+				    (char *)pointer+2);
+				break;
+			case TELQUAL_SEND:
+				(void) fprintf(NetTrace, "SEND");
+				break;
+			default:
+				(void) fprintf(NetTrace,
+				    "- unknown qualifier %d (0x%x).",
+				    pointer[1], pointer[1]);
+			}
+			break;
+		case TELOPT_TSPEED:
+			(void) fprintf(NetTrace, "TERMINAL-SPEED");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+				    " (empty suboption??\?)");
+				break;
+			}
+			switch (pointer[1]) {
+			case TELQUAL_IS:
+				(void) fprintf(NetTrace, " IS ");
+				(void) fprintf(NetTrace, "%.*s", length-2,
+				    (char *)pointer+2);
+				break;
+			default:
+				if (pointer[1] == 1)
+					(void) fprintf(NetTrace, " SEND");
+				else
+					(void) fprintf(NetTrace,
+					    " %d (unknown)", pointer[1]);
+				for (i = 2; i < length; i++)
+					(void) fprintf(NetTrace, " ?%d?",
+					    pointer[i]);
+				break;
+			}
+			break;
+
+		case TELOPT_LFLOW:
+			(void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+				    " (empty suboption??\?)");
+				break;
+			}
+			switch (pointer[1]) {
+			case LFLOW_OFF:
+				(void) fprintf(NetTrace, " OFF");
+				break;
+			case LFLOW_ON:
+				(void) fprintf(NetTrace, " ON");
+				break;
+			case LFLOW_RESTART_ANY:
+				(void) fprintf(NetTrace, " RESTART-ANY");
+				break;
+			case LFLOW_RESTART_XON:
+				(void) fprintf(NetTrace, " RESTART-XON");
+				break;
+			default:
+				(void) fprintf(NetTrace, " %d (unknown)",
+				    pointer[1]);
+			}
+			for (i = 2; i < length; i++)
+				(void) fprintf(NetTrace, " ?%d?",
+				    pointer[i]);
+			break;
+
+		case TELOPT_NAWS:
+			(void) fprintf(NetTrace, "NAWS");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+				    " (empty suboption??\?)");
+				break;
+			}
+			if (length == 2) {
+				(void) fprintf(NetTrace, " ?%d?", pointer[1]);
+				break;
+			}
+			(void) fprintf(NetTrace, " %d %d (%d)",
+			    pointer[1], pointer[2],
+			    (int)((((unsigned int)pointer[1])<<8)|
+			    ((unsigned int)pointer[2])));
+			if (length == 4) {
+				(void) fprintf(NetTrace, " ?%d?", pointer[3]);
+				break;
+			}
+			(void) fprintf(NetTrace, " %d %d (%d)",
+			    pointer[3], pointer[4],
+			    (int)((((unsigned int)pointer[3])<<8)|
+			    ((unsigned int)pointer[4])));
+			for (i = 5; i < length; i++)
+				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
+			break;
+
+		case TELOPT_AUTHENTICATION:
+			(void) fprintf(NetTrace, "AUTHENTICATION");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+					" (empty suboption??\?)");
+				break;
+			}
+			switch (pointer[1]) {
+			case TELQUAL_REPLY:
+			case TELQUAL_IS:
+				(void) fprintf(NetTrace, " %s ",
+				    (pointer[1] == TELQUAL_IS) ?
+				    "IS" : "REPLY");
+				if (AUTHTYPE_NAME_OK(pointer[2]))
+					(void) fprintf(NetTrace, "%s ",
+					    AUTHTYPE_NAME(pointer[2]));
+				else
+					(void) fprintf(NetTrace, "%d ",
+						pointer[2]);
+				if (length < 3) {
+					(void) fprintf(NetTrace,
+					    "(partial suboption??\?)");
+					break;
+				}
+				(void) fprintf(NetTrace, "%s|%s",
+				    ((pointer[3] & AUTH_WHO_MASK) ==
+				    AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER",
+				    ((pointer[3] & AUTH_HOW_MASK) ==
+				    AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY");
+
+				auth_printsub(&pointer[1], length - 1,
+				    (uchar_t *)buf, sizeof (buf));
+				(void) fprintf(NetTrace, "%s", buf);
+				break;
+
+			case TELQUAL_SEND:
+				i = 2;
+				(void) fprintf(NetTrace, " SEND ");
+				while (i < length) {
+					if (AUTHTYPE_NAME_OK(pointer[i]))
+						(void) fprintf(NetTrace, "%s ",
+						    AUTHTYPE_NAME(pointer[i]));
+					else
+						(void) fprintf(NetTrace, "%d ",
+						    pointer[i]);
+					if (++i >= length) {
+						(void) fprintf(NetTrace,
+						    "(partial "
+						    "suboption??\?)");
+						break;
+					}
+					(void) fprintf(NetTrace, "%s|%s ",
+					    ((pointer[i] & AUTH_WHO_MASK) ==
+					    AUTH_WHO_CLIENT) ?
+					    "CLIENT" : "SERVER",
+					    ((pointer[i] & AUTH_HOW_MASK) ==
+					    AUTH_HOW_MUTUAL) ?
+					    "MUTUAL" : "ONE-WAY");
+					++i;
+				}
+				break;
+
+			case TELQUAL_NAME:
+				i = 2;
+				(void) fprintf(NetTrace, " NAME \"");
+				while (i < length)
+					(void) putc(pointer[i++], NetTrace);
+				(void) putc('"', NetTrace);
+				break;
+
+			default:
+				for (i = 2; i < length; i++)
+				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
+				break;
+			}
+			break;
+
+		case TELOPT_ENCRYPT:
+			(void) fprintf(NetTrace, "ENCRYPT");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+				    " (empty suboption??\?)");
+				break;
+			}
+			switch (pointer[1]) {
+			case ENCRYPT_START:
+				(void) fprintf(NetTrace, " START");
+				break;
+
+			case ENCRYPT_END:
+				(void) fprintf(NetTrace, " END");
+				break;
+
+			case ENCRYPT_REQSTART:
+				(void) fprintf(NetTrace, " REQUEST-START");
+				break;
+
+			case ENCRYPT_REQEND:
+				(void) fprintf(NetTrace, " REQUEST-END");
+				break;
+
+			case ENCRYPT_IS:
+			case ENCRYPT_REPLY:
+				(void) fprintf(NetTrace, " %s ",
+				    (pointer[1] == ENCRYPT_IS) ?
+				    "IS" : "REPLY");
+				if (length < 3) {
+					(void) fprintf(NetTrace, " (partial "
+					    "suboption??\?)");
+					break;
+				}
+				if (ENCTYPE_NAME_OK(pointer[2]))
+					(void) fprintf(NetTrace, "%s ",
+					    ENCTYPE_NAME(pointer[2]));
+				else
+					(void) fprintf(NetTrace,
+					    " %d (unknown)", pointer[2]);
+
+				encrypt_printsub(&pointer[1], length - 1,
+				    (uchar_t *)buf, sizeof (buf));
+				(void) fprintf(NetTrace, "%s", buf);
+				break;
+
+			case ENCRYPT_SUPPORT:
+				i = 2;
+				(void) fprintf(NetTrace, " SUPPORT ");
+				while (i < length) {
+					if (ENCTYPE_NAME_OK(pointer[i]))
+						(void) fprintf(NetTrace, "%s ",
+						    ENCTYPE_NAME(pointer[i]));
+					else
+						(void) fprintf(NetTrace, "%d ",
+						    pointer[i]);
+					i++;
+				}
+				break;
+
+			case ENCRYPT_ENC_KEYID:
+				(void) fprintf(NetTrace, " ENC_KEYID ");
+				goto encommon;
+
+			case ENCRYPT_DEC_KEYID:
+				(void) fprintf(NetTrace, " DEC_KEYID ");
+				goto encommon;
+
+			default:
+				(void) fprintf(NetTrace, " %d (unknown)",
+				    pointer[1]);
+			encommon:
+				for (i = 2; i < length; i++)
+					(void) fprintf(NetTrace, " %d",
+					    pointer[i]);
+				break;
+			}
+			break;
+
+		case TELOPT_LINEMODE:
+			(void) fprintf(NetTrace, "LINEMODE ");
+			if (length < 2) {
+				(void) fprintf(NetTrace,
+				    " (empty suboption??\?)");
+				break;
+			}
+			switch (pointer[1]) {
+			case WILL:
+				(void) fprintf(NetTrace, "WILL ");
+				goto common;
+			case WONT:
+				(void) fprintf(NetTrace, "WONT ");
+				goto common;
+			case DO:
+				(void) fprintf(NetTrace, "DO ");
+				goto common;
+			case DONT:
+				(void) fprintf(NetTrace, "DONT ");
+common:
+				if (length < 3) {
+					(void) fprintf(NetTrace,
+						"(no option??\?)");
+					break;
+				}
+				switch (pointer[2]) {
+				case LM_FORWARDMASK:
+					(void) fprintf(NetTrace,
+					    "Forward Mask");
+					for (i = 3; i < length; i++)
+						(void) fprintf(NetTrace, " %x",
+						    pointer[i]);
+					break;
+				default:
+					(void) fprintf(NetTrace, "%d (unknown)",
+					    pointer[2]);
+					for (i = 3; i < length; i++)
+					(void) fprintf(NetTrace,
+					    " %d", pointer[i]);
+					break;
+				}
+				break;
+
+			case LM_SLC:
+				(void) fprintf(NetTrace, "SLC");
+				for (i = 2; i < length - 2; i += 3) {
+					if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+						(void) fprintf(NetTrace, " %s",
+						    SLC_NAME(pointer[
+						    i+SLC_FUNC]));
+					else
+						(void) fprintf(NetTrace, " %d",
+						    pointer[i+SLC_FUNC]);
+					switch (pointer[i+SLC_FLAGS] &
+					    SLC_LEVELBITS) {
+					case SLC_NOSUPPORT:
+						(void) fprintf(NetTrace,
+						    " NOSUPPORT");
+						break;
+					case SLC_CANTCHANGE:
+						(void) fprintf(NetTrace,
+						    " CANTCHANGE");
+						break;
+					case SLC_VARIABLE:
+						(void) fprintf(NetTrace,
+						    " VARIABLE");
+						break;
+					case SLC_DEFAULT:
+						(void) fprintf(NetTrace,
+						    " DEFAULT");
+						break;
+					}
+					(void) fprintf(NetTrace, "%s%s%s",
+					    pointer[i+SLC_FLAGS]&SLC_ACK ?
+						"|ACK" : "",
+					    pointer[i+SLC_FLAGS]&SLC_FLUSHIN ?
+						"|FLUSHIN" : "",
+					    pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ?
+						"|FLUSHOUT" : "");
+					if (pointer[i+SLC_FLAGS] &
+					    ~(SLC_ACK|SLC_FLUSHIN|
+					    SLC_FLUSHOUT| SLC_LEVELBITS))
+					(void) fprintf(NetTrace, "(0x%x)",
+					    pointer[i+SLC_FLAGS]);
+					(void) fprintf(NetTrace, " %d;",
+					    pointer[i+SLC_VALUE]);
+					if ((pointer[i+SLC_VALUE] == IAC) &&
+					    (pointer[i+SLC_VALUE+1] == IAC))
+						i++;
+				}
+				for (; i < length; i++)
+					(void) fprintf(NetTrace, " ?%d?",
+					    pointer[i]);
+				break;
+
+			case LM_MODE:
+				(void) fprintf(NetTrace, "MODE ");
+				if (length < 3) {
+					(void) fprintf(NetTrace,
+					    "(no mode??\?)");
+					break;
+				}
+				{
+					char tbuf[64];
+					(void) sprintf(tbuf, "%s%s%s%s%s",
+					    pointer[2]&MODE_EDIT ? "|EDIT" : "",
+					    pointer[2]&MODE_TRAPSIG ?
+					    "|TRAPSIG" : "",
+					    pointer[2]&MODE_SOFT_TAB ?
+					    "|SOFT_TAB" : "",
+					    pointer[2]&MODE_LIT_ECHO ?
+					    "|LIT_ECHO" : "",
+					    pointer[2]&MODE_ACK ? "|ACK" : "");
+					(void) fprintf(NetTrace, "%s", tbuf[1] ?
+					    &tbuf[1] : "0");
+				}
+				if (pointer[2]&~(MODE_MASK))
+					(void) fprintf(NetTrace, " (0x%x)",
+					    pointer[2]);
+				for (i = 3; i < length; i++)
+					(void) fprintf(NetTrace, " ?0x%x?",
+					    pointer[i]);
+				break;
+			default:
+				(void) fprintf(NetTrace, "%d (unknown)",
+				    pointer[1]);
+				for (i = 2; i < length; i++)
+					(void) fprintf(NetTrace, " %d",
+					    pointer[i]);
+				}
+				break;
+
+		case TELOPT_STATUS: {
+				register char *cp;
+				register int j, k;
+
+				(void) fprintf(NetTrace, "STATUS");
+
+				switch (pointer[1]) {
+				default:
+					if (pointer[1] == TELQUAL_SEND)
+						(void) fprintf(NetTrace,
+						    " SEND");
+					else
+						(void) fprintf(NetTrace,
+						    " %d (unknown)",
+						    pointer[1]);
+					for (i = 2; i < length; i++)
+					(void) fprintf(NetTrace, " ?%d?",
+					    pointer[i]);
+					break;
+				case TELQUAL_IS:
+					if (--want_status_response < 0)
+						want_status_response = 0;
+					if (NetTrace == stdout)
+						(void) fprintf(NetTrace,
+						    " IS\r\n");
+					else
+						(void) fprintf(NetTrace,
+						    " IS\n");
+
+					for (i = 2; i < length; i++) {
+						switch (pointer[i]) {
+						case DO:
+							cp = "DO";
+							goto common2;
+						case DONT:
+							cp = "DONT";
+							goto common2;
+						case WILL:
+							cp = "WILL";
+							goto common2;
+						case WONT:
+							cp = "WONT";
+							goto common2;
+common2:
+							i++;
+							if (TELOPT_OK(
+							    (int)pointer[i]))
+								(void) fprintf(
+								    NetTrace,
+								    " %s %s",
+								    cp,
+								    TELOPT(
+								    pointer[
+								    i]));
+							else
+								(void) fprintf(
+								    NetTrace,
+								    " %s %d",
+								    cp,
+								    pointer[i]);
+
+							if (NetTrace == stdout)
+								(void) fprintf(
+								    NetTrace,
+								    "\r\n");
+							else
+								(void) fprintf(
+								    NetTrace,
+								    "\n");
+							break;
+
+						case SB:
+							(void) fprintf(NetTrace,
+							    " SB ");
+							i++;
+							j = k = i;
+							while (j < length) {
+			if (pointer[j] == SE) {
+				if (j+1 == length)
+					break;
+				if (pointer[j+1] == SE)
+					j++;
+				else
+					break;
+				}
+				pointer[k++] = pointer[j++];
+							}
+							printsub(0,
+							    &pointer[i], k - i);
+							if (i < length) {
+						(void) fprintf(NetTrace, " SE");
+				i = j;
+			} else
+				i = j - 1;
+
+			if (NetTrace == stdout)
+				(void) fprintf(NetTrace, "\r\n");
+			else
+				(void) fprintf(NetTrace, "\n");
+
+							break;
+
+						default:
+							(void) fprintf(NetTrace,
+							    " %d", pointer[i]);
+							break;
+						}
+					}
+					break;
+				}
+				break;
+			}
+
+		case TELOPT_XDISPLOC:
+			(void) fprintf(NetTrace, "X-DISPLAY-LOCATION ");
+			switch (pointer[1]) {
+			case TELQUAL_IS:
+				(void) fprintf(NetTrace, "IS \"%.*s\"",
+				    length-2, (char *)pointer+2);
+				break;
+			case TELQUAL_SEND:
+				(void) fprintf(NetTrace, "SEND");
+				break;
+			default:
+				(void) fprintf(NetTrace,
+				    "- unknown qualifier %d (0x%x).",
+				    pointer[1], pointer[1]);
+			}
+			break;
+
+		case TELOPT_NEW_ENVIRON:
+	    (void) fprintf(NetTrace, "NEW-ENVIRON ");
+#ifdef	OLD_ENVIRON
+	    goto env_common1;
+	case TELOPT_OLD_ENVIRON:
+	    (void) fprintf(NetTrace, "OLD-ENVIRON ");
+	env_common1:
+#endif
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		(void) fprintf(NetTrace, "IS ");
+		goto env_common;
+	    case TELQUAL_SEND:
+		(void) fprintf(NetTrace, "SEND ");
+		goto env_common;
+	    case TELQUAL_INFO:
+		(void) fprintf(NetTrace, "INFO ");
+	    env_common:
+		{
+		    register int noquote = 2;
+#if defined(ENV_HACK) && defined(OLD_ENVIRON)
+		    extern int old_env_var, old_env_value;
+#endif
+		    for (i = 2; i < length; i++) {
+			switch (pointer[i]) {
+			case NEW_ENV_VALUE:
+#ifdef OLD_ENVIRON
+		    /*	case NEW_ENV_OVAR: */
+			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
+#ifdef	ENV_HACK
+				if (old_env_var == OLD_ENV_VALUE)
+					(void) fprintf(NetTrace,
+					    "\" (VALUE) " + noquote);
+				else
+#endif
+					(void) fprintf(NetTrace,
+					    "\" VAR " + noquote);
+			    } else
+#endif /* OLD_ENVIRON */
+				(void) fprintf(NetTrace, "\" VALUE " + noquote);
+			    noquote = 2;
+			    break;
+
+			case NEW_ENV_VAR:
+#ifdef OLD_ENVIRON
+		    /* case OLD_ENV_VALUE: */
+			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
+#ifdef	ENV_HACK
+				if (old_env_value == OLD_ENV_VAR)
+					(void) fprintf(NetTrace,
+					    "\" (VAR) " + noquote);
+				else
+#endif
+					(void) fprintf(NetTrace,
+					    "\" VALUE " + noquote);
+			    } else
+#endif /* OLD_ENVIRON */
+				(void) fprintf(NetTrace, "\" VAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_ESC:
+			    (void) fprintf(NetTrace, "\" ESC " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_USERVAR:
+			    (void) fprintf(NetTrace, "\" USERVAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			default:
+			def_case:
+			    if (isprint(pointer[i]) && pointer[i] != '"') {
+				if (noquote) {
+				    (void) putc('"', NetTrace);
+				    noquote = 0;
+				}
+				(void) putc(pointer[i], NetTrace);
+			    } else {
+				(void) fprintf(NetTrace, "\" %03o " + noquote,
+							pointer[i]);
+				noquote = 2;
+			    }
+			    break;
+			}
+		    }
+		    if (!noquote)
+			(void) putc('"', NetTrace);
+		    break;
+		}
+	    }
+	    break;
+
+	default:
+	    if (TELOPT_OK(pointer[0]))
+		(void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
+	    else
+		(void) fprintf(NetTrace, "%d (unknown)", pointer[0]);
+	    for (i = 1; i < length; i++)
+		(void) fprintf(NetTrace, " %d", pointer[i]);
+	    break;
+	}
+	if (direction) {
+	    if (NetTrace == stdout)
+		(void) fprintf(NetTrace, "\r\n");
+	    else
+		(void) fprintf(NetTrace, "\n");
+	}
+	if (NetTrace == stdout)
+	    (void) fflush(NetTrace);
+	}
+}
+
+/*
+ * EmptyTerminal - called to make sure that the terminal buffer is empty.
+ *			Note that we consider the buffer to run all the
+ *			way to the kernel (thus the select).
+ */
+
+static void
+EmptyTerminal()
+{
+	fd_set	o;
+
+	FD_ZERO(&o);
+
+	if (TTYBYTES() == 0) {
+		FD_SET(tout, &o);
+		/* wait for TTLOWAT */
+		(void) select(tout+1, NULL, &o, NULL, NULL);
+	} else {
+		while (TTYBYTES()) {
+			if (ttyflush(0) == -2) {
+				/* This will not return. */
+				fatal_tty_error("write");
+			}
+			FD_SET(tout, &o);
+			/* wait for TTLOWAT */
+			(void) select(tout+1, NULL, &o, NULL, NULL);
+		}
+	}
+}
+
+static void
+SetForExit()
+{
+	setconnmode(0);
+	do {
+		(void) telrcv();		/* Process any incoming data */
+		EmptyTerminal();
+	} while (ring_full_count(&netiring));	/* While there is any */
+	setcommandmode();
+	(void) fflush(stdout);
+	(void) fflush(stderr);
+	setconnmode(0);
+	EmptyTerminal();			/* Flush the path to the tty */
+	setcommandmode();
+}
+
+void
+Exit(returnCode)
+	int returnCode;
+{
+	SetForExit();
+	exit(returnCode);
+}
+
+void
+ExitString(string, returnCode)
+	char *string;
+	int returnCode;
+{
+	SetForExit();
+	(void) fwrite(string, 1, strlen(string), stderr);
+	exit(returnCode);
+}
+
+#define	BUFFER_CHUNK_SIZE 64
+
+/* Round up to a multiple of BUFFER_CHUNK_SIZE */
+#define	ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \
+		BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE)
+
+/*
+ * Optionally allocate a buffer, and optionally read a string from a stream
+ * into the buffer, starting at the given offset.  If the buffer isn't
+ * large enough for the given offset, or if buffer space is exhausted
+ * when reading the string, the size of the buffer is increased.
+ *
+ * A buffer can be supplied when the function is called, passing the
+ * buffer address via the first argument.  The buffer size can be
+ * passed as well, in the second argument.  If the second argument is
+ * NULL, the function makes no assumptions about the buffer size.
+ * The address of the buffer is returned via the first argument, and the
+ * buffer size via the second argument if this is not NULL.
+ * These returned values may differ from the supplied values if the buffer
+ * was reallocated.
+ *
+ * If no buffer is to be supplied, specify a buffer address of NULL, via
+ * the first argument.
+ *
+ * If the pointer to the buffer address is NULL, the function just returns
+ * NULL, and performs no other processing.
+ *
+ * If a NULL stream is passed, the function will just make sure the
+ * supplied buffer is large enough to hold the supplied offset,
+ * reallocating it if is too small or too large.
+ *
+ * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size.
+ *
+ * The function stops reading from the stream when a newline is read,
+ * end of file is reached, or an error occurs.  The newline is not
+ * returned in the buffer.  The returned string will be NULL terminated.
+ *
+ * The function returns the address of the buffer if any characters
+ * are read and no error occurred, otherwise it returns NULL.
+ *
+ * If the function returns NULL, a buffer may have been allocated.  The
+ * buffer address will be returned via the first argument, together with
+ * the buffer size if the second argument is not NULL.
+ *
+ */
+static char *
+GetStringAtOffset(bufp, cbufsiz, off, st)
+	char **bufp;
+	unsigned int *cbufsiz;
+	unsigned int off;
+	FILE *st;
+{
+	unsigned int bufsiz;
+	char *buf;
+	char *nbuf;
+	unsigned int idx = off;
+
+	if (bufp == NULL)
+		return (NULL);
+
+	buf = *bufp;
+
+	bufsiz = ROUND_CHUNK_SIZE(off + 1);
+
+	if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) {
+		if ((nbuf = realloc(buf, bufsiz)) == NULL)
+			return (NULL);
+
+		buf = nbuf;
+		*bufp = buf;
+		if (cbufsiz != NULL)
+			*cbufsiz = bufsiz;
+	}
+
+
+	if (st == NULL)
+		return (buf);
+
+	clearerr(st);
+	for (;;) {
+		int c = getc(st);
+
+		/* Expand the buffer as needed. */
+		if (idx == bufsiz) {
+			bufsiz += BUFFER_CHUNK_SIZE;
+			if ((nbuf = realloc(buf, bufsiz)) == NULL) {
+				/* Discard everything we read. */
+				buf[off] = 0;
+				buf = NULL;
+				break;
+			}
+			buf = nbuf;
+			*bufp = buf;
+			if (cbufsiz != NULL)
+				*cbufsiz = bufsiz;
+		}
+
+		if (c == EOF || c == '\n') {
+			buf[idx] = 0;
+			if (ferror(st) != 0) {
+				/* Retry if interrupted by a signal. */
+				if (errno == EINTR) {
+					clearerr(st);
+					continue;
+				}
+				buf = NULL;
+			} else if (feof(st) != 0) {
+				/* No characters transferred? */
+				if (off == idx)
+					buf = NULL;
+			}
+			break;
+		}
+		buf[idx++] = c;
+	}
+	return (buf);
+}
+
+/*
+ * Read a string from the supplied stream.  Stop reading when a newline
+ * is read, end of file reached, or an error occurs.
+ *
+ * A buffer can be supplied by specifying the buffer address via the
+ * first argument. The buffer size can be passed via the second argument.
+ * If the second argument is NULL, the function makes no assumptions
+ * about the buffer size. The buffer will be reallocated if it is too
+ * small or too large for the returned string.
+ *
+ * If no buffer is to be supplied, specify a buffer address of NULL,
+ * via the first argument.
+ *
+ * If the first argument is NULL, the function just returns NULL, and
+ * performs no other processing.
+ *
+ * The function returns the address of the buffer if any characters are
+ * read and no error occurred.
+ *
+ * If the function returns NULL, a buffer may have been allocated.  The
+ * buffer address and buffer size will be returned via the first argument,
+ * and the buffer size via the second argument, if this isn't NULL.
+ */
+char *
+GetString(bufp, bufsiz, st)
+	char **bufp;
+	unsigned int *bufsiz;
+	FILE *st;
+{
+	return (GetStringAtOffset(bufp, bufsiz, 0, st));
+}
+
+/*
+ * Allocate a buffer to hold a string of given length.
+ *
+ * An existing buffer can be reallocated by passing its address and via
+ * the first argument.  The buffer size can be passed via the second
+ * argument.  If the second argument is NULL, the function makes no
+ * assumptions about the buffer size.
+ *
+ * If no existing buffer is to be supplied, pass a NULL buffer address via
+ * the first argument.
+ *
+ * If the first argument is NULL, the function just returns NULL,
+ * and performs no other processing.
+ */
+char *
+AllocStringBuffer(bufp, bufsiz, size)
+	char **bufp;
+	unsigned int *bufsiz;
+	unsigned int size;
+{
+	return (GetStringAtOffset(bufp, bufsiz, size, (FILE *)NULL));
+}
+
+/*
+ * This function is similar to GetString(), except that the string read
+ * from the stream is appended to the supplied string.
+ */
+char *
+GetAndAppendString(bufp, bufsiz, str, st)
+	char **bufp;
+	unsigned int *bufsiz;
+	char *str;
+	FILE *st;
+{
+	unsigned int off = strlen(str);
+
+	if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL)
+		return (NULL);
+
+	return (memcpy(*bufp, str, off));
+}