RFC 1091 term type support, STATUS support, BINARY changes
authorPaul Borman <borman@ucbvax.Berkeley.EDU>
Sat, 2 Sep 1989 06:48:24 +0000 (22:48 -0800)
committerPaul Borman <borman@ucbvax.Berkeley.EDU>
Sat, 2 Sep 1989 06:48:24 +0000 (22:48 -0800)
SCCS-vsn: usr.bin/telnet/Makefile 1.16
SCCS-vsn: usr.bin/telnet/externs.h 1.18
SCCS-vsn: usr.bin/telnet/telnet.c 5.43
SCCS-vsn: usr.bin/telnet/sys_bsd.c 1.21
SCCS-vsn: usr.bin/telnet/utilities.c 1.15
SCCS-vsn: usr.bin/telnet/commands.c 1.21
SCCS-vsn: usr.bin/telnet/telnet.1 6.8

usr/src/usr.bin/telnet/Makefile
usr/src/usr.bin/telnet/commands.c
usr/src/usr.bin/telnet/externs.h
usr/src/usr.bin/telnet/sys_bsd.c
usr/src/usr.bin/telnet/telnet.1
usr/src/usr.bin/telnet/telnet.c
usr/src/usr.bin/telnet/utilities.c

index e488b77..8a8bf06 100644 (file)
@@ -14,7 +14,7 @@
 # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 #
 # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 #
-#      @(#)Makefile    1.15 (Berkeley) %G%
+#      @(#)Makefile    1.16 (Berkeley) %G%
 #
 
 # The following is the telnet makefile.  The sources are down one level
 #
 
 # The following is the telnet makefile.  The sources are down one level
 
 VPATH  =       Source
 INCLUDES=      -ISource
 
 VPATH  =       Source
 INCLUDES=      -ISource
-CFLAGS=        -O ${INCLUDES} -DSRCRT -DKLUDGELINEMODE
-LIBC=  /lib/libc.a
+
+#
+# TERMCAP      Define this if your system is termcap based,
+#              otherwise a terminfo based system is assumed.
+#
+# SRCRT                Includes code to allow you to specify source routes.
+#              Format is:
+#                      [!]@hop1@hop2...[@|:]dst
+#              Leading ! means strict source route.
+#
+# NOSTRNCASECMP        Define this if you do not have strncasecmp() in
+#              your C libarary.
+#
+# USE_TERMIO   Define this if you have System V termio structures.
+#              What is here is how things are on Cray computers.
+#
+# KLUDGELINEMODE Define this to get the kludged up version of linemode
+#              that was in 4.3BSD.  This is a good thing to have
+#              around for talking to older systems.
+#
+
+DEFINES= -DTERMCAP -DSRCRT -DKLUDGELINEMODE
+
+#
+# LIBS should be set to any libraries that need to be included,
+# like the termcap or terminfo library.  LIBPATH is the paths
+# to these libraries, for dependencies.
+#      For CRAY: LIBS= -lcurses -lnet
+#
+LIBS=  -ltermcap
+LIBPATH= /lib/libc.a /usr/lib/libtermcap.a
+
 SRCS=  commands.c main.c network.c ring.c \
        sys_bsd.c sys_dos.c telnet.c terminal.c \
        tn3270.c utilities.c
 
 SRCS=  commands.c main.c network.c ring.c \
        sys_bsd.c sys_dos.c telnet.c terminal.c \
        tn3270.c utilities.c
 
+CFLAGS=        -O ${INCLUDES} ${DEFINES}
+
 ALLHC= ${SRCS} \
        Source/defines.h Source/externs.h Source/fdset.h Source/general.h \
        Source/ring.h Source/types.h
 ALLHC= ${SRCS} \
        Source/defines.h Source/externs.h Source/fdset.h Source/general.h \
        Source/ring.h Source/types.h
@@ -39,8 +71,8 @@ MAN=  telnet.0
 
 all: telnet
 
 
 all: telnet
 
