Lots of bugfixes, add the ENVIRON and X-DISPLAY-LOC
authorPaul Borman <borman@ucbvax.Berkeley.EDU>
Fri, 29 Jun 1990 04:06:55 +0000 (20:06 -0800)
committerPaul Borman <borman@ucbvax.Berkeley.EDU>
Fri, 29 Jun 1990 04:06:55 +0000 (20:06 -0800)
options, "-l user" to the command line, diagnostic flags.

SCCS-vsn: usr.bin/telnet/ring.c 1.13
SCCS-vsn: usr.bin/telnet/terminal.c 1.21
SCCS-vsn: usr.bin/telnet/network.c 1.15
SCCS-vsn: usr.bin/telnet/general.h 1.5
SCCS-vsn: usr.bin/telnet/ring.h 1.10
SCCS-vsn: usr.bin/telnet/externs.h 1.25
SCCS-vsn: usr.bin/telnet/tn3270.c 1.21
SCCS-vsn: usr.bin/telnet/telnet.c 5.50
SCCS-vsn: usr.bin/telnet/sys_bsd.c 1.27
SCCS-vsn: usr.bin/telnet/utilities.c 1.19
SCCS-vsn: usr.bin/telnet/telnet.1 6.10
SCCS-vsn: usr.bin/telnet/defines.h 1.10
SCCS-vsn: usr.bin/telnet/main.c 1.14
SCCS-vsn: usr.bin/telnet/commands.c 1.30
SCCS-vsn: usr.bin/telnet/Makefile 5.3
SCCS-vsn: libexec/telnetd/telnetd.c 5.45
SCCS-vsn: libexec/telnetd/telnetd.8 6.7
SCCS-vsn: libexec/telnetd/Makefile 5.10
SCCS-vsn: libexec/telnetd/defs.h 5.8
SCCS-vsn: libexec/telnetd/ext.h 5.6
SCCS-vsn: libexec/telnetd/pathnames.h 5.5
SCCS-vsn: libexec/telnetd/slc.c 5.4
SCCS-vsn: libexec/telnetd/state.c 5.7
SCCS-vsn: libexec/telnetd/sys_term.c 5.8
SCCS-vsn: libexec/telnetd/utility.c 5.4
SCCS-vsn: libexec/telnetd/termstat.c 5.6

26 files changed:
usr/src/libexec/telnetd/Makefile
usr/src/libexec/telnetd/defs.h
usr/src/libexec/telnetd/ext.h
usr/src/libexec/telnetd/pathnames.h
usr/src/libexec/telnetd/slc.c
usr/src/libexec/telnetd/state.c
usr/src/libexec/telnetd/sys_term.c
usr/src/libexec/telnetd/telnetd.8
usr/src/libexec/telnetd/telnetd.c
usr/src/libexec/telnetd/termstat.c
usr/src/libexec/telnetd/utility.c
usr/src/usr.bin/telnet/Makefile
usr/src/usr.bin/telnet/commands.c
usr/src/usr.bin/telnet/defines.h
usr/src/usr.bin/telnet/externs.h
usr/src/usr.bin/telnet/general.h
usr/src/usr.bin/telnet/main.c
usr/src/usr.bin/telnet/network.c
usr/src/usr.bin/telnet/ring.c
usr/src/usr.bin/telnet/ring.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/terminal.c
usr/src/usr.bin/telnet/tn3270.c
usr/src/usr.bin/telnet/utilities.c

index 40ba8cd..7380c3b 100644 (file)
@@ -1,11 +1,12 @@
-#      @(#)Makefile    5.9 (Berkeley) %G%
+#      @(#)Makefile    5.10 (Berkeley) %G%
 
 PROG=  telnetd
 
 PROG=  telnetd
+CFLAGS+=-DNEED_GETTOS -DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO -DDIAGNOSTICS
 SRCS=  get_date.c gettytab.c global.c slc.c state.c sys_term.c telnetd.c \
        termstat.c utility.c
 DPADD= ${LIBUTIL} ${LIBTERM}
 LDADD= -lutil -ltermcap
 MAN8=  telnetd.0
 SRCS=  get_date.c gettytab.c global.c slc.c state.c sys_term.c telnetd.c \
        termstat.c utility.c
 DPADD= ${LIBUTIL} ${LIBTERM}
 LDADD= -lutil -ltermcap
 MAN8=  telnetd.0
-.PATH: ${.CURDIR}/../getty
+.PATH: /usr/src/libexec/getty
 
 .include <bsd.prog.mk>
 
 .include <bsd.prog.mk>
index b33b31c..ea760ca 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)defs.h      5.7 (Berkeley) %G%
+ *     @(#)defs.h      5.8 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 # define       BSD 43
 #endif
 
 # define       BSD 43
 #endif
 
-#if BSD > 43
-#define        USE_TERMIO
+#if    defined(CRAY) && !defined(LINEMODE)
+# define SYSV_TERMIO
+# define LINEMODE
+# define KLUDGELINEMODE
+# define NO_GETTYTAB
+# define DIAGNOSTICS
+# if !defined(UNICOS5)
+#  define BFTPDAEMON
+#  define HAS_IP_TOS
+# endif
+#endif /* CRAY */
+#if defined(UNICOS5) && !defined(NO_SETSID)
+# define NO_SETSID
 #endif
 
 #endif
 
-#ifdef CRAY
-# define       NEWINIT
-# define       SYSV_TERMIO
-# define       NO_GETTYTAB
-# define       signal sigset
-#endif /* CRAY */
+#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS)
+#define TELOPTS
+#define TELCMDS
+#endif
 
 
-#ifdef SYSV_TERMIO
+#if    defined(SYSV_TERMIO) && !defined(USE_TERMIO)
 # define       USE_TERMIO
 #endif
 
 # define       USE_TERMIO
 #endif
 
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#ifndef        FILIO_H
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
 
 #include <netinet/in.h>
 
 #include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
 
 #include <arpa/telnet.h>
 
 
 #include <arpa/telnet.h>
 
 #define        LOG_ODELAY      0
 #endif
 #include <ctype.h>
 #define        LOG_ODELAY      0
 #endif
 #include <ctype.h>
+#ifndef NO_STRING_H
 #include <string.h>
 #include <string.h>
+#else
+#include <strings.h>
+#endif
 
 #ifndef        USE_TERMIO
 #include <sgtty.h>
 
 #ifndef        USE_TERMIO
 #include <sgtty.h>
-typedef unsigned char cc_t;
 #else
 # ifdef        SYSV_TERMIO
 # include <termio.h>
 #else
 # ifdef        SYSV_TERMIO
 # include <termio.h>
@@ -71,6 +85,9 @@ typedef unsigned char cc_t;
 # include <termios.h>
 # endif
 #endif
 # include <termios.h>
 # endif
 #endif
+#if !defined(USE_TERMIO) || defined(NO_CC_T)
+typedef unsigned char cc_t;
+#endif
 
 #ifdef CRAY
 #include <sys/fcntl.h>
 
 #ifdef CRAY
 #include <sys/fcntl.h>
@@ -84,9 +101,8 @@ typedef unsigned char cc_t;
 #include <memory.h>
 #endif /* CRAY */
 
 #include <memory.h>
 #endif /* CRAY */
 
-#if    defined(TCSIG) || defined(TIOCPKT_IOCTL)
-# define       LINEMODE
-# define       KLUDGELINEMODE
+#if    !defined(TIOCSCTTY) && defined(TCSETCTTY)
+# define       TIOCSCTTY TCSETCTTY
 #endif
 
 #ifndef        FD_SET
 #endif
 
 #ifndef        FD_SET
@@ -100,11 +116,6 @@ typedef struct fd_set { int fds_bits[1]; } fd_set;
 #define FD_ZERO(p)     ((p)->fds_bits[0] = 0)
 #endif /* FD_SET */
 
 #define FD_ZERO(p)     ((p)->fds_bits[0] = 0)
 #endif /* FD_SET */
 
-#define        OPT_NO                  0               /* won't do this option */
-#define        OPT_YES                 1               /* will do this option */
-#define        OPT_YES_BUT_ALWAYS_LOOK 2
-#define        OPT_NO_BUT_ALWAYS_LOOK  3
-
 /*
  * I/O data buffers defines
  */
 /*
  * I/O data buffers defines
  */
@@ -143,3 +154,92 @@ typedef struct {
        cc_t            *sptr;          /* a pointer to the char in */
                                        /* system data structures */
 } slcfun, *Slcfun;
        cc_t            *sptr;          /* a pointer to the char in */
                                        /* system data structures */
 } slcfun, *Slcfun;
+
+#ifdef DIAGNOSTICS
+/*
+ * Diagnostics capabilities
+ */
+#define        TD_REPORT       0x01    /* Report operations to client */
+#define TD_EXERCISE    0x02    /* Exercise client's implementation */
+#define TD_NETDATA     0x04    /* Display received data stream */
+#define TD_PTYDATA     0x08    /* Display data passed to pty */
+#define        TD_OPTIONS      0x10    /* Report just telnet options */
+#endif /* DIAGNOSTICS */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define        MY_STATE_WILL           0x01
+#define        MY_WANT_STATE_WILL      0x02
+#define        MY_STATE_DO             0x04
+#define        MY_WANT_STATE_DO        0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define        my_state_is_do(opt)             (options[opt]&MY_STATE_DO)
+#define        my_state_is_will(opt)           (options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt)       (options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt)     (options[opt]&MY_WANT_STATE_WILL)
+
+#define        my_state_is_dont(opt)           (!my_state_is_do(opt))
+#define        my_state_is_wont(opt)           (!my_state_is_will(opt))
+#define my_want_state_is_dont(opt)     (!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt)     (!my_want_state_is_will(opt))
+
+#define        set_my_state_do(opt)            (options[opt] |= MY_STATE_DO)
+#define        set_my_state_will(opt)          (options[opt] |= MY_STATE_WILL)
+#define        set_my_want_state_do(opt)       (options[opt] |= MY_WANT_STATE_DO)
+#define        set_my_want_state_will(opt)     (options[opt] |= MY_WANT_STATE_WILL)
+
+#define        set_my_state_dont(opt)          (options[opt] &= ~MY_STATE_DO)
+#define        set_my_state_wont(opt)          (options[opt] &= ~MY_STATE_WILL)
+#define        set_my_want_state_dont(opt)     (options[opt] &= ~MY_WANT_STATE_DO)
+#define        set_my_want_state_wont(opt)     (options[opt] &= ~MY_WANT_STATE_WILL)
+
+/*
+ * Tricky code here.  What we want to know is if the MY_STATE_WILL
+ * and MY_WANT_STATE_WILL bits have the same value.  Since the two
+ * bits are adjacent, a little arithmatic will show that by adding
+ * in the lower bit, the upper bit will be set if the two bits were
+ * different, and clear if they were the same.
+ */
+#define my_will_wont_is_changing(opt) \
+                       ((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL)
+
+#define my_do_dont_is_changing(opt) \
+                       ((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO)
+
+/*
+ * Make everything symetrical
+ */
+
+#define        HIS_STATE_WILL                  MY_STATE_DO
+#define        HIS_WANT_STATE_WILL             MY_WANT_STATE_DO
+#define HIS_STATE_DO                   MY_STATE_WILL
+#define HIS_WANT_STATE_DO              MY_WANT_STATE_WILL
+
+#define        his_state_is_do                 my_state_is_will
+#define        his_state_is_will               my_state_is_do
+#define his_want_state_is_do           my_want_state_is_will
+#define his_want_state_is_will         my_want_state_is_do
+
+#define        his_state_is_dont               my_state_is_wont
+#define        his_state_is_wont               my_state_is_dont
+#define his_want_state_is_dont         my_want_state_is_wont
+#define his_want_state_is_wont         my_want_state_is_dont
+
+#define        set_his_state_do                set_my_state_will
+#define        set_his_state_will              set_my_state_do
+#define        set_his_want_state_do           set_my_want_state_will
+#define        set_his_want_state_will         set_my_want_state_do
+
+#define        set_his_state_dont              set_my_state_wont
+#define        set_his_state_wont              set_my_state_dont
+#define        set_his_want_state_dont         set_my_want_state_wont
+#define        set_his_want_state_wont         set_my_want_state_dont
+
+#define his_will_wont_is_changing      my_do_dont_is_changing
+#define his_do_dont_is_changing                my_will_wont_is_changing
index bdd9570..d112c6a 100644 (file)
@@ -4,16 +4,13 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ext.h       5.5 (Berkeley) %G%
+ *     @(#)ext.h       5.6 (Berkeley) %G%
  */
 
 /*
  * Telnet server variable declarations
  */
  */
 
 /*
  * Telnet server variable declarations
  */
-extern char    hisopts[256];
-extern char    myopts[256];
-extern char    hiswants[256];
-extern char    mywants[256];
+extern char    options[256];
 extern char    do_dont_resp[256];
 extern char    will_wont_resp[256];
 extern int     linemode;       /* linemode on/off */
 extern char    do_dont_resp[256];
 extern char    will_wont_resp[256];
 extern int     linemode;       /* linemode on/off */
@@ -27,6 +24,12 @@ extern int   lmodetype;      /* Client support for linemode */
 # endif        /* KLUDGELINEMODE */
 #endif /* LINEMODE */
 extern int     flowmode;       /* current flow control state */
 # endif        /* KLUDGELINEMODE */
 #endif /* LINEMODE */
 extern int     flowmode;       /* current flow control state */
+#ifdef DIAGNOSTICS
+extern int     diagnostic;     /* telnet diagnostic capabilities */
+#endif /* DIAGNOSTICS */
+#ifdef BFTPDAEMON
+extern int     bftpd;          /* behave as bftp daemon */
+#endif /* BFTPDAEMON */
 
 extern slcfun  slctab[NSLC + 1];       /* slc mapping table */
 
 
 extern slcfun  slctab[NSLC + 1];       /* slc mapping table */
 
@@ -53,6 +56,11 @@ extern int   pty, net;
 extern char    *line;
 extern int     SYNCHing;               /* we are in TELNET SYNCH mode */
 
 extern char    *line;
 extern int     SYNCHing;               /* we are in TELNET SYNCH mode */
 
+#ifdef DIAGNOSTICS
+extern void printoption();
+extern void printdata();
+#endif
+
 /*
  * The following are some clocks used to decide how to interpret
  * the relationship between various variables.
 /*
  * The following are some clocks used to decide how to interpret
  * the relationship between various variables.
@@ -66,6 +74,8 @@ extern struct {
        didnetreceive,          /* last time we read data from network */
        ttypesubopt,            /* ttype subopt is received */
        tspeedsubopt,           /* tspeed subopt is received */
        didnetreceive,          /* last time we read data from network */
        ttypesubopt,            /* ttype subopt is received */
        tspeedsubopt,           /* tspeed subopt is received */
+       environsubopt,          /* environ subopt is received */
+       xdisplocsubopt,         /* xdisploc subopt is received */
        baseline,               /* time started to do timed action */
        gotDM;                  /* when did we last see a data mark */
 } clocks;
        baseline,               /* time started to do timed action */
        gotDM;                  /* when did we last see a data mark */
 } clocks;
index cb532e0..c248061 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)pathnames.h 5.4 (Berkeley) %G%
+ *     @(#)pathnames.h 5.5 (Berkeley) %G%
  */
 
 #if BSD > 43
  */
 
 #if BSD > 43
@@ -19,3 +19,7 @@
 # define       _PATH_LOGIN     "/bin/login"
 
 #endif
 # define       _PATH_LOGIN     "/bin/login"
 
 #endif
+
+#ifdef BFTPDAEMON
+#define                BFTPPATH        "/usr/ucb/bftp"
+#endif  /* BFTPDAEMON */
index 69425f5..d1fde04 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)slc.c      5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)slc.c      5.4 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -15,11 +15,11 @@ static char sccsid[] = "@(#)slc.c   5.3 (Berkeley) %G%";
 /*
  * local varibles
  */
 /*
  * local varibles
  */
-static char    *def_slcbuf = (char *)0;
-static int     def_slclen = 0;
-static int     slcchange;      /* change to slc is requested */
-static char    *slcptr;        /* pointer into slc buffer */
-static char    slcbuf[NSLC*6]; /* buffer for slc negotiation */
+static unsigned char   *def_slcbuf = (unsigned char *)0;
+static int             def_slclen = 0;
+static int             slcchange;      /* change to slc is requested */
+static unsigned char   *slcptr;        /* pointer into slc buffer */
+static unsigned char   slcbuf[NSLC*6]; /* buffer for slc negotiation */
 
 /*
  * send_slc
 
 /*
  * send_slc
@@ -133,7 +133,7 @@ start_slc(getit)
  * Finish up the slc negotiation.  If something to send, then send it.
  */
 end_slc(bufp)
  * Finish up the slc negotiation.  If something to send, then send it.
  */
 end_slc(bufp)
-register char **bufp;
+register unsigned char **bufp;
 {
        register int len;
        void netflush();
 {
        register int len;
        void netflush();
@@ -407,10 +407,10 @@ register int len;
                 * save this slc buffer if it is the first, otherwise dump
                 * it.
                 */
                 * save this slc buffer if it is the first, otherwise dump
                 * it.
                 */
-               if (def_slcbuf == (char *)0) {
+               if (def_slcbuf == (unsigned char *)0) {
                        def_slclen = len;
                        def_slclen = len;
-                       def_slcbuf = malloc((unsigned)len);
-                       if (def_slcbuf == (char *)0)
+                       def_slcbuf = (unsigned char *)malloc((unsigned)len);
+                       if (def_slcbuf == (unsigned char *)0)
                                return;  /* too bad */
                        bcopy(ptr, def_slcbuf, len);
                }
                                return;  /* too bad */
                        bcopy(ptr, def_slcbuf, len);
                }
@@ -430,7 +430,7 @@ deferslc()
                do_opt_slc(def_slcbuf, def_slclen);
                end_slc(0);
                free(def_slcbuf);
                do_opt_slc(def_slcbuf, def_slclen);
                end_slc(0);
                free(def_slcbuf);
-               def_slcbuf = (char *)0;
+               def_slcbuf = (unsigned char *)0;
                def_slclen = 0;
        }
 
                def_slclen = 0;
        }
 
index 13ff461..98f2e73 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)state.c    5.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)state.c    5.7 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -30,6 +30,7 @@ char  subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
                        }
 #define        SB_GET()        ((*subpointer++)&0xff)
 #define        SB_EOF()        (subpointer >= subend)
                        }
 #define        SB_GET()        ((*subpointer++)&0xff)
 #define        SB_EOF()        (subpointer >= subend)
+#define        SB_LEN()        (subend - subpointer)
 
 
 
 
 
 
@@ -84,7 +85,7 @@ telrcv()
                         * unix way of saying that (\r is only good
                         * if CRMOD is set, which it normally is).
                         */
                         * unix way of saying that (\r is only good
                         * if CRMOD is set, which it normally is).
                         */
-                       if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
+                       if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
                                /*
                                 * If we are operating in linemode,
                                 * convert to local end-of-line.
                                /*
                                 * If we are operating in linemode,
                                 * convert to local end-of-line.
@@ -108,10 +109,18 @@ gotiac:                   switch (c) {
                         * interrupt char; depending on the tty mode.
                         */
                        case IP:
                         * interrupt char; depending on the tty mode.
                         */
                        case IP:
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                interrupt();
                                break;
 
                        case BREAK:
                                interrupt();
                                break;
 
                        case BREAK:
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                sendbrk();
                                break;
 
                                sendbrk();
                                break;
 
