home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / netkit-b.05 / netkit-b / NetKit-B-0.05 / telnetd / state.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  31.2 KB  |  1,445 lines

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