home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / telnetd / state.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  36KB  |  1,617 lines

  1. /*
  2.  * Copyright (c) 1989, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)state.c    8.5 (Berkeley) 5/30/95";
  36. #endif /* not lint */
  37.  
  38. #ifdef HAVE_CONFIG_H
  39. #include <config.h>
  40. #endif
  41.  
  42. #include "telnetd.h"
  43. #if    defined(AUTHENTICATION)
  44. #include <libtelnet/auth.h>
  45. #endif
  46.  
  47. unsigned char    doopt[] = { IAC, DO, '%', 'c', 0 };
  48. unsigned char    dont[] = { IAC, DONT, '%', 'c', 0 };
  49. unsigned char    will[] = { IAC, WILL, '%', 'c', 0 };
  50. unsigned char    wont[] = { IAC, WONT, '%', 'c', 0 };
  51. int    not42 = 1;
  52.  
  53. /*
  54.  * Buffer for sub-options, and macros
  55.  * for suboptions buffer manipulations
  56.  */
  57. unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
  58.  
  59. #define    SB_CLEAR()    subpointer = subbuffer
  60. #define    SB_TERM()    { subend = subpointer; SB_CLEAR(); }
  61. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof subbuffer)) { \
  62.                 *subpointer++ = (c); \
  63.             }
  64. #define    SB_GET()    ((*subpointer++)&0xff)
  65. #define    SB_EOF()    (subpointer >= subend)
  66. #define    SB_LEN()    (subend - subpointer)
  67.  
  68. #ifdef    ENV_HACK
  69. unsigned char *subsave;
  70. #define SB_SAVE()    subsave = subpointer;
  71. #define    SB_RESTORE()    subpointer = subsave;
  72. #endif
  73.  
  74.  
  75. /*
  76.  * State for recv fsm
  77.  */
  78. #define    TS_DATA        0    /* base state */
  79. #define    TS_IAC        1    /* look for double IAC's */
  80. #define    TS_CR        2    /* CR-LF ->'s CR */
  81. #define    TS_SB        3    /* throw away begin's... */
  82. #define    TS_SE        4    /* ...end's (suboption negotiation) */
  83. #define    TS_WILL        5    /* will option negotiation */
  84. #define    TS_WONT        6    /* wont " */
  85. #define    TS_DO        7    /* do " */
  86. #define    TS_DONT        8    /* dont " */
  87.  
  88.     void
  89. telrcv()
  90. {
  91.     register int c;
  92.     static int state = TS_DATA;
  93. #if    defined(CRAY2) && defined(UNICOS5)
  94.     char *opfrontp = pfrontp;
  95. #endif
  96.  
  97.     while (ncc > 0) {
  98.         if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  99.             break;
  100.         c = *netip++ & 0377, ncc--;
  101. #ifdef    ENCRYPTION
  102.         if (decrypt_input)
  103.             c = (*decrypt_input)(c);
  104. #endif    /* ENCRYPTION */
  105.         switch (state) {
  106.  
  107.         case TS_CR:
  108.             state = TS_DATA;
  109.             /* Strip off \n or \0 after a \r */
  110.             if ((c == 0) || (c == '\n')) {
  111.                 break;
  112.             }
  113.             /* FALL THROUGH */
  114.  
  115.         case TS_DATA:
  116.             if (c == IAC) {
  117.                 state = TS_IAC;
  118.                 break;
  119.             }
  120.             /*
  121.              * We now map \r\n ==> \r for pragmatic reasons.
  122.              * Many client implementations send \r\n when
  123.              * the user hits the CarriageReturn key.
  124.              *
  125.              * We USED to map \r\n ==> \n, since \r\n says
  126.              * that we want to be in column 1 of the next
  127.              * printable line, and \n is the standard
  128.              * unix way of saying that (\r is only good
  129.              * if CRMOD is set, which it normally is).
  130.              */
  131.             if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
  132.                 int nc = *netip;
  133. #ifdef    ENCRYPTION
  134.                 if (decrypt_input)
  135.                     nc = (*decrypt_input)(nc & 0xff);
  136. #endif    /* ENCRYPTION */
  137. #ifdef    LINEMODE
  138.                 /*
  139.                  * If we are operating in linemode,
  140.                  * convert to local end-of-line.
  141.                  */
  142.                 if (linemode && (ncc > 0) && (('\n' == nc) ||
  143.                      ((0 == nc) && tty_iscrnl())) ) {
  144.                     netip++; ncc--;
  145.                     c = '\n';
  146.                 } else
  147. #endif
  148.                 {
  149. #ifdef    ENCRYPTION
  150.                     if (decrypt_input)
  151.                         (void)(*decrypt_input)(-1);
  152. #endif    /* ENCRYPTION */
  153.                     state = TS_CR;
  154.                 }
  155.             }
  156.             *pfrontp++ = c;
  157.             break;
  158.  
  159.         case TS_IAC:
  160. gotiac:            switch (c) {
  161.  
  162.             /*
  163.              * Send the process on the pty side an
  164.              * interrupt.  Do this with a NULL or
  165.              * interrupt char; depending on the tty mode.
  166.              */
  167.             case IP:
  168.                 DIAG(TD_OPTIONS,
  169.                     printoption("td: recv IAC", c));
  170.                 interrupt();
  171.                 break;
  172.  
  173.             case BREAK:
  174.                 DIAG(TD_OPTIONS,
  175.                     printoption("td: recv IAC", c));
  176.                 sendbrk();
  177.                 break;
  178.  
  179.             /*
  180.              * Are You There?
  181.              */
  182.             case AYT:
  183.                 DIAG(TD_OPTIONS,
  184.                     printoption("td: recv IAC", c));
  185.                 recv_ayt();
  186.                 break;
  187.  
  188.             /*
  189.              * Abort Output
  190.              */
  191.             case AO:
  192.                 {
  193.                 DIAG(TD_OPTIONS,
  194.                     printoption("td: recv IAC", c));
  195.                 ptyflush();    /* half-hearted */
  196.                 init_termbuf();
  197.  
  198.                 if (slctab[SLC_AO].sptr &&
  199.                     *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
  200.                     *pfrontp++ =
  201.                     (unsigned char)*slctab[SLC_AO].sptr;
  202.                 }
  203.  
  204.                 netclear();    /* clear buffer back */
  205.                 *nfrontp++ = IAC;
  206.                 *nfrontp++ = DM;
  207.                 neturg = nfrontp-1; /* off by one XXX */
  208.                 DIAG(TD_OPTIONS,
  209.                     printoption("td: send IAC", DM));
  210.                 break;
  211.                 }
  212.  
  213.             /*
  214.              * Erase Character and
  215.              * Erase Line
  216.              */
  217.             case EC:
  218.             case EL:
  219.                 {
  220.                 cc_t ch;
  221.  
  222.                 DIAG(TD_OPTIONS,
  223.                     printoption("td: recv IAC", c));
  224.                 ptyflush();    /* half-hearted */
  225.                 init_termbuf();
  226.                 if (c == EC)
  227.                     ch = *slctab[SLC_EC].sptr;
  228.                 else
  229.                     ch = *slctab[SLC_EL].sptr;
  230.                 if (ch != (cc_t)(_POSIX_VDISABLE))
  231.                     *pfrontp++ = (unsigned char)ch;
  232.                 break;
  233.                 }
  234.  
  235.             /*
  236.              * Check for urgent data...
  237.              */
  238.             case DM:
  239.                 DIAG(TD_OPTIONS,
  240.                     printoption("td: recv IAC", c));
  241.                 SYNCHing = stilloob(net);
  242.                 settimer(gotDM);
  243.                 break;
  244.  
  245.  
  246.             /*
  247.              * Begin option subnegotiation...
  248.              */
  249.             case SB:
  250.                 state = TS_SB;
  251.                 SB_CLEAR();
  252.                 continue;
  253.  
  254.             case WILL:
  255.                 state = TS_WILL;
  256.                 continue;
  257.  
  258.             case WONT:
  259.                 state = TS_WONT;
  260.                 continue;
  261.  
  262.             case DO:
  263.                 state = TS_DO;
  264.                 continue;
  265.  
  266.             case DONT:
  267.                 state = TS_DONT;
  268.                 continue;
  269.             case EOR:
  270.                 if (his_state_is_will(TELOPT_EOR))
  271.                     doeof();
  272.                 break;
  273.  
  274.             /*
  275.              * Handle RFC 10xx Telnet linemode option additions
  276.              * to command stream (EOF, SUSP, ABORT).
  277.              */
  278.             case xEOF:
  279.                 doeof();
  280.                 break;
  281.  
  282.             case SUSP:
  283.                 sendsusp();
  284.                 break;
  285.  
  286.             case ABORT:
  287.                 sendbrk();
  288.                 break;
  289.  
  290.             case IAC:
  291.                 *pfrontp++ = c;
  292.                 break;
  293.             }
  294.             state = TS_DATA;
  295.             break;
  296.  
  297.         case TS_SB:
  298.             if (c == IAC) {
  299.                 state = TS_SE;
  300.             } else {
  301.                 SB_ACCUM(c);
  302.             }
  303.             break;
  304.  
  305.         case TS_SE:
  306.             if (c != SE) {
  307.                 if (c != IAC) {
  308.                     /*
  309.                      * bad form of suboption negotiation.
  310.                      * handle it in such a way as to avoid
  311.                      * damage to local state.  Parse
  312.                      * suboption buffer found so far,
  313.                      * then treat remaining stream as
  314.                      * another command sequence.
  315.                      */
  316.  
  317.                     /* for DIAGNOSTICS */
  318.                     SB_ACCUM(IAC);
  319.                     SB_ACCUM(c);
  320.                     subpointer -= 2;
  321.  
  322.                     SB_TERM();
  323.                     suboption();
  324.                     state = TS_IAC;
  325.                     goto gotiac;
  326.                 }
  327.                 SB_ACCUM(c);
  328.                 state = TS_SB;
  329.             } else {
  330.                 /* for DIAGNOSTICS */
  331.                 SB_ACCUM(IAC);
  332.                 SB_ACCUM(SE);
  333.                 subpointer -= 2;
  334.  
  335.                 SB_TERM();
  336.                 suboption();    /* handle sub-option */
  337.                 state = TS_DATA;
  338.             }
  339.             break;
  340.  
  341.         case TS_WILL:
  342.             willoption(c);
  343.             state = TS_DATA;
  344.             continue;
  345.  
  346.         case TS_WONT:
  347.             wontoption(c);
  348.             state = TS_DATA;
  349.             continue;
  350.  
  351.         case TS_DO:
  352.             dooption(c);
  353.             state = TS_DATA;
  354.             continue;
  355.  
  356.         case TS_DONT:
  357.             dontoption(c);
  358.             state = TS_DATA;
  359.             continue;
  360.  
  361.         default:
  362.             syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
  363.             printf("telnetd: panic state=%d\n", state);
  364.             exit(1);
  365.         }
  366.     }
  367. #if    defined(CRAY2) && defined(UNICOS5)
  368.     if (!linemode) {
  369.         char    xptyobuf[BUFSIZ+NETSLOP];
  370.         char    xbuf2[BUFSIZ];
  371.         register char *cp;
  372.         int n = pfrontp - opfrontp, oc;
  373.         memmove(xptyobuf, opfrontp, n);
  374.         pfrontp = opfrontp;
  375.         pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
  376.                     xbuf2, &oc, BUFSIZ);
  377.         for (cp = xbuf2; oc > 0; --oc)
  378.             if ((*nfrontp++ = *cp++) == IAC)
  379.                 *nfrontp++ = IAC;
  380.     }
  381. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  382. }  /* end of telrcv */
  383.  
  384. /*
  385.  * The will/wont/do/dont state machines are based on Dave Borman's
  386.  * Telnet option processing state machine.
  387.  *
  388.  * These correspond to the following states:
  389.  *    my_state = the last negotiated state
  390.  *    want_state = what I want the state to go to
  391.  *    want_resp = how many requests I have sent
  392.  * All state defaults are negative, and resp defaults to 0.
  393.  *
  394.  * When initiating a request to change state to new_state:
  395.  * 
  396.  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
  397.  *    do nothing;
  398.  * } else {
  399.  *    want_state = new_state;
  400.  *    send new_state;
  401.  *    want_resp++;
  402.  * }
  403.  *
  404.  * When receiving new_state:
  405.  *
  406.  * if (want_resp) {
  407.  *    want_resp--;
  408.  *    if (want_resp && (new_state == my_state))
  409.  *        want_resp--;
  410.  * }
  411.  * if ((want_resp == 0) && (new_state != want_state)) {
  412.  *    if (ok_to_switch_to new_state)
  413.  *        want_state = new_state;
  414.  *    else
  415.  *        want_resp++;
  416.  *    send want_state;
  417.  * }
  418.  * my_state = new_state;
  419.  *
  420.  * Note that new_state is implied in these functions by the function itself.
  421.  * will and do imply positive new_state, wont and dont imply negative.
  422.  *
  423.  * Finally, there is one catch.  If we send a negative response to a
  424.  * positive request, my_state will be the positive while want_state will
  425.  * remain negative.  my_state will revert to negative when the negative
  426.  * acknowlegment arrives from the peer.  Thus, my_state generally tells
  427.  * us not only the last negotiated state, but also tells us what the peer
  428.  * wants to be doing as well.  It is important to understand this difference
  429.  * as we may wish to be processing data streams based on our desired state
  430.  * (want_state) or based on what the peer thinks the state is (my_state).
  431.  *
  432.  * This all works fine because if the peer sends a positive request, the data
  433.  * that we receive prior to negative acknowlegment will probably be affected
  434.  * by the positive state, and we can process it as such (if we can; if we
  435.  * can't then it really doesn't matter).  If it is that important, then the
  436.  * peer probably should be buffering until this option state negotiation
  437.  * is complete.
  438.  *
  439.  */
  440.     void
  441. send_do(option, init)
  442.     int option, init;
  443. {
  444.     if (init) {
  445.         if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
  446.             his_want_state_is_will(option))
  447.             return;
  448.         /*
  449.          * Special case for TELOPT_TM:  We send a DO, but pretend
  450.          * that we sent a DONT, so that we can send more DOs if
  451.          * we want to.
  452.          */
  453.         if (option == TELOPT_TM)
  454.             set_his_want_state_wont(option);
  455.         else
  456.             set_his_want_state_will(option);
  457.         do_dont_resp[option]++;
  458.     }
  459.     (void) sprintf(nfrontp, (char *)doopt, option);
  460.     nfrontp += sizeof (dont) - 2;
  461.  
  462.     DIAG(TD_OPTIONS, printoption("td: send do", option));
  463. }
  464.  
  465. #ifdef    AUTHENTICATION
  466. extern void auth_request();
  467. #endif
  468. #ifdef    LINEMODE
  469. extern void doclientstat();
  470. #endif
  471. #ifdef    ENCRYPTION
  472. extern void encrypt_send_support();
  473. #endif    /* ENCRYPTION */
  474.  
  475.     void
  476. willoption(option)
  477.     int option;
  478. {
  479.     int changeok = 0;
  480.     void (*func)() = 0;
  481.  
  482.     /*
  483.      * process input from peer.
  484.      */
  485.  
  486.     DIAG(TD_OPTIONS, printoption("td: recv will", option));
  487.  
  488.     if (do_dont_resp[option]) {
  489.         do_dont_resp[option]--;
  490.         if (do_dont_resp[option] && his_state_is_will(option))
  491.             do_dont_resp[option]--;
  492.     }
  493.     if (do_dont_resp[option] == 0) {
  494.         if (his_want_state_is_wont(option)) {
  495.         switch (option) {
  496.  
  497.         case TELOPT_BINARY:
  498.             init_termbuf();
  499.             tty_binaryin(1);
  500.             set_termbuf();
  501.             changeok++;
  502.             break;
  503.  
  504.         case TELOPT_ECHO:
  505.             /*
  506.              * See comments below for more info.
  507.              */
  508.             not42 = 0;    /* looks like a 4.2 system */
  509.             break;
  510.  
  511.         case TELOPT_TM:
  512. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  513.             /*
  514.              * This telnetd implementation does not really
  515.              * support timing marks, it just uses them to
  516.              * support the kludge linemode stuff.  If we
  517.              * receive a will or wont TM in response to our
  518.              * do TM request that may have been sent to
  519.              * determine kludge linemode support, process
  520.              * it, otherwise TM should get a negative
  521.              * response back.
  522.              */
  523.             /*
  524.              * Handle the linemode kludge stuff.
  525.              * If we are not currently supporting any
  526.              * linemode at all, then we assume that this
  527.              * is the client telling us to use kludge
  528.              * linemode in response to our query.  Set the
  529.              * linemode type that is to be supported, note
  530.              * that the client wishes to use linemode, and
  531.              * eat the will TM as though it never arrived.
  532.              */
  533.             if (lmodetype < KLUDGE_LINEMODE) {
  534.                 lmodetype = KLUDGE_LINEMODE;
  535.                 clientstat(TELOPT_LINEMODE, WILL, 0);
  536.                 send_wont(TELOPT_SGA, 1);
  537.             } else if (lmodetype == NO_AUTOKLUDGE) {
  538.                 lmodetype = KLUDGE_OK;
  539.             }
  540. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  541.             /*
  542.              * We never respond to a WILL TM, and
  543.              * we leave the state WONT.
  544.              */
  545.             return;
  546.  
  547.         case TELOPT_LFLOW:
  548.             /*
  549.              * If we are going to support flow control
  550.              * option, then don't worry peer that we can't
  551.              * change the flow control characters.
  552.              */
  553.             slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
  554.             slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
  555.             slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
  556.             slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
  557.         case TELOPT_TTYPE:
  558.         case TELOPT_SGA:
  559.         case TELOPT_NAWS:
  560.         case TELOPT_TSPEED:
  561.         case TELOPT_XDISPLOC:
  562.         case TELOPT_NEW_ENVIRON:
  563.         case TELOPT_OLD_ENVIRON:
  564.             changeok++;
  565.             break;
  566.  
  567. #ifdef    LINEMODE
  568.         case TELOPT_LINEMODE:
  569. # ifdef    KLUDGELINEMODE
  570.             /*
  571.              * Note client's desire to use linemode.
  572.              */
  573.             lmodetype = REAL_LINEMODE;
  574. # endif    /* KLUDGELINEMODE */
  575.             func = doclientstat;
  576.             changeok++;
  577.             break;
  578. #endif    /* LINEMODE */
  579.  
  580. #ifdef    AUTHENTICATION
  581.         case TELOPT_AUTHENTICATION:
  582.             func = auth_request;
  583.             changeok++;
  584.             break;
  585. #endif
  586.  
  587. #ifdef    ENCRYPTION
  588.         case TELOPT_ENCRYPT:
  589.             func = encrypt_send_support;
  590.             changeok++;
  591.             break;
  592. #endif    /* ENCRYPTION */
  593.  
  594.         default:
  595.             break;
  596.         }
  597.         if (changeok) {
  598.             set_his_want_state_will(option);
  599.             send_do(option, 0);
  600.         } else {
  601.             do_dont_resp[option]++;
  602.             send_dont(option, 0);
  603.         }
  604.         } else {
  605.         /*
  606.          * Option processing that should happen when
  607.          * we receive conformation of a change in
  608.          * state that we had requested.
  609.          */
  610.         switch (option) {
  611.         case TELOPT_ECHO:
  612.             not42 = 0;    /* looks like a 4.2 system */
  613.             /*
  614.              * Egads, he responded "WILL ECHO".  Turn
  615.              * it off right now!
  616.              */
  617.             send_dont(option, 1);
  618.             /*
  619.              * "WILL ECHO".  Kludge upon kludge!
  620.              * A 4.2 client is now echoing user input at
  621.              * the tty.  This is probably undesireable and
  622.              * it should be stopped.  The client will
  623.              * respond WONT TM to the DO TM that we send to
  624.              * check for kludge linemode.  When the WONT TM
  625.              * arrives, linemode will be turned off and a
  626.              * change propogated to the pty.  This change
  627.              * will cause us to process the new pty state
  628.              * in localstat(), which will notice that
  629.              * linemode is off and send a WILL ECHO
  630.              * so that we are properly in character mode and
  631.              * all is well.
  632.              */
  633.             break;
  634. #ifdef    LINEMODE
  635.         case TELOPT_LINEMODE:
  636. # ifdef    KLUDGELINEMODE
  637.             /*
  638.              * Note client's desire to use linemode.
  639.              */
  640.             lmodetype = REAL_LINEMODE;
  641. # endif    /* KLUDGELINEMODE */
  642.             func = doclientstat;
  643.             break;
  644. #endif    /* LINEMODE */
  645.  
  646. #ifdef    AUTHENTICATION
  647.         case TELOPT_AUTHENTICATION:
  648.             func = auth_request;
  649.             break;
  650. #endif
  651.  
  652. #ifdef    ENCRYPTION
  653.         case TELOPT_ENCRYPT:
  654.             func = encrypt_send_support;
  655.             break;
  656. #endif    /* ENCRYPTION */
  657.         case TELOPT_LFLOW:
  658.             func = flowstat;
  659.             break;
  660.         }
  661.         }
  662.     }
  663.     set_his_state_will(option);
  664.     if (func)
  665.         (*func)();
  666. }  /* end of willoption */
  667.  
  668.     void
  669. send_dont(option, init)
  670.     int option, init;
  671. {
  672.     if (init) {
  673.         if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
  674.             his_want_state_is_wont(option))
  675.             return;
  676.         set_his_want_state_wont(option);
  677.         do_dont_resp[option]++;
  678.     }
  679.     (void) sprintf(nfrontp, (char *)dont, option);
  680.     nfrontp += sizeof (doopt) - 2;
  681.  
  682.     DIAG(TD_OPTIONS, printoption("td: send dont", option));
  683. }
  684.  
  685.     void
  686. wontoption(option)
  687.     int option;
  688. {
  689.     /*
  690.      * Process client input.
  691.      */
  692.  
  693.     DIAG(TD_OPTIONS, printoption("td: recv wont", option));
  694.  
  695.     if (do_dont_resp[option]) {
  696.         do_dont_resp[option]--;
  697.         if (do_dont_resp[option] && his_state_is_wont(option))
  698.             do_dont_resp[option]--;
  699.     }
  700.     if (do_dont_resp[option] == 0) {
  701.         if (his_want_state_is_will(option)) {
  702.         /* it is always ok to change to negative state */
  703.         switch (option) {
  704.         case TELOPT_ECHO:
  705.             not42 = 1; /* doesn't seem to be a 4.2 system */
  706.             break;
  707.  
  708.         case TELOPT_BINARY:
  709.             init_termbuf();
  710.             tty_binaryin(0);
  711.             set_termbuf();
  712.             break;
  713.  
  714. #ifdef    LINEMODE
  715.         case TELOPT_LINEMODE:
  716. # ifdef    KLUDGELINEMODE
  717.             /*
  718.              * If real linemode is supported, then client is
  719.              * asking to turn linemode off.
  720.              */
  721.             if (lmodetype != REAL_LINEMODE)
  722.                 break;
  723. # endif    /* KLUDGELINEMODE */
  724.             clientstat(TELOPT_LINEMODE, WONT, 0);
  725.             break;
  726. #endif    /* LINEMODE */
  727.  
  728.         case TELOPT_TM:
  729.             /*
  730.              * If we get a WONT TM, and had sent a DO TM,
  731.              * don't respond with a DONT TM, just leave it
  732.              * as is.  Short circut the state machine to
  733.              * achive this.
  734.              */
  735.             set_his_want_state_wont(TELOPT_TM);
  736.             return;
  737.  
  738.         case TELOPT_LFLOW:
  739.             /*
  740.              * If we are not going to support flow control
  741.              * option, then let peer know that we can't
  742.              * change the flow control characters.
  743.              */
  744.             slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
  745.             slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
  746.             slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
  747.             slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
  748.             break;
  749.  
  750. #if    defined(AUTHENTICATION)
  751.         case TELOPT_AUTHENTICATION:
  752.             auth_finished(0, AUTH_REJECT);
  753.             break;
  754. #endif
  755.  
  756.         /*
  757.          * For options that we might spin waiting for
  758.          * sub-negotiation, if the client turns off the
  759.          * option rather than responding to the request,
  760.          * we have to treat it here as if we got a response
  761.          * to the sub-negotiation, (by updating the timers)
  762.          * so that we'll break out of the loop.
  763.          */
  764.         case TELOPT_TTYPE:
  765.             settimer(ttypesubopt);
  766.             break;
  767.  
  768.         case TELOPT_TSPEED:
  769.             settimer(tspeedsubopt);
  770.             break;
  771.  
  772.         case TELOPT_XDISPLOC:
  773.             settimer(xdisplocsubopt);
  774.             break;
  775.  
  776.         case TELOPT_OLD_ENVIRON:
  777.             settimer(oenvironsubopt);
  778.             break;
  779.  
  780.         case TELOPT_NEW_ENVIRON:
  781.             settimer(environsubopt);
  782.             break;
  783.  
  784.         default:
  785.             break;
  786.         }
  787.         set_his_want_state_wont(option);
  788.         if (his_state_is_will(option))
  789.             send_dont(option, 0);
  790.         } else {
  791.         switch (option) {
  792.         case TELOPT_TM:
  793. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  794.             if (lmodetype < NO_AUTOKLUDGE) {
  795.                 lmodetype = NO_LINEMODE;
  796.                 clientstat(TELOPT_LINEMODE, WONT, 0);
  797.                 send_will(TELOPT_SGA, 1);
  798.                 send_will(TELOPT_ECHO, 1);
  799.             }
  800. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  801.             break;
  802.  
  803. #if    defined(AUTHENTICATION)
  804.         case TELOPT_AUTHENTICATION:
  805.             auth_finished(0, AUTH_REJECT);
  806.             break;
  807. #endif
  808.         default:
  809.             break;
  810.         }
  811.         }
  812.     }
  813.     set_his_state_wont(option);
  814.  
  815. }  /* end of wontoption */
  816.  
  817.     void
  818. send_will(option, init)
  819.     int option, init;
  820. {
  821.     if (init) {
  822.         if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
  823.             my_want_state_is_will(option))
  824.             return;
  825.         set_my_want_state_will(option);
  826.         will_wont_resp[option]++;
  827.     }
  828.     (void) sprintf(nfrontp, (char *)will, option);
  829.     nfrontp += sizeof (doopt) - 2;
  830.  
  831.     DIAG(TD_OPTIONS, printoption("td: send will", option));
  832. }
  833.  
  834. #if    !defined(LINEMODE) || !defined(KLUDGELINEMODE)
  835. /*
  836.  * When we get a DONT SGA, we will try once to turn it
  837.  * back on.  If the other side responds DONT SGA, we
  838.  * leave it at that.  This is so that when we talk to
  839.  * clients that understand KLUDGELINEMODE but not LINEMODE,
  840.  * we'll keep them in char-at-a-time mode.
  841.  */
  842. int turn_on_sga = 0;
  843. #endif
  844.  
  845.     void
  846. dooption(option)
  847.     int option;
  848. {
  849.     int changeok = 0;
  850.  
  851.     /*
  852.      * Process client input.
  853.      */
  854.  
  855.     DIAG(TD_OPTIONS, printoption("td: recv do", option));
  856.  
  857.     if (will_wont_resp[option]) {
  858.         will_wont_resp[option]--;
  859.         if (will_wont_resp[option] && my_state_is_will(option))
  860.             will_wont_resp[option]--;
  861.     }
  862.     if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
  863.         switch (option) {
  864.         case TELOPT_ECHO:
  865. #ifdef    LINEMODE
  866. # ifdef    KLUDGELINEMODE
  867.             if (lmodetype == NO_LINEMODE)
  868. # else
  869.             if (his_state_is_wont(TELOPT_LINEMODE))
  870. # endif
  871. #endif
  872.             {
  873.                 init_termbuf();
  874.                 tty_setecho(1);
  875.                 set_termbuf();
  876.             }
  877.             changeok++;
  878.             break;
  879.  
  880.         case TELOPT_BINARY:
  881.             init_termbuf();
  882.             tty_binaryout(1);
  883.             set_termbuf();
  884.             changeok++;
  885.             break;
  886.  
  887.         case TELOPT_SGA:
  888. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  889.             /*
  890.              * If kludge linemode is in use, then we must
  891.              * process an incoming do SGA for linemode
  892.              * purposes.
  893.              */
  894.             if (lmodetype == KLUDGE_LINEMODE) {
  895.                 /*
  896.                  * Receipt of "do SGA" in kludge
  897.                  * linemode is the peer asking us to
  898.                  * turn off linemode.  Make note of
  899.                  * the request.
  900.                  */
  901.                 clientstat(TELOPT_LINEMODE, WONT, 0);
  902.                 /*
  903.                  * If linemode did not get turned off
  904.                  * then don't tell peer that we did.
  905.                  * Breaking here forces a wont SGA to
  906.                  * be returned.
  907.                  */
  908.                 if (linemode)
  909.                     break;
  910.             }
  911. #else
  912.             turn_on_sga = 0;
  913. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  914.             changeok++;
  915.             break;
  916.  
  917.         case TELOPT_STATUS:
  918.             changeok++;
  919.             break;
  920.  
  921.         case TELOPT_TM:
  922.             /*
  923.              * Special case for TM.  We send a WILL, but
  924.              * pretend we sent a WONT.
  925.              */
  926.             send_will(option, 0);
  927.             set_my_want_state_wont(option);
  928.             set_my_state_wont(option);
  929.             return;
  930.  
  931.         case TELOPT_LOGOUT:
  932.             /*
  933.              * When we get a LOGOUT option, respond
  934.              * with a WILL LOGOUT, make sure that
  935.              * it gets written out to the network,
  936.              * and then just go away...
  937.              */
  938.             set_my_want_state_will(TELOPT_LOGOUT);
  939.             send_will(TELOPT_LOGOUT, 0);
  940.             set_my_state_will(TELOPT_LOGOUT);
  941.             (void)netflush();
  942.             cleanup(0);
  943.             /* NOT REACHED */
  944.             break;
  945.  
  946. #ifdef    ENCRYPTION
  947.         case TELOPT_ENCRYPT:
  948.             changeok++;
  949.             break;
  950. #endif    /* ENCRYPTION */
  951.         case TELOPT_LINEMODE:
  952.         case TELOPT_TTYPE:
  953.         case TELOPT_NAWS:
  954.         case TELOPT_TSPEED:
  955.         case TELOPT_LFLOW:
  956.         case TELOPT_XDISPLOC:
  957. #ifdef    TELOPT_ENVIRON
  958.         case TELOPT_NEW_ENVIRON:
  959. #endif
  960.         case TELOPT_OLD_ENVIRON:
  961.         default:
  962.             break;
  963.         }
  964.         if (changeok) {
  965.             set_my_want_state_will(option);
  966.             send_will(option, 0);
  967.         } else {
  968.             will_wont_resp[option]++;
  969.             send_wont(option, 0);
  970.         }
  971.     }
  972.     set_my_state_will(option);
  973.  
  974. }  /* end of dooption */
  975.  
  976.     void
  977. send_wont(option, init)
  978.     int option, init;
  979. {
  980.     if (init) {
  981.         if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
  982.             my_want_state_is_wont(option))
  983.             return;
  984.         set_my_want_state_wont(option);
  985.         will_wont_resp[option]++;
  986.     }
  987.     (void) sprintf(nfrontp, (char *)wont, option);
  988.     nfrontp += sizeof (wont) - 2;
  989.  
  990.     DIAG(TD_OPTIONS, printoption("td: send wont", option));
  991. }
  992.  
  993.     void
  994. dontoption(option)
  995.     int option;
  996. {
  997.     /*
  998.      * Process client input.
  999.      */
  1000.  
  1001.  
  1002.     DIAG(TD_OPTIONS, printoption("td: recv dont", option));
  1003.  
  1004.     if (will_wont_resp[option]) {
  1005.         will_wont_resp[option]--;
  1006.         if (will_wont_resp[option] && my_state_is_wont(option))
  1007.             will_wont_resp[option]--;
  1008.     }
  1009.     if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
  1010.         switch (option) {
  1011.         case TELOPT_BINARY:
  1012.             init_termbuf();
  1013.             tty_binaryout(0);
  1014.             set_termbuf();
  1015.             break;
  1016.  
  1017.         case TELOPT_ECHO:    /* we should stop echoing */
  1018. #ifdef    LINEMODE
  1019. # ifdef    KLUDGELINEMODE
  1020.             if ((lmodetype != REAL_LINEMODE) &&
  1021.                 (lmodetype != KLUDGE_LINEMODE))
  1022. # else
  1023.             if (his_state_is_wont(TELOPT_LINEMODE))
  1024. # endif
  1025. #endif
  1026.             {
  1027.                 init_termbuf();
  1028.                 tty_setecho(0);
  1029.                 set_termbuf();
  1030.             }
  1031.             break;
  1032.  
  1033.         case TELOPT_SGA:
  1034. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  1035.             /*
  1036.              * If kludge linemode is in use, then we
  1037.              * must process an incoming do SGA for
  1038.              * linemode purposes.
  1039.              */
  1040.             if ((lmodetype == KLUDGE_LINEMODE) ||
  1041.                 (lmodetype == KLUDGE_OK)) {
  1042.                 /*
  1043.                  * The client is asking us to turn
  1044.                  * linemode on.
  1045.                  */
  1046.                 lmodetype = KLUDGE_LINEMODE;
  1047.                 clientstat(TELOPT_LINEMODE, WILL, 0);
  1048.                 /*
  1049.                  * If we did not turn line mode on,
  1050.                  * then what do we say?  Will SGA?
  1051.                  * This violates design of telnet.
  1052.                  * Gross.  Very Gross.
  1053.                  */
  1054.             }
  1055.             break;
  1056. #else
  1057.             set_my_want_state_wont(option);
  1058.             if (my_state_is_will(option))
  1059.                 send_wont(option, 0);
  1060.             set_my_state_wont(option);
  1061.             if (turn_on_sga ^= 1)
  1062.                 send_will(option, 1);
  1063.             return;
  1064. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  1065.  
  1066.         default:
  1067.             break;
  1068.         }
  1069.  
  1070.         set_my_want_state_wont(option);
  1071.         if (my_state_is_will(option))
  1072.             send_wont(option, 0);
  1073.     }
  1074.     set_my_state_wont(option);
  1075.  
  1076. }  /* end of dontoption */
  1077.  
  1078. #ifdef    ENV_HACK
  1079. int env_ovar = -1;
  1080. int env_ovalue = -1;
  1081. #else    /* ENV_HACK */
  1082. # define env_ovar OLD_ENV_VAR
  1083. # define env_ovalue OLD_ENV_VALUE
  1084. #endif    /* ENV_HACK */
  1085.  
  1086. /*
  1087.  * suboption()
  1088.  *
  1089.  *    Look at the sub-option buffer, and try to be helpful to the other
  1090.  * side.
  1091.  *
  1092.  *    Currently we recognize:
  1093.  *
  1094.  *    Terminal type is
  1095.  *    Linemode
  1096.  *    Window size
  1097.  *    Terminal speed
  1098.  */
  1099.     void
  1100. suboption()
  1101. {
  1102.     register int subchar;
  1103.  
  1104.     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
  1105.  
  1106.     subchar = SB_GET();
  1107.     switch (subchar) {
  1108.     case TELOPT_TSPEED: {
  1109.     register int xspeed, rspeed;
  1110.  
  1111.     if (his_state_is_wont(TELOPT_TSPEED))    /* Ignore if option disabled */
  1112.         break;
  1113.  
  1114.     settimer(tspeedsubopt);
  1115.  
  1116.     if (SB_EOF() || SB_GET() != TELQUAL_IS)
  1117.         return;
  1118.  
  1119.     xspeed = atoi((char *)subpointer);
  1120.  
  1121.     while (SB_GET() != ',' && !SB_EOF());
  1122.     if (SB_EOF())
  1123.         return;
  1124.  
  1125.     rspeed = atoi((char *)subpointer);
  1126.     clientstat(TELOPT_TSPEED, xspeed, rspeed);
  1127.  
  1128.     break;
  1129.  
  1130.     }  /* end of case TELOPT_TSPEED */
  1131.  
  1132.     case TELOPT_TTYPE: {        /* Yaaaay! */
  1133.     static char terminalname[41];
  1134.  
  1135.     if (his_state_is_wont(TELOPT_TTYPE))    /* Ignore if option disabled */
  1136.         break;
  1137.     settimer(ttypesubopt);
  1138.  
  1139.     if (SB_EOF() || SB_GET() != TELQUAL_IS) {
  1140.         return;        /* ??? XXX but, this is the most robust */
  1141.     }
  1142.  
  1143.     terminaltype = terminalname;
  1144.  
  1145.     while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
  1146.                                     !SB_EOF()) {
  1147.         register int c;
  1148.  
  1149.         c = SB_GET();
  1150.         if (isupper(c)) {
  1151.         c = tolower(c);
  1152.         }
  1153.         *terminaltype++ = c;    /* accumulate name */
  1154.     }
  1155.     *terminaltype = 0;
  1156.     terminaltype = terminalname;
  1157.     break;
  1158.     }  /* end of case TELOPT_TTYPE */
  1159.  
  1160.     case TELOPT_NAWS: {
  1161.     register int xwinsize, ywinsize;
  1162.  
  1163.     if (his_state_is_wont(TELOPT_NAWS))    /* Ignore if option disabled */
  1164.         break;
  1165.  
  1166.     if (SB_EOF())
  1167.         return;
  1168.     xwinsize = SB_GET() << 8;
  1169.     if (SB_EOF())
  1170.         return;
  1171.     xwinsize |= SB_GET();
  1172.     if (SB_EOF())
  1173.         return;
  1174.     ywinsize = SB_GET() << 8;
  1175.     if (SB_EOF())
  1176.         return;
  1177.     ywinsize |= SB_GET();
  1178.     clientstat(TELOPT_NAWS, xwinsize, ywinsize);
  1179.  
  1180.     break;
  1181.  
  1182.     }  /* end of case TELOPT_NAWS */
  1183.  
  1184. #ifdef    LINEMODE
  1185.     case TELOPT_LINEMODE: {
  1186.     register int request;
  1187.  
  1188.     if (his_state_is_wont(TELOPT_LINEMODE))    /* Ignore if option disabled */
  1189.         break;
  1190.     /*
  1191.      * Process linemode suboptions.
  1192.      */
  1193.     if (SB_EOF())
  1194.         break;        /* garbage was sent */
  1195.     request = SB_GET();    /* get will/wont */
  1196.  
  1197.     if (SB_EOF())
  1198.         break;        /* another garbage check */
  1199.  
  1200.     if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
  1201.         /*
  1202.          * Process suboption buffer of slc's
  1203.          */
  1204.         start_slc(1);
  1205.         do_opt_slc(subpointer, subend - subpointer);
  1206.         (void) end_slc(0);
  1207.         break;
  1208.     } else if (request == LM_MODE) {
  1209.         if (SB_EOF())
  1210.             return;
  1211.         useeditmode = SB_GET();  /* get mode flag */
  1212.         clientstat(LM_MODE, 0, 0);
  1213.         break;
  1214.     }
  1215.  
  1216.     if (SB_EOF())
  1217.         break;
  1218.     switch (SB_GET()) {  /* what suboption? */
  1219.     case LM_FORWARDMASK:
  1220.         /*
  1221.          * According to spec, only server can send request for
  1222.          * forwardmask, and client can only return a positive response.
  1223.          * So don't worry about it.
  1224.          */
  1225.  
  1226.     default:
  1227.         break;
  1228.     }
  1229.     break;
  1230.     }  /* end of case TELOPT_LINEMODE */
  1231. #endif
  1232.     case TELOPT_STATUS: {
  1233.     int mode;
  1234.  
  1235.     if (SB_EOF())
  1236.         break;
  1237.     mode = SB_GET();
  1238.     switch (mode) {
  1239.     case TELQUAL_SEND:
  1240.         if (my_state_is_will(TELOPT_STATUS))
  1241.         send_status();
  1242.         break;
  1243.  
  1244.     case TELQUAL_IS:
  1245.         break;
  1246.  
  1247.     default:
  1248.         break;
  1249.     }
  1250.     break;
  1251.     }  /* end of case TELOPT_STATUS */
  1252.  
  1253.     case TELOPT_XDISPLOC: {
  1254.     if (SB_EOF() || SB_GET() != TELQUAL_IS)
  1255.         return;
  1256.     settimer(xdisplocsubopt);
  1257.     subpointer[SB_LEN()] = '\0';
  1258.     (void)setenv("DISPLAY", (char *)subpointer, 1);
  1259.     break;
  1260.     }  /* end of case TELOPT_XDISPLOC */
  1261.  
  1262. #ifdef    TELOPT_NEW_ENVIRON
  1263.     case TELOPT_NEW_ENVIRON:
  1264. #endif
  1265.     case TELOPT_OLD_ENVIRON: {
  1266.     register int c;
  1267.     register char *cp, *varp, *valp;
  1268.  
  1269.     if (SB_EOF())
  1270.         return;
  1271.     c = SB_GET();
  1272.     if (c == TELQUAL_IS) {
  1273.         if (subchar == TELOPT_OLD_ENVIRON)
  1274.             settimer(oenvironsubopt);
  1275.         else
  1276.             settimer(environsubopt);
  1277.     } else if (c != TELQUAL_INFO) {
  1278.         return;
  1279.     }
  1280.  
  1281. #ifdef    TELOPT_NEW_ENVIRON
  1282.     if (subchar == TELOPT_NEW_ENVIRON) {
  1283.         while (!SB_EOF()) {
  1284.         c = SB_GET();
  1285.         if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
  1286.             break;
  1287.         }
  1288.     } else
  1289. #endif
  1290.     {
  1291. #ifdef    ENV_HACK
  1292.         /*
  1293.          * We only want to do this if we haven't already decided
  1294.          * whether or not the other side has its VALUE and VAR
  1295.          * reversed.
  1296.          */
  1297.         if (env_ovar < 0) {
  1298.         register int last = -1;        /* invalid value */
  1299.         int empty = 0;
  1300.         int got_var = 0, got_value = 0, got_uservar = 0;
  1301.  
  1302.         /*
  1303.          * The other side might have its VALUE and VAR values
  1304.          * reversed.  To be interoperable, we need to determine
  1305.          * which way it is.  If the first recognized character
  1306.          * is a VAR or VALUE, then that will tell us what
  1307.          * type of client it is.  If the fist recognized
  1308.          * character is a USERVAR, then we continue scanning
  1309.          * the suboption looking for two consecutive
  1310.          * VAR or VALUE fields.  We should not get two
  1311.          * consecutive VALUE fields, so finding two
  1312.          * consecutive VALUE or VAR fields will tell us
  1313.          * what the client is.
  1314.          */
  1315.         SB_SAVE();
  1316.         while (!SB_EOF()) {
  1317.             c = SB_GET();
  1318.             switch(c) {
  1319.             case OLD_ENV_VAR:
  1320.                 if (last < 0 || last == OLD_ENV_VAR
  1321.                     || (empty && (last == OLD_ENV_VALUE)))
  1322.                     goto env_ovar_ok;
  1323.                 got_var++;
  1324.                 last = OLD_ENV_VAR;
  1325.                 break;
  1326.             case OLD_ENV_VALUE:
  1327.                 if (last < 0 || last == OLD_ENV_VALUE
  1328.                     || (empty && (last == OLD_ENV_VAR)))
  1329.                     goto env_ovar_wrong;
  1330.                 got_value++;
  1331.                 last = OLD_ENV_VALUE;
  1332.                 break;
  1333.             case ENV_USERVAR:
  1334.                 /* count strings of USERVAR as one */
  1335.                 if (last != ENV_USERVAR)
  1336.                     got_uservar++;
  1337.                 if (empty) {
  1338.                     if (last == OLD_ENV_VALUE)
  1339.                         goto env_ovar_ok;
  1340.                     if (last == OLD_ENV_VAR)
  1341.                         goto env_ovar_wrong;
  1342.                 }
  1343.                 last = ENV_USERVAR;
  1344.                 break;
  1345.             case ENV_ESC:
  1346.                 if (!SB_EOF())
  1347.                     c = SB_GET();
  1348.                 /* FALL THROUGH */
  1349.             default:
  1350.                 empty = 0;
  1351.                 continue;
  1352.             }
  1353.             empty = 1;
  1354.         }
  1355.         if (empty) {
  1356.             if (last == OLD_ENV_VALUE)
  1357.                 goto env_ovar_ok;
  1358.             if (last == OLD_ENV_VAR)
  1359.                 goto env_ovar_wrong;
  1360.         }
  1361.         /*
  1362.          * Ok, the first thing was a USERVAR, and there
  1363.          * are not two consecutive VAR or VALUE commands,
  1364.          * and none of the VAR or VALUE commands are empty.
  1365.          * If the client has sent us a well-formed option,
  1366.          * then the number of VALUEs received should always
  1367.          * be less than or equal to the number of VARs and
  1368.          * USERVARs received.
  1369.          *
  1370.          * If we got exactly as many VALUEs as VARs and
  1371.          * USERVARs, the client has the same definitions.
  1372.          *
  1373.          * If we got exactly as many VARs as VALUEs and
  1374.          * USERVARS, the client has reversed definitions.
  1375.          */
  1376.         if (got_uservar + got_var == got_value) {
  1377.         env_ovar_ok:
  1378.             env_ovar = OLD_ENV_VAR;
  1379.             env_ovalue = OLD_ENV_VALUE;
  1380.         } else if (got_uservar + got_value == got_var) {
  1381.         env_ovar_wrong:
  1382.             env_ovar = OLD_ENV_VALUE;
  1383.             env_ovalue = OLD_ENV_VAR;
  1384.             DIAG(TD_OPTIONS, {sprintf(nfrontp,
  1385.                 "ENVIRON VALUE and VAR are reversed!\r\n");
  1386.                 nfrontp += strlen(nfrontp);});
  1387.  
  1388.         }
  1389.         }
  1390.         SB_RESTORE();
  1391. #endif
  1392.  
  1393.         while (!SB_EOF()) {
  1394.         c = SB_GET();
  1395.         if ((c == env_ovar) || (c == ENV_USERVAR))
  1396.             break;
  1397.         }
  1398.     }
  1399.  
  1400.     if (SB_EOF())
  1401.         return;
  1402.  
  1403.     cp = varp = (char *)subpointer;
  1404.     valp = 0;
  1405.  
  1406.     while (!SB_EOF()) {
  1407.         c = SB_GET();
  1408.         if (subchar == TELOPT_OLD_ENVIRON) {
  1409.             if (c == env_ovar)
  1410.                 c = NEW_ENV_VAR;
  1411.             else if (c == env_ovalue)
  1412.                 c = NEW_ENV_VALUE;
  1413.         }
  1414.         switch (c) {
  1415.  
  1416.         case NEW_ENV_VALUE:
  1417.             *cp = '\0';
  1418.             cp = valp = (char *)subpointer;
  1419.             break;
  1420.  
  1421.         case NEW_ENV_VAR:
  1422.         case ENV_USERVAR:
  1423.             *cp = '\0';
  1424.             if (valp)
  1425.                 (void)setenv(varp, valp, 1);
  1426.             else
  1427.                 unsetenv(varp);
  1428.             cp = varp = (char *)subpointer;
  1429.             valp = 0;
  1430.             break;
  1431.  
  1432.         case ENV_ESC:
  1433.             if (SB_EOF())
  1434.                 break;
  1435.             c = SB_GET();
  1436.             /* FALL THROUGH */
  1437.         default:
  1438.             *cp++ = c;
  1439.             break;
  1440.         }
  1441.     }
  1442.     *cp = '\0';
  1443.     if (valp)
  1444.         (void)setenv(varp, valp, 1);
  1445.     else
  1446.         unsetenv(varp);
  1447.     break;
  1448.     }  /* end of case TELOPT_NEW_ENVIRON */
  1449. #if    defined(AUTHENTICATION)
  1450.     case TELOPT_AUTHENTICATION:
  1451.     if (SB_EOF())
  1452.         break;
  1453.     switch(SB_GET()) {
  1454.     case TELQUAL_SEND:
  1455.     case TELQUAL_REPLY:
  1456.         /*
  1457.          * These are sent by us and cannot be sent by
  1458.          * the client.
  1459.          */
  1460.         break;
  1461.     case TELQUAL_IS:
  1462.         auth_is(subpointer, SB_LEN());
  1463.         break;
  1464.     case TELQUAL_NAME:
  1465.         auth_name(subpointer, SB_LEN());
  1466.         break;
  1467.     }
  1468.     break;
  1469. #endif
  1470. #ifdef    ENCRYPTION
  1471.     case TELOPT_ENCRYPT:
  1472.     if (SB_EOF())
  1473.         break;
  1474.     switch(SB_GET()) {
  1475.     case ENCRYPT_SUPPORT:
  1476.         encrypt_support(subpointer, SB_LEN());
  1477.         break;
  1478.     case ENCRYPT_IS:
  1479.         encrypt_is(subpointer, SB_LEN());
  1480.         break;
  1481.     case ENCRYPT_REPLY:
  1482.         encrypt_reply(subpointer, SB_LEN());
  1483.         break;
  1484.     case ENCRYPT_START:
  1485.         encrypt_start(subpointer, SB_LEN());
  1486.         break;
  1487.     case ENCRYPT_END:
  1488.         encrypt_end();
  1489.         break;
  1490.     case ENCRYPT_REQSTART:
  1491.         encrypt_request_start(subpointer, SB_LEN());
  1492.         break;
  1493.     case ENCRYPT_REQEND:
  1494.         /*
  1495.          * We can always send an REQEND so that we cannot
  1496.          * get stuck encrypting.  We should only get this
  1497.          * if we have been able to get in the correct mode
  1498.          * anyhow.
  1499.          */
  1500.         encrypt_request_end();
  1501.         break;
  1502.     case ENCRYPT_ENC_KEYID:
  1503.         encrypt_enc_keyid(subpointer, SB_LEN());
  1504.         break;
  1505.     case ENCRYPT_DEC_KEYID:
  1506.         encrypt_dec_keyid(subpointer, SB_LEN());
  1507.         break;
  1508.     default:
  1509.         break;
  1510.     }
  1511.     break;
  1512. #endif    /* ENCRYPTION */
  1513.  
  1514.     default:
  1515.     break;
  1516.     }  /* end of switch */
  1517.  
  1518. }  /* end of suboption */
  1519.  
  1520.     void
  1521. doclientstat()
  1522. {
  1523.     clientstat(TELOPT_LINEMODE, WILL, 0);
  1524. }
  1525.  
  1526. #define    ADD(c)     *ncp++ = c
  1527. #define    ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
  1528.     void
  1529. send_status()
  1530. {
  1531.     unsigned char statusbuf[256];
  1532.     register unsigned char *ncp;
  1533.     register unsigned char i;
  1534.  
  1535.     ncp = statusbuf;
  1536.  
  1537.     netflush();    /* get rid of anything waiting to go out */
  1538.  
  1539.     ADD(IAC);
  1540.     ADD(SB);
  1541.     ADD(TELOPT_STATUS);
  1542.     ADD(TELQUAL_IS);
  1543.  
  1544.     /*
  1545.      * We check the want_state rather than the current state,
  1546.      * because if we received a DO/WILL for an option that we
  1547.      * don't support, and the other side didn't send a DONT/WONT
  1548.      * in response to our WONT/DONT, then the "state" will be
  1549.      * WILL/DO, and the "want_state" will be WONT/DONT.  We
  1550.      * need to go by the latter.
  1551.      */
  1552.     for (i = 0; i < (unsigned char)NTELOPTS; i++) {
  1553.         if (my_want_state_is_will(i)) {
  1554.             ADD(WILL);
  1555.             ADD_DATA(i);
  1556.         }
  1557.         if (his_want_state_is_will(i)) {
  1558.             ADD(DO);
  1559.             ADD_DATA(i);
  1560.         }
  1561.     }
  1562.  
  1563.     if (his_want_state_is_will(TELOPT_LFLOW)) {
  1564.         ADD(SB);
  1565.         ADD(TELOPT_LFLOW);
  1566.         if (flowmode) {
  1567.             ADD(LFLOW_ON);
  1568.         } else {
  1569.             ADD(LFLOW_OFF);
  1570.         }
  1571.         ADD(SE);
  1572.  
  1573.         if (restartany >= 0) {
  1574.             ADD(SB);
  1575.             ADD(TELOPT_LFLOW);
  1576.             if (restartany) {
  1577.                 ADD(LFLOW_RESTART_ANY);
  1578.             } else {
  1579.                 ADD(LFLOW_RESTART_XON);
  1580.             }
  1581.             ADD(SE);
  1582.         }
  1583.     }
  1584.  
  1585. #ifdef    LINEMODE
  1586.     if (his_want_state_is_will(TELOPT_LINEMODE)) {
  1587.         unsigned char *cp, *cpe;
  1588.         int len;
  1589.  
  1590.         ADD(SB);
  1591.         ADD(TELOPT_LINEMODE);
  1592.         ADD(LM_MODE);
  1593.         ADD_DATA(editmode);
  1594.         ADD(SE);
  1595.  
  1596.         ADD(SB);
  1597.         ADD(TELOPT_LINEMODE);
  1598.         ADD(LM_SLC);
  1599.         start_slc(0);
  1600.         send_slc();
  1601.         len = end_slc(&cp);
  1602.         for (cpe = cp + len; cp < cpe; cp++)
  1603.             ADD_DATA(*cp);
  1604.         ADD(SE);
  1605.     }
  1606. #endif    /* LINEMODE */
  1607.  
  1608.     ADD(IAC);
  1609.     ADD(SE);
  1610.  
  1611.     writenet(statusbuf, ncp - statusbuf);
  1612.     netflush();    /* Send it on its way */
  1613.  
  1614.     DIAG(TD_OPTIONS,
  1615.         {printsub('>', statusbuf, ncp - statusbuf); netflush();});
  1616. }
  1617.