@@ -119,6 +128,10 @@ gotiac:                    switch (c) {
                         * Are You There?
                         */
                        case AYT:
                         * Are You There?
                         */
                        case AYT:
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
                                nfrontp += 9;
                                break;
                                (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
                                nfrontp += 9;
                                break;
@@ -128,6 +141,10 @@ gotiac:                    switch (c) {
                         */
                        case AO:
                            {
                         */
                        case AO:
                            {
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                ptyflush();     /* half-hearted */
                                init_termbuf();
 
                                ptyflush();     /* half-hearted */
                                init_termbuf();
 
@@ -141,6 +158,10 @@ gotiac:                    switch (c) {
                                *nfrontp++ = IAC;
                                *nfrontp++ = DM;
                                neturg = nfrontp-1; /* off by one XXX */
                                *nfrontp++ = IAC;
                                *nfrontp++ = DM;
                                neturg = nfrontp-1; /* off by one XXX */
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: send IAC", DM);
+#endif /* DIAGNOSTICS */
                                break;
                            }
 
                                break;
                            }
 
@@ -153,10 +174,16 @@ gotiac:                   switch (c) {
                            {
                                cc_t ch;
 
                            {
                                cc_t ch;
 
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                ptyflush();     /* half-hearted */
                                init_termbuf();
                                ptyflush();     /* half-hearted */
                                init_termbuf();
-                               ch = (c == EC) ? *slctab[SLC_EC].sptr :
-                                                *slctab[SLC_EL].sptr;
+                               if (c == EC)
+                                       ch = *slctab[SLC_EC].sptr;
+                               else
+                                       ch = *slctab[SLC_EL].sptr;
                                if (ch != (cc_t)-1)
                                        *pfrontp++ = (unsigned char)ch;
                                break;
                                if (ch != (cc_t)-1)
                                        *pfrontp++ = (unsigned char)ch;
                                break;
@@ -166,6 +193,10 @@ gotiac:                    switch (c) {
                         * Check for urgent data...
                         */
                        case DM:
                         * Check for urgent data...
                         */
                        case DM:
+#ifdef DIAGNOSTICS
+                               if (diagnostic & TD_OPTIONS)
+                                       printoption("td: recv IAC", c);
+#endif /* DIAGNOSTICS */
                                SYNCHing = stilloob(net);
                                settimer(gotDM);
                                break;
                                SYNCHing = stilloob(net);
                                settimer(gotDM);
                                break;
@@ -195,7 +226,7 @@ gotiac:                     switch (c) {
                                state = TS_DONT;
                                continue;
                        case EOR:
                                state = TS_DONT;
                                continue;
                        case EOR:
-                               if (hisopts[TELOPT_EOR])
+                               if (his_state_is_will(TELOPT_EOR))
                                        doeof();
                                break;
 
                                        doeof();
                                break;
 
@@ -241,6 +272,11 @@ gotiac:                    switch (c) {
                                         * then treat remaining stream as
                                         * another command sequence.
                                         */
                                         * then treat remaining stream as
                                         * another command sequence.
                                         */
+#ifdef DIAGNOSTICS
+                                       SB_ACCUM(IAC);
+                                       SB_ACCUM(c);
+                                       subpointer -= 2;
+#endif
                                        SB_TERM();
                                        suboption();
                                        state = TS_IAC;
                                        SB_TERM();
                                        suboption();
                                        state = TS_IAC;
@@ -249,6 +285,11 @@ gotiac:                    switch (c) {
                                SB_ACCUM(c);
                                state = TS_SB;
                        } else {
                                SB_ACCUM(c);
                                state = TS_SB;
                        } else {
+#ifdef DIAGNOSTICS
+                               SB_ACCUM(IAC);
+                               SB_ACCUM(SE);
+                               subpointer -= 2;
+#endif
                                SB_TERM();
                                suboption();    /* handle sub-option */
                                state = TS_DATA;
                                SB_TERM();
                                suboption();    /* handle sub-option */
                                state = TS_DATA;
@@ -300,15 +341,7 @@ gotiac:                    switch (c) {
 
 /*
  * The will/wont/do/dont state machines are based on Dave Borman's
 
 /*
  * The will/wont/do/dont state machines are based on Dave Borman's
- * Telnet option processing state machine.  We keep track of the full
- * state of the option negotiation with the following state variables
- *     myopts, hisopts - The last fully negotiated state for each
- *                     side of the connection.
- *     mywants, hiswants - The state we wish to be in after a completed
- *                     negotiation.  (hiswants is slightly misleading,
- *                     this is more precisely the state I want him to
- *                     be in.
- *     resp - We count the number of requests we have sent out.
+ * Telnet option processing state machine.
  *
  * These correspond to the following states:
  *     my_state = the last negotiated state
  *
  * These correspond to the following states:
  *     my_state = the last negotiated state
@@ -366,8 +399,8 @@ send_do(option, init)
        int option, init;
 {
        if (init) {
        int option, init;
 {
        if (init) {
-               if ((do_dont_resp[option] == 0 && hisopts[option] == OPT_YES) ||
-                   hiswants[option] == OPT_YES)
+               if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
+                   his_want_state_is_will(option))
                        return;
                /*
                 * Special case for TELOPT_TM:  We send a DO, but pretend
                        return;
                /*
                 * Special case for TELOPT_TM:  We send a DO, but pretend
@@ -375,13 +408,21 @@ send_do(option, init)
                 * we want to.
                 */
                if (option == TELOPT_TM)
                 * we want to.
                 */
                if (option == TELOPT_TM)
-                       hiswants[option] = OPT_NO;
+                       set_his_want_state_wont(option);
                else
                else
-                       hiswants[option] = OPT_YES;
+                       set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
        (void) sprintf(nfrontp, doopt, option);
        nfrontp += sizeof (dont) - 2;
                do_dont_resp[option]++;
        }
        (void) sprintf(nfrontp, doopt, option);
        nfrontp += sizeof (dont) - 2;
+#ifdef DIAGNOSTICS
+       /*
+        * Report sending option to other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: send do", option);
+       }
+#endif /* DIAGNOSTICS */
 }
 
 willoption(option)
 }
 
 willoption(option)
@@ -393,13 +434,22 @@ willoption(option)
         * process input from peer.
         */
 
         * process input from peer.
         */
 
+#ifdef DIAGNOSTICS
+       /*
+        * Report receiving option from other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: recv will", option);
+       }
+#endif /* DIAGNOSTICS */
+
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
-               if (do_dont_resp[option] && hisopts[option] == OPT_YES)
+               if (do_dont_resp[option] && his_state_is_will(option))
                        do_dont_resp[option]--;
        }
        if (do_dont_resp[option] == 0) {
                        do_dont_resp[option]--;
        }
        if (do_dont_resp[option] == 0) {
-           if (hiswants[option] != OPT_YES) {
+           if (his_want_state_is_wont(option)) {
                switch (option) {
 
                case TELOPT_BINARY:
                switch (option) {
 
                case TELOPT_BINARY:
@@ -410,40 +460,10 @@ willoption(option)
                        break;
 
                case TELOPT_ECHO:
                        break;
 
                case TELOPT_ECHO:
-                       not42 = 0;      /* looks like a 4.2 system */
-#ifdef notdef
-                       /*
-                        * Now, in a 4.2 system, to break them out of
-                        * ECHOing (to the terminal) mode, we need to
-                        * send a WILL ECHO.
-                        */
-                       if (myopts[TELOPT_ECHO] == OPT_YES) {
-                               send_will(TELOPT_ECHO, 1);
-                       }
-#else
-                       /*
-                        * "WILL ECHO".  Kludge upon kludge!
-                        * A 4.2 client is now echoing user input at
-                        * the tty.  This is probably undesireable and
-                        * it should be stopped.  The client will
-                        * respond WONT TM to the DO TM that we send to
-                        * check for kludge linemode.  When the WONT TM
-                        * arrives, linemode will be turned off and a
-                        * change propogated to the pty.  This change
-                        * will cause us to process the new pty state
-                        * in localstat(), which will notice that
-                        * linemode is off and send a WILL ECHO
-                        * so that we are properly in character mode and
-                        * all is well.
-                        */
-#endif
                        /*
                        /*
-                        * Fool the state machine into sending a don't.
-                        * This also allows the initial echo sending
-                        * code to break out of the loop that it is
-                        * in.  (Look in telnet())
+                        * See comments below for more info.
                         */
                         */
-                       hiswants[TELOPT_ECHO] = OPT_NO;
+                       not42 = 0;      /* looks like a 4.2 system */
                        break;
 
                case TELOPT_TM:
                        break;
 
                case TELOPT_TM:
@@ -476,7 +496,7 @@ willoption(option)
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                        /*
                         * We never respond to a WILL TM, and
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                        /*
                         * We never respond to a WILL TM, and
-                        * we leave the state OPT_NO.
+                        * we leave the state WONT.
                         */
                        return;
 
                         */
                        return;
 
@@ -494,11 +514,24 @@ willoption(option)
                case TELOPT_SGA:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_SGA:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
+               case TELOPT_XDISPLOC:
+               case TELOPT_ENVIRON:
                        changeok++;
                        break;
 
 #ifdef LINEMODE
                case TELOPT_LINEMODE:
                        changeok++;
                        break;
 
 #ifdef LINEMODE
                case TELOPT_LINEMODE:
+                       /*
+                        * Local processing of 'will linemode' should
+                        * occur after placing 'do linemode' in the data
+                        * stream, because we may wish to send other
+                        * linemode related messages.  So, we duplicate
+                        * the other three lines of code here, and then
+                        * return.
+                        */
+                       set_his_want_state_will(option);
+                       send_do(option, 0);
+                       set_his_state_will(option);
 # ifdef        KLUDGELINEMODE
                        /*
                         * Note client's desire to use linemode.
 # ifdef        KLUDGELINEMODE
                        /*
                         * Note client's desire to use linemode.
@@ -506,55 +539,110 @@ willoption(option)
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
                        clientstat(TELOPT_LINEMODE, WILL, 0);
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
                        clientstat(TELOPT_LINEMODE, WILL, 0);
-                       changeok++;
-                       break;
+                       return;
 #endif /* LINEMODE */
 
                default:
                        break;
                }
                if (changeok) {
 #endif /* LINEMODE */
 
                default:
                        break;
                }
                if (changeok) {
-                       hiswants[option] = OPT_YES;
+                       set_his_want_state_will(option);
                        send_do(option, 0);
                } else {
                        do_dont_resp[option]++;
                        send_dont(option, 0);
                }
                        send_do(option, 0);
                } else {
                        do_dont_resp[option]++;
                        send_dont(option, 0);
                }
+           } else {
+               /*
+                * Option processing that should happen when
+                * we receive conformation of a change in
+                * state that we had requested.
+                */
+               switch (option) {
+               case TELOPT_ECHO:
+                       not42 = 0;      /* looks like a 4.2 system */
+                       /*
+                        * Egads, he responded "WILL ECHO".  Turn
+                        * it off right now!
+                        */
+                       send_dont(option, 1);
+                       /*
+                        * "WILL ECHO".  Kludge upon kludge!
+                        * A 4.2 client is now echoing user input at
+                        * the tty.  This is probably undesireable and
+                        * it should be stopped.  The client will
+                        * respond WONT TM to the DO TM that we send to
+                        * check for kludge linemode.  When the WONT TM
+                        * arrives, linemode will be turned off and a
+                        * change propogated to the pty.  This change
+                        * will cause us to process the new pty state
+                        * in localstat(), which will notice that
+                        * linemode is off and send a WILL ECHO
+                        * so that we are properly in character mode and
+                        * all is well.
+                        */
+                       break;
+#ifdef LINEMODE
+               case TELOPT_LINEMODE:
+# ifdef        KLUDGELINEMODE
+                       /*
+                        * Note client's desire to use linemode.
+                        */
+                       lmodetype = REAL_LINEMODE;
+# endif        /* KLUDGELINEMODE */
+                       clientstat(TELOPT_LINEMODE, WILL, 0);
+#endif /* LINEMODE */
+               }
            }
        }
            }
        }
-       hisopts[option] = OPT_YES;
+       set_his_state_will(option);
 }  /* end of willoption */
 
 send_dont(option, init)
        int option, init;
 {
        if (init) {
 }  /* end of willoption */
 
 send_dont(option, init)
        int option, init;
 {
        if (init) {
-               if ((do_dont_resp[option] == 0 && hisopts[option] == OPT_NO) ||
-                   hiswants[option] == OPT_NO)
+               if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
+                   his_want_state_is_wont(option))
                        return;
                        return;
-               hiswants[option] = OPT_NO;
+               set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
        (void) sprintf(nfrontp, dont, option);
        nfrontp += sizeof (doopt) - 2;
                do_dont_resp[option]++;
        }
        (void) sprintf(nfrontp, dont, option);
        nfrontp += sizeof (doopt) - 2;
+#ifdef DIAGNOSTICS
+       /*
+        * Report sending option to other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: send dont", option);
+       }
+#endif /* DIAGNOSTICS */
 }
 
 wontoption(option)
        int option;
 {
 }
 
 wontoption(option)
        int option;
 {
-       char *fmt = (char *)0;
-
        /*
         * Process client input.
         */
 
        /*
         * Process client input.
         */
 
+#ifdef DIAGNOSTICS
+       /*
+        * Report receiving option from other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: recv wont", option);
+       }
+#endif /* DIAGNOSTICS */
+
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
-               if (do_dont_resp[option] && hisopts[option] == OPT_NO)
+               if (do_dont_resp[option] && his_state_is_wont(option))
                        do_dont_resp[option]--;
        }
        if (do_dont_resp[option] == 0) {
                        do_dont_resp[option]--;
        }
        if (do_dont_resp[option] == 0) {
-           if (hiswants[option] != OPT_NO) {
+           if (his_want_state_is_will(option)) {
                /* it is always ok to change to negative state */
                switch (option) {
                case TELOPT_ECHO:
                /* it is always ok to change to negative state */
                switch (option) {
                case TELOPT_ECHO:
@@ -574,9 +662,11 @@ wontoption(option)
                         * If real linemode is supported, then client is
                         * asking to turn linemode off.
                         */
                         * If real linemode is supported, then client is
                         * asking to turn linemode off.
                         */
-                       if (lmodetype == REAL_LINEMODE)
+                       if (lmodetype != REAL_LINEMODE)
+                               break;
+                       lmodetype = KLUDGE_LINEMODE;
 # endif        /* KLUDGELINEMODE */
 # endif        /* KLUDGELINEMODE */
-                               clientstat(TELOPT_LINEMODE, WONT, 0);
+                       clientstat(TELOPT_LINEMODE, WONT, 0);
                        break;
 #endif LINEMODE
 
                        break;
 #endif LINEMODE
 
@@ -587,7 +677,7 @@ wontoption(option)
                         * as is.  Short circut the state machine to
                         * achive this.
                         */
                         * as is.  Short circut the state machine to
                         * achive this.
                         */
-                       hiswants[TELOPT_TM] = OPT_NO;
+                       set_his_want_state_wont(TELOPT_TM);
                        return;
 
                case TELOPT_LFLOW:
                        return;
 
                case TELOPT_LFLOW:
@@ -602,12 +692,36 @@ wontoption(option)
                        slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
                        break;
 
                        slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
                        break;
 
+               /*
+                * For options that we might spin waiting for
+                * sub-negotiation, if the client turns off the
+                * option rather than responding to the request,
+                * we have to treat it here as if we got a response
+                * to the sub-negotiation, (by updating the timers)
+                * so that we'll break out of the loop.
+                */
+               case TELOPT_TTYPE:
+                       settimer(ttypesubopt);
+                       break;
+
+               case TELOPT_TSPEED:
+                       settimer(tspeedsubopt);
+                       break;
+
+               case TELOPT_XDISPLOC:
+                       settimer(xdisplocsubopt);
+                       break;
+
+               case TELOPT_ENVIRON:
+                       settimer(environsubopt);
+                       break;
+
                default:
                        break;
                }
                default:
                        break;
                }
-               hiswants[option] = OPT_NO;
-               fmt = dont;
-               send_dont(option, 0);
+               set_his_want_state_wont(option);
+               if (his_state_is_will(option))
+                       send_dont(option, 0);
            } else {
                switch (option) {
                case TELOPT_TM:
            } else {
                switch (option) {
                case TELOPT_TM:
@@ -624,7 +738,7 @@ wontoption(option)
                }
            }
        }
                }
            }
        }
-       hisopts[option] = OPT_NO;
+       set_his_state_wont(option);
 
 }  /* end of wontoption */
 
 
 }  /* end of wontoption */
 
@@ -632,14 +746,22 @@ send_will(option, init)
        int option, init;
 {
        if (init) {
        int option, init;
 {
        if (init) {
-               if ((will_wont_resp[option] == 0 && myopts[option] == OPT_YES)||
-                   mywants[option] == OPT_YES)
+               if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
+                   my_want_state_is_will(option))
                        return;
                        return;
-               mywants[option] = OPT_YES;
+               set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
        (void) sprintf(nfrontp, will, option);
        nfrontp += sizeof (doopt) - 2;
                will_wont_resp[option]++;
        }
        (void) sprintf(nfrontp, will, option);
        nfrontp += sizeof (doopt) - 2;
+#ifdef DIAGNOSTICS
+       /*
+        * Report sending option to other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: send will", option);
+       }
+#endif /* DIAGNOSTICS */
 }
 
 dooption(option)
 }
 
 dooption(option)
@@ -651,12 +773,21 @@ dooption(option)
         * Process client input.
         */
 
         * Process client input.
         */
 
+#ifdef DIAGNOSTICS
+       /*
+        * Report receiving option from other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: recv do", option);
+       }
+#endif /* DIAGNOSTICS */
+
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
-               if (will_wont_resp[option] && myopts[option] == OPT_YES)
+               if (will_wont_resp[option] && my_state_is_will(option))
                        will_wont_resp[option]--;
        }
                        will_wont_resp[option]--;
        }
-       if ((will_wont_resp[option] == 0) && (mywants[option] != OPT_YES)) {
+       if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
                switch (option) {
                case TELOPT_ECHO:
 #ifdef LINEMODE
                switch (option) {
                case TELOPT_ECHO:
 #ifdef LINEMODE
@@ -716,8 +847,8 @@ dooption(option)
                         * pretend we sent a WONT.
                         */
                        send_will(option, 0);
                         * pretend we sent a WONT.
                         */
                        send_will(option, 0);
-                       mywants[option] = OPT_NO;
-                       myopts[option] = OPT_NO;
+                       set_my_want_state_wont(option);
+                       set_my_state_wont(option);
                        return;
 
                case TELOPT_LINEMODE:
                        return;
 
                case TELOPT_LINEMODE:
@@ -725,18 +856,20 @@ dooption(option)
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
+               case TELOPT_XDISPLOC:
+               case TELOPT_ENVIRON:
                default:
                        break;
                }
                if (changeok) {
                default:
                        break;
                }
                if (changeok) {
-                       mywants[option] = OPT_YES;
+                       set_my_want_state_will(option);
                        send_will(option, 0);
                } else {
                        will_wont_resp[option]++;
                        send_wont(option, 0);
                }
        }
                        send_will(option, 0);
                } else {
                        will_wont_resp[option]++;
                        send_wont(option, 0);
                }
        }
-       myopts[option] = OPT_YES;
+       set_my_state_will(option);
 
 }  /* end of dooption */
 
 
 }  /* end of dooption */
 
@@ -744,14 +877,22 @@ send_wont(option, init)
        int option, init;
 {
        if (init) {
        int option, init;
 {
        if (init) {
-               if ((will_wont_resp[option] == 0 && myopts[option] == OPT_NO) ||
-                   mywants[option] == OPT_NO)
+               if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
+                   my_want_state_is_wont(option))
                        return;
                        return;
-               mywants[option] = OPT_NO;
+               set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
        (void) sprintf(nfrontp, wont, option);
        nfrontp += sizeof (wont) - 2;
                will_wont_resp[option]++;
        }
        (void) sprintf(nfrontp, wont, option);
        nfrontp += sizeof (wont) - 2;
+#ifdef DIAGNOSTICS
+       /*
+        * Report sending option to other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: send wont", option);
+       }
+#endif /* DIAGNOSTICS */
 }
 
 dontoption(option)
 }
 
 dontoption(option)
@@ -760,13 +901,21 @@ dontoption(option)
        /*
         * Process client input.
         */
        /*
         * Process client input.
         */
+#ifdef DIAGNOSTICS
+       /*
+        * Report receiving option from other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printoption("td: recv dont", option);
+       }
+#endif /* DIAGNOSTICS */
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
-               if (will_wont_resp[option] && myopts[option] == OPT_NO)
+               if (will_wont_resp[option] && my_state_is_wont(option))
                        will_wont_resp[option]--;
        }
                        will_wont_resp[option]--;
        }
-       if ((will_wont_resp[option] == 0) && (mywants[option] != OPT_NO)) {
+       if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
                switch (option) {
                case TELOPT_BINARY:
                        init_termbuf();
                switch (option) {
                case TELOPT_BINARY:
                        init_termbuf();
@@ -812,10 +961,11 @@ dontoption(option)
                        break;
                }
 
                        break;
                }
 
-               mywants[option] = OPT_NO;
-               send_wont(option, 0);
+               set_my_want_state_wont(option);
+               if (my_state_is_will(option))
+                       send_wont(option, 0);
        }
        }
-       myopts[option] = OPT_NO;
+       set_my_state_wont(option);
 
 }  /* end of dontoption */
 
 
 }  /* end of dontoption */
 