-telnet:        ${OBJS} ${LIBC}
-       ${CC} -o $@ ${CFLAGS} ${OBJS}
+telnet:        ${OBJS} ${LIBPATH}
+       ${CC} -o $@ ${CFLAGS} ${OBJS} ${LIBS}
 
 clean: FRC
        rm -f ${OBJS} core errs l.errs telnet
 
 clean: FRC
        rm -f ${OBJS} core errs l.errs telnet
index 280b61e..9b674db 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)commands.c 1.20 (Berkeley) %G%";
+static char sccsid[] = "@(#)commands.c 1.21 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -270,6 +270,7 @@ static struct sendlist Sendlist[] = {
     { "susp",  "Send Telnet 'Suspend Process'",        0,      SUSP },
     { "eof",   "Send Telnet End of File Character",    0,      xEOF },
     { "synch", "Perform Telnet 'Synch operation'",     dosynch, SYNCH },
     { "susp",  "Send Telnet 'Suspend Process'",        0,      SUSP },
     { "eof",   "Send Telnet End of File Character",    0,      xEOF },
     { "synch", "Perform Telnet 'Synch operation'",     dosynch, SYNCH },
+    { "getstatus", "Send request for STATUS",          get_status, 0 },
     { "?",     "Display send options",                 0,      SENDQUESTION },
     { 0 }
 };
     { "?",     "Display send options",                 0,      SENDQUESTION },
     { 0 }
 };
@@ -453,6 +454,7 @@ togcrlf()
     return 1;
 }
 
     return 1;
 }
 
+int binmode;
 
 static int
 togbinary(val)
 
 static int
 togbinary(val)
@@ -460,26 +462,92 @@ int val;
 {
     donebinarytoggle = 1;
 
 {
     donebinarytoggle = 1;
 
-    if (my_want_state_is_will(TELOPT_BINARY) ||
-       my_want_state_is_do(TELOPT_BINARY)) {
-       if (val == 1)
+    if (val >= 0) {
+       binmode = val;
+    } else {
+       if (my_want_state_is_will(TELOPT_BINARY) &&
+                               my_want_state_is_do(TELOPT_BINARY)) {
+           binmode = 1;
+       } else if (my_want_state_is_wont(TELOPT_BINARY) &&
+                               my_want_state_is_dont(TELOPT_BINARY)) {
+           binmode = 0;
+       }
+       val = binmode ? 0 : 1;
+    }
+
+    if (val == 1) {
+       if (my_want_state_is_will(TELOPT_BINARY) &&
+                                       my_want_state_is_do(TELOPT_BINARY)) {
            printf("Already operating in binary mode with remote host.\n");
            printf("Already operating in binary mode with remote host.\n");
-       else {
-           /* leave binary mode */
-           printf("Negotiating network ascii mode with remote host.\n");
-           tel_leave_binary();
+       } else {
+           printf("Negotiating binary mode with remote host.\n");
+           tel_enter_binary(3);
        }
        }
-    } else {                           /* Turn off binary mode */
-       if (val == 0)
+    } else {
+       if (my_want_state_is_wont(TELOPT_BINARY) &&
+                                       my_want_state_is_dont(TELOPT_BINARY)) {
            printf("Already in network ascii mode with remote host.\n");
            printf("Already in network ascii mode with remote host.\n");
-       else {
-           printf("Negotiating binary mode with remote host.\n");
-           tel_enter_binary();
+       else {
+           printf("Negotiating network ascii mode with remote host.\n");
+           tel_leave_binary(3);
        }
     }
     return 1;
 }
 
        }
     }
     return 1;
 }
 
+static int
+togrbinary(val)
+int val;
+{
+    donebinarytoggle = 1;
+
+    if (val == -1)
+       val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
+
+    if (val == 1) {
+       if (my_want_state_is_do(TELOPT_BINARY)) {
+           printf("Already receiving in binary mode.\n");
+       } else {
+           printf("Negotiating binary mode on input.\n");
+           tel_enter_binary(1);
+       }
+    } else {
+       if (my_want_state_is_dont(TELOPT_BINARY)) {
+           printf("Already receiving in network ascii mode.\n");
+       } else {
+           printf("Negotiating network ascii mode on input.\n");
+           tel_leave_binary(1);
+       }
+    }
+    return 1;
+}
+
+static int
+togxbinary(val)
+int val;
+{
+    donebinarytoggle = 1;
+
+    if (val == -1)
+       val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
+
+    if (val == 1) {
+       if (my_want_state_is_will(TELOPT_BINARY)) {
+           printf("Already transmitting in binary mode.\n");
+       } else {
+           printf("Negotiating binary mode on output.\n");
+           tel_enter_binary(2);
+       }
+    } else {
+       if (my_want_state_is_wont(TELOPT_BINARY)) {
+           printf("Already transmitting in network ascii mode.\n");
+       } else {
+           printf("Negotiating network ascii mode on output.\n");
+           tel_leave_binary(2);
+       }
+    }
+    return 1;
+}
 
 
 extern int togglehelp();
 
 
 extern int togglehelp();
@@ -509,6 +577,16 @@ static struct togglelist Togglelist[] = {
            togbinary,
                0,
                    0 },
            togbinary,
                0,
                    0 },
