BSD 4_4_Lite2 release
[unix-history] / usr / src / libexec / telnetd / state.c
index 5daabbb..4ee8bea 100644 (file)
@@ -1,29 +1,58 @@
 /*
 /*
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)state.c    5.8 (Berkeley) %G%";
+static char sccsid[] = "@(#)state.c    8.5 (Berkeley) 5/30/95";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
+#if    defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#endif
 
 
-char   doopt[] = { IAC, DO, '%', 'c', 0 };
-char   dont[] = { IAC, DONT, '%', 'c', 0 };
-char   will[] = { IAC, WILL, '%', 'c', 0 };
-char   wont[] = { IAC, WONT, '%', 'c', 0 };
+unsigned char  doopt[] = { IAC, DO, '%', 'c', 0 };
+unsigned char  dont[] = { IAC, DONT, '%', 'c', 0 };
+unsigned char  will[] = { IAC, WILL, '%', 'c', 0 };
+unsigned char  wont[] = { IAC, WONT, '%', 'c', 0 };
 int    not42 = 1;
 
 /*
  * Buffer for sub-options, and macros
  * for suboptions buffer manipulations
  */
 int    not42 = 1;
 
 /*
  * Buffer for sub-options, and macros
  * for suboptions buffer manipulations
  */
-char   subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
+unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
 
 
-#define        SB_CLEAR()      subpointer = subbuffer;
+#define        SB_CLEAR()      subpointer = subbuffer
 #define        SB_TERM()       { subend = subpointer; SB_CLEAR(); }
 #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                                *subpointer++ = (c); \
 #define        SB_TERM()       { subend = subpointer; SB_CLEAR(); }
 #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                                *subpointer++ = (c); \
@@ -32,6 +61,11 @@ char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
 #define        SB_EOF()        (subpointer >= subend)
 #define        SB_LEN()        (subend - subpointer)
 
 #define        SB_EOF()        (subpointer >= subend)
 #define        SB_LEN()        (subend - subpointer)
 
+#ifdef ENV_HACK
+unsigned char *subsave;
+#define SB_SAVE()      subsave = subpointer;
+#define        SB_RESTORE()    subpointer = subsave;
+#endif
 
 
 /*
 
 
 /*
@@ -47,6 +81,7 @@ char  subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
 #define        TS_DO           7       /* do " */
 #define        TS_DONT         8       /* dont " */
 
 #define        TS_DO           7       /* do " */
 #define        TS_DONT         8       /* dont " */
 
+       void
 telrcv()
 {
        register int c;
 telrcv()
 {
        register int c;
@@ -59,6 +94,10 @@ telrcv()
                if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
                        break;
                c = *netip++ & 0377, ncc--;
                if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
                        break;
                c = *netip++ & 0377, ncc--;
+#ifdef ENCRYPTION
+               if (decrypt_input)
+                       c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
                switch (state) {
 
                case TS_CR:
                switch (state) {
 
                case TS_CR:
@@ -86,14 +125,27 @@ telrcv()
                         * if CRMOD is set, which it normally is).
                         */
                        if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
                         * if CRMOD is set, which it normally is).
                         */
                        if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
+                               int nc = *netip;
+#ifdef ENCRYPTION
+                               if (decrypt_input)
+                                       nc = (*decrypt_input)(nc & 0xff);
+#endif /* ENCRYPTION */
+#ifdef LINEMODE
                                /*
                                 * If we are operating in linemode,
                                 * convert to local end-of-line.
                                 */
                                /*
                                 * If we are operating in linemode,
                                 * convert to local end-of-line.
                                 */
-                               if ((linemode) && (ncc > 0)&&('\n' == *netip)) {
+                               if (linemode && (ncc > 0) && (('\n' == nc) ||
+                                        ((0 == nc) && tty_iscrnl())) ) {
                                        netip++; ncc--;
                                        c = '\n';
                                        netip++; ncc--;
                                        c = '\n';
-                               } else {
+                               } else
+#endif
+                               {
+#ifdef ENCRYPTION
+                                       if (decrypt_input)
+                                               (void)(*decrypt_input)(-1);
+#endif /* ENCRYPTION */
                                        state = TS_CR;
                                }
                        }
                                        state = TS_CR;
                                }
                        }
@@ -109,18 +161,14 @@ 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 */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                interrupt();
                                break;
 
                        case BREAK:
                                interrupt();
                                break;
 
                        case BREAK:
-#ifdef DIAGNOSTICS
-                               if (diagnostic & TD_OPTIONS)
-                                       printoption("td: recv IAC", c);
-#endif /* DIAGNOSTICS */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                sendbrk();
                                break;
 
                                sendbrk();
                                break;
 
@@ -128,10 +176,8 @@ 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 */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                recv_ayt();
                                break;
 
                                recv_ayt();
                                break;
 