@@ -835,13 +985,23 @@ dontoption(option)
 suboption()
 {
     register int subchar;
 suboption()
 {
     register int subchar;
+    extern void unsetenv();
 
 
+#ifdef DIAGNOSTICS
+       /*
+        * Report receiving option from other side.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               netflush();     /* get rid of anything waiting to go out */
+               printsub("td: recv", subpointer, SB_LEN()+2);
+       }
+#endif DIAGNOSTIC
     subchar = SB_GET();
     switch (subchar) {
     case TELOPT_TSPEED: {
        register int xspeed, rspeed;
 
     subchar = SB_GET();
     switch (subchar) {
     case TELOPT_TSPEED: {
        register int xspeed, rspeed;
 
-       if (hisopts[TELOPT_TSPEED] == OPT_NO)   /* Ignore if option disabled */
+       if (his_state_is_wont(TELOPT_TSPEED))   /* Ignore if option disabled */
                break;
 
        settimer(tspeedsubopt);
                break;
 
        settimer(tspeedsubopt);
@@ -863,9 +1023,9 @@ suboption()
     }  /* end of case TELOPT_TSPEED */
 
     case TELOPT_TTYPE: {               /* Yaaaay! */
     }  /* end of case TELOPT_TSPEED */
 
     case TELOPT_TTYPE: {               /* Yaaaay! */
-       static char terminalname[5+41] = "TERM=";
+       static char terminalname[41];
 
 
-       if (hisopts[TELOPT_TTYPE] == OPT_NO)    /* Ignore if option disabled */
+       if (his_state_is_wont(TELOPT_TTYPE))    /* Ignore if option disabled */
                break;
        settimer(ttypesubopt);
 
                break;
        settimer(ttypesubopt);
 
@@ -873,7 +1033,7 @@ suboption()
            return;             /* ??? XXX but, this is the most robust */
        }
 
            return;             /* ??? XXX but, this is the most robust */
        }
 
-       terminaltype = terminalname+sizeof("TERM=")-1;
+       terminaltype = terminalname;
 
        while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
                                                                    !SB_EOF()) {
 
        while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
                                                                    !SB_EOF()) {
@@ -893,7 +1053,7 @@ suboption()
     case TELOPT_NAWS: {
        register int xwinsize, ywinsize;
 
     case TELOPT_NAWS: {
        register int xwinsize, ywinsize;
 
-       if (hisopts[TELOPT_NAWS] == OPT_NO)     /* Ignore if option disabled */
+       if (his_state_is_wont(TELOPT_NAWS))     /* Ignore if option disabled */
                break;
 
        if (SB_EOF())
                break;
 
        if (SB_EOF())
@@ -918,7 +1078,7 @@ suboption()
     case TELOPT_LINEMODE: {
        register int request;
 
     case TELOPT_LINEMODE: {
        register int request;
 
-       if (hisopts[TELOPT_LINEMODE] == OPT_NO) /* Ignore if option disabled */
+       if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
                break;
        /*
         * Process linemode suboptions.
                break;
        /*
         * Process linemode suboptions.
@@ -960,7 +1120,7 @@ suboption()
        mode = SB_GET();
        switch (mode) {
        case TELQUAL_SEND:
        mode = SB_GET();
        switch (mode) {
        case TELQUAL_SEND:
-           if (myopts[TELOPT_STATUS] == OPT_YES)
+           if (my_state_is_will(TELOPT_STATUS))
                send_status();
            break;
 
                send_status();
            break;
 
@@ -973,6 +1133,71 @@ suboption()
        break;
     }  /* end of case TELOPT_STATUS */
 
        break;
     }  /* end of case TELOPT_STATUS */
 
+    case TELOPT_XDISPLOC: {
+       if (SB_EOF() || SB_GET() != TELQUAL_IS)
+               return;
+       settimer(xdisplocsubopt);
+       subpointer[SB_LEN()] = '\0';
+       setenv("DISPLAY", subpointer, 1);
+       break;
+    }  /* end of case TELOPT_XDISPLOC */
+
+    case TELOPT_ENVIRON: {
+       register int c;
+       register char *cp, *varp, *valp;
+
+       if (SB_EOF())
+               return;
+       c = SB_GET();
+       if (c == TELQUAL_IS)
+               settimer(environsubopt);
+       else if (c != TELQUAL_INFO)
+               return;
+
+       while (!SB_EOF() && SB_GET() != ENV_VAR)
+               ;
+
+       if (SB_EOF())
+               return;
+
+       cp = varp = subpointer;
+       valp = 0;
+
+       while (!SB_EOF()) {
+               switch (c = SB_GET()) {
+               case ENV_VALUE:
+                       *cp = '\0';
+                       cp = valp = subpointer;
+                       break;
+
+               case ENV_VAR:
+                       *cp = '\0';
+                       if (valp)
+                               setenv(varp, valp, 1);
+                       else
+                               unsetenv(varp);
+                       cp = varp = subpointer;
+                       valp = 0;
+                       break;
+
+               case ENV_ESC:
+                       if (SB_EOF())
+                               break;
+                       c = SB_GET();
+                       /* FALL THROUGH */
+               default:
+                       *cp++ = c;
+                       break;
+               }
+       }
+       *cp = '\0';
+       if (valp)
+               setenv(varp, valp, 1);
+       else
+               unsetenv(varp);
+       break;
+    }  /* end of case TELOPT_ENVIRON */
+
     default:
        break;
     }  /* end of switch */
     default:
        break;
     }  /* end of switch */
@@ -983,9 +1208,9 @@ suboption()
 #define        ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
 send_status()
 {
 #define        ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
 send_status()
 {
-       char statusbuf[256];
-       register char *ncp;
-       register int i;
+       unsigned char statusbuf[256];
+       register unsigned char *ncp;
+       register unsigned char i;
 
        ncp = statusbuf;
 
 
        ncp = statusbuf;
 
@@ -997,13 +1222,13 @@ send_status()
        ADD(TELQUAL_IS);
 
        for (i = 0; i < NTELOPTS; i++) {
        ADD(TELQUAL_IS);
 
        for (i = 0; i < NTELOPTS; i++) {
-               if (myopts[i] == OPT_YES) {
+               if (my_state_is_will(i)) {
                        ADD(WILL);
                        ADD_DATA(i);
                        if (i == IAC)
                                ADD(IAC);
                }
                        ADD(WILL);
                        ADD_DATA(i);
                        if (i == IAC)
                                ADD(IAC);
                }
-               if (hisopts[i] == OPT_YES) {
+               if (his_state_is_will(i)) {
                        ADD(DO);
                        ADD_DATA(i);
                        if (i == IAC)
                        ADD(DO);
                        ADD_DATA(i);
                        if (i == IAC)
@@ -1012,8 +1237,8 @@ send_status()
        }
 
 #ifdef LINEMODE
        }
 
 #ifdef LINEMODE
-       if (hisopts[TELOPT_LINEMODE] == OPT_YES) {
-               char *cp, *cpe;
+       if (his_state_is_will(TELOPT_LINEMODE)) {
+               unsigned char *cp, *cpe;
                int len;
 
                ADD(SB);
                int len;
 
                ADD(SB);
@@ -1041,4 +1266,17 @@ send_status()
 
        writenet(statusbuf, ncp - statusbuf);
        netflush();     /* Send it on its way */
 
        writenet(statusbuf, ncp - statusbuf);
        netflush();     /* Send it on its way */
+#ifdef DIAGNOSTICS
+       /*
+        * Report sending status suboption.
+        */
+       if (diagnostic & TD_OPTIONS) {
+               printsub("td: send", statusbuf, ncp - statusbuf);
+               netflush();     /* Send it on its way */
+       }
+#endif DIAGNOSTIC
 }
 }
+
+#ifdef NO_SETENV
+#include "setenv.c"
+#endif
index 4905e63..3379831 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)sys_term.c 5.7 (Berkeley) %G%";
+static char sccsid[] = "@(#)sys_term.c 5.8 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -29,6 +29,9 @@ char  wtmpf[] = "/etc/wtmp";
 #define SCPYN(a, b)    (void) strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
 #define SCPYN(a, b)    (void) strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
+#ifdef STREAMS
+#include <sys/stream.h>
+#endif
 #include <sys/tty.h>
 #ifdef t_erase
 #undef t_erase
 #include <sys/tty.h>
 #ifdef t_erase
 #undef t_erase
@@ -47,6 +50,10 @@ char wtmpf[] = "/etc/wtmp";
 #undef t_lnextc
 #endif
 
 #undef t_lnextc
 #endif
 
+#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
+# define EXTPROC 0400
+#endif
+
 #ifndef        USE_TERMIO
 struct termbuf {
        struct sgttyb sg;
 #ifndef        USE_TERMIO
 struct termbuf {
        struct sgttyb sg;
@@ -56,15 +63,17 @@ struct termbuf {
        int lflags;
 } termbuf, termbuf2;
 #else  /* USE_TERMIO */
        int lflags;
 } termbuf, termbuf2;
 #else  /* USE_TERMIO */
-# ifndef EXTPROC
-# define EXTPROC 0400
-# endif
 # ifdef        SYSV_TERMIO
 #      define termios termio
 # endif
 # ifndef TCSETA
 # ifdef        SYSV_TERMIO
 #      define termios termio
 # endif
 # ifndef TCSETA
-# define TCSETA TIOCSETA
-# define TCGETA TIOCGETA
+#  ifdef TCSETS
+#   define TCSETA TCSETS
+#   define TCGETA TCGETS
+#  else
+#   define TCSETA TIOCSETA
+#   define TCGETA TIOCGETA
+#  endif
 # endif /* 4.4BSD */
 struct termios termbuf, termbuf2;      /* pty control structure */
 #endif /* USE_TERMIO */
 # endif /* 4.4BSD */
 struct termios termbuf, termbuf2;      /* pty control structure */
 #endif /* USE_TERMIO */
@@ -271,8 +280,8 @@ cc_t **valpp;
                defval(0);
 #endif
        case SLC_AO:
                defval(0);
 #endif
        case SLC_AO:
-#ifdef VDISCARD
-               setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
+#ifdef VFLUSHO
+               setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT);
 #else
                defval(0);
 #endif
 #else
                defval(0);
 #endif
@@ -393,6 +402,10 @@ getpty()
  * tty_istrapsig()     Find out if signal trapping is enabled.
  * tty_setedit(on)     Turn on/off line editing.
  * tty_setsig(on)      Turn on/off signal trapping.
  * tty_istrapsig()     Find out if signal trapping is enabled.
  * tty_setedit(on)     Turn on/off line editing.
  * tty_setsig(on)      Turn on/off signal trapping.
+ * tty_issofttab()     Find out if tab expansion is enabled.
+ * tty_setsofttab(on)  Turn on/off soft tab expansion.
+ * tty_islitecho()     Find out if typed control chars are echoed literally
+ * tty_setlitecho()    Turn on/off literal echo of control chars
  * tty_tspeed(val)     Set transmit speed to val.
  * tty_rspeed(val)     Set receive speed to val.
  */
  * tty_tspeed(val)     Set transmit speed to val.
  * tty_rspeed(val)     Set receive speed to val.
  */
@@ -571,6 +584,90 @@ int on;
 }
 #endif /* LINEMODE */
 
 }
 #endif /* LINEMODE */
 
+tty_issofttab()
+{
+#ifndef        USE_TERMIO
+       return (termbuf.sg.sg_flags & XTABS);
+#else
+# ifdef        OXTABS
+       return (termbuf.c_oflag & OXTABS);
+# endif
+# ifdef        TABDLY
+       return ((termbuf.c_oflag & TABDLY) == TAB3);
+# endif
+#endif
+}
+
+tty_setsofttab(on)
+int on;
+{
+#ifndef        USE_TERMIO
+       if (on)
+               termbuf.sg.sg_flags |= XTABS;
+       else
+               termbuf.sg.sg_flags &= ~XTABS;
+#else
+       if (on) {
+# ifdef        OXTABS
+               termbuf.c_oflag |= OXTABS;
+# endif
+# ifdef        TABDLY
+               termbuf.c_oflag &= ~TABDLY;
+               termbuf.c_oflag |= TAB3;
+# endif
+       } else {
+# ifdef        OXTABS
+               termbuf.c_oflag &= ~OXTABS;
+# endif
+# ifdef        TABDLY
+               termbuf.c_oflag &= ~TABDLY;
+               termbuf.c_oflag |= TAB0;
+# endif
+       }
+#endif
+}
+
+tty_islitecho()
+{
+#ifndef        USE_TERMIO
+       return (!(termbuf.sg.sg_flags & CTLECH));
+#else
+# ifdef        ECHOCTL
+       return (!(termbuf.c_lflag & ECHOCTL));
+# endif
+# ifdef        TCTLECH
+       return (!(termbuf.c_lflag & TCTLECH));
+# endif
+# if   !defined(ECHOCTL) && !defined(TCTLECH)
+       return (0);     /* assumes ctl chars are echoed '^x' */
+# endif
+#endif
+}
+
+tty_setlitecho(on)
+int on;
+{
+#ifndef        USE_TERMIO
+       if (on)
+               termbuf.sg.sg_flags &= ~CTLECH;
+       else
+               termbuf.sg.sg_flags |= CTLECH;
+#else
+# ifdef        ECHOCTL
+       if (on)
+               termbuf.c_lflag &= ~ECHOCTL;
+       else
+               termbuf.c_lflag |= ECHOCTL;
+# endif
+# ifdef        TCTLECH
+       if (on)
+               termbuf.c_lflag &= ~TCTLECH;
+       else
+               termbuf.c_lflag |= TCTLECH;
+# endif
+#endif
+}
+
 /*
  * A table of available terminal speeds
  */
 /*
  * A table of available terminal speeds
  */
@@ -595,7 +692,7 @@ tty_tspeed(val)
 #ifndef        USE_TERMIO
        termbuf.sg.sg_ospeed = tp->value;
 #else
 #ifndef        USE_TERMIO
        termbuf.sg.sg_ospeed = tp->value;
 #else
-# ifdef        SYSV_TERMIO
+# ifdef        CBAUD
        termbuf.c_cflag &= ~CBAUD;
        termbuf.c_cflag |= tp->value;
 # else
        termbuf.c_cflag &= ~CBAUD;
        termbuf.c_cflag |= tp->value;
 # else
@@ -613,7 +710,7 @@ tty_rspeed(val)
 #ifndef        USE_TERMIO
        termbuf.sg.sg_ispeed = tp->value;
 #else
 #ifndef        USE_TERMIO
        termbuf.sg.sg_ispeed = tp->value;
 #else
-# ifdef        SYSV_TERMIO
+# ifdef        CBAUD
        termbuf.c_cflag &= ~CBAUD;
        termbuf.c_cflag |= tp->value;
 # else
        termbuf.c_cflag &= ~CBAUD;
        termbuf.c_cflag |= tp->value;
 # else
@@ -673,12 +770,14 @@ getptyslave()
                fatalperror(net, line);
        if (fchmod(t, 0))
                fatalperror(net, line);
                fatalperror(net, line);
        if (fchmod(t, 0))
                fatalperror(net, line);
+#if BSD <= 43
        (void) signal(SIGHUP, SIG_IGN);
        vhangup();
        (void) signal(SIGHUP, SIG_DFL);
        t = open(line, O_RDWR);
        if (t < 0)
                fatalperror(net, line);
        (void) signal(SIGHUP, SIG_IGN);
        vhangup();
        (void) signal(SIGHUP, SIG_DFL);
        t = open(line, O_RDWR);
        if (t < 0)
                fatalperror(net, line);
+#endif
 
        init_termbuf();
 #ifndef        USE_TERMIO
 
        init_termbuf();
 #ifndef        USE_TERMIO
@@ -686,14 +785,18 @@ getptyslave()
        termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
 #else
        termbuf.c_lflag |= ECHO;
        termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
 #else
        termbuf.c_lflag |= ECHO;
+#ifndef        OXTABS
+#define OXTABS 0
+#endif
        termbuf.c_oflag |= ONLCR|OXTABS;
        termbuf.c_iflag |= ICRNL;
        termbuf.c_iflag &= ~IXOFF;
        termbuf.c_oflag |= ONLCR|OXTABS;
        termbuf.c_iflag |= ICRNL;
        termbuf.c_iflag &= ~IXOFF;
-# ifdef        SYSV_TERMIO
-       termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
-# else SYSV_TERMIO
+# ifdef        CBAUD
+       termbuf.c_cflag &= ~CBAUD;
+       termbuf.c_cflag |= B9600;
+# else /* CBAUD */
        termbuf.c_ospeed = termbuf.c_ispeed = B9600;
        termbuf.c_ospeed = termbuf.c_ispeed = B9600;
-# endif
+# endif        /* CBAUD */
 #endif
        set_termbuf();
 #else  /* CRAY */
 #endif
        set_termbuf();
 #else  /* CRAY */
@@ -739,7 +842,7 @@ char *host;
                register int pid = i;
 
                setpgrp();
                register int pid = i;
 
                setpgrp();
-               (void) signal(SIGUSR1, func);   /* reset handler to default */
+               utmp_sig_reset();               /* reset handler to default */
                /*
                 * Create utmp entry for child
                 */
                /*
                 * Create utmp entry for child
                 */
@@ -784,11 +887,19 @@ char *host;
        SCPYN(request.gen_id, gen_id);
        SCPYN(request.tty_id, &line[8]);
        SCPYN(request.host, host);
        SCPYN(request.gen_id, gen_id);
        SCPYN(request.tty_id, &line[8]);
        SCPYN(request.host, host);
-       SCPYN(request.term_type, &terminaltype[5]);
-#if    defined(UNICOS5)
+       SCPYN(request.term_type, terminaltype);
+#if    !defined(UNICOS5)
        request.signal = SIGCLD;
        request.pid = getpid();
 #endif
        request.signal = SIGCLD;
        request.pid = getpid();
 #endif
+#ifdef BFTPDAEMON
+       /*
+        * Are we working as the bftp daemon?
+        */
+       if (bftpd) {
+               SCPYN(request.exec_name, BFTPPATH);
+       }
+#endif /* BFTPDAEMON */
        if (write(i, (char *)&request, sizeof(request)) < 0) {
                char tbuf[128];
                (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
        if (write(i, (char *)&request, sizeof(request)) < 0) {
                char tbuf[128];
                (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
@@ -816,8 +927,45 @@ char *host;
 #endif /* NEWINIT */
 }
 
 #endif /* NEWINIT */
 }
 
-#ifndef        NEWINIT
 char   *envinit[3];
 char   *envinit[3];
+extern char **environ;
+
+init_env()
+{
+       extern char *getenv();
+       char **envp;
+
+       envp = envinit;
+       if (*envp = getenv("TZ"))
+               *envp++ -= 3;
+#ifdef CRAY
+       else
+               *envp++ = "TZ=GMT0";
+#endif
+       *envp = 0;
+       environ = envinit;
+}
+
+#ifdef CRAY
+/*
+ * These are environment variable that we
+ * don't put on the argument line.
+ */
+char *invalid[] = {
+       "USER=",        /* Set up by login */
+       "HOME=",        /* Set up by login */
+       "LOGNAME=",     /* Set up by login */
+       "TMPDIR=",      /* Set up by login */
+       "SHELL=",       /* Set up by login */
+       "PATH=",        /* Set up by login */
+       "MAIL=",        /* Set up by login */
+       "TZ=",          /* Login gets it from the environment */
+       "TERM=",        /* Login gets it from the environment */
+       0
+};
+#endif
+
+#ifndef        NEWINIT
 
 /*
  * start_login(t, host)
 
 /*
  * start_login(t, host)
@@ -830,10 +978,11 @@ start_login(t, host)
 int t;
 char *host;
 {
 int t;
 char *host;
 {
-       extern char *getenv();
-       char **envp;
-
+       register char *cp;
+       register char **argv;
+       char **addarg();
 #ifdef CRAY
 #ifdef CRAY
+       register char **cpp, **cpp2;
        utmp_sig_wait();
 # ifndef TCVHUP
        setpgrp();
        utmp_sig_wait();
 # ifndef TCVHUP
        setpgrp();
@@ -872,9 +1021,12 @@ char *host;
        /*
         * set up standard paths before forking to login
         */
        /*
         * set up standard paths before forking to login
         */
-#if    BSD >43
+#ifndef        NO_SETSID
        if (setsid() < 0)
                fatalperror(net, "setsid");
        if (setsid() < 0)
                fatalperror(net, "setsid");
+#endif
+
+#ifdef TIOCSCTTY
        if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
                fatalperror(net, "ioctl(sctty)");
 #endif
        if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
                fatalperror(net, "ioctl(sctty)");
 #endif
@@ -884,31 +1036,82 @@ char *host;
        (void) dup2(t, 1);
        (void) dup2(t, 2);
        (void) close(t);
        (void) dup2(t, 1);
        (void) dup2(t, 2);
        (void) close(t);
-       envp = envinit;
-       *envp++ = terminaltype;
-       if (*envp = getenv("TZ"))
-               *envp++ -= 3;
-#ifdef CRAY
-       else
-               *envp++ = "TZ=GMT0";
-#endif
-       *envp = 0;
-       environ = envinit;
        /*
         * -h : pass on name of host.
         *              WARNING:  -h is accepted by login if and only if
         *                      getuid() == 0.
         * -p : don't clobber the environment (so terminal type stays set).
         */
        /*
         * -h : pass on name of host.
         *              WARNING:  -h is accepted by login if and only if
         *                      getuid() == 0.
         * -p : don't clobber the environment (so terminal type stays set).
         */
-       execl(_PATH_LOGIN, "login", "-h", host,
-#ifndef CRAY
-                                       terminaltype ? "-p" : 0,
+       argv = addarg(0, "login");
+       argv = addarg(argv, "-h");
+       argv = addarg(argv, host);
+#if    !defined(CRAY) && !defined(NO_LOGIN_P)
+       argv = addarg(argv, "-p");
+#endif
+#ifdef BFTPDAEMON
+       /*
+        * Are we working as the bftp daemon?  If so, then ask login
+        * to start bftp instead of shell.
+        */
+       if (bftpd) {
+               argv = addarg(argv, "-e");
+               argv = addarg(argv, BFTPPATH);
+       } else 
+#endif
+       if (getenv("USER")) {
+               argv = addarg(argv, getenv("USER"));
+       }
+#ifdef CRAY
+       for (cpp = environ; *cpp; cpp++) {
+               for (cpp2 = invalid; *cpp2; cpp2++)
+                       if (strncmp(*cpp2, *cpp, strlen(*cpp2)) == 0)
+                               break;
+               if (*cpp2)
+                       continue;
+               argv = addarg(argv, *cpp);
+       }
 #endif
 #endif
-                                                               0);
+
+       execv(_PATH_LOGIN, argv);
+
        syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
        fatalperror(net, _PATH_LOGIN);
        /*NOTREACHED*/
 }
        syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
        fatalperror(net, _PATH_LOGIN);
        /*NOTREACHED*/
 }
+
+char **
+addarg(argv, val)
+register char **argv;
+register char *val;
+{
+       register char **cpp;
+       char *malloc();
+
+       if (argv == NULL) {
+               /*
+                * 10 entries, a leading length, and a null
+                */
+               argv = (char **)malloc(sizeof(*argv) * 12);
+               if (argv == NULL)
+                       return(NULL);
+               *argv++ = (char *)10;
+               *argv = (char *)0;
+       }
+       for (cpp = argv; *cpp; cpp++)
+               ;
+       if (cpp == &argv[(int)argv[-1]]) {
+               --argv;
+               *argv = (char *)((int)(*argv) + 10);
+               argv = (char **)realloc(argv, (int)(*argv) + 2);
+               if (argv == NULL)
+                       return(NULL);
+               argv++;
+               cpp = &argv[(int)argv[-1] - 10];
+       }
+       *cpp++ = val;
+       *cpp = 0;
+       return(argv);
+}
 #endif NEWINIT
 
 /*
 #endif NEWINIT
 
 /*
@@ -944,7 +1147,6 @@ cleanup()
        kill(0, SIGHUP);
 # else /* NEWINIT */
        (void) shutdown(net, 2);
        kill(0, SIGHUP);
 # else /* NEWINIT */
        (void) shutdown(net, 2);
-       sleep(2);
 # endif        /* NEWINT */
 #endif /* CRAY */
        exit(1);
 # endif        /* NEWINT */
 #endif /* CRAY */
        exit(1);
@@ -981,6 +1183,11 @@ utmp_sig_init()
                fatalperror(net, "telnetd/signal");
 }
 
                fatalperror(net, "telnetd/signal");
 }
 
+utmp_sig_reset()
+{
+       (void) signal(SIGUSR1, func);   /* reset handler to default */
+}
+
 utmp_sig_wait()
 {
        /*
 utmp_sig_wait()
 {
        /*
index 85331a2..f86c33c 100644 (file)
@@ -1,16 +1,33 @@
 .\" Copyright (c) 1983 The Regents of the University of California.
 .\" All rights reserved.
 .\"
 .\" Copyright (c) 1983 The Regents of the University of California.
 .\" All rights reserved.
 .\"
-.\" %sccs.include.redist.man%
+.\" 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
 .\"
-.\"    @(#)telnetd.8   6.6 (Berkeley) %G%
+.\"    @(#)telnetd.8   6.7 (Berkeley) %G%
 .\"
 .TH TELNETD 8 ""
 .UC 5
 .SH NAME
 telnetd \- DARPA TELNET protocol server
 .SH SYNOPSIS
 .\"
 .TH TELNETD 8 ""
 .UC 5
 .SH NAME
 telnetd \- DARPA TELNET protocol server
 .SH SYNOPSIS
-.B telnetd
+.B /etc/telnetd
+[\fB\-debug\fP [\fIport\fP]]
+[\fB\-l]
+[\fB\-D options\fP]
+[\fB\-D report\fP]
+[\fB\-D exercise\fP]
+[\fB\-D netdata\fP]
+[\fB\-D ptydata\fP]
 .SH DESCRIPTION
 .I Telnetd
 is a server which supports the DARPA standard
 .SH DESCRIPTION
 .I Telnetd
 is a server which supports the DARPA standard
@@ -25,6 +42,24 @@ port as indicated by the
 .I /etc/services
 file (see
 .IR services (5)).
 .I /etc/services
 file (see
 .IR services (5)).
+If the \fB\-debug\fP may be used, to start up \fBtelnetd\fP
+manually, instead of through
+.IR inetd (8).
+If started up this way, \fIport\fP may be specified to
+run \fItelnetd\fP on an alternate TCP port number.
+.PP
+The \fB\-D\fP option may be used for debugging purposes.
+This allows \fItelnet\fR to print out debugging information
+to the connection, allowing the user to see what telnetd
+is doing.
+There are several modifiers:
+\fBoptions\fR prints information about the negotiation
+of \fBTELNET\fR options,
+\fBreport\fR prints the \fBoptions\fR information, plus
+some additional information about what processing is going on,
+\fBnetdata\fP displays the data stream received by \fItelnetd\fP,
+\fBptydata\fP displays data written to the pty, and
+\fBexercise\fR has not been implemented yet.
 .PP
 .I Telnetd
 operates by allocating a pseudo-terminal device (see
 .PP
 .I Telnetd
 operates by allocating a pseudo-terminal device (see
@@ -85,6 +120,7 @@ and
 .I Telnetd
 is willing to have the remote client
 .IR do :
 .I Telnetd
 is willing to have the remote client
 .IR do :
+.IR linemode ,
 .IR binary ,
 .I terminal
 .IR type ,
 .IR binary ,
 .I terminal
 .IR type ,
@@ -94,6 +130,9 @@ is willing to have the remote client
 .IR size ,
 .I toggle flow
 .IR control ,
 .IR size ,
 .I toggle flow
 .IR control ,
+.IR environment ,
+.I X display
+.IR location ,
 and
 .I suppress go
 .IR ahead .
 and
 .I suppress go
 .IR ahead .
index 3817f94..2df6780 100644 (file)
@@ -12,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  5.44 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnetd.c  5.45 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -36,17 +36,37 @@ int lowpty = 0, highpty;    /* low, high pty numbers */
 int debug = 0;
 char *progname;
 
 int debug = 0;
 char *progname;
 
+#if    defined(NEED_GETTOS)
+struct tosent {
+       char    *t_name;        /* name */
+       char    **t_aliases;    /* alias list */
+       char    *t_proto;       /* protocol */
+       int     t_tos;          /* Type Of Service bits */
+};
+
+struct tosent *
+gettosbyname(name, proto)
+char *name, *proto;
+{
+       static struct tosent te;
+       static char *aliasp = 0;
+
+       te.t_name = name;
+       te.t_aliases = &aliasp;
+       te.t_proto = proto;
+       te.t_tos = 020; /* Low Delay bit */
+       return(&te);
+}
+#endif
+
 main(argc, argv)
        char *argv[];
 {
        struct sockaddr_in from;
        int on = 1, fromlen;
 main(argc, argv)
        char *argv[];
 {
        struct sockaddr_in from;
        int on = 1, fromlen;
-#ifdef IP_TOS
-       int tos;
-#ifdef CRAY
+#if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
        struct tosent *tp;
        struct tosent *tp;
-#endif
-#endif /* IP_TOS */
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
@@ -103,13 +123,8 @@ top:
                if (**argv != '\0')
                        lowpty = atoi(*argv);
                if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
                if (**argv != '\0')
                        lowpty = atoi(*argv);
                if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
-       usage:
-                       fprintf(stderr, "Usage: telnetd [-debug] [-h] ");
-# ifdef        NEWINIT
-                       fprintf(stderr, "[-Iinitid] ");
-# endif        /* NEWINIT */
-                       fprintf(stderr, "[-l] [-r[lowpty]-[highpty]] [port]\n");
-                       exit(1);
+                       usage();
+                       /* NOT REACHED */
                }
                goto top;
        }
                }
                goto top;
        }
@@ -119,11 +134,15 @@ top:
 
                *argv += 2;
                if (**argv == '\0') {
 
                *argv += 2;
                if (**argv == '\0') {
-                       if (argc < 2)
-                               goto usage;
+                       if (argc < 2) {
+                               usage();
+                               /* NOT REACHED */
+                       }
                        argv++, argc--;
                        argv++, argc--;
-                       if (**argv == '\0')
-                               goto usage;
+                       if (**argv == '\0') {
+                               usage();
+                               /* NOT REACHED */
+                       }
                }
                gen_id = *argv;
                goto top;
                }
                gen_id = *argv;
                goto top;
@@ -131,27 +150,81 @@ top:
 # endif        /* NEWINIT */
 #endif /* CRAY */
 
 # endif        /* NEWINIT */
 #endif /* CRAY */
 
+#ifdef DIAGNOSTICS
+       /*
+        * Check for desired diagnostics capabilities.
+        */
+       if (argc > 0 && !strncmp(*argv, "-D", 2)) {
+               *argv += 2;
+               if (**argv == '\0') {
+                       if (argc < 2) {
+                               usage();
+                               /* NOT REACHED */
+                       }
+                       argv++, argc--;
+                       if (**argv == '\0') {
+                               usage();
+                               /* NOT REACHED */
+                       }
+               }
+               if (!strcmp(*argv, "report")) {
+                       diagnostic |= TD_REPORT|TD_OPTIONS;
+               } else if (!strcmp(*argv, "exercise")) {
+                       diagnostic |= TD_EXERCISE;
+               } else if (!strcmp(*argv, "netdata")) {
+                       diagnostic |= TD_NETDATA;
+               } else if (!strcmp(*argv, "ptydata")) {
+                       diagnostic |= TD_PTYDATA;
+               } else if (!strcmp(*argv, "options")) {
+                       diagnostic |= TD_OPTIONS;
+               } else {
+                       usage();
+                       /* NOT REACHED */
+               }
+               goto top;
+       }
+#endif /* DIAGNOSTICS */
+
+#ifdef BFTPDAEMON
+       /*
+        * Check for bftp daemon
+        */
+       if (argc > 0 && !strncmp(*argv, "-B", 2)) {
+               bftpd++;
+               goto top;
+       }
+#endif /* BFTPDAEMON */
+
+       if (argc > 0 && **argv == '-') {
+               fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
+               usage();
+               /* NOT REACHED */
+       }
+
        if (debug) {
            int s, ns, foo;
            struct servent *sp;
            static struct sockaddr_in sin = { AF_INET };
 
        if (debug) {
            int s, ns, foo;
            struct servent *sp;
            static struct sockaddr_in sin = { AF_INET };
 
-           if (argc > 0) {
+           if (argc > 1) {
+               usage();
+               /* NOT REACHED */
+           } else if (argc == 1) {
                    if (sp = getservbyname(*argv, "tcp")) {
                        sin.sin_port = sp->s_port;
                    } else {
                        sin.sin_port = atoi(*argv);
                        if ((int)sin.sin_port <= 0) {
                            fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
                    if (sp = getservbyname(*argv, "tcp")) {
                        sin.sin_port = sp->s_port;
                    } else {
                        sin.sin_port = atoi(*argv);
                        if ((int)sin.sin_port <= 0) {
                            fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
-                           exit(1);
+                           usage();
+                           /* NOT REACHED */
                        }
                        sin.sin_port = htons((u_short)sin.sin_port);
                   }
            } else {
                sp = getservbyname("telnet", "tcp");
                if (sp == 0) {
                        }
                        sin.sin_port = htons((u_short)sin.sin_port);
                   }
            } else {
                sp = getservbyname("telnet", "tcp");
                if (sp == 0) {
-                       fprintf(stderr,
-                               "telnetd: tcp/telnet: unknown service\n");
+                   fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
                    exit(1);
                }
                sin.sin_port = sp->s_port;
                    exit(1);
                }
                sin.sin_port = sp->s_port;
@@ -180,6 +253,9 @@ top:
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
+       } else if (argc > 0) {
+               usage();
+               /* NOT REACHED */
        }
 
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
        }
 
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
@@ -193,21 +269,38 @@ top:
                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
 
                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
 
-#ifdef IP_TOS
-#ifdef CRAY
-       if (tp = gettosbyname("telnet", "tcp"))
-               tos = tp->t_tos;
-       else
-#endif /* CRAY */
-       tos = IPTOS_LOWDELAY;
-       if (setsockopt(0, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
+#if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
+       if ((tp = gettosbyname("telnet", "tcp")) &&
+           (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
                syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
                syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
-#endif /* IP_TOS */
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
+usage()
+{
+       fprintf(stderr, "Usage: telnetd [-debug] [-h]");
+#ifdef NEWINIT
+       fprintf(stderr, " [-Iinitid]");
+#endif /* NEWINIT */
+#ifdef DIAGNOSTICS
+       fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
+#endif /* DIAGNOSTICS */
+#ifdef LINEMODE
+       fprintf(stderr, " [-l]");
+#endif
+#ifdef CRAY
+       fprintf(stderr, " [-r[lowpty]-[highpty]]");
+#endif
+#ifdef BFTPDAEMON
+       fprintf(stderr, " [-B]");
+#endif /* BFTPDAEMON */
+       fprintf(stderr, " [port]\n");
+       exit(1);
+}
+
 void   cleanup();
 
 /*
 void   cleanup();
 
 /*
@@ -225,32 +318,60 @@ getterminaltype()
     settimer(baseline);
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
     settimer(baseline);
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
-    while ((hiswants[TELOPT_TTYPE] != hisopts[TELOPT_TTYPE]) ||
-          (hiswants[TELOPT_TSPEED] != hisopts[TELOPT_TSPEED])) {
+    send_do(TELOPT_XDISPLOC, 1);
+    send_do(TELOPT_ENVIRON, 1);
+    while (his_will_wont_is_changing(TELOPT_TTYPE) ||
+          his_will_wont_is_changing(TELOPT_TSPEED) ||
+          his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+          his_will_wont_is_changing(TELOPT_ENVIRON)) {
        ttloop();
     }
        ttloop();
     }
-    if (hisopts[TELOPT_TSPEED] == OPT_YES) {
+    if (his_state_is_will(TELOPT_TSPEED)) {
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
        bcopy(sbbuf, nfrontp, sizeof sbbuf);
        nfrontp += sizeof sbbuf;
     }
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
        bcopy(sbbuf, nfrontp, sizeof sbbuf);
        nfrontp += sizeof sbbuf;
     }
-    if (hisopts[TELOPT_TTYPE] == OPT_YES) {
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+       static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+       bcopy(sbbuf, nfrontp, sizeof sbbuf);
+       nfrontp += sizeof sbbuf;
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+       static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+       bcopy(sbbuf, nfrontp, sizeof sbbuf);
+       nfrontp += sizeof sbbuf;
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
 
        bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
        nfrontp += sizeof ttytype_sbbuf;
     }
 
        bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
        nfrontp += sizeof ttytype_sbbuf;
     }
-    if (hisopts[TELOPT_TSPEED] == OPT_YES) {
+    if (his_state_is_will(TELOPT_TSPEED)) {
        while (sequenceIs(tspeedsubopt, baseline))
            ttloop();
     }
        while (sequenceIs(tspeedsubopt, baseline))
            ttloop();
     }
-    if (hisopts[TELOPT_TTYPE] == OPT_YES) {
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+       while (sequenceIs(xdisplocsubopt, baseline))
+           ttloop();
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+       while (sequenceIs(environsubopt, baseline))
+           ttloop();
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
        char first[256], last[256];
 
        while (sequenceIs(ttypesubopt, baseline))
            ttloop();
 
        char first[256], last[256];
 
        while (sequenceIs(ttypesubopt, baseline))
            ttloop();
 
-       if (!terminaltypeok(&terminaltype[5])) {
+       /*
+        * If the other side has already disabled the option, then
+        * we have to just go with what we (might) have already gotten.
+        */
+       if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
            (void) strncpy(first, terminaltype, sizeof(first));
            for(;;) {
                /*
            (void) strncpy(first, terminaltype, sizeof(first));
            for(;;) {
                /*
@@ -258,9 +379,10 @@ getterminaltype()
                 */
                (void) strncpy(last, terminaltype, sizeof(last));
                _gettermname();
                 */
                (void) strncpy(last, terminaltype, sizeof(last));
                _gettermname();
-               if (terminaltypeok(&terminaltype[5]))
+               if (terminaltypeok(terminaltype))
                    break;
                    break;
-               if (strncmp(last, terminaltype, sizeof(last)) == 0) {
+               if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+                   his_state_is_wont(TELOPT_TTYPE)) {
                    /*
                     * We've hit the end.  If this is the same as
                     * the first name, just go with it.
                    /*
                     * We've hit the end.  If this is the same as
                     * the first name, just go with it.
@@ -268,11 +390,11 @@ getterminaltype()
                    if (strncmp(first, terminaltype, sizeof(first) == 0))
                        break;
                    /*
                    if (strncmp(first, terminaltype, sizeof(first) == 0))
                        break;
                    /*
-                    * Get the terminal name one more type, so that
+                    * Get the terminal name one more time, so that
                     * RFC1091 compliant telnets will cycle back to
                     * the start of the list.
                     */
                     * RFC1091 compliant telnets will cycle back to
                     * the start of the list.
                     */
-                   _gettermname();
+                    _gettermname();
                    if (strncmp(first, terminaltype, sizeof(first) != 0))
                        (void) strncpy(terminaltype, first, sizeof(first));
                    break;
                    if (strncmp(first, terminaltype, sizeof(first) != 0))
                        (void) strncpy(terminaltype, first, sizeof(first));
                    break;
@@ -284,6 +406,13 @@ getterminaltype()
 
 _gettermname()
 {
 
 _gettermname()
 {
+    /*
+     * If the client turned off the option,
+     * we can't send another request, so we
+     * just return.
+     */
+    if (his_state_is_wont(TELOPT_TTYPE))
+       return;
     settimer(baseline);
     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
     nfrontp += sizeof ttytype_sbbuf;
     settimer(baseline);
     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
     nfrontp += sizeof ttytype_sbbuf;
@@ -338,12 +467,12 @@ doit(who)
        else
                host = inet_ntoa(who->sin_addr);
 
        else
                host = inet_ntoa(who->sin_addr);
 
+       init_env();
        /*
         * get terminal type.
         */
        getterminaltype();
        /*
         * get terminal type.
         */
        getterminaltype();
-       if (terminaltype == NULL)
-               terminaltype = "TERM=network";
+       setenv("TERM", terminaltype ? terminaltype : "network", 1);
 
        /*
         * Start up the login process on the slave side of the terminal
 
        /*
         * Start up the login process on the slave side of the terminal
@@ -389,7 +518,7 @@ int f, p;
         * Rather than doing them slowly, one at a time, do them all
         * at once.
         */
         * Rather than doing them slowly, one at a time, do them all
         * at once.
         */
-       if (!myopts[TELOPT_SGA])
+       if (my_state_is_wont(TELOPT_SGA))
                send_will(TELOPT_SGA, 1);
        /*
         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
                send_will(TELOPT_SGA, 1);
        /*
         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
@@ -404,11 +533,11 @@ int f, p;
        send_do(TELOPT_ECHO, 1);
 
 #ifdef LINEMODE
        send_do(TELOPT_ECHO, 1);
 
 #ifdef LINEMODE
-       if (hisopts[TELOPT_LINEMODE] == OPT_NO) {
+       if (his_state_is_wont(TELOPT_LINEMODE)) {
                /* Query the peer for linemode support by trying to negotiate
                 * the linemode option.
                 */
                /* Query the peer for linemode support by trying to negotiate
                 * the linemode option.
                 */
-               linemode = 1;
+               linemode = 0;
                editmode = 0;
                send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
        }
                editmode = 0;
                send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
        }
@@ -431,9 +560,25 @@ int f, p;
         * response, it will already have processed the DO ECHO.
         * Kludge upon kludge.
         */
         * response, it will already have processed the DO ECHO.
         * Kludge upon kludge.
         */
-       while (hiswants[TELOPT_NAWS] != hisopts[TELOPT_NAWS])
+       while (his_will_wont_is_changing(TELOPT_NAWS))
                ttloop();
 
                ttloop();
 
+       /*
+        * But...
+        * The client might have sent a WILL NAWS as part of its
+        * startup code; if so, we'll be here before we get the
+        * response to the DO ECHO.  We'll make the assumption
+        * that any implementation that understands about NAWS
+        * is a modern enough implementation that it will respond
+        * to our DO ECHO request; hence we'll do another spin
+        * waiting for the ECHO option to settle down, which is
+        * what we wanted to do in the first place...
+        */
+       if (his_want_state_is_will(TELOPT_ECHO) &&
+           his_state_is_will(TELOPT_NAWS)) {
+               while (his_will_wont_is_changing(TELOPT_ECHO))
+                       ttloop();
+       }
        /*
         * On the off chance that the telnet client is broken and does not
         * respond to the DO ECHO we sent, (after all, we did send the
        /*
         * On the off chance that the telnet client is broken and does not
         * respond to the DO ECHO we sent, (after all, we did send the
@@ -444,7 +589,13 @@ int f, p;
         * respond because it believes that it is already in DO ECHO
         * mode, which we do not want.
         */
         * respond because it believes that it is already in DO ECHO
         * mode, which we do not want.
         */
-       if (hiswants[TELOPT_ECHO] == OPT_YES) {
+       if (his_want_state_is_will(TELOPT_ECHO)) {
+#ifdef DIAGNOSTICS
+               if (diagnostic & TD_OPTIONS) {
+                       sprintf(nfrontp, "td: simulating recv\r\n");
+                       nfrontp += strlen(nfrontp);
+               }
+#endif /* DIAGNOSTICS */
                willoption(TELOPT_ECHO);
        }
 
                willoption(TELOPT_ECHO);
        }
 
@@ -453,7 +604,7 @@ int f, p;
         * will break stupid 4.2 telnets out of local terminal echo.
         */
 
         * will break stupid 4.2 telnets out of local terminal echo.
         */
 
-       if (!myopts[TELOPT_ECHO])
+       if (my_state_is_wont(TELOPT_ECHO))
                send_will(TELOPT_ECHO, 1);
 
        /*
                send_will(TELOPT_ECHO, 1);
 
        /*
@@ -519,9 +670,13 @@ int f, p;
        termstat();
 #endif
 
        termstat();
 #endif
 
+#ifdef NO_SETSID
        (void) setpgrp(0, 0);
        (void) setpgrp(0, 0);
-#ifdef TCSETCTTY
-       ioctl(p, TCSETCTTY, 0);
+#else
+       (void) setsid();
+#endif
+#if    defined(TIOCSCTTY) && defined(CRAY)
+       ioctl(p, TIOCSCTTY, 0);
 #endif
 
        /*
 #endif
 
        /*
@@ -570,6 +725,13 @@ int f, p;
        localstat();
 #endif /* LINEMODE */
 
        localstat();
 #endif /* LINEMODE */
 
+#ifdef DIAGNOSTICS
+       if (diagnostic & TD_REPORT) {
+               sprintf(nfrontp, "td: Entering processing loop\r\n");
+               nfrontp += strlen(nfrontp);
+       }
+#endif /* DIAGNOSTICS */
+
        for (;;) {
                fd_set ibits, obits, xbits;
                register int c;
        for (;;) {
                fd_set ibits, obits, xbits;
                register int c;
@@ -688,6 +850,15 @@ int f, p;
                        }
                        netip = netibuf;
                    }
                        }
                        netip = netibuf;
                    }
+#ifdef DIAGNOSTICS
+                   if (diagnostic & (TD_REPORT | TD_NETDATA)) {
+                           sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
+                           nfrontp += strlen(nfrontp);
+                   }
+                   if (diagnostic & TD_NETDATA) {
+                           printdata("nd", netip, ncc);
+                   }
+#endif /* DIAGNOSTICS */
                }
 
                /*
                }
 
                /*
@@ -727,7 +898,7 @@ int f, p;
                                        neturg = nfrontp-1; /* off by one XXX */
 #endif
                                }
                                        neturg = nfrontp-1; /* off by one XXX */
 #endif
                                }
-                               if (hisopts[TELOPT_LFLOW] &&
+                               if (his_state_is_will(TELOPT_LFLOW) &&
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                                        (void) sprintf(nfrontp, "%c%c%c%c%c%c",
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                                        (void) sprintf(nfrontp, "%c%c%c%c%c%c",
@@ -759,11 +930,11 @@ int f, p;
                                *nfrontp++ = c;
 #if    defined(CRAY2) && defined(UNICOS5)
                        else if (c == '\n' &&
                                *nfrontp++ = c;
 #if    defined(CRAY2) && defined(UNICOS5)
                        else if (c == '\n' &&
-                                    myopts[TELOPT_BINARY] == OPT_NO && newmap)
+                                    my_state_is_wont(TELOPT_BINARY) && newmap)
                                *nfrontp++ = '\r';
 #endif /* defined(CRAY2) && defined(UNICOS5) */
                        *nfrontp++ = c;
                                *nfrontp++ = '\r';
 #endif /* defined(CRAY2) && defined(UNICOS5) */
                        *nfrontp++ = c;
-                       if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
+                       if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
index c181962..962f966 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)termstat.c 5.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)termstat.c 5.6 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -105,7 +105,7 @@ localstat()
 {
        void netflush();
 
 {
        void netflush();
 
-#ifdef defined(CRAY2) && defined(UNICOS5)
+#if    defined(CRAY2) && defined(UNICOS5)
        /*
         * Keep track of that ol' CR/NL mapping while we're in the
         * neighborhood.
        /*
         * Keep track of that ol' CR/NL mapping while we're in the
         * neighborhood.
@@ -117,25 +117,25 @@ localstat()
         * Check for state of BINARY options.
         */
        if (tty_isbinaryin()) {
         * Check for state of BINARY options.
         */
        if (tty_isbinaryin()) {
-               if (hiswants[TELOPT_BINARY] == OPT_NO)
+               if (his_want_state_is_wont(TELOPT_BINARY))
                        send_do(TELOPT_BINARY, 1);
        } else {
                        send_do(TELOPT_BINARY, 1);
        } else {
-               if (hiswants[TELOPT_BINARY] == OPT_YES)
+               if (his_want_state_is_will(TELOPT_BINARY))
                        send_dont(TELOPT_BINARY, 1);
        }
 
        if (tty_isbinaryout()) {
                        send_dont(TELOPT_BINARY, 1);
        }
 
        if (tty_isbinaryout()) {
-               if (mywants[TELOPT_BINARY] == OPT_NO)
+               if (my_want_state_is_wont(TELOPT_BINARY))
                        send_will(TELOPT_BINARY, 1);
        } else {
                        send_will(TELOPT_BINARY, 1);
        } else {
-               if (mywants[TELOPT_BINARY] == OPT_YES)
+               if (my_want_state_is_will(TELOPT_BINARY))
                        send_wont(TELOPT_BINARY, 1);
        }
 
        /*
         * Check for changes to flow control if client supports it.
         */
                        send_wont(TELOPT_BINARY, 1);
        }
 
        /*
         * Check for changes to flow control if client supports it.
         */
-       if (hisopts[TELOPT_LFLOW] == OPT_YES) {
+       if (his_state_is_will(TELOPT_LFLOW)) {
                if (tty_flowmode() != flowmode) {
                        flowmode = tty_flowmode();
                        (void) sprintf(nfrontp, "%c%c%c%c%c%c", IAC, SB,
                if (tty_flowmode() != flowmode) {
                        flowmode = tty_flowmode();
                        (void) sprintf(nfrontp, "%c%c%c%c%c%c", IAC, SB,
@@ -158,19 +158,6 @@ localstat()
                tty_setlinemode(uselinemode);
        }
 
                tty_setlinemode(uselinemode);
        }
 
-# ifdef        KLUDGELINEMODE
-       /*
-        * If using kludge linemode and linemode is desired, it can't
-        * be done if normal line editing is not available on the
-        * pty.  This becomes the test for linemode on/off when
-        * using kludge linemode.
-        */
-       if (lmodetype == KLUDGE_LINEMODE && uselinemode && tty_israw()) {
-               uselinemode = 0;
-               tty_setlinemode(uselinemode);
-       }
-# endif        /* KLUDGELINEMODE */
-
        /*
         * Do echo mode handling as soon as we know what the
         * linemode is going to be.
        /*
         * Do echo mode handling as soon as we know what the
         * linemode is going to be.
@@ -206,6 +193,7 @@ localstat()
 # ifdef        KLUDGELINEMODE
        /*
         * If using real linemode check edit modes for possible later use.
 # ifdef        KLUDGELINEMODE
        /*
         * If using real linemode check edit modes for possible later use.
+        * If we are in kludge linemode, do the SGA negotiation.
         */
        if (lmodetype == REAL_LINEMODE) {
 # endif        /* KLUDGELINEMODE */
         */
        if (lmodetype == REAL_LINEMODE) {
 # endif        /* KLUDGELINEMODE */
@@ -214,7 +202,16 @@ localstat()
                        useeditmode |= MODE_EDIT;
                if (tty_istrapsig())
                        useeditmode |= MODE_TRAPSIG;
                        useeditmode |= MODE_EDIT;
                if (tty_istrapsig())
                        useeditmode |= MODE_TRAPSIG;
+               if (tty_issofttab())
+                       useeditmode |= MODE_SOFT_TAB;
+               if (tty_islitecho())
+                       useeditmode |= MODE_LIT_ECHO;
 # ifdef        KLUDGELINEMODE
 # ifdef        KLUDGELINEMODE
+       } else if (lmodetype == KLUDGE_LINEMODE) {
+               if (tty_isediting() && uselinemode)
+                       send_wont(TELOPT_SGA, 1);
+               else
+                       send_will(TELOPT_SGA, 1);
        }
 # endif        /* KLUDGELINEMODE */
 
        }
 # endif        /* KLUDGELINEMODE */
 
@@ -357,6 +354,10 @@ register int code, parm1, parm2;
                                        useeditmode |= MODE_EDIT;
                                if (tty_istrapsig)
                                        useeditmode |= MODE_TRAPSIG;
                                        useeditmode |= MODE_EDIT;
                                if (tty_istrapsig)
                                        useeditmode |= MODE_TRAPSIG;
+                               if (tty_issofttab())
+                                       useeditmode |= MODE_SOFT_TAB;
+                               if (tty_islitecho())
+                                       useeditmode |= MODE_LIT_ECHO;
                                (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
                                        SB, TELOPT_LINEMODE, LM_MODE,
                                                        useeditmode, IAC, SE);
                                (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
                                        SB, TELOPT_LINEMODE, LM_MODE,
                                                        useeditmode, IAC, SE);
@@ -374,7 +375,7 @@ register int code, parm1, parm2;
        
        case LM_MODE:
            {
        
        case LM_MODE:
            {
-               register int mode, sig, ack;
+               register int ack, changed;
 
                /*
                 * Client has sent along a mode mask.  If it agrees with
 
                /*
                 * Client has sent along a mode mask.  If it agrees with
@@ -387,16 +388,18 @@ register int code, parm1, parm2;
                 ack = (useeditmode & MODE_ACK);
                 useeditmode &= ~MODE_ACK;
 
                 ack = (useeditmode & MODE_ACK);
                 useeditmode &= ~MODE_ACK;
 
-                if (useeditmode != editmode) {
-                       mode = (useeditmode & MODE_EDIT);
-                       sig = (useeditmode & MODE_TRAPSIG);
+                if (changed = (useeditmode ^ editmode)) {
+                       if (changed & MODE_EDIT)
+                               tty_setedit(useeditmode & MODE_EDIT);
 
 
-                       if (mode != (editmode & LM_MODE)) {
-                               tty_setedit(mode);
-                       }
-                       if (sig != (editmode & MODE_TRAPSIG)) {
-                               tty_setsig(sig);
-                       }
+                       if (changed & MODE_TRAPSIG)
+                               tty_setsig(useeditmode & MODE_TRAPSIG);
+
+                       if (changed & MODE_SOFT_TAB)
+                               tty_setsofttab(useeditmode & MODE_SOFT_TAB);
+
+                       if (changed & MODE_LIT_ECHO)
+                               tty_setlitecho(useeditmode & MODE_LIT_ECHO);
 
                        set_termbuf();
 
 
                        set_termbuf();
 
index 263a058..516043d 100644 (file)
@@ -6,10 +6,10 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utility.c  5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)utility.c  5.4 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-
+#define PRINTOPTIONS
 #include "telnetd.h"
 
 /*
 #include "telnetd.h"
 
 /*
@@ -30,6 +30,12 @@ ttloop()
 {
     void netflush();
 
 {
     void netflush();
 
+#ifdef DIAGNOSTICS
+    if (diagnostic & TD_REPORT) {
+       sprintf(nfrontp, "td: ttloop\r\n");
+       nfrontp += strlen(nfrontp);
+    }
+#endif /* DIAGNOSTICS */
     if (nfrontp-nbackp) {
        netflush();
     }
     if (nfrontp-nbackp) {
        netflush();
     }
@@ -41,6 +47,12 @@ ttloop()
        syslog(LOG_INFO, "ttloop:  peer died: %m\n");
        exit(1);
     }
        syslog(LOG_INFO, "ttloop:  peer died: %m\n");
        exit(1);
     }
+#ifdef DIAGNOSTICS
+    if (diagnostic & TD_REPORT) {
+       sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
+       nfrontp += strlen(nfrontp);
+    }
+#endif /* DIAGNOSTICS */
     netip = netibuf;
     telrcv();                  /* state machine */
     if (ncc > 0) {
     netip = netibuf;
     telrcv();                  /* state machine */
     if (ncc > 0) {
@@ -79,8 +91,18 @@ ptyflush()
 {
        int n;
 
 {
        int n;
 
-       if ((n = pfrontp - pbackp) > 0)
+       if ((n = pfrontp - pbackp) > 0) {
+#ifdef DIAGNOSTICS
+               if (diagnostic & (TD_REPORT | TD_PTYDATA)) {
+                       sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
+                       nfrontp += strlen(nfrontp);
+               }
+               if (diagnostic & TD_PTYDATA) {
+                       printdata("pd", pbackp, n);
+               }
+#endif /* DIAGNOSTICS */
                n = write(pty, pbackp, n);
                n = write(pty, pbackp, n);
+       }
        if (n < 0)
                return;
        pbackp += n;
        if (n < 0)
                return;
        pbackp += n;
@@ -196,6 +218,13 @@ netflush()
     extern int not42;
 
     if ((n = nfrontp - nbackp) > 0) {
     extern int not42;
 
     if ((n = nfrontp - nbackp) > 0) {
+#ifdef DIAGNOSTICS
+       if (diagnostic & TD_REPORT) {
+           sprintf(nfrontp, "td: netflush %d chars\r\n", n);
+           n += strlen(nfrontp);  /* get count first */
+           nfrontp += strlen(nfrontp);  /* then move pointer */
+       }
+#endif /* DIAGNOSTICS */
        /*
         * if no urgent data, or if the other side appears to be an
         * old 4.2 client (and thus unable to survive TCP urgent data),
        /*
         * if no urgent data, or if the other side appears to be an
         * old 4.2 client (and thus unable to survive TCP urgent data),
@@ -408,3 +437,523 @@ char *cp, **cpp;
        return(0);
 }
 #endif /* NO_GETTYTAB */
        return(0);
 }
 #endif /* NO_GETTYTAB */
+
+#ifdef DIAGNOSTICS
+/*
+ * Print telnet options and commands in plain text, if possible.
+ */
+void
+printoption(fmt, option)
+register char *fmt;
+register int option;
+{
+       if (TELOPT_OK(option))
+               sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
+       else if (TELCMD_OK(option))
+               sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
+       else
+               sprintf(nfrontp, "%s %d\r\n", fmt, option);
+       nfrontp += strlen(nfrontp);
+       return;
+}
+
+char *slcnames[] = { SLC_NAMES };
+
+void
+printsub(dirp, pointer, length)
+char   *dirp;
+unsigned char  *pointer;       /* where suboption data sits */
+int    length;                 /* length of suboption data */
+{
+    register int i;
+
+       if (dirp) {
+           sprintf(nfrontp, "%s suboption ", dirp);
+           nfrontp += strlen(nfrontp);
+           if (length >= 3) {
+               register int j;
+
+               i = pointer[length-2];
+               j = pointer[length-1];
+
+               if (i != IAC || j != SE) {
+                   sprintf(nfrontp, "(terminated by ");
+                   nfrontp += strlen(nfrontp);
+                   if (TELOPT_OK(i))
+                       sprintf(nfrontp, "%s ", TELOPT(i));
+                   else if (TELCMD_OK(i))
+                       sprintf(nfrontp, "%s ", TELCMD(i));
+                   else
+                       sprintf(nfrontp, "%d ", i);
+                   nfrontp += strlen(nfrontp);
+                   if (TELOPT_OK(j))
+                       sprintf(nfrontp, "%s", TELOPT(j));
+                   else if (TELCMD_OK(j))
+                       sprintf(nfrontp, "%s", TELCMD(j));
+                   else
+                       sprintf(nfrontp, "%d", j);
+                   nfrontp += strlen(nfrontp);
+                   sprintf(nfrontp, ", not IAC SE!) ");
+                   nfrontp += strlen(nfrontp);
+               }
+           }
+           length -= 2;
+       }
+       if (length < 1) {
+           sprintf(nfrontp, "(Empty suboption???)");
+           nfrontp += strlen(nfrontp);
+           return;
+       }
+       switch (pointer[0]) {
+       case TELOPT_TTYPE:
+           sprintf(nfrontp, "TERMINAL-TYPE ");
+           nfrontp += strlen(nfrontp);
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
+               break;
+           case TELQUAL_SEND:
+               sprintf(nfrontp, "SEND");
+               break;
+           default:
+               sprintf(nfrontp,
+                               "- unknown qualifier %d (0x%x).",
+                               pointer[1], pointer[1]);
+           }
+           nfrontp += strlen(nfrontp);
+           break;
+       case TELOPT_TSPEED:
+           sprintf(nfrontp, "TERMINAL-SPEED");
+           nfrontp += strlen(nfrontp);
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
+               nfrontp += strlen(nfrontp);
+               break;
+           default:
+               if (pointer[1] == 1)
+                   sprintf(nfrontp, " SEND");
+               else
+                   sprintf(nfrontp, " %d (unknown)", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               for (i = 2; i < length; i++) {
+                   sprintf(nfrontp, " ?%d?", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+               break;
+           }
+           break;
+
+       case TELOPT_LFLOW:
+           sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
+           nfrontp += strlen(nfrontp);
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           switch (pointer[1]) {
+           case 0:
+               sprintf(nfrontp, " OFF"); break;
+           case 1:
+               sprintf(nfrontp, " ON"); break;
+           default:
+               sprintf(nfrontp, " %d (unknown)", pointer[1]);
+           }
+           nfrontp += strlen(nfrontp);
+           for (i = 2; i < length; i++) {
+               sprintf(nfrontp, " ?%d?", pointer[i]);
+               nfrontp += strlen(nfrontp);
+           }
+           break;
+
+       case TELOPT_NAWS:
+           sprintf(nfrontp, "NAWS");
+           nfrontp += strlen(nfrontp);
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           if (length == 2) {
+               sprintf(nfrontp, " ?%d?", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           sprintf(nfrontp, " %d %d (%d)",
+               pointer[1], pointer[2],
+               (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+           nfrontp += strlen(nfrontp);
+           if (length == 4) {
+               sprintf(nfrontp, " ?%d?", pointer[3]);
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           sprintf(nfrontp, " %d %d (%d)",
+               pointer[3], pointer[4],
+               (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+           nfrontp += strlen(nfrontp);
+           for (i = 5; i < length; i++) {
+               sprintf(nfrontp, " ?%d?", pointer[i]);
+               nfrontp += strlen(nfrontp);
+           }
+           break;
+
+       case TELOPT_LINEMODE:
+           sprintf(nfrontp, "LINEMODE ");
+           nfrontp += strlen(nfrontp);
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           switch (pointer[1]) {
+           case WILL:
+               sprintf(nfrontp, "WILL ");
+               goto common;
+           case WONT:
+               sprintf(nfrontp, "WONT ");
+               goto common;
+           case DO:
+               sprintf(nfrontp, "DO ");
+               goto common;
+           case DONT:
+               sprintf(nfrontp, "DONT ");
+           common:
+               nfrontp += strlen(nfrontp);
+               if (length < 3) {
+                   sprintf(nfrontp, "(no option???)");
+                   nfrontp += strlen(nfrontp);
+                   break;
+               }
+               switch (pointer[2]) {
+               case LM_FORWARDMASK:
+                   sprintf(nfrontp, "Forward Mask");
+                   nfrontp += strlen(nfrontp);
+                   for (i = 3; i < length; i++) {
+                       sprintf(nfrontp, " %x", pointer[i]);
+                       nfrontp += strlen(nfrontp);
+                   }
+                   break;
+               default:
+                   sprintf(nfrontp, "%d (unknown)", pointer[2]);
+                   nfrontp += strlen(nfrontp);
+                   for (i = 3; i < length; i++) {
+                       sprintf(nfrontp, " %d", pointer[i]);
+                       nfrontp += strlen(nfrontp);
+                   }
+                   break;
+               }
+               break;
+               
+           case LM_SLC:
+               sprintf(nfrontp, "SLC");
+               nfrontp += strlen(nfrontp);
+               for (i = 2; i < length - 2; i += 3) {
+                   if (pointer[i+SLC_FUNC] <= NSLC)
+                       sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]);
+                   else
+                       sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
+                   nfrontp += strlen(nfrontp);
+                   switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+                   case SLC_NOSUPPORT:
+                       sprintf(nfrontp, " NOSUPPORT"); break;
+                   case SLC_CANTCHANGE:
+                       sprintf(nfrontp, " CANTCHANGE"); break;
+                   case SLC_VARIABLE:
+                       sprintf(nfrontp, " VARIABLE"); break;
+                   case SLC_DEFAULT:
+                       sprintf(nfrontp, " DEFAULT"); break;
+                   }
+                   nfrontp += strlen(nfrontp);
+                   sprintf(nfrontp, "%s%s%s",
+                       pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+                       pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+                       pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+                   nfrontp += strlen(nfrontp);
+                   if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+                                               SLC_FLUSHOUT| SLC_LEVELBITS)) {
+                       sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
+                       nfrontp += strlen(nfrontp);
+                   }
+                   sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
+                   nfrontp += strlen(nfrontp);
+                   if ((pointer[i+SLC_VALUE] == IAC) &&
+                       (pointer[i+SLC_VALUE+1] == IAC))
+                               i++;
+               }
+               for (; i < length; i++) {
+                   sprintf(nfrontp, " ?%d?", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+               break;
+
+           case LM_MODE:
+               sprintf(nfrontp, "MODE ");
+               nfrontp += strlen(nfrontp);
+               if (length < 3) {
+                   sprintf(nfrontp, "(no mode???)");
+                   nfrontp += strlen(nfrontp);
+                   break;
+               }
+               {
+                   char tbuf[32];
+                   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" : "");
+                   sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
+                   nfrontp += strlen(nfrontp);
+               }
+               if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
+                   sprintf(nfrontp, " (0x%x)", pointer[2]);
+                   nfrontp += strlen(nfrontp);
+               }
+               for (i = 3; i < length; i++) {
+                   sprintf(nfrontp, " ?0x%x?", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+               break;
+           default:
+               sprintf(nfrontp, "%d (unknown)", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               for (i = 2; i < length; i++) {
+                   sprintf(nfrontp, " %d", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+           }
+           break;
+
+       case TELOPT_STATUS: {
+           register char *cp;
+           register int j, k;
+
+           sprintf(nfrontp, "STATUS");
+           nfrontp += strlen(nfrontp);
+
+           switch (pointer[1]) {
+           default:
+               if (pointer[1] == TELQUAL_SEND)
+                   sprintf(nfrontp, " SEND");
+               else
+                   sprintf(nfrontp, " %d (unknown)", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               for (i = 2; i < length; i++) {
+                   sprintf(nfrontp, " ?%d?", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+               break;
+           case TELQUAL_IS:
+               sprintf(nfrontp, " IS\r\n");
+               nfrontp += strlen(nfrontp);
+
+               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]))
+                           sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
+                       else
+                           sprintf(nfrontp, " %s %d", cp, pointer[i]);
+                       nfrontp += strlen(nfrontp);
+
+                       sprintf(nfrontp, "\r\n");
+                       nfrontp += strlen(nfrontp);
+                       break;
+
+                   case SB:
+                       sprintf(nfrontp, " SB ");
+                       nfrontp += strlen(nfrontp);
+                       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) {
+                           sprintf(nfrontp, " SE");
+                           nfrontp += strlen(nfrontp);
+                           i = j;
+                       } else
+                           i = j - 1;
+
+                       sprintf(nfrontp, "\r\n");
+                       nfrontp += strlen(nfrontp);
+
+                       break;
+                               
+                   default:
+                       sprintf(nfrontp, " %d", pointer[i]);
+                       nfrontp += strlen(nfrontp);
+                       break;
+                   }
+               }
+               break;
+           }
+           break;
+         }
+
+       case TELOPT_XDISPLOC:
+           sprintf(nfrontp, "X-DISPLAY-LOCATION ");
+           nfrontp += strlen(nfrontp);
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
+               break;
+           case TELQUAL_SEND:
+               sprintf(nfrontp, "SEND");
+               break;
+           default:
+               sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
+                               pointer[1], pointer[1]);
+           }
+           nfrontp += strlen(nfrontp);
+           break;
+
+       case TELOPT_ENVIRON:
+           sprintf(nfrontp, "ENVIRON ");
+           nfrontp += strlen(nfrontp);
+           switch (pointer[1]) {
+           case TELQUAL_IS:
+               sprintf(nfrontp, "IS ");
+               goto env_common;
+           case TELQUAL_SEND:
+               sprintf(nfrontp, "SEND ");
+               goto env_common;
+           case TELQUAL_INFO:
+               sprintf(nfrontp, "INFO ");
+           env_common:
+           nfrontp += strlen(nfrontp);
+               {
+                   register int noquote = 2;
+                   for (i = 2; i < length; i++ ) {
+                       switch (pointer[i]) {
+                       case ENV_VAR:
+                           if (pointer[1] == TELQUAL_SEND)
+                               goto def_case;
+                           sprintf(nfrontp, "\" VAR " + noquote);
+                           nfrontp += strlen(nfrontp);
+                           noquote = 2;
+                           break;
+
+                       case ENV_VALUE:
+                           sprintf(nfrontp, "\" VALUE " + noquote);
+                           nfrontp += strlen(nfrontp);
+                           noquote = 2;
+                           break;
+
+                       case ENV_ESC:
+                           sprintf(nfrontp, "\" ESC " + noquote);
+                           nfrontp += strlen(nfrontp);
+                           noquote = 2;
+                           break;
+
+                       default:
+                       def_case:
+                           if (isprint(pointer[i]) && pointer[i] != '"') {
+                               if (noquote) {
+                                   *nfrontp++ = '"';
+                                   noquote = 0;
+                               }
+                               *nfrontp++ = pointer[i];
+                           } else {
+                               sprintf(nfrontp, "\" %03o " + noquote,
+                                                       pointer[i]);
+                               nfrontp += strlen(nfrontp);
+                               noquote = 2;
+                           }
+                           break;
+                       }
+                   }
+                   if (!noquote)
+                       *nfrontp++ = '"';
+                   break;
+               }
+           }
+           break;
+
+       default:
+           sprintf(nfrontp, "Unknown option ");
+           nfrontp += strlen(nfrontp);
+           for (i = 0; i < length; i++) {
+               sprintf(nfrontp, " %d", pointer[i]);
+               nfrontp += strlen(nfrontp);
+           }
+           break;
+       }
+       sprintf(nfrontp, "\r\n");
+       nfrontp += strlen(nfrontp);
+}
+
+/*
+ * Dump a data buffer in hex and ascii to the output data stream.
+ */
+void
+printdata(tag, ptr, cnt)
+register char *tag;
+register char *ptr;
+register int cnt;
+{
+register int i;
+char xbuf[30];
+
+       while (cnt) {
+               /* flush net output buffer if no room for new data) */
+               if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
+                       netflush();
+               }
+
+               /* add a line of output */
+               sprintf(nfrontp, "%s: ", tag);
+               nfrontp += strlen(nfrontp);
+               for (i = 0; i < 20 && cnt; i++) {
+                       sprintf(nfrontp, "%02x", *ptr);
+                       nfrontp += strlen(nfrontp); 
+                       if (isprint(*ptr)) {
+                               xbuf[i] = *ptr;
+                       } else {
+                               xbuf[i] = '.';
+                       }
+                       if (i % 2) { 
+                               *nfrontp = ' ';
+                               nfrontp++;
+                       }
+                       cnt--;
+                       ptr++;
+               }
+               xbuf[i] = '\0';
+               sprintf(nfrontp, " %s\r\n", xbuf );
+               nfrontp += strlen(nfrontp);
+       } 
+}
+
+#endif /* DIAGNOSTICS */
+
+#ifdef NO_STRERROR
+char *
+strerror(errno)
+{
+       extern char *sys_errlist[];
+
+       return(sys_errlist[errno]);
+}
+#endif
index 0329e53..4ab511c 100644 (file)
@@ -1,4 +1,4 @@
-#      @(#)Makefile    5.2 (Berkeley) %G%
+#      @(#)Makefile    5.3 (Berkeley) %G%
 #
 # TERMCAP      Define this if your system is termcap based,
 #              otherwise a terminfo based system is assumed.
 #
 # TERMCAP      Define this if your system is termcap based,
 #              otherwise a terminfo based system is assumed.
@@ -22,8 +22,8 @@
 #              C libaray (but you do have rindex...)
 #
 PROG=  telnet
 #              C libaray (but you do have rindex...)
 #
 PROG=  telnet
-CFLAGS+=-DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO
-#CFLAGS+=-DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO -DKERBEROS
+CFLAGS+=-DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO -DNEED_GETTOS
+#CFLAGS+=-DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO -DNEED_GETTOS -DKERBEROS
 LDADD= -ltermcap
 #LDADD=        -ltermcap -ldes -lkrb
 DPADD= ${LIBTERMCAP}
 LDADD= -ltermcap
 #LDADD=        -ltermcap -ldes -lkrb
 DPADD= ${LIBTERMCAP}
index 47a38ae..097edce 100644 (file)
@@ -6,17 +6,15 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)commands.c 1.29 (Berkeley) %G%";
+static char sccsid[] = "@(#)commands.c 1.30 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/param.h>
+#include <sys/types.h>
 #if    defined(unix)
 #include <sys/file.h>
 #endif /* defined(unix) */
 #include <sys/socket.h>
 #include <netinet/in.h>
 #if    defined(unix)
 #include <sys/file.h>
 #endif /* defined(unix) */
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
 #ifdef CRAY
 #include <sys/fcntl.h>
 #endif /* CRAY */
 #ifdef CRAY
 #include <sys/fcntl.h>
 #endif /* CRAY */
@@ -36,9 +34,18 @@ static char sccsid[] = "@(#)commands.c       1.29 (Berkeley) %G%";
 #include "defines.h"
 #include "types.h"
 
 #include "defines.h"
 #include "types.h"
 
+#ifdef SRCRT
+# ifndef CRAY
+# include <netinet/in_systm.h>
+#  if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
+#  include <machine/endian.h>
+#  endif /* vax */
+# endif /* CRAY */
+#include <netinet/ip.h>
+#endif /* SRCRT */
 
 #if defined(CRAY) && defined(IP_TOS) && !defined(HAS_IP_TOS)
 
 #if defined(CRAY) && defined(IP_TOS) && !defined(HAS_IP_TOS)
-# define HAS_IP_TOS            /* have gettos() lookup */
+# define HAS_IP_TOS
 #endif
 
 
 #endif
 
 
@@ -47,6 +54,7 @@ extern char *getenv();
 
 #define Ambiguous(s)   ((char **)s == &ambiguous)
 static char *ambiguous;                /* special return value for command routines */
 
 #define Ambiguous(s)   ((char **)s == &ambiguous)
 static char *ambiguous;                /* special return value for command routines */
+static call();
 
 typedef struct {
        char    *name;          /* command name */
 
 typedef struct {
        char    *name;          /* command name */
@@ -102,7 +110,7 @@ herror(s)
 static void
 makeargv()
 {
 static void
 makeargv()
 {
-    register char *cp;
+    register char *cp, *cp2, c;
     register char **argp = margv;
 
     margc = 0;
     register char **argp = margv;
 
     margc = 0;
@@ -113,18 +121,39 @@ makeargv()
        margc++;
        cp++;
     }
        margc++;
        cp++;
     }
-    while (*cp) {
-       while (isspace(*cp))
-           cp++;
-       if (*cp == '\0')
+    while (c = *cp) {
+       register int inquote = 0;
+       while (isspace(c))
+           c = *++cp;
+       if (c == '\0')
            break;
        *argp++ = cp;
        margc += 1;
            break;
        *argp++ = cp;
        margc += 1;
-       while (*cp != '\0' && !isspace(*cp))
-           cp++;
-       if (*cp == '\0')
+       for (cp2 = cp; c != '\0'; c = *++cp) {
+           if (inquote) {
+               if (c == inquote) {
+                   inquote = 0;
+                   continue;
+               }
+           } else {
+               if (c == '\\') {
+                   if ((c = *++cp) == '\0')
+                       break;
+               } else if (c == '"') {
+                   inquote = '"';
+                   continue;
+               } else if (c == '\'') {
+                   inquote = '\'';
+                   continue;
+               } else if (isspace(c))
+                   break;
+           }
+           *cp2++ = c;
+       }
+       *cp2 = '\0';
+       if (c == '\0')
            break;
            break;
-       *cp++ = '\0';
+       cp++;
     }
     *argp++ = 0;
 }
     }
     *argp++ = 0;
 }
@@ -202,14 +231,20 @@ static char *
 control(c)
        register cc_t c;
 {
 control(c)
        register cc_t c;
 {
-       static char buf[3];
+       static char buf[5];
 
        if (c == 0x7f)
                return ("^?");
        if (c == (cc_t)-1) {
                return "off";
        }
 
        if (c == 0x7f)
                return ("^?");
        if (c == (cc_t)-1) {
                return "off";
        }
-       if (c >= 0x20) {
+       if (c >= 0x80) {
+               buf[0] = '\\';
+               buf[1] = ((c>>6)&07) + '0';
+               buf[2] = ((c>>3)&07) + '0';
+               buf[3] = (c&07) + '0';
+               buf[4] = 0;
+       } else if (c >= 0x20) {
                buf[0] = c;
                buf[1] = 0;
        } else {
                buf[0] = c;
                buf[1] = 0;
        } else {
@@ -370,7 +405,7 @@ char        **argv;
     for (i = 1; i < argc; i++) {
        if ((s = getsend(argv[i])) == 0) {
            fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
     for (i = 1; i < argc; i++) {
        if ((s = getsend(argv[i])) == 0) {
            fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
-           quit();
+           (void) quit();
            /*NOTREACHED*/
        }
        if (s->handler) {
            /*NOTREACHED*/
        }
        if (s->handler) {
@@ -756,7 +791,9 @@ struct setlist {
 };
 
 static struct setlist Setlist[] = {
 };
 
 static struct setlist Setlist[] = {
+#ifdef KLUDGELINEMODE
     { "echo",  "character to toggle local echoing on/off", 0, &echoc },
     { "echo",  "character to toggle local echoing on/off", 0, &echoc },
+#endif
     { "escape",        "character to escape back to telnet command mode", 0, &escape },
     { "tracefile", "file to write trace intormation to", SetNetTrace, (cc_t *)NetTraceFile},
     { " ", "" },
     { "escape",        "character to escape back to telnet command mode", 0, &escape },
     { "tracefile", "file to write trace intormation to", SetNetTrace, (cc_t *)NetTraceFile},
     { " ", "" },
@@ -770,11 +807,13 @@ static struct setlist Setlist[] = {
     { "erase", "character to use to erase a character", 0, termEraseCharp },
     { "kill",  "character to use to erase a line", 0, termKillCharp },
     { "lnext", "character to use for literal next", 0, termLiteralNextCharp },
     { "erase", "character to use to erase a character", 0, termEraseCharp },
     { "kill",  "character to use to erase a line", 0, termKillCharp },
     { "lnext", "character to use for literal next", 0, termLiteralNextCharp },
-    { "susp",  "character to cuase a Suspend Process", 0, termSuspCharp },
+    { "susp",  "character to cause a Suspend Process", 0, termSuspCharp },
     { "reprint", "character to use for line reprint", 0, termRprntCharp },
     { "worderase", "character to use to erase a word", 0, termWerasCharp },
     { "start", "character to use for XON", 0, termStartCharp },
     { "reprint", "character to use for line reprint", 0, termRprntCharp },
     { "worderase", "character to use to erase a word", 0, termWerasCharp },
     { "start", "character to use for XON", 0, termStartCharp },
-    { "stop",  "character to sue for XOFF", 0, termStopCharp },
+    { "stop",  "character to use for XOFF", 0, termStopCharp },
+    { "forw1", "alternate end of line character", 0, termForw1Charp },
+    { "forw2", "alternate end of line character", 0, termForw2Charp },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -782,18 +821,26 @@ static struct setlist Setlist[] = {
 /* Work around compiler bug */
 _setlist_init()
 {
 /* Work around compiler bug */
 _setlist_init()
 {
-       Setlist[5].charp = &termFlushChar;
-       Setlist[6].charp = &termIntChar;
-       Setlist[7].charp = &termQuitChar;
-       Setlist[8].charp = &termEofChar;
-       Setlist[11].charp = &termEraseChar;
-       Setlist[12].charp = &termKillChar;
-       Setlist[13].charp = &termLiteralNextChar;
-       Setlist[14].charp = &termSuspChar;
-       Setlist[15].charp = &termRprntChar;
-       Setlist[16].charp = &termWerasChar;
-       Setlist[17].charp = &termStartChar;
-       Setlist[18].charp = &termStopChar;
+#ifndef        KLUDGELINEMODE
+#define        N 4
+#else
+#define        N 5
+#endif
+       Setlist[N+0].charp = &termFlushChar;
+       Setlist[N+1].charp = &termIntChar;
+       Setlist[N+2].charp = &termQuitChar;
+       Setlist[N+3].charp = &termEofChar;
+       Setlist[N+6].charp = &termEraseChar;
+       Setlist[N+7].charp = &termKillChar;
+       Setlist[N+8].charp = &termLiteralNextChar;
+       Setlist[N+9].charp = &termSuspChar;
+       Setlist[N+10].charp = &termRprntChar;
+       Setlist[N+11].charp = &termWerasChar;
+       Setlist[N+12].charp = &termStartChar;
+       Setlist[N+13].charp = &termStopChar;
+       Setlist[N+14].charp = &termForw1Char;
+       Setlist[N+15].charp = &termForw2Char;
+#undef N
 }
 #endif /* CRAY */
 
 }
 #endif /* CRAY */
 
@@ -813,6 +860,13 @@ char *name;
     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
 }
 
     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
 }
 
+set_escape_char(s)
+char *s;
+{
+       escape = (s && *s) ? special(s) : -1;
+       printf("escape character is '%s'.\n", control(escape));
+}
+
 static
 setcmd(argc, argv)
 int    argc;
 static
 setcmd(argc, argv)
 int    argc;
@@ -873,7 +927,7 @@ char        *argv[];
        return 0;
     } else if (ct->handler) {
        (*ct->handler)(argv[2]);
        return 0;
     } else if (ct->handler) {
        (*ct->handler)(argv[2]);
-       printf("%s set to \"%s\".\n", ct->name, (unsigned char *)ct->charp);
+       printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
     } else {
        if (strcmp("off", argv[2])) {
            value = special(argv[2]);
     } else {
        if (strcmp("off", argv[2])) {
            value = special(argv[2]);
@@ -892,7 +946,6 @@ unsetcmd(argc, argv)
 int    argc;
 char   *argv[];
 {
 int    argc;
 char   *argv[];
 {
-    int value;
     struct setlist *ct;
     struct togglelist *c;
     register char *name;
     struct setlist *ct;
     struct togglelist *c;
     register char *name;
@@ -942,9 +995,8 @@ char        *argv[];
            return 0;
        } else if (ct->handler) {
            (*ct->handler)(0);
            return 0;
        } else if (ct->handler) {
            (*ct->handler)(0);
-           printf("%s reset to \"%s\".\n", ct->name, ct->charp);
+           printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
        } else {
        } else {
-           value = -1;
            *(ct->charp) = -1;
            printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
        }
            *(ct->charp) = -1;
            printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
        }
@@ -958,6 +1010,14 @@ char      *argv[];
  */
 #ifdef KLUDGELINEMODE
 extern int kludgelinemode;
  */
 #ifdef KLUDGELINEMODE
 extern int kludgelinemode;
+
+dokludgemode()
+{
+    kludgelinemode = 1;
+    send_wont(TELOPT_LINEMODE, 1);
+    send_dont(TELOPT_SGA, 1);
+    send_dont(TELOPT_ECHO, 1);
+}
 #endif
 
 static
 #endif
 
 static
@@ -1042,7 +1102,17 @@ static struct modelist ModeList[] = {
     { "edit",  "Enable character editing",     setmode, 1, MODE_EDIT },
     { "+edit", 0,                              setmode, 1, MODE_EDIT },
     { "-edit", "Disable character editing",    clearmode, 1, MODE_EDIT },
     { "edit",  "Enable character editing",     setmode, 1, MODE_EDIT },
     { "+edit", 0,                              setmode, 1, MODE_EDIT },
     { "-edit", "Disable character editing",    clearmode, 1, MODE_EDIT },
+    { "softtabs", "Enable tab expansion",      setmode, 1, MODE_SOFT_TAB },
+    { "+softtabs", 0,                          setmode, 1, MODE_SOFT_TAB },
+    { "-softtabs", "Disable character editing",        clearmode, 1, MODE_SOFT_TAB },
+    { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
+    { "+litecho", 0,                           setmode, 1, MODE_LIT_ECHO },
+    { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
     { "help",  0,                              modehelp, 0 },
     { "help",  0,                              modehelp, 0 },
+#ifdef KLUDGELINEMODE
+    { "kludgeline", 0,                         dokludgemode, 1 },
+#endif
+    { "", "", 0 },
     { "?",     "Print help information",       modehelp, 0 },
     { 0 },
 };
     { "?",     "Print help information",       modehelp, 0 },
     { 0 },
 };
@@ -1123,7 +1193,7 @@ char      *argv[];
                        if (sl->handler == 0) \
                            printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
                        else \
                        if (sl->handler == 0) \
                            printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
                        else \
-                           printf("%-15s \"%s\"\n", sl->name, sl->charp); \
+                           printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
                    }
 
     struct togglelist *tl;
                    }
 
     struct togglelist *tl;
@@ -1217,15 +1287,14 @@ suspend()
 #ifdef SIGTSTP
     setcommandmode();
     {
 #ifdef SIGTSTP
     setcommandmode();
     {
-       long oldrows, oldcols, newrows, newcols;
+       long oldrows, oldcols, newrows, newcols, err;
 
 
-       TerminalWindowSize(&oldrows, &oldcols);
+       err = TerminalWindowSize(&oldrows, &oldcols);
        (void) kill(0, SIGTSTP);
        (void) kill(0, SIGTSTP);
-       TerminalWindowSize(&newrows, &newcols);
-       if ((oldrows != newrows) || (oldcols != newcols)) {
-           if (connected) {
+       err += TerminalWindowSize(&newrows, &newcols);
+       if (connected && !err &&
+           ((oldrows != newrows) || (oldcols != newcols))) {
                sendnaws();
                sendnaws();
-           }
        }
     }
     /* reget parameters in case they were changed */
        }
     }
     /* reget parameters in case they were changed */
@@ -1238,12 +1307,12 @@ suspend()
 }
 
 #if    !defined(TN3270)
 }
 
 #if    !defined(TN3270)
+/*ARGSUSED*/
 shell(argc, argv)
 int argc;
 char *argv[];
 {
     extern char *rindex();
 shell(argc, argv)
 int argc;
 char *argv[];
 {
     extern char *rindex();
-    char cmdbuf[256];
 
     setcommandmode();
     switch(vfork()) {
 
     setcommandmode();
     switch(vfork()) {
@@ -1273,7 +1342,7 @@ char *argv[];
            _exit(1);
        }
     default:
            _exit(1);
        }
     default:
-           wait((int *)0);     /* Wait for the shell to complete */
+           (void)wait((int *)0);       /* Wait for the shell to complete */
     }
 }
 #endif /* !defined(TN3270) */
     }
 }
 #endif /* !defined(TN3270) */
@@ -1307,7 +1376,7 @@ quit()
 {
        (void) call(bye, "bye", "fromquit", 0);
        Exit(0);
 {
        (void) call(bye, "bye", "fromquit", 0);
        Exit(0);
-       return 1;                       /* just to keep lint happy */
+       /*NOTREACHED*/
 }
 \f
 /*
 }
 \f
 /*
@@ -1392,8 +1461,276 @@ char    *argv[];
     slcstate();
     return 1;
 }
     slcstate();
     return 1;
 }
+\f
+/*
+ * The ENVIRON command.
+ */
+
+struct envlist {
+       char    *name;
+       char    *help;
+       int     (*handler)();
+       int     narg;
+};
+
+extern struct env_lst *env_define();
+extern int env_undefine();
+extern int env_export(), env_unexport();
+extern int env_list(), env_help();
+
+struct envlist EnvList[] = {
+    { "define",        "Define an environment variable",
+                                               (int (*)())env_define,  2 },
+    { "undefine", "Undefine an environment variable",
+                                               env_undefine,   1 },
+    { "export",        "Mark an environment variable for automatic export",
+                                               env_export,     1 },
+    { "unexport", "Dont mark an environment variable for automatic export",
+                                               env_unexport,   1 },
+    { "list",  "List the current environment variables",
+                                               env_list,       0 },
+    { "help",  0,                              env_help,               0 },
+    { "?",     "Print help information",       env_help,               0 },
+    { 0 },
+};
+
+static
+env_help()
+{
+    struct envlist *c;
+
+    for (c = EnvList; c->name; c++) {
+       if (c->help) {
+           if (*c->help)
+               printf("%-15s %s\n", c->name, c->help);
+           else
+               printf("\n");
+       }
+    }
+}
+
+static char **
+getnextenv(name)
+char *name;
+{
+    return (char **)(((struct envlist *)name)+1);
+}
+
+static struct envlist *
+getenvcmd(name)
+char *name;
+{
+    return (struct envlist *)genget(name, (char **) EnvList, getnextenv);
+}
+
+env_cmd(argc, argv)
+int    argc;
+char   *argv[];
+{
+    struct envlist *c;
+
+    if (argc < 2) {
+       fprintf(stderr,
+           "Need an argument to 'environ' command.  'environ ?' for help.\n");
+       return 0;
+    }
+    c = getenvcmd(argv[1]);
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
+                               argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
+                               argv[1]);
+        return 0;
+    }
+    if (c->narg + 2 != argc) {
+       fprintf(stderr,
+           "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
+               c->narg < argc + 2 ? "only " : "",
+               c->narg, c->narg == 1 ? "" : "s", c->name);
+       return 0;
+    }
+    (void)(*c->handler)(argv[2], argv[3]);
+    return 1;
+}
+
+struct env_lst {
+       struct env_lst *next;   /* pointer to next structure */
+       struct env_lst *prev;   /* pointer to next structure */
+       char *var;              /* pointer to variable name */
+       char *value;            /* pointer to varialbe value */
+       int export;             /* 1 -> export with default list of variables */
+};
+
+struct env_lst envlisthead;
+
+struct env_lst *
+env_find(var)
+{
+       register struct env_lst *ep;
+
+       for (ep = envlisthead.next; ep; ep = ep->next) {
+               if (strcmp(ep->var, var) == 0)
+                       return(ep);
+       }
+       return(NULL);
+}
+
+env_init()
+{
+       extern char **environ, *index();
+       register char **epp, *cp;
+       register struct env_lst *ep;
+
+       for (epp = environ; *epp; epp++) {
+               if (cp = index(*epp, '=')) {
+                       *cp = '\0';
+                       ep = env_define(*epp, cp+1);
+                       ep->export = 0;
+                       *cp = '=';
+               }
+       }
+       /*
+        * Special case for DISPLAY variable.  If it is ":0.0" or
+        * "unix:0.0", we have to get rid of "unix" and insert our
+        * hostname.
+        */
+       if ((ep = env_find("DISPLAY")) &&
+           ((*ep->value == ':') || (strncmp(ep->value, "unix:", 5) == 0))) {
+               char hbuf[256+1];
+               char *cp2 = index(ep->value, ':');
+
+               gethostname(hbuf, 256);
+               hbuf[256] = '\0';
+               cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
+               sprintf(cp, "%s%s", hbuf, cp2);
+               free(ep->value);
+               ep->value = cp;
+       }
+       /*
+        * If USER is not defined, but LOGNAME is, then add
+        * USER with the value from LOGNAME.
+        */
+       if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME")))
+               env_define("USER", ep->value);
+       env_export("USER");
+       env_export("DISPLAY");
+       env_export("PRINTER");
+}
+
+struct env_lst *
+env_define(var, value)
+char *var, *value;
+{
+       register struct env_lst *ep;
+       extern char *savestr();
+
+       if (ep = env_find(var)) {
+               if (ep->var)
+                       free(ep->var);
+               if (ep->value)
+                       free(ep->value);
+       } else {
+               ep = (struct env_lst *)malloc(sizeof(struct env_lst));
+               ep->export = 1;
+               ep->next = envlisthead.next;
+               envlisthead.next = ep;
+               ep->prev = &envlisthead;
+               if (ep->next)
+                       ep->next->prev = ep;
+       }
+       ep->var = savestr(var);
+       ep->value = savestr(value);
+       return(ep);
+}
+
+env_undefine(var)
+char *var;
+{
+       register struct env_lst *ep;
+
+       if (ep = env_find(var)) {
+               ep->prev->next = ep->next;
+               ep->next->prev = ep->prev;
+               if (ep->var)
+                       free(ep->var);
+               if (ep->value)
+                       free(ep->value);
+               free(ep);
+       }
+}
+
+env_export(var)
+char *var;
+{
+       register struct env_lst *ep;
+
+       if (ep = env_find(var))
+               ep->export = 1;
+}
+
+env_unexport(var)
+char *var;
+{
+       register struct env_lst *ep;
+
+       if (ep = env_find(var))
+               ep->export = 0;
+}
+
+env_list()
+{
+       register struct env_lst *ep;
+
+       for (ep = envlisthead.next; ep; ep = ep->next) {
+               printf("%c %-20s %s\n", ep->export ? '*' : ' ',
+                                       ep->var, ep->value);
+       }
+}
+
+char *
+env_default(init)
+{
+       static struct env_lst *nep = NULL;
+
+       if (init) {
+               nep = &envlisthead;
+               return;
+       }
+       if (nep) {
+               while (nep = nep->next) {
+                       if (nep->export)
+                               return(nep->var);
+               }
+       }
+       return(NULL);
+}
+
+char *
+env_getvalue(var)
+char *var;
+{
+       register struct env_lst *ep;
+
+       if (ep = env_find(var))
+               return(ep->value);
+       return(NULL);
+}
+
+char *
+savestr(s)
+register char *s;
+{
+       register char *ret;
+       if (ret = (char *)malloc(strlen(s)+1))
+               strcpy(ret, s);
+       return(ret);
+}
 
 #if    defined(unix)
 
 #if    defined(unix)
+#ifdef notdef
 /*
  * Some information about our file descriptors.
  */
 /*
  * Some information about our file descriptors.
  */
@@ -1453,7 +1790,9 @@ int mask;
     return buffer;
 }
 #undef do
     return buffer;
 }
 #undef do
+#endif /* notdef */
 
 
+#if defined(TN3270)
 static void
 filestuff(fd)
 int fd;
 static void
 filestuff(fd)
 int fd;
@@ -1482,6 +1821,7 @@ int fd;
     }
     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
 }
     }
     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
 }
+#endif /* defined(TN3270) */
 
 
 #endif /* defined(unix) */
 
 
 #endif /* defined(unix) */
@@ -1557,6 +1897,29 @@ char     *argv[];
 }
 
 
 }
 
 
+#if    defined(NEED_GETTOS)
+struct tosent {
+       char    *t_name;        /* name */
+       char    **t_aliases;    /* alias list */
+       char    *t_proto;       /* protocol */
+       int     t_tos;          /* Type Of Service bits */
+};
+
+struct tosent *
+gettosbyname(name, proto)
+char *name, *proto;
+{
+       static struct tosent te;
+       static char *aliasp = 0;
+
+       te.t_name = name;
+       te.t_aliases = &aliasp;
+       te.t_proto = proto;
+       te.t_tos = 020; /* Low Delay bit */
+       return(&te);
+}
+#endif
+
 int
 tn(argc, argv)
        int argc;
 int
 tn(argc, argv)
        int argc;
@@ -1568,14 +1931,14 @@ tn(argc, argv)
     static char        hnamebuf[32];
     unsigned long temp, inet_addr();
     extern char *inet_ntoa();
     static char        hnamebuf[32];
     unsigned long temp, inet_addr();
     extern char *inet_ntoa();
-    int tos;
 #if    defined(SRCRT) && defined(IPPROTO_IP)
     char *srp = 0, *strrchr();
     unsigned long sourceroute(), srlen;
 #endif
 #if    defined(SRCRT) && defined(IPPROTO_IP)
     char *srp = 0, *strrchr();
     unsigned long sourceroute(), srlen;
 #endif
-#if defined(HAS_IP_TOS)
+#if defined(HAS_IP_TOS) || defined(NEED_GETTOS)
     struct tosent *tp;
     struct tosent *tp;
-#endif /* defined(HAS_IP_TOS) */
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
+    char *cmd, *hostp = 0, *portp = 0, *user = 0;
 
 
     if (connected) {
 
 
     if (connected) {
@@ -1590,22 +1953,43 @@ tn(argc, argv)
        argc = margc;
        argv = margv;
     }
        argc = margc;
        argv = margv;
     }
-    if ((argc < 2) || (argc > 3)) {
-       printf("usage: %s host-name [port]\n", argv[0]);
+    cmd = *argv;
+    --argc; ++argv;
+    while (argc) {
+       if (strcmp(*argv, "-l") == 0) {
+           --argc; ++argv;
+           if (argc == 0)
+               goto usage;
+           user = *argv++;
+           --argc;
+           continue;
+       }
+       if (hostp == 0) {
+           hostp = *argv++;
+           --argc;
+           continue;
+       }
+       if (portp == 0) {
+           portp = *argv++;
+           --argc;
+           continue;
+       }
+    usage:
+       printf("usage: %s [-l user] host-name [port]\n", cmd);
        return 0;
     }
 #if    defined(SRCRT) && defined(IPPROTO_IP)
        return 0;
     }
 #if    defined(SRCRT) && defined(IPPROTO_IP)
-    if (argv[1][0] == '@' || argv[1][0] == '!') {
-       if ((hostname = strrchr(argv[1], ':')) == NULL)
-           hostname = strrchr(argv[1], '@');
+    if (hostp[0] == '@' || hostp[0] == '!') {
+       if ((hostname = strrchr(hostp, ':')) == NULL)
+           hostname = strrchr(hostp, '@');
        hostname++;
        srp = 0;
        hostname++;
        srp = 0;
-       temp = sourceroute(argv[1], &srp, &srlen);
+       temp = sourceroute(hostp, &srp, &srlen);
        if (temp == 0) {
            herror(srp);
            return 0;
        } else if (temp == -1) {
        if (temp == 0) {
            herror(srp);
            return 0;
        } else if (temp == -1) {
-           printf("Bad source route option: %s\n", argv[1]);
+           printf("Bad source route option: %s\n", hostp);
            return 0;
        } else {
            sin.sin_addr.s_addr = temp;
            return 0;
        } else {
            sin.sin_addr.s_addr = temp;
@@ -1613,14 +1997,14 @@ tn(argc, argv)
        }
     } else {
 #endif
        }
     } else {
 #endif
-       temp = inet_addr(argv[1]);
+       temp = inet_addr(hostp);
        if (temp != (unsigned long) -1) {
            sin.sin_addr.s_addr = temp;
            sin.sin_family = AF_INET;
        if (temp != (unsigned long) -1) {
            sin.sin_addr.s_addr = temp;
            sin.sin_family = AF_INET;
-           (void) strcpy(hnamebuf, argv[1]);
+           (void) strcpy(hnamebuf, hostp);
            hostname = hnamebuf;
        } else {
            hostname = hnamebuf;
        } else {
-           host = gethostbyname(argv[1]);
+           host = gethostbyname(hostp);
            if (host) {
                sin.sin_family = host->h_addrtype;
 #if    defined(h_addr)         /* In 4.3, this is a #define */
            if (host) {
                sin.sin_family = host->h_addrtype;
 #if    defined(h_addr)         /* In 4.3, this is a #define */
@@ -1631,28 +2015,26 @@ tn(argc, argv)
 #endif /* defined(h_addr) */
                hostname = host->h_name;
            } else {
 #endif /* defined(h_addr) */
                hostname = host->h_name;
            } else {
-               herror(argv[1]);
+               herror(hostp);
                return 0;
            }
        }
 #if    defined(SRCRT) && defined(IPPROTO_IP)
     }
 #endif
                return 0;
            }
        }
 #if    defined(SRCRT) && defined(IPPROTO_IP)
     }
 #endif
-    if (argc == 3) {
-       int tmp;
-
-       if (*argv[2] == '-') {
-           argv[2]++;
+    if (portp) {
+       if (*portp == '-') {
+           portp++;
            telnetport = 1;
        } else
            telnetport = 0;
            telnetport = 1;
        } else
            telnetport = 0;
-       sin.sin_port = atoi(argv[2]);
+       sin.sin_port = atoi(portp);
        if (sin.sin_port == 0) {
        if (sin.sin_port == 0) {
-           sp = getservbyname(argv[2], "tcp");
+           sp = getservbyname(portp, "tcp");
            if (sp)
                sin.sin_port = sp->s_port;
            else {
            if (sp)
                sin.sin_port = sp->s_port;
            else {
-               printf("%s: bad port number\n", argv[2]);
+               printf("%s: bad port number\n", portp);
                return 0;
            }
        } else {
                return 0;
            }
        } else {
@@ -1683,16 +2065,11 @@ tn(argc, argv)
        if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
                perror("setsockopt (IP_OPTIONS)");
 #endif
        if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
                perror("setsockopt (IP_OPTIONS)");
 #endif
-#ifdef IP_TOS
-#ifdef HAS_IP_TOS
-       if (tp = gettosbyname("telnet", "tcp"))
-               tos = tp->t_tos;
-       else
-#endif
-       tos = IPTOS_LOWDELAY;
-       if (setsockopt(net, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+#if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
+       if ((tp = gettosbyname("telnet", "tcp")) &&
+           (setsockopt(net, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
                perror("telnet: setsockopt TOS (ignored)");
                perror("telnet: setsockopt TOS (ignored)");
-#endif /* IP_TOS */
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
 
        if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
                perror("setsockopt (SO_DEBUG)");
 
        if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
                perror("setsockopt (SO_DEBUG)");
@@ -1719,7 +2096,9 @@ tn(argc, argv)
        }
        connected++;
     } while (connected == 0);
        }
        connected++;
     } while (connected == 0);
-    cmdrc(argv[1], hostname);
+    cmdrc(hostp, hostname);
+    if (user)
+       env_define("USER", user);
     (void) call(status, "status", "notmuch", 0);
     if (setjmp(peerdied) == 0)
        telnet();
     (void) call(status, "status", "notmuch", 0);
     if (setjmp(peerdied) == 0)
        telnet();
@@ -1750,7 +2129,8 @@ static char
        zhelp[] =       "suspend telnet",
 #endif /* defined(unix) */
        shellhelp[] =   "invoke a subshell",
        zhelp[] =       "suspend telnet",
 #endif /* defined(unix) */
        shellhelp[] =   "invoke a subshell",
-       modestring[] = "try to enter line-by-line or character-at-a-time mode";
+       envhelp[] =     "change environment variables ('environ ?' for more)",
+       modestring[] = "try to enter line or character mode ('mode ?' for more)";
 
 extern int     help(), shell();
 
 
 extern int     help(), shell();
 
@@ -1777,6 +2157,7 @@ static Command cmdtab[] = {
 #else
        { "!",          shellhelp,      shell,          0 },
 #endif
 #else
        { "!",          shellhelp,      shell,          0 },
 #endif
+       { "environ",    envhelp,        env_cmd,        0 },
        { "?",          helphelp,       help,           0 },
        0
 };
        { "?",          helphelp,       help,           0 },
        0
 };
@@ -1852,8 +2233,8 @@ command(top, tbuf, cnt)
        putchar('\n');
 #if    defined(unix)
     } else {
        putchar('\n');
 #if    defined(unix)
     } else {
-       signal(SIGINT, SIG_DFL);
-       signal(SIGQUIT, SIG_DFL);
+       (void) signal(SIGINT, SIG_DFL);
+       (void) signal(SIGQUIT, SIG_DFL);
 #endif /* defined(unix) */
     }
     for (;;) {
 #endif /* defined(unix) */
     }
     for (;;) {
@@ -1871,8 +2252,10 @@ command(top, tbuf, cnt)
        } else {
        getline:
            if (gets(line) == NULL) {
        } else {
        getline:
            if (gets(line) == NULL) {
-               if (feof(stdin) || ferror(stdin))
-                   quit();
+               if (feof(stdin) || ferror(stdin)) {
+                   (void) quit();
+                   /*NOTREACHED*/
+               }
                break;
            }
        }
                break;
            }
        }
index 3bfa455..8d7d9de 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)defines.h   1.9 (Berkeley) %G%
+ *     @(#)defines.h   1.10 (Berkeley) %G%
  */
 
 #define        settimer(x)     clocks.x = clocks.system++
  */
 
 #define        settimer(x)     clocks.x = clocks.system++
@@ -31,3 +31,5 @@
 #define        MODE_LOCAL_CHARS(m)     ((m)&(MODE_EDIT|MODE_TRAPSIG))
 #define        MODE_LOCAL_ECHO(m)      ((m)&MODE_ECHO)
 #define        MODE_COMMAND_LINE(m)    ((m)==-1)
 #define        MODE_LOCAL_CHARS(m)     ((m)&(MODE_EDIT|MODE_TRAPSIG))
 #define        MODE_LOCAL_ECHO(m)      ((m)&MODE_ECHO)
 #define        MODE_COMMAND_LINE(m)    ((m)==-1)
+
+#define        CONTROL(x)      ((x)&0x1f)              /* CTRL(x) is not portable */
index 62e7f32..254f5a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)externs.h   1.24 (Berkeley) %G%
+ *     @(#)externs.h   1.25 (Berkeley) %G%
  */
 
 #ifndef        BSD
  */
 
 #ifndef        BSD
 
 #include <stdio.h>
 #include <setjmp.h>
 
 #include <stdio.h>
 #include <setjmp.h>
+#ifndef        FILIO_H
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
 #ifdef USE_TERMIO
 # ifndef       VINTR
 #  ifdef SYSV_TERMIO
 #ifdef USE_TERMIO
 # ifndef       VINTR
 #  ifdef SYSV_TERMIO
 #   define termio termios
 #  endif
 # endif
 #   define termio termios
 #  endif
 # endif
-#else
+#endif
+#if defined(NO_CC_T) || !defined(USE_TERMIO)
+# if !defined(USE_TERMIO)
 typedef char cc_t;
 typedef char cc_t;
+# else
+typedef unsigned char cc_t;
+# endif
 #endif
 
 #define        SUBBUFSIZE      256
 #endif
 
 #define        SUBBUFSIZE      256
@@ -73,11 +82,12 @@ extern int
 #endif /* defined(unix) */
     debug;                     /* Debug level */
 
 #endif /* defined(unix) */
     debug;                     /* Debug level */
 
-extern cc_t
-    echoc,             /* Toggle local echoing */
-    escape;            /* Escape to command mode */
+extern cc_t escape;    /* Escape to command mode */
+#ifdef KLUDGELINEMODE
+extern cc_t echoc;     /* Toggle local echoing */
+#endif
 
 
-extern unsigned char
+extern char
     *prompt;           /* Prompt for command. */
 
 extern char
     *prompt;           /* Prompt for command. */
 
 extern char
@@ -211,7 +221,7 @@ extern struct       sgttyb nttyb;
 # define termStartChar         ntc.t_startc
 # define termStopChar          ntc.t_stopc
 # define termForw1Char         ntc.t_brkc
 # define termStartChar         ntc.t_startc
 # define termStopChar          ntc.t_stopc
 # define termForw1Char         ntc.t_brkc
-extern char termForw2Char;
+extern cc_t termForw2Char;
 
 # define termEofCharp          (cc_t *)&ntc.t_eofc
 # define termEraseCharp                (cc_t *)&nttyb.sg_erase
 
 # define termEofCharp          (cc_t *)&ntc.t_eofc
 # define termEraseCharp                (cc_t *)&nttyb.sg_erase
@@ -239,47 +249,50 @@ extern struct     termio new_tc;
 # define termQuitChar          new_tc.c_cc[VQUIT]
 
 # ifndef       VSUSP
 # define termQuitChar          new_tc.c_cc[VQUIT]
 
 # ifndef       VSUSP
-extern char termSuspChar;
+extern cc_t termSuspChar;
 # else
 #  define termSuspChar         new_tc.c_cc[VSUSP]
 # endif
 # else
 #  define termSuspChar         new_tc.c_cc[VSUSP]
 # endif
-# ifndef       VDISCARD
-extern char termFlushChar;
+# if   !defined(VFLUSHO) && defined(VDISCARD)
+#  define VFLUSHO VDISCARD
+# endif
+# ifndef       VFLUSHO
+extern cc_t termFlushChar;
 # else
 # else
-#  define termFlushChar                new_tc.c_cc[VDISCARD]
+#  define termFlushChar                new_tc.c_cc[VFLUSHO]
 # endif
 # ifndef VWERASE
 # endif
 # ifndef VWERASE
-extern char termWerasChar;
+extern cc_t termWerasChar;
 # else
 #  define termWerasChar                new_tc.c_cc[VWERASE]
 # endif
 # ifndef       VREPRINT
 # else
 #  define termWerasChar                new_tc.c_cc[VWERASE]
 # endif
 # ifndef       VREPRINT
-extern char termRprntChar;
+extern cc_t termRprntChar;
 # else
 #  define termRprntChar                new_tc.c_cc[VREPRINT]
 # endif
 # ifndef       VLNEXT
 # else
 #  define termRprntChar                new_tc.c_cc[VREPRINT]
 # endif
 # ifndef       VLNEXT
-extern char termLiteralNextChar;
+extern cc_t termLiteralNextChar;
 # else
 #  define termLiteralNextChar  new_tc.c_cc[VLNEXT]
 # endif
 # ifndef       VSTART
 # else
 #  define termLiteralNextChar  new_tc.c_cc[VLNEXT]
 # endif
 # ifndef       VSTART
-extern char termStartChar;
+extern cc_t termStartChar;
 # else
 #  define termStartChar                new_tc.c_cc[VSTART]
 # endif
 # ifndef       VSTOP
 # else
 #  define termStartChar                new_tc.c_cc[VSTART]
 # endif
 # ifndef       VSTOP
-extern char termStopChar;
+extern cc_t termStopChar;
 # else
 #  define termStopChar         new_tc.c_cc[VSTOP]
 # endif
 # ifndef       VEOL
 # else
 #  define termStopChar         new_tc.c_cc[VSTOP]
 # endif
 # ifndef       VEOL
-extern char termForw1Char;
+extern cc_t termForw1Char;
 # else
 #  define termForw1Char                new_tc.c_cc[VEOL]
 # endif
 # ifndef       VEOL2
 # else
 #  define termForw1Char                new_tc.c_cc[VEOL]
 # endif
 # ifndef       VEOL2
-extern char termForw2Char;
+extern cc_t termForw2Char;
 # else
 #  define termForw2Char                new_tc.c_cc[VEOL]
 # endif
 # else
 #  define termForw2Char                new_tc.c_cc[VEOL]
 # endif
index ad360af..7492b8d 100644 (file)
@@ -4,13 +4,11 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)general.h   1.4 (Berkeley) %G%
+ *     @(#)general.h   1.5 (Berkeley) %G%
  */
 
 /*
  * Some general definitions.
  */
 
 /*
  * Some general definitions.
- *
- * @(#)general.h       3.1 (Berkeley) 8/11/87
  */
 
 
  */
 
 
index 3d9f033..a159c3e 100644 (file)
@@ -12,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     1.13 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     1.14 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -51,6 +51,8 @@ main(argc, argv)
        int argc;
        char *argv[];
 {
        int argc;
        char *argv[];
 {
+    char *user = 0;
+
     tninit();          /* Clear out things */
 #ifdef CRAY
     _setlist_init();   /* Work around compiler bug */
     tninit();          /* Clear out things */
 #ifdef CRAY
     _setlist_init();   /* Work around compiler bug */
@@ -58,7 +60,7 @@ main(argc, argv)
 
     TerminalSaveState();
 
 
     TerminalSaveState();
 
-    prompt = (unsigned char *)argv[0];
+    prompt = argv[0];
     while ((argc > 1) && (argv[1][0] == '-')) {
        if (!strcmp(argv[1], "-d")) {
            debug = 1;
     while ((argc > 1) && (argv[1][0] == '-')) {
        if (!strcmp(argv[1], "-d")) {
            debug = 1;
@@ -68,6 +70,14 @@ main(argc, argv)
                argv++;
                argc--;
            }
                argv++;
                argc--;
            }
+       } else if (!strcmp(argv[1], "-l")) {
+           if ((argc > 1) && (argv[2][0] != '-')) {    /* get user name */
+               user = argv[2];
+               argv++;
+               argc--;
+           }
+       } else if (!strncmp(argv[1], "-e", 2)) {
+               set_escape_char(&argv[1][2]);
        } else {
 #if    defined(TN3270) && defined(unix)
            if (!strcmp(argv[1], "-t")) {
        } else {
 #if    defined(TN3270) && defined(unix)
            if (!strcmp(argv[1], "-t")) {
@@ -96,6 +106,13 @@ main(argc, argv)
     if (argc != 1) {
        if (setjmp(toplevel) != 0)
            Exit(0);
     if (argc != 1) {
        if (setjmp(toplevel) != 0)
            Exit(0);
+       if (user) {
+           argc += 2;
+           argv -= 2;
+           argv[0] = argv[2];
+           argv[1] = "-l";
+           argv[2] = user;
+       }
        if (tn(argc, argv) == 1) {
            return 0;
        } else {
        if (tn(argc, argv) == 1) {
            return 0;
        } else {
index 79bb39a..972ca63 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)network.c  1.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)network.c  1.15 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -63,6 +63,7 @@ stilloob()
     if (value < 0) {
        perror("select");
        (void) quit();
     if (value < 0) {
        perror("select");
        (void) quit();
+       /* NOTREACHED */
     }
     if (FD_ISSET(net, &excepts)) {
        return 1;
     }
     if (FD_ISSET(net, &excepts)) {
        return 1;
@@ -119,7 +120,7 @@ netflush()
        if (errno != ENOBUFS && errno != EWOULDBLOCK) {
            setcommandmode();
            perror(hostname);
        if (errno != ENOBUFS && errno != EWOULDBLOCK) {
            setcommandmode();
            perror(hostname);
-           NetClose(net);
+           (void)NetClose(net);
            ring_clear_mark(&netoring);
            longjmp(peerdied, -1);
            /*NOTREACHED*/
            ring_clear_mark(&netoring);
            longjmp(peerdied, -1);
            /*NOTREACHED*/
index a24061c..de738e7 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)ring.c     1.12 (Berkeley) %G%";
+static char sccsid[] = "@(#)ring.c     1.13 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -28,7 +28,9 @@ static char sccsid[] = "@(#)ring.c    1.12 (Berkeley) %G%";
 #endif
 
 #include       <sys/types.h>
 #endif
 
 #include       <sys/types.h>
+#ifndef        FILIO_H
 #include       <sys/ioctl.h>
 #include       <sys/ioctl.h>
+#endif
 #include       <sys/socket.h>
 
 #include       "ring.h"
 #include       <sys/socket.h>
 
 #include       "ring.h"
@@ -261,6 +263,7 @@ int count;
     }
 }
 
     }
 }
 
+#ifdef notdef
 
 /*
  * Move data from the "consume" portion of the ring buffer
 
 /*
  * Move data from the "consume" portion of the ring buffer
@@ -281,3 +284,4 @@ int count;
        buffer += i;
     }
 }
        buffer += i;
     }
 }
+#endif
index e9f9af0..78d555a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ring.h      1.9 (Berkeley) %G%
+ *     @(#)ring.h      1.10 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -39,8 +39,11 @@ extern int
 
 /* Data movement routines */
 extern void
 
 /* Data movement routines */
 extern void
-       ring_supply_data(Ring *ring, char *buffer, int count),
+       ring_supply_data(Ring *ring, char *buffer, int count);
+#ifdef notdef
+extern void
        ring_consume_data(Ring *ring, char *buffer, int count);
        ring_consume_data(Ring *ring, char *buffer, int count);
+#endif
 
 /* Buffer state transition routines */
 extern void
 
 /* Buffer state transition routines */
 extern void
@@ -59,8 +62,11 @@ extern int
        ring_init();
 
 extern void
        ring_init();
 
 extern void
-    ring_supply_data(),
+    ring_supply_data();
+#ifdef notdef
+extern void
     ring_consume_data();
     ring_consume_data();
+#endif
 
 extern void
     ring_supplied(),
 
 extern void
     ring_supplied(),
index addde8a..0d17ef6 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)sys_bsd.c  1.26 (Berkeley) %G%";
+static char sccsid[] = "@(#)sys_bsd.c  1.27 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -53,9 +53,15 @@ struct       termio old_tc = { 0 };
 extern struct termio new_tc;
 
 #ifndef        TCGETA
 extern struct termio new_tc;
 
 #ifndef        TCGETA
-#define        TCGETA  TIOCGETA
-#define        TCSETA  TIOCSETA
-#define        TCSETAW TIOCSETAW
+# ifdef TCGETS
+#  define      TCGETA  TCGETS
+#  define      TCSETA  TCSETS
+#  define      TCSETAW TCSETSW
+# else
+#  define      TCGETA  TIOCGETA
+#  define      TCSETA  TIOCSETA
+#  define      TCSETAW TIOCSETAW
+# endif
 #endif /* TCGETA */
 #endif /* USE_TERMIO */
 
 #endif /* TCGETA */
 #endif /* USE_TERMIO */
 
@@ -194,12 +200,12 @@ TerminalSaveState()
 
     new_tc = old_tc;
 
 
     new_tc = old_tc;
 
-    termFlushChar = 'O'&0x37;
-    termWerasChar = 'W'&0x37;
-    termRprntChar = 'R'&0x37;
-    termLiteralNextChar = 'V'&0x37;
-    termStartChar = 'Q'&0x37;
-    termStopChar = 'S'&0x37;
+    termFlushChar = CONTROL('O');
+    termWerasChar = CONTROL('W');
+    termRprntChar = CONTROL('R');
+    termLiteralNextChar = CONTROL('V');
+    termStartChar = CONTROL('Q');
+    termStopChar = CONTROL('S');
 #endif /* USE_TERMIO */
 }
 
 #endif /* USE_TERMIO */
 }
 
@@ -215,6 +221,7 @@ register int func;
     case SLC_EL:       return(&termKillChar);
     case SLC_XON:      return(&termStartChar);
     case SLC_XOFF:     return(&termStopChar);
     case SLC_EL:       return(&termKillChar);
     case SLC_XON:      return(&termStartChar);
     case SLC_XOFF:     return(&termStopChar);
+    case SLC_FORW1:    return(&termForw1Char);
 #ifndef        SYSV_TERMIO
     case SLC_AO:       return(&termFlushChar);
     case SLC_SUSP:     return(&termSuspChar);
 #ifndef        SYSV_TERMIO
     case SLC_AO:       return(&termFlushChar);
     case SLC_SUSP:     return(&termSuspChar);
@@ -222,13 +229,14 @@ register int func;
     case SLC_RP:       return(&termRprntChar);
     case SLC_LNEXT:    return(&termLiteralNextChar);
 #endif /* SYSV_TERMIO */
     case SLC_RP:       return(&termRprntChar);
     case SLC_LNEXT:    return(&termLiteralNextChar);
 #endif /* SYSV_TERMIO */
+#ifdef USE_TERMIO
+    case SLC_FORW2:    return(&termForw2Char);
+#endif
 
     case SLC_SYNCH:
     case SLC_BRK:
     case SLC_AYT:
     case SLC_EOR:
 
     case SLC_SYNCH:
     case SLC_BRK:
     case SLC_AYT:
     case SLC_EOR:
-    case SLC_FORW1:
-    case SLC_FORW2:
     default:
        return((cc_t *)0);
     }
     default:
        return((cc_t *)0);
     }
@@ -244,31 +252,33 @@ TerminalDefaultChars()
     nttyb.sg_erase = ottyb.sg_erase;
 #else  /* USE_TERMIO */
     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
     nttyb.sg_erase = ottyb.sg_erase;
 #else  /* USE_TERMIO */
     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
-# ifndef       VDISCARD
-    termFlushChar = 'O'&0x37;
+# ifndef       VFLUSHO
+    termFlushChar = CONTROL('O');
 # endif
 # ifndef       VWERASE
 # endif
 # ifndef       VWERASE
-    termWerasChar = 'W'&0x37;
+    termWerasChar = CONTROL('W');
 # endif
 # ifndef       VREPRINT
 # endif
 # ifndef       VREPRINT
-    termRprntChar = 'R'&0x37;
+    termRprntChar = CONTROL('R');
 # endif
 # ifndef       VLNEXT
 # endif
 # ifndef       VLNEXT
-    termLiteralNextChar = 'V'&0x37;
+    termLiteralNextChar = CONTROL('V');
 # endif
 # ifndef       VSTART
 # endif
 # ifndef       VSTART
-    termStartChar = 'Q'&0x37;
+    termStartChar = CONTROL('Q');
 # endif
 # ifndef       VSTOP
 # endif
 # ifndef       VSTOP
-    termStopChar = 'S'&0x37;
+    termStopChar = CONTROL('S');
 # endif
 #endif /* USE_TERMIO */
 }
 
 # endif
 #endif /* USE_TERMIO */
 }
 
+#ifdef notdef
 void
 TerminalRestoreState()
 {
 }
 void
 TerminalRestoreState()
 {
 }
+#endif
 
 /*
  * TerminalNewMode - set up terminal to a specific mode.
 
 /*
  * TerminalNewMode - set up terminal to a specific mode.
@@ -424,6 +434,59 @@ register int f;
 #endif
     }
 
 #endif
     }
 
+    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
+#ifndef        USE_TERMIO
+       ltc.t_lnextc = -1;
+#else
+# ifdef VLNEXT
+       tmp_tc.c_cc[VLNEXT] = (cc_t)(-1);
+# endif
+#endif
+    }
+
+    if (f&MODE_SOFT_TAB) {
+#ifndef USE_TERMIO
+       sb.sg_flags |= XTABS;
+#else
+# ifdef        OXTABS
+       tmp_tc.c_oflag |= OXTABS;
+# endif
+# ifdef        TABDLY
+       tmp_tc.c_oflag &= ~TABDLY;
+       tmp_tc.c_oflag |= TAB3;
+# endif
+#endif
+    } else {
+#ifndef USE_TERMIO
+       sb.sg_flags &= ~XTABS;
+#else
+# ifdef        OXTABS
+       tmp_tc.c_oflag &= ~OXTABS;
+# endif
+# ifdef        TABDLY
+       tmp_tc.c_oflag &= ~TABDLY;
+# endif
+#endif
+    }
+
+    if (f&MODE_LIT_ECHO) {
+#ifndef USE_TERMIO
+       sb.sg_flags &= ~CTLECH;
+#else
+# ifdef        ECHOCTL
+       tmp_tc.c_lflag &= ~ECHOCTL;
+# endif
+#endif
+    } else {
+#ifndef USE_TERMIO
+       sb.sg_flags |= CTLECH;
+#else
+# ifdef        ECHOCTL
+       tmp_tc.c_lflag |= ECHOCTL;
+# endif
+#endif
+    }
+
     if (f == -1) {
        onoff = 0;
     } else {
     if (f == -1) {
        onoff = 0;
     } else {
@@ -457,33 +520,50 @@ register int f;
 
     if (f != -1) {
 #ifdef SIGTSTP
 
     if (f != -1) {
 #ifdef SIGTSTP
-       void susp();
+       static void susp();
 
        (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
 #endif /* SIGTSTP */
 
        (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
 #endif /* SIGTSTP */
+       /*
+        * We don't want to process ^Y here.  It's just another
+        * character that we'll pass on to the back end.  It has
+        * to process it because it will be processed when the
+        * user attempts to read it, not when we send it.
+        */
+#ifndef        USE_TERMIO
+       ltc.t_dsuspc = -1;
+#else
+# ifdef        VDSUSP
+       tmp_tc.c_cc[VDSUSP] = (cc_t)(-1);
+# endif
+#endif
 #ifdef USE_TERMIO
 #ifdef USE_TERMIO
-#ifdef VEOL2
        /*
         * If the VEOL character is already set, then use VEOL2,
         * otherwise use VEOL.
         */
        /*
         * If the VEOL character is already set, then use VEOL2,
         * otherwise use VEOL.
         */
-       if (tmp_tc.c_cc[VEOL] != (cc_t)(-1))
-               tmp_tc.c_cc[VEOL2] = escape;
-       else
-#endif
+       if (tmp_tc.c_cc[VEOL] == (cc_t)(-1))
                tmp_tc.c_cc[VEOL] = escape;
                tmp_tc.c_cc[VEOL] = escape;
+# ifdef        VEOL2
+       else if (tmp_tc.c_cc[VEOL2] == (cc_t)(-1))
+               tmp_tc.c_cc[VEOL2] = escape;
+# endif
 #else
 #else
-       tc.t_brkc = escape;
+       if (tc.t_brkc == (cc_t)(-1))
+               tc.t_brkc = escape;
 #endif
     } else {
 #ifdef SIGTSTP
        (void) signal(SIGTSTP, SIG_DFL);
 #endif
     } else {
 #ifdef SIGTSTP
        (void) signal(SIGTSTP, SIG_DFL);
-       sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+       (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
 #endif /* SIGTSTP */
 #ifndef USE_TERMIO
        ltc = oltc;
        tc = otc;
        sb = ottyb;
 #endif /* SIGTSTP */
 #ifndef USE_TERMIO
        ltc = oltc;
        tc = otc;
        sb = ottyb;
+       lmode = olmode;
+#else
+       tmp_tc = old_tc;
 #endif
     }
 #ifndef USE_TERMIO
 #endif
     }
 #ifndef USE_TERMIO
@@ -536,7 +616,7 @@ struct termspeeds {
 # define       ISPEED  ottyb.sg_ispeed
 # define       OSPEED  ottyb.sg_ospeed
 #else
 # define       ISPEED  ottyb.sg_ispeed
 # define       OSPEED  ottyb.sg_ospeed
 #else
-# ifdef        SYSV_TERMIO
+# ifdef        CBAUD
 #  define      ISPEED  (old_tc.c_cflag&CBAUD)
 #  define      OSPEED  ISPEED
 # else
 #  define      ISPEED  (old_tc.c_cflag&CBAUD)
 #  define      OSPEED  ISPEED
 # else
@@ -668,11 +748,6 @@ sendwin()
     }
 }
 
     }
 }
 
-static void
-doescape()
-{
-    command(0, 0, 0);
-}
 \f
 void
 sys_telnet_init()
 \f
 void
 sys_telnet_init()
@@ -797,7 +872,7 @@ int poll;           /* If 0, then block until something to do */
     if (FD_ISSET(net, &xbits)) {
        FD_CLR(net, &xbits);
        SYNCHing = 1;
     if (FD_ISSET(net, &xbits)) {
        FD_CLR(net, &xbits);
        SYNCHing = 1;
-       ttyflush(1);    /* flush already enqueued data */
+       (void) ttyflush(1);     /* flush already enqueued data */
     }
 
     /*
     }
 
     /*
index 70876b6..44e2a42 100644 (file)
@@ -3,7 +3,7 @@
 .\"
 .\" %sccs.include.redist.man%
 .\"
 .\"
 .\" %sccs.include.redist.man%
 .\"
-.\"     @(#)telnet.1   6.9 (Berkeley) %G%
+.\"     @(#)telnet.1   6.10 (Berkeley) %G%
 .\"
 .Dd 
 .Dt TELNET 1
 .\"
 .Dd 
 .Dt TELNET 1
@@ -17,6 +17,8 @@ protocol
 .Nm telnet
 .Op Fl d
 .Op Fl n Ar tracefile
 .Nm telnet
 .Op Fl d
 .Op Fl n Ar tracefile
+.Op Fl l Ar user
+.Op Fl e Ar escapechar
 .Op Ar host Op Ar port
 .Sh DESCRIPTION
 The
 .Op Ar host Op Ar port
 .Sh DESCRIPTION
 The
@@ -54,6 +56,30 @@ for recording trace information.
 See the
 .Ic set tracefile
 command below.
 See the
 .Ic set tracefile
 command below.
+.Tp Cx Fl l
+.Cx \&\ \&
+.Ar user
+.Cx
+When connecting to the remote system, if the remote system
+understands the ENVIRON option, then
+.Ar user
+will be sent to the remote system as the value for the variable USER.
+This option may also be used with the
+.Ic open
+command.
+.Tp Cx Fl e
+.Cx \&\ \&
+.Ar escape char
+.Cx
+Sets the initial
+.Nm
+.B telnet
+escape character to
+.Ar escape char.
+If
+.Ar escape char
+is ommitted, then
+there will be no escape character.
 .Tp Ar host
 Indicates the official name, an alias, or the Internet address
 of a remote host.
 .Tp Ar host
 Indicates the official name, an alias, or the Internet address
 of a remote host.
@@ -156,6 +182,7 @@ Only enough of each command to uniquely identify it need be typed
 .Ic toggle  ,
 .Ic unset ,
 .Ic slc  ,
 .Ic toggle  ,
 .Ic unset ,
 .Ic slc  ,
+.Ic environ ,
 and
 .Ic display
 commands).
 and
 .Ic display
 commands).
@@ -222,6 +249,30 @@ option.
 This requires that the 
 .Li LINEMODE
 option be enabled.
 This requires that the 
 .Li LINEMODE
 option be enabled.
+.Tp Cx Ic softtabs
+.Cx \&\ \&
+.Pq Ic \-softtabs
+.Cx
+Attempt to enable (disable) the 
+.Li SOFT_TAB
+mode of the 
+.Li LINEMODE
+option.
+This requires that the 
+.Li LINEMODE
+option be enabled.
+.Tp Cx Ic litecho
+.Cx \&\ \&
+.Pq Ic \-litecho
+.Cx
+Attempt to enable (disable) the 
+.Li LIT_ECHO
+mode of the 
+.Li LINEMODE
+option.
+This requires that the 
+.Li LINEMODE
+option be enabled.
 .Tp Ic \&?
 Prints out help information for the
 .Ic mode
 .Tp Ic \&?
 Prints out help information for the
 .Ic mode
@@ -232,6 +283,11 @@ command.
 .Ar host
 .Cx \&\ \&
 .Cx [
 .Ar host
 .Cx \&\ \&
 .Cx [
+.Op Fl l
+.Cx \&\ \&
+.Ar user
+.Cx ]
+.Cx [
 .Op Fl
 .Cx \&\ \&
 .Ar port
 .Op Fl
 .Cx \&\ \&
 .Ar port
@@ -248,6 +304,12 @@ The host specification may be either a host name (see
 .Xr hosts  5  )
 or an Internet address specified in the \*(Lqdot notation\*(Rq (see
 .Xr inet 3 ) .
 .Xr hosts  5  )
 or an Internet address specified in the \*(Lqdot notation\*(Rq (see
 .Xr inet 3 ) .
+The
+.Op Fl l
+option may be used to specify the user name
+to be passed to the remote system via the
+.Li ENVIRON
+option.
 When connecting to a non-standard port,
 .Nm telnet
 omits any automatic initiation of
 When connecting to a non-standard port,
 .Nm telnet
 omits any automatic initiation of
@@ -637,6 +699,11 @@ The initial value for the worderase character is taken to be
 the terminal's
 .Ic worderase
 character.
 the terminal's
 .Ic worderase
 character.
+.Tp Ic \&?
+Displays the legal
+.Ic set
+.Pq Ic unset
+commands.
 .Tp
 .Tp Cx Ic slc
 .Cx \&\ \&
 .Tp
 .Tp Cx Ic slc
 .Cx \&\ \&
@@ -679,16 +746,74 @@ Verify the current settings for the current special characters.
 The remote side is requested to send all the current special
 character settings, and if there are any discrepencies with
 the local side, the local side will switch to the remote value.
 The remote side is requested to send all the current special
 character settings, and if there are any discrepencies with
 the local side, the local side will switch to the remote value.
-.Ic Ic \&?
+.Tp Ic \&?
 Prints out help information for the
 .Ic slc
 command.
 .Tp
 Prints out help information for the
 .Ic slc
 command.
 .Tp
+.Tp Cx Ic environ
+.Cx \&\ \&
+.Ar arguments...
+.Cx
+The
+.Ic environ
+command is used to manipulate the
+the variables that my be sent through the
+.Li TELNET ENVIRON
+option.
+The initial set of variables is taken from the users
+environment; with only the
+.Ev USER
+and
+.Ev DISPLAY variables
+being exported.
+.br
+Valid arguments for the \fBenviron\fP command are:
+.Tw Fl
+.Tp Cx Ic define
+.Cx \&\ \&
+.Ar variable value
+.Cx
+Define the variable
+.Ar variable
+to have a value of
+.Ar value.
+Any variables defined by this command are automatically exported.
+The
+.Ar value
+may be enclosed in single or double quotes so
+that tabs and spaces may be included.
+.Tp Cx Ic undefine
+.Cx \&\ \&
+.Ar variable
+.Cx
+Remove
+.Ar variable
+from the list of environment variables.
+.Tp Cx Ic export
+.Cx \&\ \&
+.Ar variable
+.Cx
+Mark the variable
+.Ar variable
+to be exported to the remote side.
+.Tp Cx Ic unexport
+.Cx \&\ \&
+.Ar variable
+.Cx
+Mark the variable
+.Ar variable
+to not be exported unless
+explicitly asked for by the remote side.
+.Tp Ic list
+List the current set of environment variables.
+Those marked with a \fB*\fR will be sent automatically,
+other variables will only be sent if explicitly requested.
 .Tp Ic \&?
 .Tp Ic \&?
-Displays the legal
-.Ic set
-.Pq Ic unset
-commands.
+Prints out help information for the
+.Ic environ
+command.
+.Tp
 .Tp Cx Ic toggle
 .Cx \&\ \&
 .Ar arguments ...
 .Tp Cx Ic toggle
 .Cx \&\ \&
 .Ar arguments ...
@@ -803,7 +928,9 @@ If this is
 TRUE,
 then the
 .Ic flush  ,
 TRUE,
 then the
 .Ic flush  ,
+.Ic interrupt ,
 .Ic quit  ,
 .Ic quit  ,
+.Ic erase ,
 and
 .Ic kill
 characters (see
 and
 .Ic kill
 characters (see
@@ -813,7 +940,9 @@ above) are recognized locally, and transformed into (hopefully) appropriate
 control sequences
 (respectively
 .Ic ao  ,
 control sequences
 (respectively
 .Ic ao  ,
+.Ic ip ,
 .Ic brk  ,
 .Ic brk  ,
+.Ic ec ,
 and
 .Ic el  ;
 see
 and
 .Ic el  ;
 see
@@ -837,6 +966,7 @@ and
 .B suspend
 are sent as
 .Ic eof and
 .B suspend
 are sent as
 .Ic eof and
+.Ic susp ,
 see
 .Ic send
 above).
 see
 .Ic send
 above).
@@ -898,12 +1028,18 @@ If a command is specified,
 will print the help information for just that command.
 .Sh ENVIRONMENT
 .Nm Telnet
 will print the help information for just that command.
 .Sh ENVIRONMENT
 .Nm Telnet
-uses the
+uses at least the
 .Ev HOME ,
 .Ev HOME ,
-.Ev SHELL
+.Ev SHELL ,
+.Ev USER ,
+.Ev DISPLAY ,
 and
 .Ev TERM
 environent variables.
 and
 .Ev TERM
 environent variables.
+Other envirnoment variables may be propogated
+to the other side via the
+.Li TELNET ENVIRON
+option.
 .Sh FILES
 .Dw ~/.telnetrc
 .Di L
 .Sh FILES
 .Dw ~/.telnetrc
 .Di L
index 8f28869..68acc42 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnet.c   5.49 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnet.c   5.50 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -29,7 +29,11 @@ static char sccsid[] = "@(#)telnet.c 5.49 (Berkeley) %G%";
 
 #include <arpa/telnet.h>
 
 
 #include <arpa/telnet.h>
 
+#if    defined(unix)
+#include <strings.h>
+#else  /* defined(unix) */
 #include <string.h>
 #include <string.h>
+#endif /* defined(unix) */
 
 #include <ctype.h>
 
 
 #include <ctype.h>
 
@@ -43,6 +47,7 @@ static char sccsid[] = "@(#)telnet.c  5.49 (Berkeley) %G%";
 \f
 #define        strip(x)        ((x)&0x7f)
 
 \f
 #define        strip(x)        ((x)&0x7f)
 
+extern char *env_getvalue();
 
 static char    subbuffer[SUBBUFSIZE],
                *subpointer, *subend;    /* buffer for sub-options */
 
 static char    subbuffer[SUBBUFSIZE],
                *subpointer, *subend;    /* buffer for sub-options */
@@ -85,11 +90,12 @@ int
        dontlecho,      /* do we suppress local echoing right now? */
        globalmode;
 
        dontlecho,      /* do we suppress local echoing right now? */
        globalmode;
 
-#define        CONTROL(x)      ((x)&0x1f)              /* CTRL(x) is not portable */
+char *prompt = 0;
 
 
-unsigned char *prompt = 0;
-
-cc_t escape, echoc;
+cc_t escape;
+#ifdef KLUDGELINEMODE
+cc_t echoc;
+#endif
 
 /*
  * Telnet receiver states for fsm
 
 /*
  * Telnet receiver states for fsm
@@ -142,6 +148,8 @@ Modelist modelist[] = {
 
 init_telnet()
 {
 
 init_telnet()
 {
+    env_init();
+
     SB_CLEAR();
     ClearArray(options);
 
     SB_CLEAR();
     ClearArray(options);
 
@@ -152,13 +160,16 @@ init_telnet()
     /* Don't change NetTrace */
 
     escape = CONTROL(']');
     /* Don't change NetTrace */
 
     escape = CONTROL(']');
+#ifdef KLUDGELINEMODE
     echoc = CONTROL('E');
     echoc = CONTROL('E');
+#endif
 
     flushline = 1;
     telrcv_state = TS_DATA;
 }
 \f
 
 
     flushline = 1;
     telrcv_state = TS_DATA;
 }
 \f
 
+#ifdef notdef
 #include <varargs.h>
 
 /*VARARGS*/
 #include <varargs.h>
 
 /*VARARGS*/
@@ -206,6 +217,7 @@ va_dcl
     }
     ring_supply_data(ring, buffer, ptr-buffer);
 }
     }
     ring_supply_data(ring, buffer, ptr-buffer);
 }
+#endif
 
 /*
  * These routines are in charge of sending option negotiations
 
 /*
  * These routines are in charge of sending option negotiations
@@ -283,7 +295,6 @@ void
 willoption(option)
        int option;
 {
 willoption(option)
        int option;
 {
-       char *fmt;
        int new_state_ok = 0;
 
        if (do_dont_resp[option]) {
        int new_state_ok = 0;
 
        if (do_dont_resp[option]) {
@@ -361,8 +372,6 @@ void
 wontoption(option)
        int option;
 {
 wontoption(option)
        int option;
 {
-       char *fmt;
-
        if (do_dont_resp[option]) {
            --do_dont_resp[option];
            if (do_dont_resp[option] && my_state_is_dont(option))
        if (do_dont_resp[option]) {
            --do_dont_resp[option];
            if (do_dont_resp[option] && my_state_is_dont(option))
@@ -394,7 +403,8 @@ wontoption(option)
                break;
            }
            set_my_want_state_dont(option);
                break;
            }
            set_my_want_state_dont(option);
-           send_dont(option, 0);
+           if (my_state_is_do(option))
+               send_dont(option, 0);
            setconnmode(0);                     /* Set new tty mode */
        } else if (option == TELOPT_TM) {
            /*
            setconnmode(0);                     /* Set new tty mode */
        } else if (option == TELOPT_TM) {
            /*
@@ -411,7 +421,6 @@ static void
 dooption(option)
        int option;
 {
 dooption(option)
        int option;
 {
-       char *fmt;
        int new_state_ok = 0;
 
        if (will_wont_resp[option]) {
        int new_state_ok = 0;
 
        if (will_wont_resp[option]) {
@@ -450,12 +459,19 @@ dooption(option)
            case TELOPT_LFLOW:          /* local flow control */
            case TELOPT_TTYPE:          /* terminal type option */
            case TELOPT_SGA:            /* no big deal */
            case TELOPT_LFLOW:          /* local flow control */
            case TELOPT_TTYPE:          /* terminal type option */
            case TELOPT_SGA:            /* no big deal */
+           case TELOPT_ENVIRON:        /* environment variable option */
                new_state_ok = 1;
                break;
 
                new_state_ok = 1;
                break;
 
+           case TELOPT_XDISPLOC:       /* X Display location */
+               if (env_getvalue("DISPLAY"))
+                   new_state_ok = 1;
+               break;
+
            case TELOPT_LINEMODE:
 #ifdef KLUDGELINEMODE
                kludgelinemode = 0;
            case TELOPT_LINEMODE:
 #ifdef KLUDGELINEMODE
                kludgelinemode = 0;
+               send_do(TELOPT_SGA, 1);
 #endif
                set_my_want_state_will(TELOPT_LINEMODE);
                send_will(option, 0);
 #endif
                set_my_want_state_will(TELOPT_LINEMODE);
                send_will(option, 0);
@@ -484,9 +500,11 @@ dooption(option)
            case TELOPT_LINEMODE:
 #ifdef KLUDGELINEMODE
                kludgelinemode = 0;
            case TELOPT_LINEMODE:
 #ifdef KLUDGELINEMODE
                kludgelinemode = 0;
+               send_do(TELOPT_SGA, 1);
 #endif
                set_my_state_will(option);
                slc_init();
 #endif
                set_my_state_will(option);
                slc_init();
+               send_do(TELOPT_SGA, 0);
                return;
            }
          }
                return;
            }
          }
@@ -513,7 +531,8 @@ dontoption(option)
            }
            /* we always accept a DONT */
            set_my_want_state_wont(option);
            }
            /* we always accept a DONT */
            set_my_want_state_wont(option);
-           send_wont(option, 0);
+           if (my_state_is_will(option))
+               send_wont(option, 0);
            setconnmode(0);                     /* Set new tty mode */
        }
        set_my_state_wont(option);
            setconnmode(0);                     /* Set new tty mode */
        }
        set_my_state_wont(option);
@@ -649,6 +668,7 @@ register char *name, **as, **ae;
 
 #ifdef TERMCAP
 char termbuf[1024];
 
 #ifdef TERMCAP
 char termbuf[1024];
+/*ARGSUSED*/
 setupterm(tname, fd, errp)
 char *tname;
 int fd, *errp;
 setupterm(tname, fd, errp)
 char *tname;
 int fd, *errp;
@@ -675,12 +695,11 @@ gettermname()
        static int first = 1;
        static char **tnamep;
        static char **next;
        static int first = 1;
        static char **tnamep;
        static char **next;
-       char *getenv();
        int err;
 
        if (first) {
                first = 0;
        int err;
 
        if (first) {
                first = 0;
-               if ((tname = getenv("TERM")) &&
+               if ((tname = env_getvalue("TERM")) &&
                                (setupterm(tname, 1, &err) == 0)) {
                        tnamep = mklist(termbuf, tname);
                } else {
                                (setupterm(tname, 1, &err) == 0)) {
                        tnamep = mklist(termbuf, tname);
                } else {
@@ -722,7 +741,6 @@ suboption()
            ;
        } else {
            char *name;
            ;
        } else {
            char *name;
-           extern char *getenv();
            char temp[50];
            int len;
 
            char temp[50];
            int len;
 
@@ -748,7 +766,7 @@ suboption()
        if (my_want_state_is_wont(TELOPT_TSPEED))
            return;
        if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
        if (my_want_state_is_wont(TELOPT_TSPEED))
            return;
        if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
-           long ospeed,ispeed;
+           int ospeed, ispeed;
            char temp[50];
            int len;
 
            char temp[50];
            int len;
 
@@ -762,6 +780,7 @@ suboption()
                ring_supply_data(&netoring, temp, len);
                printsub('>', temp+2, len - 2);
            }
                ring_supply_data(&netoring, temp, len);
                printsub('>', temp+2, len - 2);
            }
+/*@*/      else printf("lm_will: not enough room in buffer\n");
        }
        break;
     case TELOPT_LFLOW:
        }
        break;
     case TELOPT_LFLOW:
@@ -799,8 +818,54 @@ suboption()
            lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
            break;
        default:
            lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
            break;
        default:
+           break;
+       }
+       break;
+
+    case TELOPT_ENVIRON:
+       switch(subbuffer[1]&0xff) {
+       case TELQUAL_IS:
+       case TELQUAL_INFO:
+           if (my_want_state_is_dont(TELOPT_ENVIRON))
+               return;
+           break;
+       case TELQUAL_SEND:
+           if (my_want_state_is_wont(TELOPT_ENVIRON)) {
+               return;
+           }
+           break;
+       default:
+           return;
+       }
+       env_opt(&subbuffer[1], subend - &subbuffer[1]);
+       break;
+
+    case TELOPT_XDISPLOC:
+       if (my_want_state_is_wont(TELOPT_XDISPLOC))
+           return;
+       if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
+           char temp[50], *dp;
+           int len;
+
+           if ((dp = env_getvalue("DISPLAY")) == NULL) {
+               /*
+                * Something happened, we no longer have a DISPLAY
+                * variable.  So, turn off the option.
+                */
+               send_wont(TELOPT_XDISPLOC, 1);
                break;
                break;
+           }
+           sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
+                   TELQUAL_IS, dp, IAC, SE);
+           len = strlen(temp+4) + 4;   /* temp[3] is 0 ... */
+
+           if (len < NETROOM()) {
+               ring_supply_data(&netoring, temp, len);
+               printsub('>', temp+2, len - 2);
+           }
+/*@*/      else printf("lm_will: not enough room in buffer\n");
        }
        }
+       break;
 
 #ifdef KERBEROS
     case TELOPT_AUTHENTICATION:
 
 #ifdef KERBEROS
     case TELOPT_AUTHENTICATION:
@@ -921,6 +986,7 @@ cantsend4:
        }
        break;
 #endif /* KERBEROS */
        }
        break;
 #endif /* KERBEROS */