+    { "inbinary",
+       "receiving of binary data",
+           togrbinary,
+               0,
+                   0 },
+    { "outbinary",
+       "sending of binary data",
+           togxbinary,
+               0,
+                   0 },
     { "crlf",
        "sending carriage returns as telnet <CR><LF>",
            togcrlf,
     { "crlf",
        "sending carriage returns as telnet <CR><LF>",
            togcrlf,
@@ -2096,7 +2174,7 @@ int       *lenp;
 }
 #endif
 
 }
 #endif
 
-#if    defined(sun)
+#if    defined(NOSTRNCASECMP)
 strncasecmp(p1, p2, len)
 register char *p1, *p2;
 int len;
 strncasecmp(p1, p2, len)
 register char *p1, *p2;
 int len;
index ab1d842..d83b20c 100644 (file)
@@ -14,7 +14,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)externs.h   1.17 (Berkeley) %G%
+ *     @(#)externs.h   1.18 (Berkeley) %G%
  */
 
 #ifdef CRAY
  */
 
 #ifdef CRAY
@@ -158,6 +158,7 @@ extern void
 #if    !defined(NOT43)
     dosynch(),
 #endif /* !defined(NOT43) */
 #if    !defined(NOT43)
     dosynch(),
 #endif /* !defined(NOT43) */
+    get_status(),
     Dump(),
     init_3270(),
     printoption(),
     Dump(),
     init_3270(),
     printoption(),
index 8858a76..d16647a 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)sys_bsd.c  1.20 (Berkeley) %G%";
+static char sccsid[] = "@(#)sys_bsd.c  1.21 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -51,6 +51,7 @@ int
 struct tchars otc = { 0 }, ntc = { 0 };
 struct ltchars oltc = { 0 }, nltc = { 0 };
 struct sgttyb ottyb = { 0 }, nttyb = { 0 };
 struct tchars otc = { 0 }, ntc = { 0 };
 struct ltchars oltc = { 0 }, nltc = { 0 };
 struct sgttyb ottyb = { 0 }, nttyb = { 0 };
+int    olmode = 0;
 
 #define        ISPEED  ottyb.sg_ispeed
 #define        OSPEED  ottyb.sg_ospeed
 
 #define        ISPEED  ottyb.sg_ispeed
 #define        OSPEED  ottyb.sg_ospeed
@@ -186,6 +187,7 @@ TerminalSaveState()
     ioctl(0, TIOCGETP, (char *)&ottyb);
     ioctl(0, TIOCGETC, (char *)&otc);
     ioctl(0, TIOCGLTC, (char *)&oltc);
     ioctl(0, TIOCGETP, (char *)&ottyb);
     ioctl(0, TIOCGETC, (char *)&otc);
     ioctl(0, TIOCGLTC, (char *)&oltc);