@@ -140,10 +186,8 @@ gotiac:                    switch (c) {
                         */
                        case AO:
                            {
                         */
                        case AO:
                            {
-#ifdef DIAGNOSTICS
-                               if (diagnostic & TD_OPTIONS)
-                                       printoption("td: recv IAC", c);
-#endif /* DIAGNOSTICS */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                ptyflush();     /* half-hearted */
                                init_termbuf();
 
                                ptyflush();     /* half-hearted */
                                init_termbuf();
 
@@ -157,10 +201,8 @@ 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 */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: send IAC", DM));
                                break;
                            }
 
                                break;
                            }
 
@@ -173,10 +215,8 @@ gotiac:                    switch (c) {
                            {
                                cc_t ch;
 
                            {
                                cc_t ch;
 
-#ifdef DIAGNOSTICS
-                               if (diagnostic & TD_OPTIONS)
-                                       printoption("td: recv IAC", c);
-#endif /* DIAGNOSTICS */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                ptyflush();     /* half-hearted */
                                init_termbuf();
                                if (c == EC)
                                ptyflush();     /* half-hearted */
                                init_termbuf();
                                if (c == EC)
@@ -192,10 +232,8 @@ 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 */
+                               DIAG(TD_OPTIONS,
+                                       printoption("td: recv IAC", c));
                                SYNCHing = stilloob(net);
                                settimer(gotDM);
                                break;
                                SYNCHing = stilloob(net);
                                settimer(gotDM);
                                break;
@@ -271,11 +309,12 @@ gotiac:                   switch (c) {
                                         * then treat remaining stream as
                                         * another command sequence.
                                         */
                                         * then treat remaining stream as
                                         * another command sequence.
                                         */
-#ifdef DIAGNOSTICS
+
+                                       /* for DIAGNOSTICS */
                                        SB_ACCUM(IAC);
                                        SB_ACCUM(c);
                                        subpointer -= 2;
                                        SB_ACCUM(IAC);
                                        SB_ACCUM(c);
                                        subpointer -= 2;
-#endif
+
                                        SB_TERM();
                                        suboption();
                                        state = TS_IAC;
                                        SB_TERM();
                                        suboption();
                                        state = TS_IAC;
@@ -284,11 +323,11 @@ gotiac:                   switch (c) {
                                SB_ACCUM(c);
                                state = TS_SB;
                        } else {
                                SB_ACCUM(c);
                                state = TS_SB;
                        } else {
-#ifdef DIAGNOSTICS
+                               /* for DIAGNOSTICS */
                                SB_ACCUM(IAC);
                                SB_ACCUM(SE);
                                subpointer -= 2;
                                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;
@@ -327,7 +366,7 @@ gotiac:                     switch (c) {
                char    xbuf2[BUFSIZ];
                register char *cp;
                int n = pfrontp - opfrontp, oc;
                char    xbuf2[BUFSIZ];
                register char *cp;
                int n = pfrontp - opfrontp, oc;
-               bcopy(opfrontp, xptyobuf, n);
+               memmove(xptyobuf, opfrontp, n);
                pfrontp = opfrontp;
                pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
                                        xbuf2, &oc, BUFSIZ);
                pfrontp = opfrontp;
                pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
                                        xbuf2, &oc, BUFSIZ);
@@ -349,7 +388,7 @@ gotiac:                     switch (c) {
  * All state defaults are negative, and resp defaults to 0.
  *
  * When initiating a request to change state to new_state:
  * All state defaults are negative, and resp defaults to 0.
  *
  * When initiating a request to change state to new_state:
- * 
+ *
  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
  *     do nothing;
  * } else {
  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
  *     do nothing;
  * } else {
@@ -394,6 +433,7 @@ gotiac:                     switch (c) {
  * is complete.
  *
  */
  * is complete.
  *
  */
+       void
 send_do(option, init)
        int option, init;
 {
 send_do(option, init)
        int option, init;
 {
@@ -412,35 +452,34 @@ send_do(option, init)
                        set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
                        set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, doopt, option);
+       (void) sprintf(nfrontp, (char *)doopt, option);
        nfrontp += sizeof (dont) - 2;
        nfrontp += sizeof (dont) - 2;
-#ifdef DIAGNOSTICS
-       /*
-        * Report sending option to other side.
-        */
-       if (diagnostic & TD_OPTIONS) {
-               printoption("td: send do", option);
-       }
-#endif /* DIAGNOSTICS */
+
+       DIAG(TD_OPTIONS, printoption("td: send do", option));
 }
 
 }
 
+#ifdef AUTHENTICATION
+extern void auth_request();
+#endif
+#ifdef LINEMODE
+extern void doclientstat();
+#endif
+#ifdef ENCRYPTION
+extern void encrypt_send_support();
+#endif /* ENCRYPTION */
+
+       void
 willoption(option)
        int option;
 {
        int changeok = 0;
 willoption(option)
        int option;
 {
        int changeok = 0;
+       void (*func)() = 0;
 
        /*
         * 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 */
+       DIAG(TD_OPTIONS, printoption("td: recv will", option));
 
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
 
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
@@ -491,6 +530,8 @@ willoption(option)
                                lmodetype = KLUDGE_LINEMODE;
                                clientstat(TELOPT_LINEMODE, WILL, 0);
                                send_wont(TELOPT_SGA, 1);
                                lmodetype = KLUDGE_LINEMODE;
                                clientstat(TELOPT_LINEMODE, WILL, 0);
                                send_wont(TELOPT_SGA, 1);
+                       } else if (lmodetype == NO_AUTOKLUDGE) {
+                               lmodetype = KLUDGE_OK;
                        }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                        /*
                        }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                        /*
@@ -514,33 +555,38 @@ willoption(option)
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_XDISPLOC:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_XDISPLOC:
-               case TELOPT_ENVIRON:
+               case TELOPT_NEW_ENVIRON:
+               case TELOPT_OLD_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.
                         */
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
 # ifdef        KLUDGELINEMODE
                        /*
                         * Note client's desire to use linemode.
                         */
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
-                       clientstat(TELOPT_LINEMODE, WILL, 0);
-                       return;
+                       func = doclientstat;
+                       changeok++;
+                       break;
 #endif /* LINEMODE */
 
 #endif /* LINEMODE */
 
+#ifdef AUTHENTICATION
+               case TELOPT_AUTHENTICATION:
+                       func = auth_request;
+                       changeok++;
+                       break;
+#endif
+
+#ifdef ENCRYPTION
+               case TELOPT_ENCRYPT:
+                       func = encrypt_send_support;
+                       changeok++;
+                       break;
+#endif /* ENCRYPTION */
+
                default:
                        break;
                }
                default:
                        break;
                }
@@ -589,14 +635,33 @@ willoption(option)
                         */
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
                         */
                        lmodetype = REAL_LINEMODE;
 # endif        /* KLUDGELINEMODE */
-                       clientstat(TELOPT_LINEMODE, WILL, 0);
+                       func = doclientstat;
+                       break;
 #endif /* LINEMODE */
 #endif /* LINEMODE */
+
+#ifdef AUTHENTICATION
+               case TELOPT_AUTHENTICATION:
+                       func = auth_request;
+                       break;
+#endif
+
+#ifdef ENCRYPTION
+               case TELOPT_ENCRYPT:
+                       func = encrypt_send_support;
+                       break;
+#endif /* ENCRYPTION */
+               case TELOPT_LFLOW:
+                       func = flowstat;
+                       break;
                }
            }
        }
        set_his_state_will(option);
                }
            }
        }
        set_his_state_will(option);