+
     default:
        break;
     }
     default:
        break;
     }
@@ -931,6 +997,10 @@ static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
 lm_will(cmd, len)
 char *cmd;
 {
 lm_will(cmd, len)
 char *cmd;
 {
+    if (len < 1) {
+/*@*/  printf("lm_will: no command!!!\n");     /* Should not happen... */
+       return;
+    }
     switch(cmd[0]) {
     case LM_FORWARDMASK:       /* We shouldn't ever get this... */
     default:
     switch(cmd[0]) {
     case LM_FORWARDMASK:       /* We shouldn't ever get this... */
     default:
@@ -948,6 +1018,10 @@ char *cmd;
 lm_wont(cmd, len)
 char *cmd;
 {
 lm_wont(cmd, len)
 char *cmd;
 {
+    if (len < 1) {
+/*@*/  printf("lm_wont: no command!!!\n");     /* Should not happen... */
+       return;
+    }
     switch(cmd[0]) {
     case LM_FORWARDMASK:       /* We shouldn't ever get this... */
     default:
     switch(cmd[0]) {
     case LM_FORWARDMASK:       /* We shouldn't ever get this... */
     default:
@@ -959,6 +1033,10 @@ char *cmd;
 lm_do(cmd, len)
 char *cmd;
 {
 lm_do(cmd, len)
 char *cmd;
 {
+    if (len < 1) {
+/*@*/  printf("lm_do: no command!!!\n");       /* Should not happen... */
+       return;
+    }
     switch(cmd[0]) {
     case LM_FORWARDMASK:
     default:
     switch(cmd[0]) {
     case LM_FORWARDMASK:
     default:
@@ -976,6 +1054,10 @@ char *cmd;
 lm_dont(cmd, len)
 char *cmd;
 {
 lm_dont(cmd, len)
 char *cmd;
 {
+    if (len < 1) {
+/*@*/  printf("lm_dont: no command!!!\n");     /* Should not happen... */
+       return;
+    }
     switch(cmd[0]) {
     case LM_FORWARDMASK:
     default:
     switch(cmd[0]) {
     case LM_FORWARDMASK:
     default:
@@ -992,11 +1074,11 @@ int len, init;
 {
        if (len != 1)
                return;
 {
        if (len != 1)
                return;
-       if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd)
+       if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
                return;
        if (*cmd&MODE_ACK)
                return;
                return;
        if (*cmd&MODE_ACK)
                return;
-       linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG));
+       linemode = *cmd&(MODE_MASK&~MODE_ACK);
        str_lm_mode[4] = linemode;
        if (!init)
            str_lm_mode[4] |= MODE_ACK;
        str_lm_mode[4] = linemode;
        if (!init)
            str_lm_mode[4] |= MODE_ACK;
@@ -1073,8 +1155,11 @@ slc_init()
        spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
        spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
 #endif
        spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
        spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
 #endif
-       /* No FORW1 */
+       initfunc(SLC_FORW1, 0);
+#ifdef USE_TERMIO
+       initfunc(SLC_FORW2, 0);
        /* No FORW2 */
        /* No FORW2 */
+#endif
 
        initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
 #undef initfunc
 
        initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
 #undef initfunc
@@ -1261,7 +1346,6 @@ cc_t value;
 
 slc_end_reply()
 {
 
 slc_end_reply()
 {
-    register char *cp;
     register int len;
 
     *slc_replyp++ = IAC;
     register int len;
 
     *slc_replyp++ = IAC;
@@ -1293,6 +1377,161 @@ slc_update()
        return(need_update);
 }
 
        return(need_update);
 }
 
+env_opt(buf, len)
+register char *buf;
+register int len;
+{
+       register char *ep = 0, *epc = 0;
+       register int i;
+
+       switch(buf[0]) {
+       case TELQUAL_SEND:
+               env_opt_start();
+               if (len == 1) {
+                       env_opt_add(NULL);
+               } else for (i = 1; i < len; i++) {
+                       switch (buf[i]) {
+                       case ENV_VALUE:
+                               if (ep) {
+                                       *epc = 0;
+                                       env_opt_add(ep);
+                               }
+                               ep = epc = &buf[i+1];
+                               break;
+                       case ENV_ESC:
+                               i++;
+                               /*FALL THROUGH*/
+                       default:
+                               if (epc)
+                                       *epc++ = buf[i];
+                               break;
+                       }
+                       if (ep) {
+                               *epc = 0;
+                               env_opt_add(ep);
+                       }
+               }
+               env_opt_end(1);
+               break;
+
+       case TELQUAL_IS:
+       case TELQUAL_INFO:
+               /* Ignore for now.  We shouldn't get it anyway. */
+               break;
+
+       default:
+               break;
+       }
+}
+
+#define        OPT_REPLY_SIZE  256
+unsigned char *opt_reply;
+unsigned char *opt_replyp;
+unsigned char *opt_replyend;
+
+env_opt_start()
+{
+       extern char *realloc();
+       extern char *malloc();
+
+       if (opt_reply)
+               opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+       else
+               opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
+       if (opt_reply == NULL) {
+/*@*/          printf("env_opt_start: malloc()/realloc() failed!!!\n");
+               opt_reply = opt_replyp = opt_replyend = NULL;
+               return;
+       }
+       opt_replyp = opt_reply;
+       opt_replyend = opt_reply + OPT_REPLY_SIZE;
+       *opt_replyp++ = IAC;
+       *opt_replyp++ = SB;
+       *opt_replyp++ = TELOPT_ENVIRON;
+       *opt_replyp++ = TELQUAL_IS;
+}
+
+env_opt_start_info()
+{
+       env_opt_start();
+       if (opt_replyp)
+           opt_replyp[-1] = TELQUAL_INFO;
+}
+
+env_opt_add(ep)
+register char *ep;
+{
+       register char *vp, c;
+       extern char *realloc();
+       extern char *env_default();
+
+       if (opt_reply == NULL)          /*XXX*/
+               return;                 /*XXX*/
+
+       if (ep == NULL || *ep == '\0') {
+               env_default(1);
+               while (ep = env_default(0))
+                       env_opt_add(ep);
+               return;
+       }
+       vp = env_getvalue(ep);
+       if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) {
+               register int len;
+               opt_replyend += OPT_REPLY_SIZE;
+               len = opt_replyend - opt_reply;
+               opt_reply = (unsigned char *)realloc(opt_reply, len);
+               if (opt_reply == NULL) {
+/*@*/                  printf("env_opt_add: realloc() failed!!!\n");
+                       opt_reply = opt_replyp = opt_replyend = NULL;
+                       return;
+               }
+               opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
+               opt_replyend = opt_reply + len;
+       }
+       *opt_replyp++ = ENV_VAR;
+       for (;;) {
+               while (c = *ep++) {
+                       switch(c) {
+                       case IAC:
+                               *opt_replyp++ = IAC;
+                               break;
+                       case ENV_VALUE:
+                       case ENV_VAR:
+                       case ENV_ESC:
+                               *opt_replyp++ = ENV_ESC;
+                               break;
+                       }
+                       *opt_replyp++ = c;
+               }
+               if (ep = vp) {
+                       *opt_replyp++ = ENV_VALUE;
+                       vp = NULL;
+               } else
+                       break;
+       }
+}
+
+env_opt_end(emptyok)
+register int emptyok;
+{
+       register int len;
+
+       len = opt_replyp - opt_reply + 2;
+       if (emptyok || len > 6) {
+               *opt_replyp++ = IAC;
+               *opt_replyp++ = SE;
+               if (NETROOM() > len) {
+                       ring_supply_data(&netoring, opt_reply, len);
+                       printsub('>', &opt_reply[2], len - 2);
+               }
+/*@*/          else printf("slc_end_reply: not enough room\n");
+       }
+       if (opt_reply) {
+               free(opt_reply);
+               opt_reply = opt_replyp = opt_replyend = NULL;
+       }
+}
+
 \f
 
 int
 \f
 
 int
@@ -1417,15 +1656,11 @@ process_iac:
                     * buffer currently.
                     */
                SYNCHing = 1;
                     * buffer currently.
                     */
                SYNCHing = 1;
-               ttyflush(1);
+               (void) ttyflush(1);
                SYNCHing = stilloob();
                settimer(gotDM);
                break;
 
                SYNCHing = stilloob();
                settimer(gotDM);
                break;
 
-           case NOP:
-           case GA:
-               break;
-
            case SB:
                SB_CLEAR();
                telrcv_state = TS_SB;
            case SB:
                SB_CLEAR();
                telrcv_state = TS_SB;
@@ -1435,11 +1670,11 @@ process_iac:
 #          if defined(TN3270)
            case EOR:
                if (In3270) {
 #          if defined(TN3270)
            case EOR:
                if (In3270) {
-                   Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
                    if (Ibackp == Ifrontp) {
                        Ibackp = Ifrontp = Ibuf;
                        ISend = 0;      /* should have been! */
                    } else {
                    if (Ibackp == Ifrontp) {
                        Ibackp = Ifrontp = Ibuf;
                        ISend = 0;      /* should have been! */
                    } else {
+                       Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
                        ISend = 1;
                    }
                }
                        ISend = 1;
                    }
                }
@@ -1458,7 +1693,10 @@ process_iac:
 #          endif /* !defined(TN3270) */
                break;
 
 #          endif /* !defined(TN3270) */
                break;
 
+           case NOP:
+           case GA:
            default:
            default:
+               printoption("RCVD", "IAC", c);
                break;
            }
            telrcv_state = TS_DATA;
                break;
            }
            telrcv_state = TS_DATA;
@@ -1703,7 +1941,7 @@ int       block;                  /* should we block in the select ? */
 #   if defined(TN3270) && defined(unix)
     if (HaveInput) {
        HaveInput = 0;
 #   if defined(TN3270) && defined(unix)
     if (HaveInput) {
        HaveInput = 0;
-       signal(SIGIO, inputAvailable);
+       (void) signal(SIGIO, inputAvailable);
     }
 #endif /* defined(TN3270) && defined(unix) */
 
     }
 #endif /* defined(TN3270) && defined(unix) */
 
@@ -1763,6 +2001,9 @@ telnet()
                send_will(TELOPT_AUTHENTICATION, 1);
 #endif
        send_do(TELOPT_STATUS, 1);
                send_will(TELOPT_AUTHENTICATION, 1);
 #endif
        send_do(TELOPT_STATUS, 1);
+       if (env_getvalue("DISPLAY"))
+           send_will(TELOPT_XDISPLOC, 1);
+       send_will(TELOPT_ENVIRON, 1);
     }
 #   endif /* !defined(TN3270) */
 
     }
 #   endif /* !defined(TN3270) */
 
@@ -1933,7 +2174,7 @@ doflush()
     NETADD(TELOPT_TM);
     flushline = 1;
     flushout = 1;
     NETADD(TELOPT_TM);
     flushline = 1;
     flushout = 1;
-    ttyflush(1);                       /* Flush/drop output */
+    (void) ttyflush(1);                        /* Flush/drop output */
     /* do printoption AFTER flush, otherwise the output gets tossed... */
     printoption("SENT", "do", TELOPT_TM);
 }
     /* do printoption AFTER flush, otherwise the output gets tossed... */
     printoption("SENT", "do", TELOPT_TM);
 }
index 1886941..8a61f2d 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)terminal.c 1.20 (Berkeley) %G%";
+static char sccsid[] = "@(#)terminal.c 1.21 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <arpa/telnet.h>
 #endif /* not lint */
 
 #include <arpa/telnet.h>
@@ -23,35 +23,35 @@ char        ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
 int termdata;                  /* Debugging flag */
 
 #ifdef USE_TERMIO
 int termdata;                  /* Debugging flag */
 
 #ifdef USE_TERMIO
-# ifndef VDISCARD
-char termFlushChar;
+# ifndef VFLUSHO
+cc_t termFlushChar;
 # endif
 # ifndef VLNEXT
 # endif
 # ifndef VLNEXT
-char termLiteralNextChar;
+cc_t termLiteralNextChar;
 # endif
 # ifndef VSUSP
 # endif
 # ifndef VSUSP
-char termSuspChar;
+cc_t termSuspChar;
 # endif
 # ifndef VWERASE
 # endif
 # ifndef VWERASE
-char termWerasChar;
+cc_t termWerasChar;
 # endif
 # ifndef VREPRINT
 # endif
 # ifndef VREPRINT
-char termRprntChar;
+cc_t termRprntChar;
 # endif
 # ifndef VSTART
 # endif
 # ifndef VSTART
-char termStartChar;
+cc_t termStartChar;
 # endif
 # ifndef VSTOP
 # endif
 # ifndef VSTOP
-char termStopChar;
+cc_t termStopChar;
 # endif
 # ifndef VEOL
 # endif
 # ifndef VEOL
-char termForw1Char;
+cc_t termForw1Char;
 # endif
 # ifndef VEOL2
 # endif
 # ifndef VEOL2
-char termForw2Char;
+cc_t termForw2Char;
 # endif
 #else
 # endif
 #else
-char termForw2Char;
+cc_t termForw2Char;
 #endif
 
 /*
 #endif
 
 /*
index 76f5bdb..dbb72ed 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)tn3270.c   1.20 (Berkeley) %G%";
+static char sccsid[] = "@(#)tn3270.c   1.21 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -148,7 +148,7 @@ inputAvailable()
 void
 outputPurge()
 {
 void
 outputPurge()
 {
-    ttyflush(1);
+    (void) ttyflush(1);
 }
 
 
 }
 
 
@@ -181,14 +181,14 @@ register int      count;                  /* how much to send */
 
            FD_ZERO(&o);
 #endif /* defined(unix) */
 
            FD_ZERO(&o);
 #endif /* defined(unix) */
-           ttyflush(0);
+           (void) ttyflush(0);
            while (TTYROOM() == 0) {
 #if    defined(unix)
                FD_SET(tout, &o);
                (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
                                                (struct timeval *) 0);
 #endif /* defined(unix) */
            while (TTYROOM() == 0) {
 #if    defined(unix)
                FD_SET(tout, &o);
                (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
                                                (struct timeval *) 0);
 #endif /* defined(unix) */
-               ttyflush(0);
+               (void) ttyflush(0);
            }
        }
        c = TTYROOM();
            }
        }
        c = TTYROOM();
@@ -221,7 +221,7 @@ Push3270()
            }
        }
        if (Ifrontp+save < Ibuf+sizeof Ibuf) {
            }
        }
        if (Ifrontp+save < Ibuf+sizeof Ibuf) {
-           telrcv();
+           (void)telrcv();
        }
     }
     return save != ring_full_count(&netiring);
        }
     }
     return save != ring_full_count(&netiring);