+    ioctl(0, TIOCLGET, (char *)&olmode);
 
     ntc = otc;
     nltc = oltc;
 
     ntc = otc;
     nltc = oltc;
@@ -292,6 +294,7 @@ register int f;
     struct tchars tc;
     struct ltchars ltc;
     struct sgttyb sb;
     struct tchars tc;
     struct ltchars ltc;
     struct sgttyb sb;
+    int lmode;
 #else  /* USE_TERMIO */
     struct termio tmp_tc;
 #endif /* USE_TERMIO */
 #else  /* USE_TERMIO */
     struct termio tmp_tc;
 #endif /* USE_TERMIO */
@@ -335,6 +338,7 @@ register int f;
     sb = nttyb;
     tc = ntc;
     ltc = nltc;
     sb = nttyb;
     tc = ntc;
     ltc = nltc;
+    lmode = olmode;
 #else
     tmp_tc = new_tc;
 #endif
 #else
     tmp_tc = new_tc;
 #endif
@@ -411,6 +415,21 @@ register int f;
     if (f == -1) {
        onoff = 0;
     } else {
     if (f == -1) {
        onoff = 0;
     } else {
+#ifndef        USE_TERMIO
+       if (his_want_state_is_will(TELOPT_BINARY))
+               lmode |= LLITOUT;
+       else
+               lmode &= ~LLITOUT;
+       if (my_want_state_is_will(TELOPT_BINARY))
+               lmode |= LPASS8;
+       else
+               lmode &= ~LPASS8;
+#else
+       if (my_want_state_is_will(TELOPT_BINARY))
+               tmp.tc.c_lflag &= ~ISTRIP;
+       else
+               tmp.tc.c_lflag |= ISTRIP;
+#endif
        onoff = 1;
     }
 
        onoff = 1;
     }
 
@@ -425,12 +444,14 @@ register int f;
            (void) signal(SIGTSTP, SIG_DFL);
            sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
        }
            (void) signal(SIGTSTP, SIG_DFL);
            sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
        }
+       ioctl(tin, TIOCLSET, (char *)&lmode);
        ioctl(tin, TIOCSLTC, (char *)&ltc);
        ioctl(tin, TIOCSETC, (char *)&tc);
        ioctl(tin, TIOCSETP, (char *)&sb);
     } else {
        (void) signal(SIGTSTP, SIG_DFL);
        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
        ioctl(tin, TIOCSLTC, (char *)&ltc);
        ioctl(tin, TIOCSETC, (char *)&tc);
        ioctl(tin, TIOCSETP, (char *)&sb);
     } else {
        (void) signal(SIGTSTP, SIG_DFL);
        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+       ioctl(tin, TIOCLSET, (char *)&lmode);
        ioctl(tin, TIOCSLTC, (char *)&oltc);
        ioctl(tin, TIOCSETC, (char *)&otc);
        ioctl(tin, TIOCSETP, (char *)&ottyb);
        ioctl(tin, TIOCSLTC, (char *)&oltc);
        ioctl(tin, TIOCSETC, (char *)&otc);
        ioctl(tin, TIOCSETP, (char *)&ottyb);
index 8a57815..2922ccd 100644 (file)
@@ -13,7 +13,7 @@
 .\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 .\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
 .\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 .\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.\"    @(#)telnet.1    6.7 (Berkeley) %G%
+.\"    @(#)telnet.1    6.8 (Berkeley) %G%
 .\"
 .TH TELNET 1 ""
 .UC 5
 .\"
 .TH TELNET 1 ""
 .UC 5
@@ -320,6 +320,15 @@ Sends the
 (Go Ahead)
 sequence, which likely has no significance to the remote system.
 .TP
 (Go Ahead)
 sequence, which likely has no significance to the remote system.
 .TP
+.B getstatus
+.br
+If the remote side supports the
+\s-1TELNET STATUS\s+1
+command,
+.B getstatus
+will send the subnegotiation to request that the server send
+its current option status.
+.TP
 .B ip
 .br
 Sends the
 .B ip
 .br
 Sends the
@@ -780,7 +789,19 @@ The initial value of this toggle is FALSE.
 .br
 Enable or disable the
 \s-1TELNET BINARY\s+1
 .br
 Enable or disable the
 \s-1TELNET BINARY\s+1
-option.
+option on both input and output.
+.TP
+.B inbinary
+.br
+Enable or disable the
+\s-1TELNET BINARY\s+1
+option on input.
+.TP
+.B outbinary
+.br
+Enable or disable the
+\s-1TELNET BINARY\s+1
+option on output.
 .TP
 .B crlf
 .br
 .TP
 .B crlf
 .br
index 19e4b5b..e915383 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnet.c   5.42 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnet.c   5.43 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -38,6 +38,8 @@ static char sccsid[] = "@(#)telnet.c  5.42 (Berkeley) %G%";
 #include <string.h>
 #endif /* defined(unix) */
 
 #include <string.h>
 #endif /* defined(unix) */
 
+#include <ctype.h>
+
 #include "ring.h"
 
 #include "defines.h"
 #include "ring.h"
 
 #include "defines.h"
@@ -323,10 +325,12 @@ willoption(option)
                }
                    /* Fall through */
            case TELOPT_EOR:
                }
                    /* Fall through */
            case TELOPT_EOR:
-           case TELOPT_BINARY:
 #endif     /* defined(TN3270) */
 #endif     /* defined(TN3270) */
+           case TELOPT_BINARY:
            case TELOPT_SGA:
                settimer(modenegotiated);
            case TELOPT_SGA:
                settimer(modenegotiated);
+               /* FALL THROUGH */
+           case TELOPT_STATUS:
                new_state_ok = 1;
                break;
 
                new_state_ok = 1;
                break;
 
@@ -438,8 +442,8 @@ dooption(option)
 
 #      if defined(TN3270)
            case TELOPT_EOR:            /* end of record */
 
 #      if defined(TN3270)
            case TELOPT_EOR:            /* end of record */
-           case TELOPT_BINARY:         /* binary mode */
 #      endif   /* defined(TN3270) */
 #      endif   /* defined(TN3270) */
+           case TELOPT_BINARY:         /* binary mode */
            case TELOPT_NAWS:           /* window size */
            case TELOPT_TSPEED:         /* terminal speed */
            case TELOPT_LFLOW:          /* local flow control */
            case TELOPT_NAWS:           /* window size */
            case TELOPT_TSPEED:         /* terminal speed */
            case TELOPT_LFLOW:          /* local flow control */
@@ -513,6 +517,181 @@ dontoption(option)
        set_my_state_wont(option);
 }
 
        set_my_state_wont(option);
 }
 
