BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / telnet / utilities.c
index a86dce9..0a6a882 100644 (file)
@@ -2,27 +2,45 @@
  * Copyright (c) 1988 Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1988 Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utilities.c        1.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)utilities.c        5.3 (Berkeley) 3/22/91";
 #endif /* not lint */
 
 #define        TELOPTS
 #define        TELCMDS
 #endif /* not lint */
 
 #define        TELOPTS
 #define        TELCMDS
+#define        SLC_NAMES
 #include <arpa/telnet.h>
 #include <sys/types.h>
 #include <arpa/telnet.h>
 #include <sys/types.h>
+#include <sys/time.h>
 
 #include <ctype.h>
 
 
 #include <ctype.h>
 
@@ -45,9 +63,9 @@ int   prettydump;
  *     Upcase (in place) the argument.
  */
 
  *     Upcase (in place) the argument.
  */
 
-void
+    void
 upcase(argument)
 upcase(argument)
-register char *argument;
+    register char *argument;
 {
     register int c;
 
 {
     register int c;
 
@@ -65,13 +83,9 @@ register char *argument;
  * Compensate for differences in 4.2 and 4.3 systems.
  */
 
  * Compensate for differences in 4.2 and 4.3 systems.
  */
 
-int
+    int
 SetSockOpt(fd, level, option, yesno)
 SetSockOpt(fd, level, option, yesno)
-int
-       fd,
-       level,
-       option,
-       yesno;
+    int fd, level, option, yesno;
 {
 #ifndef        NOT43
     return setsockopt(fd, level, option,
 {
 #ifndef        NOT43
     return setsockopt(fd, level, option,
@@ -90,35 +104,35 @@ int
  * The following are routines used to print out debugging information.
  */
 
  * The following are routines used to print out debugging information.
  */
 
-char NetTraceFile[256] = "(standard output)";
+unsigned char NetTraceFile[256] = "(standard output)";
 
 
-void
+    void
 SetNetTrace(file)
 SetNetTrace(file)
-register char *file;
+    register char *file;
 {
     if (NetTrace && NetTrace != stdout)
        fclose(NetTrace);
     if (file  && (strcmp(file, "-") != 0)) {
        NetTrace = fopen(file, "w");
        if (NetTrace) {
 {
     if (NetTrace && NetTrace != stdout)
        fclose(NetTrace);
     if (file  && (strcmp(file, "-") != 0)) {
        NetTrace = fopen(file, "w");
        if (NetTrace) {
-           strcpy(NetTraceFile, file);
+           strcpy((char *)NetTraceFile, file);
            return;
        }
        fprintf(stderr, "Cannot open %s.\n", file);
     }
     NetTrace = stdout;
            return;
        }
        fprintf(stderr, "Cannot open %s.\n", file);
     }
     NetTrace = stdout;
-    strcpy(NetTraceFile, "(standard output)");
+    strcpy((char *)NetTraceFile, "(standard output)");
 }
 
 }
 
-void
+    void
 Dump(direction, buffer, length)
 Dump(direction, buffer, length)
-char   direction;
-char   *buffer;
-int    length;
+    char direction;
+    unsigned char *buffer;
+    int length;
 {
 #   define BYTES_PER_LINE      32
 #   define min(x,y)    ((x<y)? x:y)
 {
 #   define BYTES_PER_LINE      32
 #   define min(x,y)    ((x<y)? x:y)
-    char *pThis;
+    unsigned char *pThis;
     int offset;
     extern pettydump;
 
     int offset;
     extern pettydump;
 
@@ -129,27 +143,29 @@ int       length;
        fprintf(NetTrace, "%c 0x%x\t", direction, offset);
        pThis = buffer;
        if (prettydump) {
        fprintf(NetTrace, "%c 0x%x\t", direction, offset);
        pThis = buffer;
        if (prettydump) {
-           buffer = buffer + min(length, BYTES_PER_LINE);
+           buffer = buffer + min(length, BYTES_PER_LINE/2);
            while (pThis < buffer) {
                fprintf(NetTrace, "%c%.2x",
                    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
                    (*pThis)&0xff);
                pThis++;
            }
            while (pThis < buffer) {
                fprintf(NetTrace, "%c%.2x",
                    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
                    (*pThis)&0xff);
                pThis++;
            }
+           length -= BYTES_PER_LINE/2;
+           offset += BYTES_PER_LINE/2;
        } else {
        } else {
-           buffer = buffer + min(length, BYTES_PER_LINE/2);
+           buffer = buffer + min(length, BYTES_PER_LINE);
            while (pThis < buffer) {
                fprintf(NetTrace, "%.2x", (*pThis)&0xff);
                pThis++;
            }
            while (pThis < buffer) {
                fprintf(NetTrace, "%.2x", (*pThis)&0xff);
                pThis++;
            }
+           length -= BYTES_PER_LINE;
+           offset += BYTES_PER_LINE;
        }
        if (NetTrace == stdout) {
            fprintf(NetTrace, "\r\n");
        } else {
            fprintf(NetTrace, "\n");
        }
        }
        if (NetTrace == stdout) {
            fprintf(NetTrace, "\r\n");
        } else {
            fprintf(NetTrace, "\n");
        }
-       length -= BYTES_PER_LINE;
-       offset += BYTES_PER_LINE;
        if (length < 0) {
            fflush(NetTrace);
            return;
        if (length < 0) {
            fflush(NetTrace);
            return;
@@ -160,20 +176,33 @@ int       length;
 }
 
 
 }
 
 
-void
-printoption(direction, fmt, option)
-       char *direction, *fmt;
-       int option;
+       void
+printoption(direction, cmd, option)
+       char *direction;
+       int cmd, option;
 {
        if (!showoptions)
                return;
 {
        if (!showoptions)
                return;
-       fprintf(NetTrace, "%s ", direction);
-       if (TELOPT_OK(option))
-               fprintf(NetTrace, "%s %s", fmt, TELOPT(option));
-       else if (TELCMD_OK(option))
-               fprintf(NetTrace, "%s %s", fmt, TELCMD(option));
-       else
-               fprintf(NetTrace, "%s %d", fmt, option);
+       if (cmd == IAC) {
+               if (TELCMD_OK(option))
+                   fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
+               else
+                   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) {
+                   fprintf(NetTrace, "%s %s ", direction, fmt);
+                   if (TELOPT_OK(option))
+                       fprintf(NetTrace, "%s", TELOPT(option));
+                   else if (option == TELOPT_EXOPL)
+                       fprintf(NetTrace, "EXOPL");
+                   else
+                       fprintf(NetTrace, "%d", option);
+               } else
+                   fprintf(NetTrace, "%s %d %d", direction, cmd, option);
+       }
        if (NetTrace == stdout)
            fprintf(NetTrace, "\r\n");
        else
        if (NetTrace == stdout)
            fprintf(NetTrace, "\r\n");
        else
@@ -181,6 +210,7 @@ printoption(direction, fmt, option)
        return;
 }
 
        return;
 }
 
+    void
 optionstatus()
 {
     register int i;
 optionstatus()
 {
     register int i;
@@ -257,43 +287,46 @@ optionstatus()
 
 }
 
 
 }
 
-char *slcnames[] = { SLC_NAMES };
-
-void
+    void
 printsub(direction, pointer, length)
 printsub(direction, pointer, length)
-char   direction;              /* '<' or '>' */
-unsigned char  *pointer;       /* where suboption data sits */
-int    length;                 /* length of suboption data */
+    char direction;    /* '<' or '>' */
+    unsigned char *pointer;    /* where suboption data sits */
+    int                  length;       /* length of suboption data */
 {
     register int i;
 {
     register int i;
-
-    if (showoptions) {
-       fprintf(NetTrace, "%s suboption ",
-                               (direction == '<')? "Received":"Sent");
-       if (length >= 3) {
-           register int j;
-
-           i = pointer[length-2];
-           j = pointer[length-1];
-
-           if (i != IAC || j != SE) {
-               fprintf(NetTrace, "(terminated by ");
-               if (TELOPT_OK(i))
-                   fprintf(NetTrace, "%s ", TELOPT(i));
-               else if (TELCMD_OK(i))
-                   fprintf(NetTrace, "%s ", TELCMD(i));
-               else
-                   fprintf(NetTrace, "%d ", i);
-               if (TELOPT_OK(j))
-                   fprintf(NetTrace, "%s", TELOPT(j));
-               else if (TELCMD_OK(j))
-                   fprintf(NetTrace, "%s", TELCMD(j));
-               else
-                   fprintf(NetTrace, "%d", j);
-               fprintf(NetTrace, ", not IAC SE!) ");
+    char buf[512];
+    extern int want_status_response;
+
+    if (showoptions || direction == 0 ||
+       (want_status_response && (pointer[0] == TELOPT_STATUS))) {
+       if (direction) {
+           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) {
+                   fprintf(NetTrace, "(terminated by ");
+                   if (TELOPT_OK(i))
+                       fprintf(NetTrace, "%s ", TELOPT(i));
+                   else if (TELCMD_OK(i))
+                       fprintf(NetTrace, "%s ", TELCMD(i));
+                   else
+                       fprintf(NetTrace, "%d ", i);
+                   if (TELOPT_OK(j))
+                       fprintf(NetTrace, "%s", TELOPT(j));
+                   else if (TELCMD_OK(j))
+                       fprintf(NetTrace, "%s", TELCMD(j));
+                   else
+                       fprintf(NetTrace, "%d", j);
+                   fprintf(NetTrace, ", not IAC SE!) ");
+               }
            }
            }
+           length -= 2;
        }
        }
-       length -= 2;
        if (length < 1) {
            fprintf(NetTrace, "(Empty suboption???)");
            return;
        if (length < 1) {
            fprintf(NetTrace, "(Empty suboption???)");
            return;
@@ -303,7 +336,7 @@ int length;                 /* length of suboption data */
            fprintf(NetTrace, "TERMINAL-TYPE ");
            switch (pointer[1]) {
            case TELQUAL_IS:
            fprintf(NetTrace, "TERMINAL-TYPE ");
            switch (pointer[1]) {
            case TELQUAL_IS:
-               fprintf(NetTrace, "IS \"%.*s\"", length-2, pointer+2);
+               fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
                break;
            case TELQUAL_SEND:
                fprintf(NetTrace, "SEND");
                break;
            case TELQUAL_SEND:
                fprintf(NetTrace, "SEND");
@@ -321,15 +354,15 @@ int       length;                 /* length of suboption data */
                break;
            }
            switch (pointer[1]) {
                break;
            }
            switch (pointer[1]) {
-           case 0:
+           case TELQUAL_IS:
                fprintf(NetTrace, " IS ");
                fprintf(NetTrace, " IS ");
-               fprintf(NetTrace, "%.*s", length-2, pointer+2);
+               fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
                break;
            default:
                if (pointer[1] == 1)
                    fprintf(NetTrace, " SEND");
                else
                break;
            default:
                if (pointer[1] == 1)
                    fprintf(NetTrace, " SEND");
                else
-                   fprintf(NetTrace, " %d (unknown)");
+                   fprintf(NetTrace, " %d (unknown)", pointer[1]);
                for (i = 2; i < length; i++)
                    fprintf(NetTrace, " ?%d?", pointer[i]);
                break;
                for (i = 2; i < length; i++)
                    fprintf(NetTrace, " ?%d?", pointer[i]);
                break;
@@ -348,7 +381,7 @@ int length;                 /* length of suboption data */
            case 1:
                fprintf(NetTrace, " ON"); break;
            default:
            case 1:
                fprintf(NetTrace, " ON"); break;
            default:
-               fprintf(NetTrace, " %d (unknown)");
+               fprintf(NetTrace, " %d (unknown)", pointer[1]);
            }
            for (i = 2; i < length; i++)
                fprintf(NetTrace, " ?%d?", pointer[i]);
            }
            for (i = 2; i < length; i++)
                fprintf(NetTrace, " ?%d?", pointer[i]);
@@ -366,18 +399,156 @@ int      length;                 /* length of suboption data */
            }
            fprintf(NetTrace, " %d %d (%d)",
                pointer[1], pointer[2],
            }
            fprintf(NetTrace, " %d %d (%d)",
                pointer[1], pointer[2],
-               (((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]));
+               (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
            if (length == 4) {
                fprintf(NetTrace, " ?%d?", pointer[3]);
                break;
            }
            fprintf(NetTrace, " %d %d (%d)",
                pointer[3], pointer[4],
            if (length == 4) {
                fprintf(NetTrace, " ?%d?", pointer[3]);
                break;
            }
            fprintf(NetTrace, " %d %d (%d)",
                pointer[3], pointer[4],
-               (((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]));
+               (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
            for (i = 5; i < length; i++)
                fprintf(NetTrace, " ?%d?", pointer[i]);
            break;
 
            for (i = 5; i < length; i++)
                fprintf(NetTrace, " ?%d?", pointer[i]);
            break;
 
+#if    defined(AUTHENTICATE)
+       case TELOPT_AUTHENTICATION:
+           fprintf(NetTrace, "AUTHENTICATION");
+           if (length < 2) {
+               fprintf(NetTrace, " (empty suboption???)");
+               break;
+           }
+           switch (pointer[1]) {
+           case TELQUAL_REPLY:
+           case TELQUAL_IS:
+               fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
+                                                       "IS" : "REPLY");
+               if (AUTHTYPE_NAME_OK(pointer[2]))
+                   fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
+               else
+                   fprintf(NetTrace, "%d ", pointer[2]);
+               if (length < 3) {
+                   fprintf(NetTrace, "(partial suboption???)");
+                   break;
+               }
+               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, buf, sizeof(buf));
+               fprintf(NetTrace, "%s", buf);
+               break;
+
+           case TELQUAL_SEND:
+               i = 2;
+               fprintf(NetTrace, " SEND ");
+               while (i < length) {
+                   if (AUTHTYPE_NAME_OK(pointer[i]))
+                       fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
+                   else
+                       fprintf(NetTrace, "%d ", pointer[i]);
+                   if (++i >= length) {
+                       fprintf(NetTrace, "(partial suboption???)");
+                       break;
+                   }
+                   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;
+               fprintf(NetTrace, " NAME \"");
+               while (i < length)
+                   putc(pointer[i++], NetTrace);
+               putc('"', NetTrace);
+               break;
+
+           default:
+                   for (i = 2; i < length; i++)
+                       fprintf(NetTrace, " ?%d?", pointer[i]);
+                   break;
+           }
+           break;
+#endif
+
+#if    defined(ENCRYPT)
+       case TELOPT_ENCRYPT:
+           fprintf(NetTrace, "ENCRYPT");
+           if (length < 2) {
+               fprintf(NetTrace, " (empty suboption???)");
+               break;
+           }
+           switch (pointer[1]) {
+           case ENCRYPT_START:
+               fprintf(NetTrace, " START");
+               break;
+
+           case ENCRYPT_END:
+               fprintf(NetTrace, " END");
+               break;
+
+           case ENCRYPT_REQSTART:
+               fprintf(NetTrace, " REQUEST-START");
+               break;
+
+           case ENCRYPT_REQEND:
+               fprintf(NetTrace, " REQUEST-END");
+               break;
+
+           case ENCRYPT_IS:
+           case ENCRYPT_REPLY:
+               fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
+                                                       "IS" : "REPLY");
+               if (length < 3) {
+                   fprintf(NetTrace, " (partial suboption???)");
+                   break;
+               }
+               if (ENCTYPE_NAME_OK(pointer[2]))
+                   fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
+               else
+                   fprintf(NetTrace, " %d (unknown)", pointer[2]);
+
+               encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+               fprintf(NetTrace, "%s", buf);
+               break;
+
+           case ENCRYPT_SUPPORT:
+               i = 2;
+               fprintf(NetTrace, " SUPPORT ");
+               while (i < length) {
+                   if (ENCTYPE_NAME_OK(pointer[i]))
+                       fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
+                   else
+                       fprintf(NetTrace, "%d ", pointer[i]);
+                   i++;
+               }
+               break;
+
+           case ENCRYPT_ENC_KEYID:
+               fprintf(NetTrace, " ENC_KEYID ");
+               goto encommon;
+
+           case ENCRYPT_DEC_KEYID:
+               fprintf(NetTrace, " DEC_KEYID ");
+               goto encommon;
+
+           default:
+               fprintf(NetTrace, " %d (unknown)", pointer[1]);
+           encommon:
+               for (i = 2; i < length; i++)
+                   fprintf(NetTrace, " %d", pointer[i]);
+               break;
+           }
+           break;
+#endif
+
        case TELOPT_LINEMODE:
            fprintf(NetTrace, "LINEMODE ");
            if (length < 2) {
        case TELOPT_LINEMODE:
            fprintf(NetTrace, "LINEMODE ");
            if (length < 2) {
@@ -418,8 +589,8 @@ int length;                 /* length of suboption data */
            case LM_SLC:
                fprintf(NetTrace, "SLC");
                for (i = 2; i < length - 2; i += 3) {
            case LM_SLC:
                fprintf(NetTrace, "SLC");
                for (i = 2; i < length - 2; i += 3) {
-                   if (pointer[i+SLC_FUNC] <= NSLC)
-                       fprintf(NetTrace, " %s", slcnames[pointer[i+SLC_FUNC]]);
+                   if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+                       fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
                    else
                        fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
                    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
                    else
                        fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
                    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
@@ -440,6 +611,9 @@ int length;                 /* length of suboption data */
                                                SLC_FLUSHOUT| SLC_LEVELBITS))
                        fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
                    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
                                                SLC_FLUSHOUT| SLC_LEVELBITS))
                        fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
                    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
+                   if ((pointer[i+SLC_VALUE] == IAC) &&
+                       (pointer[i+SLC_VALUE+1] == IAC))
+                               i++;
                }
                for (; i < length; i++)
                    fprintf(NetTrace, " ?%d?", pointer[i]);
                }
                for (; i < length; i++)
                    fprintf(NetTrace, " ?%d?", pointer[i]);
@@ -452,14 +626,16 @@ int       length;                 /* length of suboption data */
                    break;
                }
                {
                    break;
                }
                {
-                   char tbuf[32];
-                   sprintf(tbuf, "%s%s%s",
+                   char tbuf[64];
+                   sprintf(tbuf, "%s%s%s%s%s",
                        pointer[2]&MODE_EDIT ? "|EDIT" : "",
                        pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
                        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" : "");
                    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
                }
                        pointer[2]&MODE_ACK ? "|ACK" : "");
                    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
                }
-               if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
+               if (pointer[2]&~(MODE_MASK))
                    fprintf(NetTrace, " (0x%x)", pointer[2]);
                for (i = 3; i < length; i++)
                    fprintf(NetTrace, " ?0x%x?", pointer[i]);
                    fprintf(NetTrace, " (0x%x)", pointer[2]);
                for (i = 3; i < length; i++)
                    fprintf(NetTrace, " ?0x%x?", pointer[i]);
@@ -471,16 +647,173 @@ int      length;                 /* length of suboption data */
            }
            break;
 
            }
            break;
 
+       case TELOPT_STATUS: {
+           register char *cp;
+           register int j, k;
+
+           fprintf(NetTrace, "STATUS");
+
+           switch (pointer[1]) {
+           default:
+               if (pointer[1] == TELQUAL_SEND)
+                   fprintf(NetTrace, " SEND");
+               else
+                   fprintf(NetTrace, " %d (unknown)", pointer[1]);
+               for (i = 2; i < length; i++)
+                   fprintf(NetTrace, " ?%d?", pointer[i]);
+               break;
+           case TELQUAL_IS:
+               if (--want_status_response < 0)
+                   want_status_response = 0;
+               if (NetTrace == stdout)
+                   fprintf(NetTrace, " IS\r\n");
+               else
+                   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]))
+                           fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
+                       else
+                           fprintf(NetTrace, " %s %d", cp, pointer[i]);
+
+                       if (NetTrace == stdout)
+                           fprintf(NetTrace, "\r\n");
+                       else
+                           fprintf(NetTrace, "\n");
+                       break;
+
+                   case SB:
+                       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) {
+                           fprintf(NetTrace, " SE");
+                           i = j;
+                       } else
+                           i = j - 1;
+
+                       if (NetTrace == stdout)
+                           fprintf(NetTrace, "\r\n");
+                       else
+                           fprintf(NetTrace, "\n");
+
+                       break;
+                               
+                   default:
+                       fprintf(NetTrace, " %d", pointer[i]);
+                       break;
+                   }
+               }
+               break;
+           }
+           break;
+         }
+
+       case TELOPT_XDISPLOC:
+           fprintf(NetTrace, "X-DISPLAY-LOCATION ");
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+               break;
+           case TELQUAL_SEND:
+               fprintf(NetTrace, "SEND");
+               break;
+           default:
+               fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
+                               pointer[1], pointer[1]);
+           }
+           break;
+
+       case TELOPT_ENVIRON:
+           fprintf(NetTrace, "ENVIRON ");
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               fprintf(NetTrace, "IS ");
+               goto env_common;
+           case TELQUAL_SEND:
+               fprintf(NetTrace, "SEND ");
+               goto env_common;
+           case TELQUAL_INFO:
+               fprintf(NetTrace, "INFO ");
+           env_common:
+               {
+                   register int noquote = 2;
+                   for (i = 2; i < length; i++ ) {
+                       switch (pointer[i]) {
+                       case ENV_VAR:
+                           if (pointer[1] == TELQUAL_SEND)
+                               goto def_case;
+                           fprintf(NetTrace, "\" VAR " + noquote);
+                           noquote = 2;
+                           break;
+
+                       case ENV_VALUE:
+                           fprintf(NetTrace, "\" VALUE " + noquote);
+                           noquote = 2;
+                           break;
+
+                       case ENV_ESC:
+                           fprintf(NetTrace, "\" ESC " + noquote);
+                           noquote = 2;
+                           break;
+
+                       default:
+                       def_case:
+                           if (isprint(pointer[i]) && pointer[i] != '"') {
+                               if (noquote) {
+                                   putc('"', NetTrace);
+                                   noquote = 0;
+                               }
+                               putc(pointer[i], NetTrace);
+                           } else {
+                               fprintf(NetTrace, "\" %03o " + noquote,
+                                                       pointer[i]);
+                               noquote = 2;
+                           }
+                           break;
+                       }
+                   }
+                   if (!noquote)
+                       putc('"', NetTrace);
+                   break;
+               }
+           }
+           break;
+
        default:
        default:
-           fprintf(NetTrace, "Unknown option ");
-           for (i = 0; i < length; i++)
+           if (TELOPT_OK(pointer[0]))
+               fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
+           else
+               fprintf(NetTrace, "%d (unknown)", pointer[i]);
+           for (i = 1; i < length; i++)
                fprintf(NetTrace, " %d", pointer[i]);
            break;
        }
                fprintf(NetTrace, " %d", pointer[i]);
            break;
        }
-       if (NetTrace == stdout)
-           fprintf(NetTrace, "\r\n");
-       else
-           fprintf(NetTrace, "\n");
+       if (direction) {
+           if (NetTrace == stdout)
+               fprintf(NetTrace, "\r\n");
+           else
+               fprintf(NetTrace, "\n");
+       }
     }
 }
 
     }
 }
 
@@ -489,7 +822,7 @@ int length;                 /* length of suboption data */
  *                     way to the kernel (thus the select).
  */
 
  *                     way to the kernel (thus the select).
  */
 
-void
+    void
 EmptyTerminal()
 {
 #if    defined(unix)
 EmptyTerminal()
 {
 #if    defined(unix)
@@ -506,7 +839,7 @@ EmptyTerminal()
 #endif /* defined(unix) */
     } else {
        while (TTYBYTES()) {
 #endif /* defined(unix) */
     } else {
        while (TTYBYTES()) {
-           ttyflush(0);
+           (void) ttyflush(0);
 #if    defined(unix)
            FD_SET(tout, &o);
            (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
 #if    defined(unix)
            FD_SET(tout, &o);
            (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
@@ -516,7 +849,7 @@ EmptyTerminal()
     }
 }
 
     }
 }
 
-void
+    void
 SetForExit()
 {
     setconnmode(0);
 SetForExit()
 {
     setconnmode(0);
@@ -526,7 +859,7 @@ SetForExit()
     }
 #else  /* defined(TN3270) */
     do {
     }
 #else  /* defined(TN3270) */
     do {
-       telrcv();                       /* Process any incoming data */
+       (void)telrcv();                 /* Process any incoming data */
        EmptyTerminal();
     } while (ring_full_count(&netiring));      /* While there is any */
 #endif /* defined(TN3270) */
        EmptyTerminal();
     } while (ring_full_count(&netiring));      /* While there is any */
 #endif /* defined(TN3270) */
@@ -543,32 +876,20 @@ SetForExit()
     setcommandmode();
 }
 
     setcommandmode();
 }
 
-void
+    void
 Exit(returnCode)
 Exit(returnCode)
-int returnCode;
+    int returnCode;
 {
     SetForExit();
     exit(returnCode);
 }
 
 {
     SetForExit();
     exit(returnCode);
 }
 
-void
+    void
 ExitString(string, returnCode)
 ExitString(string, returnCode)
-char *string;
-int returnCode;
+    char *string;
+    int returnCode;
 {
     SetForExit();
     fwrite(string, 1, strlen(string), stderr);
     exit(returnCode);
 }
 {
     SetForExit();
     fwrite(string, 1, strlen(string), stderr);
     exit(returnCode);
 }
-
-#if defined(MSDOS)
-void
-ExitPerror(string, returnCode)
-char *string;
-int returnCode;
-{
-    SetForExit();
-    perror(string);
-    exit(returnCode);
-}
-#endif /* defined(MSDOS) */