+       if (func)
+               (*func)();
 }  /* end of willoption */
 
 }  /* end of willoption */
 
+       void
 send_dont(option, init)
        int option, init;
 {
 send_dont(option, init)
        int option, init;
 {
@@ -607,18 +672,13 @@ send_dont(option, init)
                set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
                set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, dont, option);
+       (void) sprintf(nfrontp, (char *)dont, option);
        nfrontp += sizeof (doopt) - 2;
        nfrontp += sizeof (doopt) - 2;
-#ifdef DIAGNOSTICS
-       /*
-        * Report sending option to other side.
-        */
-       if (diagnostic & TD_OPTIONS) {
-               printoption("td: send dont", option);
-       }
-#endif /* DIAGNOSTICS */
+
+       DIAG(TD_OPTIONS, printoption("td: send dont", option));
 }
 
 }
 
+       void
 wontoption(option)
        int option;
 {
 wontoption(option)
        int option;
 {
@@ -626,14 +686,7 @@ wontoption(option)
         * 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 */
+       DIAG(TD_OPTIONS, printoption("td: recv wont", option));
 
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
 
        if (do_dont_resp[option]) {
                do_dont_resp[option]--;
@@ -663,11 +716,10 @@ wontoption(option)
                         */
                        if (lmodetype != REAL_LINEMODE)
                                break;
                         */
                        if (lmodetype != REAL_LINEMODE)
                                break;
-                       lmodetype = KLUDGE_LINEMODE;
 # endif        /* KLUDGELINEMODE */
                        clientstat(TELOPT_LINEMODE, WONT, 0);
                        break;
 # endif        /* KLUDGELINEMODE */
                        clientstat(TELOPT_LINEMODE, WONT, 0);
                        break;
-#endif LINEMODE
+#endif /* LINEMODE */
 
                case TELOPT_TM:
                        /*
 
                case TELOPT_TM:
                        /*
@@ -691,6 +743,12 @@ wontoption(option)
                        slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
                        break;
 
                        slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
                        break;
 
+#if    defined(AUTHENTICATION)
+               case TELOPT_AUTHENTICATION:
+                       auth_finished(0, AUTH_REJECT);
+                       break;
+#endif
+
                /*
                 * For options that we might spin waiting for
                 * sub-negotiation, if the client turns off the
                /*
                 * For options that we might spin waiting for
                 * sub-negotiation, if the client turns off the
@@ -711,7 +769,11 @@ wontoption(option)
                        settimer(xdisplocsubopt);
                        break;
 
                        settimer(xdisplocsubopt);
                        break;
 
-               case TELOPT_ENVIRON:
+               case TELOPT_OLD_ENVIRON:
+                       settimer(oenvironsubopt);
+                       break;
+
+               case TELOPT_NEW_ENVIRON:
                        settimer(environsubopt);
                        break;
 
                        settimer(environsubopt);
                        break;
 
@@ -725,13 +787,20 @@ wontoption(option)
                switch (option) {
                case TELOPT_TM:
 #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
                switch (option) {
                case TELOPT_TM:
 #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
-                       if (lmodetype < REAL_LINEMODE) {
+                       if (lmodetype < NO_AUTOKLUDGE) {
                                lmodetype = NO_LINEMODE;
                                clientstat(TELOPT_LINEMODE, WONT, 0);
                                send_will(TELOPT_SGA, 1);
                                send_will(TELOPT_ECHO, 1);
                        }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                                lmodetype = NO_LINEMODE;
                                clientstat(TELOPT_LINEMODE, WONT, 0);
                                send_will(TELOPT_SGA, 1);
                                send_will(TELOPT_ECHO, 1);
                        }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+                       break;
+
+#if    defined(AUTHENTICATION)
+               case TELOPT_AUTHENTICATION:
+                       auth_finished(0, AUTH_REJECT);
+                       break;
+#endif
                default:
                        break;
                }
                default:
                        break;
                }
@@ -741,6 +810,7 @@ wontoption(option)
 
 }  /* end of wontoption */
 
 
 }  /* end of wontoption */
 
+       void
 send_will(option, init)
        int option, init;
 {
 send_will(option, init)
        int option, init;
 {
@@ -751,16 +821,10 @@ send_will(option, init)
                set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
                set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, will, option);
+       (void) sprintf(nfrontp, (char *)will, option);
        nfrontp += sizeof (doopt) - 2;
        nfrontp += sizeof (doopt) - 2;
-#ifdef DIAGNOSTICS
-       /*
-        * Report sending option to other side.
-        */
-       if (diagnostic & TD_OPTIONS) {
-               printoption("td: send will", option);
-       }
-#endif /* DIAGNOSTICS */
+
+       DIAG(TD_OPTIONS, printoption("td: send will", option));
 }
 
 #if    !defined(LINEMODE) || !defined(KLUDGELINEMODE)
 }
 
 #if    !defined(LINEMODE) || !defined(KLUDGELINEMODE)
@@ -774,6 +838,7 @@ send_will(option, init)
 int turn_on_sga = 0;
 #endif
 
 int turn_on_sga = 0;
 #endif
 
+       void
 dooption(option)
        int option;
 {
 dooption(option)
        int option;
 {
@@ -783,14 +848,7 @@ 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 */
+       DIAG(TD_OPTIONS, printoption("td: recv do", option));
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
@@ -866,13 +924,36 @@ dooption(option)
                        set_my_state_wont(option);
                        return;
 
                        set_my_state_wont(option);
                        return;
 
+               case TELOPT_LOGOUT:
+                       /*
+                        * When we get a LOGOUT option, respond
+                        * with a WILL LOGOUT, make sure that
+                        * it gets written out to the network,
+                        * and then just go away...
+                        */
+                       set_my_want_state_will(TELOPT_LOGOUT);
+                       send_will(TELOPT_LOGOUT, 0);
+                       set_my_state_will(TELOPT_LOGOUT);
+                       (void)netflush();
+                       cleanup(0);
+                       /* NOT REACHED */
+                       break;
+
+#ifdef ENCRYPTION
+               case TELOPT_ENCRYPT:
+                       changeok++;
+                       break;
+#endif /* ENCRYPTION */
                case TELOPT_LINEMODE:
                case TELOPT_TTYPE:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
                case TELOPT_XDISPLOC:
                case TELOPT_LINEMODE:
                case TELOPT_TTYPE:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
                case TELOPT_XDISPLOC:
-               case TELOPT_ENVIRON:
+#ifdef TELOPT_ENVIRON
+               case TELOPT_NEW_ENVIRON:
+#endif
+               case TELOPT_OLD_ENVIRON:
                default:
                        break;
                }
                default:
                        break;
                }
@@ -888,6 +969,7 @@ dooption(option)
 
 }  /* end of dooption */
 
 
 }  /* end of dooption */
 