+/*
+ * Given a buffer returned by tgetent(), this routine will turn
+ * the pipe seperated list of names in the buffer into an array
+ * of pointers to null terminated names.  We toss out any bad,
+ * duplicate, or verbose names (names with spaces).
+ */
+
+static char *unknown[] = { "UNKNOWN", 0 };
+
+char **
+mklist(buf, name)
+char *buf, *name;
+{
+       register int n;
+       register char c, *cp, **argvp, *cp2, **argv;
+       char *malloc();
+
+       if (name) {
+               if (strlen(name) > 40)
+                       name = 0;
+               else {
+                       unknown[0] = name;
+                       upcase(name);
+               }
+       }
+       /*
+        * Count up the number of names.
+        */
+       for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
+               if (*cp == '|')
+                       n++;
+       }
+       /*
+        * Allocate an array to put the name pointers into
+        */
+       argv = (char **)malloc((n+3)*sizeof(char *));
+       if (argv == 0)
+               return(unknown);
+
+       /*
+        * Fill up the array of pointers to names.
+        */
+       *argv = 0;
+       argvp = argv+1;
+       n = 0;
+       for (cp = cp2 = buf; (c = *cp);  cp++) {
+               if (c == '|' || c == ':') {
+                       *cp++ = '\0';
+                       /*
+                        * Skip entries that have spaces or are over 40
+                        * characters long.  If this is our environment
+                        * name, then put it up front.  Otherwise, as
+                        * long as this is not a duplicate name (case
+                        * insensitive) add it to the list.
+                        */
+                       if (n || (cp - cp2 > 41))
+                               ;
+                       else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
+                               *argv = cp2;
+                       else if (is_unique(cp2, argv+1, argvp))
+                               *argvp++ = cp2;
+                       if (c == ':')
+                               break;
+                       /*
+                        * Skip multiple delimiters. Reset cp2 to
+                        * the beginning of the next name. Reset n,
+                        * the flag for names with spaces.
+                        */
+                       while ((c = *cp) == '|')
+                               cp++;
+                       cp2 = cp;
+                       n = 0;
+               }
+               /*
+                * Skip entries with spaces or non-ascii values.
+                * Convert lower case letters to upper case.
+                */
+               if ((c == ' ') || !isascii(c))
+                       n = 1;
+               else if (islower(c))
+                       *cp = toupper(c);
+       }
+       
+       /*
+        * Check for an old V6 2 character name.  If the second
+        * name points to the beginning of the buffer, and is
+        * only 2 characters long, move it to the end of the array.
+        */
+       if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
+               *argvp++ = buf;
+               cp = *argv++;
+               *argv = cp;
+       }
+
+       /*
+        * Duplicate last name, for TTYPE option, and null
+        * terminate the array.  If we didn't find a match on
+        * our terminal name, put that name at the beginning.
+        */
+       cp = *(argvp-1);
+       *argvp++ = cp;
+       *argvp = 0;
+
+       if (*argv == 0) {
+               if (name)
+                       *argv = name;
+               else
+                       argv++;
+       }
+       if (*argv)
+               return(argv);
+       else
+               return(unknown);
+}
+
+is_unique(name, as, ae)
+register char *name, **as, **ae;
+{
+       register char **ap;
+       register int n;
+
+       n = strlen(name) + 1;
+       for (ap = as; ap < ae; ap++)
+               if (strncasecmp(*ap, name, n) == 0)
+                       return(0);
+       return (1);
+}
+
+#ifdef TERMCAP
+char ttytype[1024];
+setupterm(tname, fd, errp)
+char *tname;
+int fd, *errp;
+{
+       if (tgetent(ttytype, tname) == 1) {
+               ttytype[1023] = '\0';
+               if (errp)
+                       *errp = 1;
+               return(0);
+       }
+       if (errp)
+               *errp = 0;
+       return(-1);
+}
+#endif
+
+char *
+gettermname()
+{
+       char *tname;
+       static int first = 1;
+       extern char ttytype[];
+       static char **tnamep;
+       static char **next;
+       char *getenv();
+       int err;
+
+       if (first) {
+               first = 0;
+               if ((tname = getenv("TERM")) &&
+                               (setupterm(tname, 1, &err) == 0)) {
+                       tnamep = mklist(ttytype, tname);
+               } else {
+                       if (tname && (strlen(tname) <= 40)) {
+                               unknown[0] = tname;
+                               upcase(tname);
+                       }
+                       tnamep = unknown;
+               }
+               next = tnamep;
+       }
+       if (*next == 0)
+               next = tnamep;
+       return(*next++);
+}
 /*
  * suboption()
  *
 /*
  * suboption()
  *
@@ -527,9 +706,6 @@ dontoption(option)
  *             Linemode
  */
 
  *             Linemode
  */
 
-static char tty1[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 0 };
-static char tty2[] = { IAC, SE, 0 };
-
 static void
 suboption()
 {
 static void
 suboption()
 {
@@ -543,6 +719,7 @@ suboption()
        } else {
            char *name;
            extern char *getenv();
        } else {
            char *name;
            extern char *getenv();
+           char temp[50];
            int len;
 
 #if    defined(TN3270)
            int len;
 
 #if    defined(TN3270)
@@ -550,21 +727,13 @@ suboption()
                return;
            }
 #endif /* defined(TN3270) */
                return;
            }
 #endif /* defined(TN3270) */