index 8f4e0f5..cf8641a 100644 (file)
@@ -2,29 +2,18 @@
  * 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: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement:  ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utilities.c        1.17 (Berkeley) 6/1/90";
+static char sccsid[] = "@(#)utilities.c        1.19 (Berkeley) %G%";
 #endif /* not lint */
 
 #define        TELOPTS
 #define        TELCMDS
 #include <arpa/telnet.h>
 #include <sys/types.h>
 #endif /* not lint */
 
 #define        TELOPTS
 #define        TELCMDS
 #include <arpa/telnet.h>
 #include <sys/types.h>
+#include <sys/time.h>
 
 #include <ctype.h>
 
 
 #include <ctype.h>
 
@@ -265,8 +254,6 @@ char *slcnames[] = { SLC_NAMES };
 
 #ifdef KERBEROS
 static char *authtypes[3] = { "NONE", "PRIVATE", "KERBEROS" };
 
 #ifdef KERBEROS
 static char *authtypes[3] = { "NONE", "PRIVATE", "KERBEROS" };
-#else
-static char *authtypes[2] = { "NONE", "PRIVATE" };
 #endif
 
 void
 #endif
 
 void
@@ -315,7 +302,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");
@@ -335,13 +322,13 @@ int       length;                 /* length of suboption data */
            switch (pointer[1]) {
            case TELQUAL_IS:
                fprintf(NetTrace, " IS ");
            switch (pointer[1]) {
            case TELQUAL_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;
@@ -360,7 +347,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]);
@@ -378,14 +365,14 @@ 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;
@@ -497,6 +484,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]);
@@ -509,10 +499,12 @@ 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");
                }
@@ -539,7 +531,7 @@ int length;                 /* length of suboption data */
                if (pointer[1] == TELQUAL_SEND)
                    fprintf(NetTrace, " SEND");
                else
                if (pointer[1] == TELQUAL_SEND)
                    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;
@@ -557,7 +549,7 @@ int length;                 /* length of suboption data */
                    case WONT:  cp = "WONT"; goto common2;
                    common2:
                        i++;
                    case WONT:  cp = "WONT"; goto common2;
                    common2:
                        i++;
-                       if (TELOPT_OK(pointer[i]))
+                       if (TELOPT_OK((int)pointer[i]))
                            fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
                        else
                            fprintf(NetTrace, " %s %d", cp, pointer[i]);
                            fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
                        else
                            fprintf(NetTrace, " %s %d", cp, pointer[i]);
@@ -607,6 +599,77 @@ int        length;                 /* length of suboption data */
            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:
            fprintf(NetTrace, "Unknown option ");
            for (i = 0; i < length; i++)
        default:
            fprintf(NetTrace, "Unknown option ");
            for (i = 0; i < length; i++)
@@ -644,7 +707,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,
@@ -664,7 +727,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) */