+       void
 send_wont(option, init)
        int option, init;
 {
 send_wont(option, init)
        int option, init;
 {
@@ -898,32 +980,22 @@ send_wont(option, init)
                set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
                set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, wont, option);
+       (void) sprintf(nfrontp, (char *)wont, option);
        nfrontp += sizeof (wont) - 2;
        nfrontp += sizeof (wont) - 2;
-#ifdef DIAGNOSTICS
-       /*
-        * Report sending option to other side.
-        */
-       if (diagnostic & TD_OPTIONS) {
-               printoption("td: send wont", option);
-       }
-#endif /* DIAGNOSTICS */
+
+       DIAG(TD_OPTIONS, printoption("td: send wont", option));
 }
 
 }
 
+       void
 dontoption(option)
        int option;
 {
        /*
         * Process client input.
         */
 dontoption(option)
        int option;
 {
        /*
         * Process client input.
         */
-#ifdef DIAGNOSTICS
-       /*
-        * Report receiving option from other side.
-        */
-       if (diagnostic & TD_OPTIONS) {
-               printoption("td: recv dont", option);
-       }
-#endif /* DIAGNOSTICS */
+
+
+       DIAG(TD_OPTIONS, printoption("td: recv dont", option));
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
 
        if (will_wont_resp[option]) {
                will_wont_resp[option]--;
@@ -941,7 +1013,8 @@ dontoption(option)
                case TELOPT_ECHO:       /* we should stop echoing */
 #ifdef LINEMODE
 # ifdef        KLUDGELINEMODE
                case TELOPT_ECHO:       /* we should stop echoing */
 #ifdef LINEMODE
 # ifdef        KLUDGELINEMODE
-                       if (lmodetype == NO_LINEMODE)
+                       if ((lmodetype != REAL_LINEMODE) &&
+                           (lmodetype != KLUDGE_LINEMODE))
 # else
                        if (his_state_is_wont(TELOPT_LINEMODE))
 # endif
 # else
                        if (his_state_is_wont(TELOPT_LINEMODE))
 # endif
@@ -960,11 +1033,13 @@ dontoption(option)
                         * must process an incoming do SGA for
                         * linemode purposes.
                         */
                         * must process an incoming do SGA for
                         * linemode purposes.
                         */
-                       if (lmodetype == KLUDGE_LINEMODE) {
+                       if ((lmodetype == KLUDGE_LINEMODE) ||
+                           (lmodetype == KLUDGE_OK)) {
                                /*
                                 * The client is asking us to turn
                                 * linemode on.
                                 */
                                /*
                                 * The client is asking us to turn
                                 * linemode on.
                                 */
+                               lmodetype = KLUDGE_LINEMODE;
                                clientstat(TELOPT_LINEMODE, WILL, 0);
                                /*
                                 * If we did not turn line mode on,
                                clientstat(TELOPT_LINEMODE, WILL, 0);
                                /*
                                 * If we did not turn line mode on,
@@ -980,7 +1055,7 @@ dontoption(option)
                                send_wont(option, 0);
                        set_my_state_wont(option);
                        if (turn_on_sga ^= 1)
                                send_wont(option, 0);
                        set_my_state_wont(option);
                        if (turn_on_sga ^= 1)
-                               send_will(option);
+                               send_will(option, 1);
                        return;
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
                        return;
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
@@ -996,6 +1071,14 @@ dontoption(option)
 
 }  /* end of dontoption */
 
 
 }  /* end of dontoption */
 
+#ifdef ENV_HACK
+int env_ovar = -1;
+int env_ovalue = -1;
+#else  /* ENV_HACK */
+# define env_ovar OLD_ENV_VAR
+# define env_ovalue OLD_ENV_VALUE
+#endif /* ENV_HACK */
+
 /*
  * suboption()
  *
 /*
  * suboption()
  *
@@ -1009,20 +1092,13 @@ dontoption(option)
  *     Window size
  *     Terminal speed
  */
  *     Window size
  *     Terminal speed
  */
+       void
 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
+    DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
+
     subchar = SB_GET();
     switch (subchar) {
     case TELOPT_TSPEED: {
     subchar = SB_GET();
     switch (subchar) {
     case TELOPT_TSPEED: {
@@ -1036,13 +1112,13 @@ suboption()
        if (SB_EOF() || SB_GET() != TELQUAL_IS)
                return;
 
        if (SB_EOF() || SB_GET() != TELQUAL_IS)
                return;
 
-       xspeed = atoi(subpointer);
+       xspeed = atoi((char *)subpointer);
 
        while (SB_GET() != ',' && !SB_EOF());
        if (SB_EOF())
                return;
 
 
        while (SB_GET() != ',' && !SB_EOF());
        if (SB_EOF())
                return;
 
-       rspeed = atoi(subpointer);
+       rspeed = atoi((char *)subpointer);
        clientstat(TELOPT_TSPEED, xspeed, rspeed);
 
        break;
        clientstat(TELOPT_TSPEED, xspeed, rspeed);
 
        break;
@@ -1056,7 +1132,7 @@ suboption()
                break;
        settimer(ttypesubopt);
 
                break;
        settimer(ttypesubopt);
 
-       if (SB_GET() != TELQUAL_IS) {
+       if (SB_EOF() || SB_GET() != TELQUAL_IS) {
            return;             /* ??? XXX but, this is the most robust */
        }
 
            return;             /* ??? XXX but, this is the most robust */
        }
 
@@ -1110,9 +1186,12 @@ suboption()
        /*
         * Process linemode suboptions.
         */
        /*
         * Process linemode suboptions.
         */
-       if (SB_EOF()) break;  /* garbage was sent */
-       request = SB_GET();  /* get will/wont */
-       if (SB_EOF()) break;  /* another garbage check */
+       if (SB_EOF())
+           break;              /* garbage was sent */
+       request = SB_GET();     /* get will/wont */
+
+       if (SB_EOF())
+           break;              /* another garbage check */
 
        if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
                /*
 
        if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
                /*
@@ -1120,13 +1199,18 @@ suboption()
                 */
                start_slc(1);
                do_opt_slc(subpointer, subend - subpointer);
                 */
                start_slc(1);
                do_opt_slc(subpointer, subend - subpointer);
-               end_slc(0);
-
+               (void) end_slc(0);
+               break;
        } else if (request == LM_MODE) {
        } else if (request == LM_MODE) {
+               if (SB_EOF())
+                   return;
                useeditmode = SB_GET();  /* get mode flag */
                clientstat(LM_MODE, 0, 0);
                useeditmode = SB_GET();  /* get mode flag */
                clientstat(LM_MODE, 0, 0);
+               break;
        }
 
        }
 
+       if (SB_EOF())
+           break;
        switch (SB_GET()) {  /* what suboption? */
        case LM_FORWARDMASK:
                /*
        switch (SB_GET()) {  /* what suboption? */
        case LM_FORWARDMASK:
                /*
@@ -1144,6 +1228,8 @@ suboption()
     case TELOPT_STATUS: {
        int mode;
 
     case TELOPT_STATUS: {
        int mode;
 
+       if (SB_EOF())
+           break;
        mode = SB_GET();
        switch (mode) {
        case TELQUAL_SEND:
        mode = SB_GET();
        switch (mode) {
        case TELQUAL_SEND:
@@ -1165,45 +1251,177 @@ suboption()
                return;
        settimer(xdisplocsubopt);
        subpointer[SB_LEN()] = '\0';
                return;
        settimer(xdisplocsubopt);
        subpointer[SB_LEN()] = '\0';
-       setenv("DISPLAY", subpointer, 1);
+       (void)setenv("DISPLAY", (char *)subpointer, 1);
        break;
     }  /* end of case TELOPT_XDISPLOC */
 
        break;
     }  /* end of case TELOPT_XDISPLOC */
 
-    case TELOPT_ENVIRON: {
+#ifdef TELOPT_NEW_ENVIRON
+    case TELOPT_NEW_ENVIRON:
+#endif
+    case TELOPT_OLD_ENVIRON: {
        register int c;
        register char *cp, *varp, *valp;
 
        if (SB_EOF())
                return;
        c = SB_GET();
        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)
+       if (c == TELQUAL_IS) {
+               if (subchar == TELOPT_OLD_ENVIRON)
+                       settimer(oenvironsubopt);
+               else
+                       settimer(environsubopt);
+       } else if (c != TELQUAL_INFO) {
                return;
                return;
+       }
+
+#ifdef TELOPT_NEW_ENVIRON
+       if (subchar == TELOPT_NEW_ENVIRON) {
+           while (!SB_EOF()) {
+               c = SB_GET();
+               if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
+                       break;
+           }
+       } else
+#endif
+       {
+#ifdef ENV_HACK
+           /*
+            * We only want to do this if we haven't already decided
+            * whether or not the other side has its VALUE and VAR
+            * reversed.
+            */
+           if (env_ovar < 0) {
+               register int last = -1;         /* invalid value */
+               int empty = 0;
+               int got_var = 0, got_value = 0, got_uservar = 0;
+
+               /*
+                * The other side might have its VALUE and VAR values
+                * reversed.  To be interoperable, we need to determine
+                * which way it is.  If the first recognized character
+                * is a VAR or VALUE, then that will tell us what
+                * type of client it is.  If the fist recognized
+                * character is a USERVAR, then we continue scanning
+                * the suboption looking for two consecutive
+                * VAR or VALUE fields.  We should not get two
+                * consecutive VALUE fields, so finding two
+                * consecutive VALUE or VAR fields will tell us
+                * what the client is.
+                */
+               SB_SAVE();
+               while (!SB_EOF()) {
+                       c = SB_GET();
+                       switch(c) {
+                       case OLD_ENV_VAR:
+                               if (last < 0 || last == OLD_ENV_VAR
+                                   || (empty && (last == OLD_ENV_VALUE)))
+                                       goto env_ovar_ok;
+                               got_var++;
+                               last = OLD_ENV_VAR;
+                               break;
+                       case OLD_ENV_VALUE:
+                               if (last < 0 || last == OLD_ENV_VALUE
+                                   || (empty && (last == OLD_ENV_VAR)))
+                                       goto env_ovar_wrong;
+                               got_value++;
+                               last = OLD_ENV_VALUE;
+                               break;
+                       case ENV_USERVAR:
+                               /* count strings of USERVAR as one */
+                               if (last != ENV_USERVAR)
+                                       got_uservar++;
+                               if (empty) {
+                                       if (last == OLD_ENV_VALUE)
+                                               goto env_ovar_ok;
+                                       if (last == OLD_ENV_VAR)
+                                               goto env_ovar_wrong;
+                               }
+                               last = ENV_USERVAR;
+                               break;
+                       case ENV_ESC:
+                               if (!SB_EOF())
+                                       c = SB_GET();
+                               /* FALL THROUGH */
+                       default:
+                               empty = 0;
+                               continue;
+                       }
+                       empty = 1;
+               }
+               if (empty) {
+                       if (last == OLD_ENV_VALUE)
+                               goto env_ovar_ok;
+                       if (last == OLD_ENV_VAR)
+                               goto env_ovar_wrong;
+               }
+               /*
+                * Ok, the first thing was a USERVAR, and there
+                * are not two consecutive VAR or VALUE commands,
+                * and none of the VAR or VALUE commands are empty.
+                * If the client has sent us a well-formed option,
+                * then the number of VALUEs received should always
+                * be less than or equal to the number of VARs and
+                * USERVARs received.
+                *
+                * If we got exactly as many VALUEs as VARs and
+                * USERVARs, the client has the same definitions.
+                *
+                * If we got exactly as many VARs as VALUEs and
+                * USERVARS, the client has reversed definitions.
+                */
+               if (got_uservar + got_var == got_value) {
+           env_ovar_ok:
+                       env_ovar = OLD_ENV_VAR;
+                       env_ovalue = OLD_ENV_VALUE;
+               } else if (got_uservar + got_value == got_var) {
+           env_ovar_wrong:
+                       env_ovar = OLD_ENV_VALUE;
+                       env_ovalue = OLD_ENV_VAR;
+                       DIAG(TD_OPTIONS, {sprintf(nfrontp,
+                               "ENVIRON VALUE and VAR are reversed!\r\n");
+                               nfrontp += strlen(nfrontp);});
 
 
-       while (!SB_EOF() && SB_GET() != ENV_VAR)
-               ;
+               }
+           }
+           SB_RESTORE();
+#endif
+
+           while (!SB_EOF()) {
+               c = SB_GET();
+               if ((c == env_ovar) || (c == ENV_USERVAR))
+                       break;
+           }
+       }
 
        if (SB_EOF())
                return;
 
 
        if (SB_EOF())
                return;
 
-       cp = varp = subpointer;
+       cp = varp = (char *)subpointer;
        valp = 0;
 
        while (!SB_EOF()) {
        valp = 0;
 
        while (!SB_EOF()) {
-               switch (c = SB_GET()) {
-               case ENV_VALUE:
+               c = SB_GET();
+               if (subchar == TELOPT_OLD_ENVIRON) {
+                       if (c == env_ovar)
+                               c = NEW_ENV_VAR;
+                       else if (c == env_ovalue)
+                               c = NEW_ENV_VALUE;
+               }
+               switch (c) {
+
+               case NEW_ENV_VALUE:
                        *cp = '\0';
                        *cp = '\0';
-                       cp = valp = subpointer;
+                       cp = valp = (char *)subpointer;
                        break;
 
                        break;
 
-               case ENV_VAR:
+               case NEW_ENV_VAR:
+               case ENV_USERVAR:
                        *cp = '\0';
                        if (valp)
                        *cp = '\0';
                        if (valp)
-                               setenv(varp, valp, 1);
+                               (void)setenv(varp, valp, 1);
                        else
                                unsetenv(varp);
                        else
                                unsetenv(varp);
-                       cp = varp = subpointer;
+                       cp = varp = (char *)subpointer;
                        valp = 0;
                        break;
 
                        valp = 0;
                        break;
 
@@ -1219,11 +1437,75 @@ suboption()
        }
        *cp = '\0';
        if (valp)
        }
        *cp = '\0';
        if (valp)
-               setenv(varp, valp, 1);
+               (void)setenv(varp, valp, 1);
        else
                unsetenv(varp);
        break;
        else
                unsetenv(varp);
        break;
-    }  /* end of case TELOPT_ENVIRON */
+    }  /* end of case TELOPT_NEW_ENVIRON */
+#if    defined(AUTHENTICATION)
+    case TELOPT_AUTHENTICATION:
+       if (SB_EOF())
+               break;
+       switch(SB_GET()) {
+       case TELQUAL_SEND:
+       case TELQUAL_REPLY:
+               /*
+                * These are sent by us and cannot be sent by
+                * the client.
+                */
+               break;
+       case TELQUAL_IS:
+               auth_is(subpointer, SB_LEN());
+               break;
+       case TELQUAL_NAME:
+               auth_name(subpointer, SB_LEN());
+               break;
+       }
+       break;
+#endif
+#ifdef ENCRYPTION
+    case TELOPT_ENCRYPT:
+       if (SB_EOF())
+               break;
+       switch(SB_GET()) {
+       case ENCRYPT_SUPPORT:
+               encrypt_support(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_IS:
+               encrypt_is(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_REPLY:
+               encrypt_reply(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_START:
+               encrypt_start(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_END:
+               encrypt_end();
+               break;
+       case ENCRYPT_REQSTART:
+               encrypt_request_start(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_REQEND:
+               /*
+                * We can always send an REQEND so that we cannot
+                * get stuck encrypting.  We should only get this
+                * if we have been able to get in the correct mode
+                * anyhow.
+                */
+               encrypt_request_end();
+               break;
+       case ENCRYPT_ENC_KEYID:
+               encrypt_enc_keyid(subpointer, SB_LEN());
+               break;
+       case ENCRYPT_DEC_KEYID:
+               encrypt_dec_keyid(subpointer, SB_LEN());
+               break;
+       default:
+               break;
+       }
+       break;
+#endif /* ENCRYPTION */
 
     default:
        break;
 
     default:
        break;
@@ -1231,8 +1513,15 @@ suboption()
 
 }  /* end of suboption */
 
 
 }  /* end of suboption */
 
-#define        ADD(c)   *ncp++ = c;
-#define        ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
+       void
+doclientstat()
+{
+       clientstat(TELOPT_LINEMODE, WILL, 0);
+}
+
+#define        ADD(c)   *ncp++ = c
+#define        ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
+       void
 send_status()
 {
        unsigned char statusbuf[256];
 send_status()
 {
        unsigned char statusbuf[256];
@@ -1248,23 +1537,49 @@ send_status()
        ADD(TELOPT_STATUS);
        ADD(TELQUAL_IS);
 
        ADD(TELOPT_STATUS);
        ADD(TELQUAL_IS);
 
-       for (i = 0; i < NTELOPTS; i++) {
-               if (my_state_is_will(i)) {
+       /*
+        * We check the want_state rather than the current state,
+        * because if we received a DO/WILL for an option that we
+        * don't support, and the other side didn't send a DONT/WONT
+        * in response to our WONT/DONT, then the "state" will be
+        * WILL/DO, and the "want_state" will be WONT/DONT.  We
+        * need to go by the latter.
+        */
+       for (i = 0; i < (unsigned char)NTELOPTS; i++) {
+               if (my_want_state_is_will(i)) {
                        ADD(WILL);
                        ADD_DATA(i);
                        ADD(WILL);
                        ADD_DATA(i);
-                       if (i == IAC)
-                               ADD(IAC);
                }
                }
-               if (his_state_is_will(i)) {
+               if (his_want_state_is_will(i)) {
                        ADD(DO);
                        ADD_DATA(i);
                        ADD(DO);
                        ADD_DATA(i);
-                       if (i == IAC)
-                               ADD(IAC);
+               }
+       }
+
+       if (his_want_state_is_will(TELOPT_LFLOW)) {
+               ADD(SB);
+               ADD(TELOPT_LFLOW);
+               if (flowmode) {
+                       ADD(LFLOW_ON);
+               } else {
+                       ADD(LFLOW_OFF);
+               }
+               ADD(SE);
+
+               if (restartany >= 0) {
+                       ADD(SB);
+                       ADD(TELOPT_LFLOW);
+                       if (restartany) {
+                               ADD(LFLOW_RESTART_ANY);
+                       } else {
+                               ADD(LFLOW_RESTART_XON);
+                       }
+                       ADD(SE);
                }
        }
 
 #ifdef LINEMODE
                }
        }
 
 #ifdef LINEMODE
-       if (his_state_is_will(TELOPT_LINEMODE)) {
+       if (his_want_state_is_will(TELOPT_LINEMODE)) {
                unsigned char *cp, *cpe;
                int len;
 
                unsigned char *cp, *cpe;
                int len;
 
@@ -1272,8 +1587,6 @@ send_status()
                ADD(TELOPT_LINEMODE);
                ADD(LM_MODE);
                ADD_DATA(editmode);
                ADD(TELOPT_LINEMODE);
                ADD(LM_MODE);
                ADD_DATA(editmode);
-               if (editmode == IAC)
-                       ADD(IAC);
                ADD(SE);
 
                ADD(SB);
                ADD(SE);
 
                ADD(SB);
@@ -1293,17 +1606,7 @@ 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
+       DIAG(TD_OPTIONS,
+               {printsub('>', statusbuf, ncp - statusbuf); netflush();});
+}