-           name = getenv("TERM");
-           if ((name == 0) || ((len = strlen(name)) > 40)) {
-               name = "UNKNOWN";
-               len = strlen(name);
-           }
-           if ((len + 4+2) < NETROOM()) {
-               char temp[50];
-
-               strcpy(temp, tty1);
-               strcpy(&temp[4], name);
-               upcase(&temp[4]);
-               strcpy(&temp[4+len], tty2);
-               len += 6;
+           name = gettermname();
+           len = strlen(name) + 4 + 2;
+           if (len < NETROOM()) {
+               sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+                               TELQUAL_IS, name, IAC, SE);
                ring_supply_data(&netoring, temp, len);
                ring_supply_data(&netoring, temp, len);
-               printsub('>', temp+2, len-2);
+               printsub('>', &temp[2], len-2);
            } else {
                ExitString("No room in buffer for terminal type.\n", 1);
                /*NOTREACHED*/
            } else {
                ExitString("No room in buffer for terminal type.\n", 1);
                /*NOTREACHED*/
@@ -1465,6 +1634,7 @@ telnet()
        send_will(TELOPT_TSPEED, 1);
        send_will(TELOPT_LFLOW, 1);
        send_will(TELOPT_LINEMODE, 1);
        send_will(TELOPT_TSPEED, 1);
        send_will(TELOPT_LFLOW, 1);
        send_will(TELOPT_LINEMODE, 1);
+       send_do(TELOPT_STATUS, 1);
     }
 #   endif /* !defined(TN3270) */
 
     }
 #   endif /* !defined(TN3270) */
 
@@ -1644,6 +1814,7 @@ void
 xmitAO()
 {
     NET2ADD(IAC, AO);
 xmitAO()
 {
     NET2ADD(IAC, AO);
+    printoption("SENT", "IAC", AO);
     if (autoflush) {
        doflush();
     }
     if (autoflush) {
        doflush();
     }
@@ -1654,12 +1825,14 @@ void
 xmitEL()
 {
     NET2ADD(IAC, EL);
 xmitEL()
 {
     NET2ADD(IAC, EL);
+    printoption("SENT", "IAC", EL);
 }
 
 void
 xmitEC()
 {
     NET2ADD(IAC, EC);
 }
 
 void
 xmitEC()
 {
     NET2ADD(IAC, EC);
+    printoption("SENT", "IAC", EC);
 }
 
 
 }
 
 
@@ -1674,16 +1847,45 @@ dosynch()
     NETADD(IAC);
     setneturg();
     NETADD(DM);
     NETADD(IAC);
     setneturg();
     NETADD(DM);
+    printoption("SENT", "IAC", DM);
 
 #if    defined(NOT43)
     return 0;
 #endif /* defined(NOT43) */
 }
 
 
 #if    defined(NOT43)
     return 0;
 #endif /* defined(NOT43) */
 }
 
+void
+get_status()
+{
+    char tmp[16];
+    register char *cp;
+
+    if (my_want_state_is_dont(TELOPT_STATUS)) {
+       printf("Remote side does not support STATUS option\n");
+       return;
+    }
+    if (!showoptions)
+       printf("You will not see the response unless you set \"options\"\n");
+
+    cp = tmp;
+
+    *cp++ = IAC;
+    *cp++ = SB;
+    *cp++ = TELOPT_STATUS;
+    *cp++ = TELQUAL_SEND;
+    *cp++ = IAC;
+    *cp++ = SE;
+    if (NETROOM() >= cp - tmp) {
+       ring_supply_data(&netoring, tmp, cp-tmp);
+       printsub('>', tmp+2, cp - tmp - 2);
+    }
+}
+
 void
 intp()
 {
     NET2ADD(IAC, IP);
 void
 intp()
 {
     NET2ADD(IAC, IP);
+    printoption("SENT", "IAC", IP);
     flushline = 1;
     if (autoflush) {
        doflush();
     flushline = 1;
     if (autoflush) {
        doflush();
@@ -1697,6 +1899,7 @@ void
 sendbrk()
 {
     NET2ADD(IAC, BREAK);
 sendbrk()
 {
     NET2ADD(IAC, BREAK);
+    printoption("SENT", "IAC", BREAK);
     flushline = 1;
     if (autoflush) {
        doflush();
     flushline = 1;
     if (autoflush) {
        doflush();
@@ -1710,6 +1913,7 @@ void
 sendabort()
 {
     NET2ADD(IAC, ABORT);
 sendabort()
 {
     NET2ADD(IAC, ABORT);
+    printoption("SENT", "IAC", ABORT);
     flushline = 1;
     if (autoflush) {
        doflush();
     flushline = 1;
     if (autoflush) {
        doflush();
@@ -1723,6 +1927,7 @@ void
 sendsusp()
 {
     NET2ADD(IAC, SUSP);
 sendsusp()
 {
     NET2ADD(IAC, SUSP);
+    printoption("SENT", "IAC", SUSP);
     flushline = 1;
     if (autoflush) {
        doflush();
     flushline = 1;
     if (autoflush) {
        doflush();
@@ -1735,7 +1940,8 @@ sendsusp()
 void
 sendeof()
 {
 void
 sendeof()
 {
-   NET2ADD(IAC, xEOF);
+    NET2ADD(IAC, xEOF);
+    printoption("SENT", "IAC", xEOF);
 }
 
 /*
 }
 
 /*
@@ -1774,14 +1980,20 @@ sendnaws()
     }
 }
 
     }
 }
 
-tel_enter_binary()
+tel_enter_binary(rw)
+int rw;
 {
 {
-    send_do(TELOPT_BINARY, 1);
-    send_will(TELOPT_BINARY, 1);
+    if (rw&1)
+       send_do(TELOPT_BINARY, 1);
+    if (rw&2)
+       send_will(TELOPT_BINARY, 1);
 }
 
 }
 
-tel_leave_binary()
+tel_leave_binary(rw)
+int rw;
 {
 {
-    send_dont(TELOPT_BINARY, 1);
-    send_wont(TELOPT_BINARY, 1);
+    if (rw&1)
+       send_dont(TELOPT_BINARY, 1);
+    if (rw&2)
+       send_wont(TELOPT_BINARY, 1);
 }
 }
index a86dce9..af73ea4 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utilities.c        1.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)utilities.c        1.15 (Berkeley) %G%";
 #endif /* not lint */
 
 #define        TELOPTS
 #endif /* not lint */
 
 #define        TELOPTS
@@ -129,27 +129,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;
@@ -268,32 +270,34 @@ int       length;                 /* length of suboption data */
     register int i;
 
     if (showoptions) {
     register int i;
 
     if (showoptions) {
-       fprintf(NetTrace, "%s suboption ",
+       if (direction) {
+           fprintf(NetTrace, "%s suboption ",
                                (direction == '<')? "Received":"Sent");
                                (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!) ");
+           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;
@@ -321,7 +325,7 @@ int length;                 /* length of suboption data */
                break;
            }
            switch (pointer[1]) {
                break;
            }
            switch (pointer[1]) {
-           case 0:
+           case TELQUAL_IS:
                fprintf(NetTrace, " IS ");
                fprintf(NetTrace, "%.*s", length-2, pointer+2);
                break;
                fprintf(NetTrace, " IS ");
                fprintf(NetTrace, "%.*s", length-2, pointer+2);
                break;
@@ -471,16 +475,97 @@ 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)");
+               for (i = 2; i < length; i++)
+                   fprintf(NetTrace, " ?%d?", pointer[i]);
+               break;
+           case TELQUAL_IS:
+               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(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;
+         }
+
        default:
            fprintf(NetTrace, "Unknown option ");
            for (i = 0; i < length; i++)
                fprintf(NetTrace, " %d", pointer[i]);
            break;
        }
        default:
            fprintf(NetTrace, "Unknown option ");
            for (i = 0; i < length; i++)
                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");
+       }
     }
 }
 
     }
 }