home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnunet10.zip / source / telnet / telnet.c < prev    next >
C/C++ Source or Header  |  1996-07-13  |  56KB  |  2,651 lines

  1. /*
  2.  * Copyright (c) 1988, 1990, 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[] = "@(#)telnet.c    8.4 (Berkeley) 5/30/95";
  36. #endif /* not lint */
  37.  
  38. #include <sys/types.h>
  39.  
  40. #if    defined(unix)
  41. #include <signal.h>
  42. /* By the way, we need to include curses.h before telnet.h since,
  43.  * among other things, telnet.h #defines 'DO', which is a variable
  44.  * declared in curses.h.
  45.  */
  46. #endif    /* defined(unix) */
  47.  
  48. #include <arpa/telnet.h>
  49.  
  50. #include <ctype.h>
  51.  
  52. #include "ring.h"
  53.  
  54. #include "defines.h"
  55. #include "externs.h"
  56. #include "types.h"
  57. #include "general.h"
  58.  
  59.  
  60. #define    strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
  61.  
  62. static unsigned char    subbuffer[SUBBUFSIZE],
  63.             *subpointer, *subend;     /* buffer for sub-options */
  64. #define    SB_CLEAR()    subpointer = subbuffer;
  65. #define    SB_TERM()    { subend = subpointer; SB_CLEAR(); }
  66. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof subbuffer)) { \
  67.                 *subpointer++ = (c); \
  68.             }
  69.  
  70. #define    SB_GET()    ((*subpointer++)&0xff)
  71. #define    SB_PEEK()    ((*subpointer)&0xff)
  72. #define    SB_EOF()    (subpointer >= subend)
  73. #define    SB_LEN()    (subend - subpointer)
  74.  
  75. char    options[256];        /* The combined options */
  76. char    do_dont_resp[256];
  77. char    will_wont_resp[256];
  78.  
  79. int
  80.     eight = 0,
  81.     autologin = 0,    /* Autologin anyone? */
  82.     skiprc = 0,
  83.     connected,
  84.     showoptions,
  85.     In3270,        /* Are we in 3270 mode? */
  86.     ISend,        /* trying to send network data in */
  87.     debug = 0,
  88.     crmod,
  89.     netdata,    /* Print out network data flow */
  90.     crlf,        /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
  91. #if    defined(TN3270)
  92.     noasynchtty = 0,/* User specified "-noasynch" on command line */
  93.     noasynchnet = 0,/* User specified "-noasynch" on command line */
  94.     askedSGA = 0,    /* We have talked about suppress go ahead */
  95. #endif    /* defined(TN3270) */
  96.     telnetport,
  97.     SYNCHing,    /* we are in TELNET SYNCH mode */
  98.     flushout,    /* flush output */
  99.     autoflush = 0,    /* flush output when interrupting? */
  100.     autosynch,    /* send interrupt characters with SYNCH? */
  101.     localflow,    /* we handle flow control locally */
  102.     restartany,    /* if flow control enabled, restart on any character */
  103.     localchars,    /* we recognize interrupt/quit */
  104.     donelclchars,    /* the user has set "localchars" */
  105.     donebinarytoggle,    /* the user has put us in binary */
  106.     dontlecho,    /* do we suppress local echoing right now? */
  107.     globalmode;
  108.  
  109. char *prompt = 0;
  110.  
  111. cc_t escape;
  112. cc_t rlogin;
  113. #ifdef    KLUDGELINEMODE
  114. cc_t echoc;
  115. #endif
  116.  
  117. /*
  118.  * Telnet receiver states for fsm
  119.  */
  120. #define    TS_DATA        0
  121. #define    TS_IAC        1
  122. #define    TS_WILL        2
  123. #define    TS_WONT        3
  124. #define    TS_DO        4
  125. #define    TS_DONT        5
  126. #define    TS_CR        6
  127. #define    TS_SB        7        /* sub-option collection */
  128. #define    TS_SE        8        /* looking for sub-option end */
  129.  
  130. static int    telrcv_state;
  131. #ifdef    OLD_ENVIRON
  132. unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
  133. #else
  134. # define telopt_environ TELOPT_NEW_ENVIRON
  135. #endif
  136.  
  137. jmp_buf    toplevel = { 0 };
  138. jmp_buf    peerdied;
  139.  
  140. int    flushline;
  141. int    linemode;
  142.  
  143. #ifdef    KLUDGELINEMODE
  144. int    kludgelinemode = 1;
  145. #endif
  146.  
  147. /*
  148.  * The following are some clocks used to decide how to interpret
  149.  * the relationship between various variables.
  150.  */
  151.  
  152. Clocks clocks;
  153.  
  154. #ifdef    notdef
  155. Modelist modelist[] = {
  156.     { "telnet command mode", COMMAND_LINE },
  157.     { "character-at-a-time mode", 0 },
  158.     { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
  159.     { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
  160.     { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
  161.     { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
  162.     { "3270 mode", 0 },
  163. };
  164. #endif
  165.  
  166.  
  167. /*
  168.  * Initialize telnet environment.
  169.  */
  170.  
  171.     void
  172. init_telnet()
  173. {
  174.     env_init();
  175.  
  176.     SB_CLEAR();
  177.     ClearArray(options);
  178.  
  179.     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
  180. #if    defined(AUTHENTICATION) || defined(ENCRYPTION) 
  181.     auth_encrypt_connect(connected);
  182. #endif    /* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
  183.     restartany = -1;
  184.  
  185.     SYNCHing = 0;
  186.  
  187.     /* Don't change NetTrace */
  188.  
  189.     escape = CONTROL(']');
  190.     rlogin = _POSIX_VDISABLE;
  191. #ifdef    KLUDGELINEMODE
  192.     echoc = CONTROL('E');
  193. #endif
  194.  
  195.     flushline = 1;
  196.     telrcv_state = TS_DATA;
  197. }
  198.  
  199.  
  200. #ifdef    notdef
  201. #include <varargs.h>
  202.  
  203.     /*VARARGS*/
  204.     static void
  205. printring(va_alist)
  206.     va_dcl
  207. {
  208.     va_list ap;
  209.     char buffer[100];        /* where things go */
  210.     char *ptr;
  211.     char *format;
  212.     char *string;
  213.     Ring *ring;
  214.     int i;
  215.  
  216.     va_start(ap);
  217.  
  218.     ring = va_arg(ap, Ring *);
  219.     format = va_arg(ap, char *);
  220.     ptr = buffer;
  221.  
  222.     while ((i = *format++) != 0) {
  223.     if (i == '%') {
  224.         i = *format++;
  225.         switch (i) {
  226.         case 'c':
  227.         *ptr++ = va_arg(ap, int);
  228.         break;
  229.         case 's':
  230.         string = va_arg(ap, char *);
  231.         ring_supply_data(ring, buffer, ptr-buffer);
  232.         ring_supply_data(ring, string, strlen(string));
  233.         ptr = buffer;
  234.         break;
  235.         case 0:
  236.         ExitString("printring: trailing %%.\n", 1);
  237.         /*NOTREACHED*/
  238.         default:
  239.         ExitString("printring: unknown format character.\n", 1);
  240.         /*NOTREACHED*/
  241.         }
  242.     } else {
  243.         *ptr++ = i;
  244.     }
  245.     }
  246.     ring_supply_data(ring, buffer, ptr-buffer);
  247. }
  248. #endif
  249.  
  250. /*
  251.  * These routines are in charge of sending option negotiations
  252.  * to the other side.
  253.  *
  254.  * The basic idea is that we send the negotiation if either side
  255.  * is in disagreement as to what the current state should be.
  256.  */
  257.  
  258.     void
  259. send_do(c, init)
  260.     register int c, init;
  261. {
  262.     if (init) {
  263.     if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
  264.                 my_want_state_is_do(c))
  265.         return;
  266.     set_my_want_state_do(c);
  267.     do_dont_resp[c]++;
  268.     }
  269.     NET2ADD(IAC, DO);
  270.     NETADD(c);
  271.     printoption("SENT", DO, c);
  272. }
  273.  
  274.     void
  275. send_dont(c, init)
  276.     register int c, init;
  277. {
  278.     if (init) {
  279.     if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
  280.                 my_want_state_is_dont(c))
  281.         return;
  282.     set_my_want_state_dont(c);
  283.     do_dont_resp[c]++;
  284.     }
  285.     NET2ADD(IAC, DONT);
  286.     NETADD(c);
  287.     printoption("SENT", DONT, c);
  288. }
  289.  
  290.     void
  291. send_will(c, init)
  292.     register int c, init;
  293. {
  294.     if (init) {
  295.     if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
  296.                 my_want_state_is_will(c))
  297.         return;
  298.     set_my_want_state_will(c);
  299.     will_wont_resp[c]++;
  300.     }
  301.     NET2ADD(IAC, WILL);
  302.     NETADD(c);
  303.     printoption("SENT", WILL, c);
  304. }
  305.  
  306.     void
  307. send_wont(c, init)
  308.     register int c, init;
  309. {
  310.     if (init) {
  311.     if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
  312.                 my_want_state_is_wont(c))
  313.         return;
  314.     set_my_want_state_wont(c);
  315.     will_wont_resp[c]++;
  316.     }
  317.     NET2ADD(IAC, WONT);
  318.     NETADD(c);
  319.     printoption("SENT", WONT, c);
  320. }
  321.  
  322.  
  323.     void
  324. willoption(option)
  325.     int option;
  326. {
  327.     int new_state_ok = 0;
  328.  
  329.     if (do_dont_resp[option]) {
  330.         --do_dont_resp[option];
  331.         if (do_dont_resp[option] && my_state_is_do(option))
  332.         --do_dont_resp[option];
  333.     }
  334.  
  335.     if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
  336.  
  337.         switch (option) {
  338.  
  339.         case TELOPT_ECHO:
  340. #        if defined(TN3270)
  341.         /*
  342.          * The following is a pain in the rear-end.
  343.          * Various IBM servers (some versions of Wiscnet,
  344.          * possibly Fibronics/Spartacus, and who knows who
  345.          * else) will NOT allow us to send "DO SGA" too early
  346.          * in the setup proceedings.  On the other hand,
  347.          * 4.2 servers (telnetd) won't set SGA correctly.
  348.          * So, we are stuck.  Empirically (but, based on
  349.          * a VERY small sample), the IBM servers don't send
  350.          * out anything about ECHO, so we postpone our sending
  351.          * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
  352.          * DO send).
  353.           */
  354.         {
  355.             if (askedSGA == 0) {
  356.             askedSGA = 1;
  357.             if (my_want_state_is_dont(TELOPT_SGA))
  358.                 send_do(TELOPT_SGA, 1);
  359.             }
  360.         }
  361.             /* Fall through */
  362.         case TELOPT_EOR:
  363. #endif        /* defined(TN3270) */
  364.         case TELOPT_BINARY:
  365.         case TELOPT_SGA:
  366.         settimer(modenegotiated);
  367.         /* FALL THROUGH */
  368.         case TELOPT_STATUS:
  369. #if    defined(AUTHENTICATION)
  370.         case TELOPT_AUTHENTICATION:
  371. #endif
  372. #ifdef    ENCRYPTION
  373.         case TELOPT_ENCRYPT:
  374. #endif /* ENCRYPTION */
  375.         new_state_ok = 1;
  376.         break;
  377.  
  378.         case TELOPT_TM:
  379.         if (flushout)
  380.             flushout = 0;
  381.         /*
  382.          * Special case for TM.  If we get back a WILL,
  383.          * pretend we got back a WONT.
  384.          */
  385.         set_my_want_state_dont(option);
  386.         set_my_state_dont(option);
  387.         return;            /* Never reply to TM will's/wont's */
  388.  
  389.         case TELOPT_LINEMODE:
  390.         default:
  391.         break;
  392.         }
  393.  
  394.         if (new_state_ok) {
  395.         set_my_want_state_do(option);
  396.         send_do(option, 0);
  397.         setconnmode(0);        /* possibly set new tty mode */
  398.         } else {
  399.         do_dont_resp[option]++;
  400.         send_dont(option, 0);
  401.         }
  402.     }
  403.     set_my_state_do(option);
  404. #ifdef    ENCRYPTION
  405.     if (option == TELOPT_ENCRYPT)
  406.         encrypt_send_support();
  407. #endif    /* ENCRYPTION */
  408. }
  409.  
  410.     void
  411. wontoption(option)
  412.     int option;
  413. {
  414.     if (do_dont_resp[option]) {
  415.         --do_dont_resp[option];
  416.         if (do_dont_resp[option] && my_state_is_dont(option))
  417.         --do_dont_resp[option];
  418.     }
  419.  
  420.     if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
  421.  
  422.         switch (option) {
  423.  
  424. #ifdef    KLUDGELINEMODE
  425.         case TELOPT_SGA:
  426.         if (!kludgelinemode)
  427.             break;
  428.         /* FALL THROUGH */
  429. #endif
  430.         case TELOPT_ECHO:
  431.         settimer(modenegotiated);
  432.         break;
  433.  
  434.         case TELOPT_TM:
  435.         if (flushout)
  436.             flushout = 0;
  437.         set_my_want_state_dont(option);
  438.         set_my_state_dont(option);
  439.         return;        /* Never reply to TM will's/wont's */
  440.  
  441.         default:
  442.         break;
  443.         }
  444.         set_my_want_state_dont(option);
  445.         if (my_state_is_do(option))
  446.         send_dont(option, 0);
  447.         setconnmode(0);            /* Set new tty mode */
  448.     } else if (option == TELOPT_TM) {
  449.         /*
  450.          * Special case for TM.
  451.          */
  452.         if (flushout)
  453.         flushout = 0;
  454.         set_my_want_state_dont(option);
  455.     }
  456.     set_my_state_dont(option);
  457. }
  458.  
  459.     static void
  460. dooption(option)
  461.     int option;
  462. {
  463.     int new_state_ok = 0;
  464.  
  465.     if (will_wont_resp[option]) {
  466.         --will_wont_resp[option];
  467.         if (will_wont_resp[option] && my_state_is_will(option))
  468.         --will_wont_resp[option];
  469.     }
  470.  
  471.     if (will_wont_resp[option] == 0) {
  472.       if (my_want_state_is_wont(option)) {
  473.  
  474.         switch (option) {
  475.  
  476.         case TELOPT_TM:
  477.         /*
  478.          * Special case for TM.  We send a WILL, but pretend
  479.          * we sent WONT.
  480.          */
  481.         send_will(option, 0);
  482.         set_my_want_state_wont(TELOPT_TM);
  483.         set_my_state_wont(TELOPT_TM);
  484.         return;
  485.  
  486. #    if defined(TN3270)
  487.         case TELOPT_EOR:        /* end of record */
  488. #    endif    /* defined(TN3270) */
  489.         case TELOPT_BINARY:        /* binary mode */
  490.         case TELOPT_NAWS:        /* window size */
  491.         case TELOPT_TSPEED:        /* terminal speed */
  492.         case TELOPT_LFLOW:        /* local flow control */
  493.         case TELOPT_TTYPE:        /* terminal type option */
  494.         case TELOPT_SGA:        /* no big deal */
  495. #ifdef    ENCRYPTION
  496.         case TELOPT_ENCRYPT:    /* encryption variable option */
  497. #endif    /* ENCRYPTION */
  498.         new_state_ok = 1;
  499.         break;
  500.  
  501.         case TELOPT_NEW_ENVIRON:    /* New environment variable option */
  502. #ifdef    OLD_ENVIRON
  503.         if (my_state_is_will(TELOPT_OLD_ENVIRON))
  504.             send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
  505.         goto env_common;
  506.         case TELOPT_OLD_ENVIRON:    /* Old environment variable option */
  507.         if (my_state_is_will(TELOPT_NEW_ENVIRON))
  508.             break;        /* Don't enable if new one is in use! */
  509.         env_common:
  510.         telopt_environ = option;
  511. #endif
  512.         new_state_ok = 1;
  513.         break;
  514.  
  515. #if    defined(AUTHENTICATION)
  516.         case TELOPT_AUTHENTICATION:
  517.         if (autologin)
  518.             new_state_ok = 1;
  519.         break;
  520. #endif
  521.  
  522.         case TELOPT_XDISPLOC:    /* X Display location */
  523.         if (env_getvalue((unsigned char *)"DISPLAY"))
  524.             new_state_ok = 1;
  525.         break;
  526.  
  527.         case TELOPT_LINEMODE:
  528. #ifdef    KLUDGELINEMODE
  529.         kludgelinemode = 0;
  530.         send_do(TELOPT_SGA, 1);
  531. #endif
  532.         set_my_want_state_will(TELOPT_LINEMODE);
  533.         send_will(option, 0);
  534.         set_my_state_will(TELOPT_LINEMODE);
  535.         slc_init();
  536.         return;
  537.  
  538.         case TELOPT_ECHO:        /* We're never going to echo... */
  539.         default:
  540.         break;
  541.         }
  542.  
  543.         if (new_state_ok) {
  544.         set_my_want_state_will(option);
  545.         send_will(option, 0);
  546.         setconnmode(0);            /* Set new tty mode */
  547.         } else {
  548.         will_wont_resp[option]++;
  549.         send_wont(option, 0);
  550.         }
  551.       } else {
  552.         /*
  553.          * Handle options that need more things done after the
  554.          * other side has acknowledged the option.
  555.          */
  556.         switch (option) {
  557.         case TELOPT_LINEMODE:
  558. #ifdef    KLUDGELINEMODE
  559.         kludgelinemode = 0;
  560.         send_do(TELOPT_SGA, 1);
  561. #endif
  562.         set_my_state_will(option);
  563.         slc_init();
  564.         send_do(TELOPT_SGA, 0);
  565.         return;
  566.         }
  567.       }
  568.     }
  569.     set_my_state_will(option);
  570. }
  571.  
  572.     static void
  573. dontoption(option)
  574.     int option;
  575. {
  576.  
  577.     if (will_wont_resp[option]) {
  578.         --will_wont_resp[option];
  579.         if (will_wont_resp[option] && my_state_is_wont(option))
  580.         --will_wont_resp[option];
  581.     }
  582.  
  583.     if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
  584.         switch (option) {
  585.         case TELOPT_LINEMODE:
  586.         linemode = 0;    /* put us back to the default state */
  587.         break;
  588. #ifdef    OLD_ENVIRON
  589.         case TELOPT_NEW_ENVIRON:
  590.         /*
  591.          * The new environ option wasn't recognized, try
  592.          * the old one.
  593.          */
  594.         send_will(TELOPT_OLD_ENVIRON, 1);
  595.         telopt_environ = TELOPT_OLD_ENVIRON;
  596.         break;
  597. #endif
  598.         }
  599.         /* we always accept a DONT */
  600.         set_my_want_state_wont(option);
  601.         if (my_state_is_will(option))
  602.         send_wont(option, 0);
  603.         setconnmode(0);            /* Set new tty mode */
  604.     }
  605.     set_my_state_wont(option);
  606. }
  607.  
  608. /*
  609.  * Given a buffer returned by tgetent(), this routine will turn
  610.  * the pipe seperated list of names in the buffer into an array
  611.  * of pointers to null terminated names.  We toss out any bad,
  612.  * duplicate, or verbose names (names with spaces).
  613.  */
  614.  
  615. static char *name_unknown = "UNKNOWN";
  616. static char *unknown[] = { 0, 0 };
  617.  
  618.     char **
  619. mklist(buf, name)
  620.     char *buf, *name;
  621. {
  622.     register int n;
  623.     register char c, *cp, **argvp, *cp2, **argv, **avt;
  624.  
  625.     if (name) {
  626.         if ((int)strlen(name) > 40) {
  627.             name = 0;
  628.             unknown[0] = name_unknown;
  629.         } else {
  630.             unknown[0] = name;
  631.             upcase(name);
  632.         }
  633.     } else
  634.         unknown[0] = name_unknown;
  635.     /*
  636.      * Count up the number of names.
  637.      */
  638.     for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
  639.         if (*cp == '|')
  640.             n++;
  641.     }
  642.     /*
  643.      * Allocate an array to put the name pointers into
  644.      */
  645.     argv = (char **)malloc((n+3)*sizeof(char *));
  646.     if (argv == 0)
  647.         return(unknown);
  648.  
  649.     /*
  650.      * Fill up the array of pointers to names.
  651.      */
  652.     *argv = 0;
  653.     argvp = argv+1;
  654.     n = 0;
  655.     for (cp = cp2 = buf; (c = *cp);  cp++) {
  656.         if (c == '|' || c == ':') {
  657.             *cp++ = '\0';
  658.             /*
  659.              * Skip entries that have spaces or are over 40
  660.              * characters long.  If this is our environment
  661.              * name, then put it up front.  Otherwise, as
  662.              * long as this is not a duplicate name (case
  663.              * insensitive) add it to the list.
  664.              */
  665.             if (n || (cp - cp2 > 41))
  666.                 ;
  667.             else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
  668.                 *argv = cp2;
  669.             else if (is_unique(cp2, argv+1, argvp))
  670.                 *argvp++ = cp2;
  671.             if (c == ':')
  672.                 break;
  673.             /*
  674.              * Skip multiple delimiters. Reset cp2 to
  675.              * the beginning of the next name. Reset n,
  676.              * the flag for names with spaces.
  677.              */
  678.             while ((c = *cp) == '|')
  679.                 cp++;
  680.             cp2 = cp;
  681.             n = 0;
  682.         }
  683.         /*
  684.          * Skip entries with spaces or non-ascii values.
  685.          * Convert lower case letters to upper case.
  686.          */
  687.         if ((c == ' ') || !isascii(c))
  688.             n = 1;
  689.         else if (islower(c))
  690.             *cp = toupper(c);
  691.     }
  692.     
  693.     /*
  694.      * Check for an old V6 2 character name.  If the second
  695.      * name points to the beginning of the buffer, and is
  696.      * only 2 characters long, move it to the end of the array.
  697.      */
  698.     if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
  699.         --argvp;
  700.         for (avt = &argv[1]; avt < argvp; avt++)
  701.             *avt = *(avt+1);
  702.         *argvp++ = buf;
  703.     }
  704.  
  705.     /*
  706.      * Duplicate last name, for TTYPE option, and null
  707.      * terminate the array.  If we didn't find a match on
  708.      * our terminal name, put that name at the beginning.
  709.      */
  710.     cp = *(argvp-1);
  711.     *argvp++ = cp;
  712.     *argvp = 0;
  713.  
  714.     if (*argv == 0) {
  715.         if (name)
  716.             *argv = name;
  717.         else {
  718.             --argvp;
  719.             for (avt = argv; avt < argvp; avt++)
  720.                 *avt = *(avt+1);
  721.         }
  722.     }
  723.     if (*argv)
  724.         return(argv);
  725.     else
  726.         return(unknown);
  727. }
  728.  
  729.     int
  730. is_unique(name, as, ae)
  731.     register char *name, **as, **ae;
  732. {
  733.     register char **ap;
  734.     register int n;
  735.  
  736.     n = strlen(name) + 1;
  737.     for (ap = as; ap < ae; ap++)
  738.         if (strncasecmp(*ap, name, n) == 0)
  739.             return(0);
  740.     return (1);
  741. }
  742.  
  743. #ifdef    TERMCAP
  744. char termbuf[1024];
  745.  
  746.     /*ARGSUSED*/
  747.     int
  748. setupterm(tname, fd, errp)
  749.     char *tname;
  750.     int fd, *errp;
  751. {
  752.     if (tgetent(termbuf, tname) == 1) {
  753.         termbuf[1023] = '\0';
  754.         if (errp)
  755.             *errp = 1;
  756.         return(0);
  757.     }
  758.     if (errp)
  759.         *errp = 0;
  760.     return(-1);
  761. }
  762. #else
  763. #define    termbuf    ttytype
  764. extern char ttytype[];
  765. #endif
  766.  
  767. int resettermname = 1;
  768.  
  769.     char *
  770. gettermname()
  771. {
  772.     char *tname;
  773.     static char **tnamep = 0;
  774.     static char **next;
  775.     int err;
  776.  
  777.     if (resettermname) {
  778.         resettermname = 0;
  779.         if (tnamep && tnamep != unknown)
  780.             free(tnamep);
  781.         if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
  782.                 (setupterm(tname, 1, &err) == 0)) {
  783.             tnamep = mklist(termbuf, tname);
  784.         } else {
  785.             if (tname && ((int)strlen(tname) <= 40)) {
  786.                 unknown[0] = tname;
  787.                 upcase(tname);
  788.             } else
  789.                 unknown[0] = name_unknown;
  790.             tnamep = unknown;
  791.         }
  792.         next = tnamep;
  793.     }
  794.     if (*next == 0)
  795.         next = tnamep;
  796.     return(*next++);
  797. }
  798. /*
  799.  * suboption()
  800.  *
  801.  *    Look at the sub-option buffer, and try to be helpful to the other
  802.  * side.
  803.  *
  804.  *    Currently we recognize:
  805.  *
  806.  *        Terminal type, send request.
  807.  *        Terminal speed (send request).
  808.  *        Local flow control (is request).
  809.  *        Linemode
  810.  */
  811.  
  812.     static void
  813. suboption()
  814. {
  815.     unsigned char subchar;
  816.  
  817.     printsub('<', subbuffer, SB_LEN()+2);
  818.     switch (subchar = SB_GET()) {
  819.     case TELOPT_TTYPE:
  820.     if (my_want_state_is_wont(TELOPT_TTYPE))
  821.         return;
  822.     if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
  823.         return;
  824.     } else {
  825.         char *name;
  826.         unsigned char temp[50];
  827.         int len;
  828.  
  829. #if    defined(TN3270)
  830.         if (tn3270_ttype()) {
  831.         return;
  832.         }
  833. #endif    /* defined(TN3270) */
  834.         name = gettermname();
  835.         len = strlen(name) + 4 + 2;
  836.         if (len < NETROOM()) {
  837.         sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
  838.                 TELQUAL_IS, name, IAC, SE);
  839.         ring_supply_data(&netoring, temp, len);
  840.         printsub('>', &temp[2], len-2);
  841.         } else {
  842.         ExitString("No room in buffer for terminal type.\n", 1);
  843.         /*NOTREACHED*/
  844.         }
  845.     }
  846.     break;
  847.     case TELOPT_TSPEED:
  848.     if (my_want_state_is_wont(TELOPT_TSPEED))
  849.         return;
  850.     if (SB_EOF())
  851.         return;
  852.     if (SB_GET() == TELQUAL_SEND) {
  853.         long ospeed, ispeed;
  854.         unsigned char temp[50];
  855.         int len;
  856.  
  857.         TerminalSpeeds(&ispeed, &ospeed);
  858.  
  859.         sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
  860.             TELQUAL_IS, ospeed, ispeed, IAC, SE);
  861.         len = strlen((char *)temp+4) + 4;    /* temp[3] is 0 ... */
  862.  
  863.         if (len < NETROOM()) {
  864.         ring_supply_data(&netoring, temp, len);
  865.         printsub('>', temp+2, len - 2);
  866.         }
  867. /*@*/        else printf("lm_will: not enough room in buffer\n");
  868.     }
  869.     break;
  870.     case TELOPT_LFLOW:
  871.     if (my_want_state_is_wont(TELOPT_LFLOW))
  872.         return;
  873.     if (SB_EOF())
  874.         return;
  875.     switch(SB_GET()) {
  876.     case LFLOW_RESTART_ANY:
  877.         restartany = 1;
  878.         break;
  879.     case LFLOW_RESTART_XON:
  880.         restartany = 0;
  881.         break;
  882.     case LFLOW_ON:
  883.         localflow = 1;
  884.         break;
  885.     case LFLOW_OFF:
  886.         localflow = 0;
  887.         break;
  888.     default:
  889.         return;
  890.     }
  891.     setcommandmode();
  892.     setconnmode(0);
  893.     break;
  894.  
  895.     case TELOPT_LINEMODE:
  896.     if (my_want_state_is_wont(TELOPT_LINEMODE))
  897.         return;
  898.     if (SB_EOF())
  899.         return;
  900.     switch (SB_GET()) {
  901.     case WILL:
  902.         lm_will(subpointer, SB_LEN());
  903.         break;
  904.     case WONT:
  905.         lm_wont(subpointer, SB_LEN());
  906.         break;
  907.     case DO:
  908.         lm_do(subpointer, SB_LEN());
  909.         break;
  910.     case DONT:
  911.         lm_dont(subpointer, SB_LEN());
  912.         break;
  913.     case LM_SLC:
  914.         slc(subpointer, SB_LEN());
  915.         break;
  916.     case LM_MODE:
  917.         lm_mode(subpointer, SB_LEN(), 0);
  918.         break;
  919.     default:
  920.         break;
  921.     }
  922.     break;
  923.  
  924. #ifdef    OLD_ENVIRON
  925.     case TELOPT_OLD_ENVIRON:
  926. #endif
  927.     case TELOPT_NEW_ENVIRON:
  928.     if (SB_EOF())
  929.         return;
  930.     switch(SB_PEEK()) {
  931.     case TELQUAL_IS:
  932.     case TELQUAL_INFO:
  933.         if (my_want_state_is_dont(subchar))
  934.         return;
  935.         break;
  936.     case TELQUAL_SEND:
  937.         if (my_want_state_is_wont(subchar)) {
  938.         return;
  939.         }
  940.         break;
  941.     default:
  942.         return;
  943.     }
  944.     env_opt(subpointer, SB_LEN());
  945.     break;
  946.  
  947.     case TELOPT_XDISPLOC:
  948.     if (my_want_state_is_wont(TELOPT_XDISPLOC))
  949.         return;
  950.     if (SB_EOF())
  951.         return;
  952.     if (SB_GET() == TELQUAL_SEND) {
  953.         unsigned char temp[50], *dp;
  954.         int len;
  955.  
  956.         if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
  957.         /*
  958.          * Something happened, we no longer have a DISPLAY
  959.          * variable.  So, turn off the option.
  960.          */
  961.         send_wont(TELOPT_XDISPLOC, 1);
  962.         break;
  963.         }
  964.         sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
  965.             TELQUAL_IS, dp, IAC, SE);
  966.         len = strlen((char *)temp+4) + 4;    /* temp[3] is 0 ... */
  967.  
  968.         if (len < NETROOM()) {
  969.         ring_supply_data(&netoring, temp, len);
  970.         printsub('>', temp+2, len - 2);
  971.         }
  972. /*@*/        else printf("lm_will: not enough room in buffer\n");
  973.     }
  974.     break;
  975.  
  976. #if    defined(AUTHENTICATION)
  977.     case TELOPT_AUTHENTICATION: {
  978.         if (!autologin)
  979.             break;
  980.         if (SB_EOF())
  981.             return;
  982.         switch(SB_GET()) {
  983.         case TELQUAL_IS:
  984.             if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
  985.                 return;
  986.             auth_is(subpointer, SB_LEN());
  987.             break;
  988.         case TELQUAL_SEND:
  989.             if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
  990.                 return;
  991.             auth_send(subpointer, SB_LEN());
  992.             break;
  993.         case TELQUAL_REPLY:
  994.             if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
  995.                 return;
  996.             auth_reply(subpointer, SB_LEN());
  997.             break;
  998.         case TELQUAL_NAME:
  999.             if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
  1000.                 return;
  1001.             auth_name(subpointer, SB_LEN());
  1002.             break;
  1003.         }
  1004.     }
  1005.     break;
  1006. #endif
  1007. #ifdef    ENCRYPTION
  1008.     case TELOPT_ENCRYPT:
  1009.         if (SB_EOF())
  1010.             return;
  1011.         switch(SB_GET()) {
  1012.         case ENCRYPT_START:
  1013.             if (my_want_state_is_dont(TELOPT_ENCRYPT))
  1014.                 return;
  1015.             encrypt_start(subpointer, SB_LEN());
  1016.             break;
  1017.         case ENCRYPT_END:
  1018.             if (my_want_state_is_dont(TELOPT_ENCRYPT))
  1019.                 return;
  1020.             encrypt_end();
  1021.             break;
  1022.         case ENCRYPT_SUPPORT:
  1023.             if (my_want_state_is_wont(TELOPT_ENCRYPT))
  1024.                 return;
  1025.             encrypt_support(subpointer, SB_LEN());
  1026.             break;
  1027.         case ENCRYPT_REQSTART:
  1028.             if (my_want_state_is_wont(TELOPT_ENCRYPT))
  1029.                 return;
  1030.             encrypt_request_start(subpointer, SB_LEN());
  1031.             break;
  1032.         case ENCRYPT_REQEND:
  1033.             if (my_want_state_is_wont(TELOPT_ENCRYPT))
  1034.                 return;
  1035.             /*
  1036.              * We can always send an REQEND so that we cannot
  1037.              * get stuck encrypting.  We should only get this
  1038.              * if we have been able to get in the correct mode
  1039.              * anyhow.
  1040.              */
  1041.             encrypt_request_end();
  1042.             break;
  1043.         case ENCRYPT_IS:
  1044.             if (my_want_state_is_dont(TELOPT_ENCRYPT))
  1045.                 return;
  1046.             encrypt_is(subpointer, SB_LEN());
  1047.             break;
  1048.         case ENCRYPT_REPLY:
  1049.             if (my_want_state_is_wont(TELOPT_ENCRYPT))
  1050.                 return;
  1051.             encrypt_reply(subpointer, SB_LEN());
  1052.             break;
  1053.         case ENCRYPT_ENC_KEYID:
  1054.             if (my_want_state_is_dont(TELOPT_ENCRYPT))
  1055.                 return;
  1056.             encrypt_enc_keyid(subpointer, SB_LEN());
  1057.             break;
  1058.         case ENCRYPT_DEC_KEYID:
  1059.             if (my_want_state_is_wont(TELOPT_ENCRYPT))
  1060.                 return;
  1061.             encrypt_dec_keyid(subpointer, SB_LEN());
  1062.             break;
  1063.         default:
  1064.             break;
  1065.         }
  1066.         break;
  1067. #endif    /* ENCRYPTION */
  1068.     default:
  1069.     break;
  1070.     }
  1071. }
  1072.  
  1073. static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
  1074.  
  1075.     void
  1076. lm_will(cmd, len)
  1077.     unsigned char *cmd;
  1078.     int len;
  1079. {
  1080.     if (len < 1) {
  1081. /*@*/    printf("lm_will: no command!!!\n");    /* Should not happen... */
  1082.     return;
  1083.     }
  1084.     switch(cmd[0]) {
  1085.     case LM_FORWARDMASK:    /* We shouldn't ever get this... */
  1086.     default:
  1087.     str_lm[3] = DONT;
  1088.     str_lm[4] = cmd[0];
  1089.     if (NETROOM() > sizeof(str_lm)) {
  1090.         ring_supply_data(&netoring, str_lm, sizeof(str_lm));
  1091.         printsub('>', &str_lm[2], sizeof(str_lm)-2);
  1092.     }
  1093. /*@*/    else printf("lm_will: not enough room in buffer\n");
  1094.     break;
  1095.     }
  1096. }
  1097.  
  1098.     void
  1099. lm_wont(cmd, len)
  1100.     unsigned char *cmd;
  1101.     int len;
  1102. {
  1103.     if (len < 1) {
  1104. /*@*/    printf("lm_wont: no command!!!\n");    /* Should not happen... */
  1105.     return;
  1106.     }
  1107.     switch(cmd[0]) {
  1108.     case LM_FORWARDMASK:    /* We shouldn't ever get this... */
  1109.     default:
  1110.     /* We are always DONT, so don't respond */
  1111.     return;
  1112.     }
  1113. }
  1114.  
  1115.     void
  1116. lm_do(cmd, len)
  1117.     unsigned char *cmd;
  1118.     int len;
  1119. {
  1120.     if (len < 1) {
  1121. /*@*/    printf("lm_do: no command!!!\n");    /* Should not happen... */
  1122.     return;
  1123.     }
  1124.     switch(cmd[0]) {
  1125.     case LM_FORWARDMASK:
  1126.     default:
  1127.     str_lm[3] = WONT;
  1128.     str_lm[4] = cmd[0];
  1129.     if (NETROOM() > sizeof(str_lm)) {
  1130.         ring_supply_data(&netoring, str_lm, sizeof(str_lm));
  1131.         printsub('>', &str_lm[2], sizeof(str_lm)-2);
  1132.     }
  1133. /*@*/    else printf("lm_do: not enough room in buffer\n");
  1134.     break;
  1135.     }
  1136. }
  1137.  
  1138.     void
  1139. lm_dont(cmd, len)
  1140.     unsigned char *cmd;
  1141.     int len;
  1142. {
  1143.     if (len < 1) {
  1144. /*@*/    printf("lm_dont: no command!!!\n");    /* Should not happen... */
  1145.     return;
  1146.     }
  1147.     switch(cmd[0]) {
  1148.     case LM_FORWARDMASK:
  1149.     default:
  1150.     /* we are always WONT, so don't respond */
  1151.     break;
  1152.     }
  1153. }
  1154.  
  1155. static unsigned char str_lm_mode[] = {
  1156.     IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
  1157. };
  1158.  
  1159.     void
  1160. lm_mode(cmd, len, init)
  1161.     unsigned char *cmd;
  1162.     int len, init;
  1163. {
  1164.     if (len != 1)
  1165.         return;
  1166.     if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
  1167.         return;
  1168.     if (*cmd&MODE_ACK)
  1169.         return;
  1170.     linemode = *cmd&(MODE_MASK&~MODE_ACK);
  1171.     str_lm_mode[4] = linemode;
  1172.     if (!init)
  1173.         str_lm_mode[4] |= MODE_ACK;
  1174.     if (NETROOM() > sizeof(str_lm_mode)) {
  1175.         ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
  1176.         printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
  1177.     }
  1178. /*@*/    else printf("lm_mode: not enough room in buffer\n");
  1179.     setconnmode(0);    /* set changed mode */
  1180. }
  1181.  
  1182.  
  1183.  
  1184. /*
  1185.  * slc()
  1186.  * Handle special character suboption of LINEMODE.
  1187.  */
  1188.  
  1189. struct spc {
  1190.     cc_t val;
  1191.     cc_t *valp;
  1192.     char flags;    /* Current flags & level */
  1193.     char mylevel;    /* Maximum level & flags */
  1194. } spc_data[NSLC+1];
  1195.  
  1196. #define SLC_IMPORT    0
  1197. #define    SLC_EXPORT    1
  1198. #define SLC_RVALUE    2
  1199. static int slc_mode = SLC_EXPORT;
  1200.  
  1201.     void
  1202. slc_init()
  1203. {
  1204.     register struct spc *spcp;
  1205.  
  1206.     localchars = 1;
  1207.     for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
  1208.         spcp->val = 0;
  1209.         spcp->valp = 0;
  1210.         spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
  1211.     }
  1212.  
  1213. #define    initfunc(func, flags) { \
  1214.                     spcp = &spc_data[func]; \
  1215.                     if (spcp->valp = tcval(func)) { \
  1216.                         spcp->val = *spcp->valp; \
  1217.                         spcp->mylevel = SLC_VARIABLE|flags; \
  1218.                     } else { \
  1219.                         spcp->val = 0; \
  1220.                         spcp->mylevel = SLC_DEFAULT; \
  1221.                     } \
  1222.                     }
  1223.  
  1224.     initfunc(SLC_SYNCH, 0);
  1225.     /* No BRK */
  1226.     initfunc(SLC_AO, 0);
  1227.     initfunc(SLC_AYT, 0);
  1228.     /* No EOR */
  1229.     initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
  1230.     initfunc(SLC_EOF, 0);
  1231. #ifndef    SYSV_TERMIO
  1232.     initfunc(SLC_SUSP, SLC_FLUSHIN);
  1233. #endif
  1234.     initfunc(SLC_EC, 0);
  1235.     initfunc(SLC_EL, 0);
  1236. #ifndef    SYSV_TERMIO
  1237.     initfunc(SLC_EW, 0);
  1238.     initfunc(SLC_RP, 0);
  1239.     initfunc(SLC_LNEXT, 0);
  1240. #endif
  1241.     initfunc(SLC_XON, 0);
  1242.     initfunc(SLC_XOFF, 0);
  1243. #ifdef    SYSV_TERMIO
  1244.     spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
  1245.     spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
  1246. #endif
  1247.     initfunc(SLC_FORW1, 0);
  1248. #ifdef    USE_TERMIO
  1249.     initfunc(SLC_FORW2, 0);
  1250.     /* No FORW2 */
  1251. #endif
  1252.  
  1253.     initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
  1254. #undef    initfunc
  1255.  
  1256.     if (slc_mode == SLC_EXPORT)
  1257.         slc_export();
  1258.     else
  1259.         slc_import(1);
  1260.  
  1261. }
  1262.  
  1263.     void
  1264. slcstate()
  1265. {
  1266.     printf("Special characters are %s values\n",
  1267.         slc_mode == SLC_IMPORT ? "remote default" :
  1268.         slc_mode == SLC_EXPORT ? "local" :
  1269.                      "remote");
  1270. }
  1271.  
  1272.     void
  1273. slc_mode_export()
  1274. {
  1275.     slc_mode = SLC_EXPORT;
  1276.     if (my_state_is_will(TELOPT_LINEMODE))
  1277.     slc_export();
  1278. }
  1279.  
  1280.     void
  1281. slc_mode_import(def)
  1282.     int def;
  1283. {
  1284.     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
  1285.     if (my_state_is_will(TELOPT_LINEMODE))
  1286.     slc_import(def);
  1287. }
  1288.  
  1289. unsigned char slc_import_val[] = {
  1290.     IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
  1291. };
  1292. unsigned char slc_import_def[] = {
  1293.     IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
  1294. };
  1295.  
  1296.     void
  1297. slc_import(def)
  1298.     int def;
  1299. {
  1300.     if (NETROOM() > sizeof(slc_import_val)) {
  1301.     if (def) {
  1302.         ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
  1303.         printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
  1304.     } else {
  1305.         ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
  1306.         printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
  1307.     }
  1308.     }
  1309. /*@*/ else printf("slc_import: not enough room\n");
  1310. }
  1311.  
  1312.     void
  1313. slc_export()
  1314. {
  1315.     register struct spc *spcp;
  1316.  
  1317.     TerminalDefaultChars();
  1318.  
  1319.     slc_start_reply();
  1320.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  1321.     if (spcp->mylevel != SLC_NOSUPPORT) {
  1322.         if (spcp->val == (cc_t)(_POSIX_VDISABLE))
  1323.         spcp->flags = SLC_NOSUPPORT;
  1324.         else
  1325.         spcp->flags = spcp->mylevel;
  1326.         if (spcp->valp)
  1327.         spcp->val = *spcp->valp;
  1328.         slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
  1329.     }
  1330.     }
  1331.     slc_end_reply();
  1332.     (void)slc_update();
  1333.     setconnmode(1);    /* Make sure the character values are set */
  1334. }
  1335.  
  1336.     void
  1337. slc(cp, len)
  1338.     register unsigned char *cp;
  1339.     int len;
  1340. {
  1341.     register struct spc *spcp;
  1342.     register int func,level;
  1343.  
  1344.     slc_start_reply();
  1345.  
  1346.     for (; len >= 3; len -=3, cp +=3) {
  1347.  
  1348.         func = cp[SLC_FUNC];
  1349.  
  1350.         if (func == 0) {
  1351.             /*
  1352.              * Client side: always ignore 0 function.
  1353.              */
  1354.             continue;
  1355.         }
  1356.         if (func > NSLC) {
  1357.             if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
  1358.                 slc_add_reply(func, SLC_NOSUPPORT, 0);
  1359.             continue;
  1360.         }
  1361.  
  1362.         spcp = &spc_data[func];
  1363.  
  1364.         level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
  1365.  
  1366.         if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
  1367.             ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
  1368.             continue;
  1369.         }
  1370.  
  1371.         if (level == (SLC_DEFAULT|SLC_ACK)) {
  1372.             /*
  1373.              * This is an error condition, the SLC_ACK
  1374.              * bit should never be set for the SLC_DEFAULT
  1375.              * level.  Our best guess to recover is to
  1376.              * ignore the SLC_ACK bit.
  1377.              */
  1378.             cp[SLC_FLAGS] &= ~SLC_ACK;
  1379.         }
  1380.  
  1381.         if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
  1382.             spcp->val = (cc_t)cp[SLC_VALUE];
  1383.             spcp->flags = cp[SLC_FLAGS];    /* include SLC_ACK */
  1384.             continue;
  1385.         }
  1386.  
  1387.         level &= ~SLC_ACK;
  1388.  
  1389.         if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
  1390.             spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
  1391.             spcp->val = (cc_t)cp[SLC_VALUE];
  1392.         }
  1393.         if (level == SLC_DEFAULT) {
  1394.             if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
  1395.                 spcp->flags = spcp->mylevel;
  1396.             else
  1397.                 spcp->flags = SLC_NOSUPPORT;
  1398.         }
  1399.         slc_add_reply(func, spcp->flags, spcp->val);
  1400.     }
  1401.     slc_end_reply();
  1402.     if (slc_update())
  1403.         setconnmode(1);    /* set the  new character values */
  1404. }
  1405.  
  1406.     void
  1407. slc_check()
  1408. {
  1409.     register struct spc *spcp;
  1410.  
  1411.     slc_start_reply();
  1412.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  1413.     if (spcp->valp && spcp->val != *spcp->valp) {
  1414.         spcp->val = *spcp->valp;
  1415.         if (spcp->val == (cc_t)(_POSIX_VDISABLE))
  1416.         spcp->flags = SLC_NOSUPPORT;
  1417.         else
  1418.         spcp->flags = spcp->mylevel;
  1419.         slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
  1420.     }
  1421.     }
  1422.     slc_end_reply();
  1423.     setconnmode(1);
  1424. }
  1425.  
  1426.  
  1427. unsigned char slc_reply[128];
  1428. unsigned char *slc_replyp;
  1429.  
  1430.     void
  1431. slc_start_reply()
  1432. {
  1433.     slc_replyp = slc_reply;
  1434.     *slc_replyp++ = IAC;
  1435.     *slc_replyp++ = SB;
  1436.     *slc_replyp++ = TELOPT_LINEMODE;
  1437.     *slc_replyp++ = LM_SLC;
  1438. }
  1439.  
  1440.     void
  1441. slc_add_reply(func, flags, value)
  1442.     unsigned char func;
  1443.     unsigned char flags;
  1444.     cc_t value;
  1445. {
  1446.     if ((*slc_replyp++ = func) == IAC)
  1447.         *slc_replyp++ = IAC;
  1448.     if ((*slc_replyp++ = flags) == IAC)
  1449.         *slc_replyp++ = IAC;
  1450.     if ((*slc_replyp++ = (unsigned char)value) == IAC)
  1451.         *slc_replyp++ = IAC;
  1452. }
  1453.  
  1454.     void
  1455. slc_end_reply()
  1456. {
  1457.     register int len;
  1458.  
  1459.     *slc_replyp++ = IAC;
  1460.     *slc_replyp++ = SE;
  1461.     len = slc_replyp - slc_reply;
  1462.     if (len <= 6)
  1463.     return;
  1464.     if (NETROOM() > len) {
  1465.     ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
  1466.     printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
  1467.     }
  1468. /*@*/else printf("slc_end_reply: not enough room\n");
  1469. }
  1470.  
  1471.     int
  1472. slc_update()
  1473. {
  1474.     register struct spc *spcp;
  1475.     int need_update = 0;
  1476.  
  1477.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  1478.         if (!(spcp->flags&SLC_ACK))
  1479.             continue;
  1480.         spcp->flags &= ~SLC_ACK;
  1481.         if (spcp->valp && (*spcp->valp != spcp->val)) {
  1482.             *spcp->valp = spcp->val;
  1483.             need_update = 1;
  1484.         }
  1485.     }
  1486.     return(need_update);
  1487. }
  1488.  
  1489. #ifdef    OLD_ENVIRON
  1490. # ifdef    ENV_HACK
  1491. /*
  1492.  * Earlier version of telnet/telnetd from the BSD code had
  1493.  * the definitions of VALUE and VAR reversed.  To ensure
  1494.  * maximum interoperability, we assume that the server is
  1495.  * an older BSD server, until proven otherwise.  The newer
  1496.  * BSD servers should be able to handle either definition,
  1497.  * so it is better to use the wrong values if we don't
  1498.  * know what type of server it is.
  1499.  */
  1500. int env_auto = 1;
  1501. int old_env_var = OLD_ENV_VAR;
  1502. int old_env_value = OLD_ENV_VALUE;
  1503. # else
  1504. #  define old_env_var OLD_ENV_VAR
  1505. #  define old_env_value OLD_ENV_VALUE
  1506. # endif
  1507. #endif
  1508.  
  1509.     void
  1510. env_opt(buf, len)
  1511.     register unsigned char *buf;
  1512.     register int len;
  1513. {
  1514.     register unsigned char *ep = 0, *epc = 0;
  1515.     register int i;
  1516.  
  1517.     switch(buf[0]&0xff) {
  1518.     case TELQUAL_SEND:
  1519.         env_opt_start();
  1520.         if (len == 1) {
  1521.             env_opt_add(NULL);
  1522.         } else for (i = 1; i < len; i++) {
  1523.             switch (buf[i]&0xff) {
  1524. #ifdef    OLD_ENVIRON
  1525.             case OLD_ENV_VAR:
  1526. # ifdef    ENV_HACK
  1527.                 if (telopt_environ == TELOPT_OLD_ENVIRON
  1528.                     && env_auto) {
  1529.                     /* Server has the same definitions */
  1530.                     old_env_var = OLD_ENV_VAR;
  1531.                     old_env_value = OLD_ENV_VALUE;
  1532.                 }
  1533.                 /* FALL THROUGH */
  1534. # endif
  1535.             case OLD_ENV_VALUE:
  1536.                 /*
  1537.                  * Although OLD_ENV_VALUE is not legal, we will
  1538.                  * still recognize it, just in case it is an
  1539.                  * old server that has VAR & VALUE mixed up...
  1540.                  */
  1541.                 /* FALL THROUGH */
  1542. #else
  1543.             case NEW_ENV_VAR:
  1544. #endif
  1545.             case ENV_USERVAR:
  1546.                 if (ep) {
  1547.                     *epc = 0;
  1548.                     env_opt_add(ep);
  1549.                 }
  1550.                 ep = epc = &buf[i+1];
  1551.                 break;
  1552.             case ENV_ESC:
  1553.                 i++;
  1554.                 /*FALL THROUGH*/
  1555.             default:
  1556.                 if (epc)
  1557.                     *epc++ = buf[i];
  1558.                 break;
  1559.             }
  1560.         }
  1561.         if (ep) {
  1562.             *epc = 0;
  1563.             env_opt_add(ep);
  1564.         }
  1565.         env_opt_end(1);
  1566.         break;
  1567.  
  1568.     case TELQUAL_IS:
  1569.     case TELQUAL_INFO:
  1570.         /* Ignore for now.  We shouldn't get it anyway. */
  1571.         break;
  1572.  
  1573.     default:
  1574.         break;
  1575.     }
  1576. }
  1577.  
  1578. #define    OPT_REPLY_SIZE    256
  1579. unsigned char *opt_reply;
  1580. unsigned char *opt_replyp;
  1581. unsigned char *opt_replyend;
  1582.  
  1583.     void
  1584. env_opt_start()
  1585. {
  1586.     if (opt_reply)
  1587.         opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
  1588.     else
  1589.         opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
  1590.     if (opt_reply == NULL) {
  1591. /*@*/        printf("env_opt_start: malloc()/realloc() failed!!!\n");
  1592.         opt_reply = opt_replyp = opt_replyend = NULL;
  1593.         return;
  1594.     }
  1595.     opt_replyp = opt_reply;
  1596.     opt_replyend = opt_reply + OPT_REPLY_SIZE;
  1597.     *opt_replyp++ = IAC;
  1598.     *opt_replyp++ = SB;
  1599.     *opt_replyp++ = telopt_environ;
  1600.     *opt_replyp++ = TELQUAL_IS;
  1601. }
  1602.  
  1603.     void
  1604. env_opt_start_info()
  1605. {
  1606.     env_opt_start();
  1607.     if (opt_replyp)
  1608.         opt_replyp[-1] = TELQUAL_INFO;
  1609. }
  1610.  
  1611.     void
  1612. env_opt_add(ep)
  1613.     register unsigned char *ep;
  1614. {
  1615.     register unsigned char *vp, c;
  1616.  
  1617.     if (opt_reply == NULL)        /*XXX*/
  1618.         return;            /*XXX*/
  1619.  
  1620.     if (ep == NULL || *ep == '\0') {
  1621.         /* Send user defined variables first. */
  1622.         env_default(1, 0);
  1623.         while (ep = env_default(0, 0))
  1624.             env_opt_add(ep);
  1625.  
  1626.         /* Now add the list of well know variables.  */
  1627.         env_default(1, 1);
  1628.         while (ep = env_default(0, 1))
  1629.             env_opt_add(ep);
  1630.         return;
  1631.     }
  1632.     vp = env_getvalue(ep);
  1633.     if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
  1634.                 strlen((char *)ep) + 6 > opt_replyend)
  1635.     {
  1636.         register int len;
  1637.         opt_replyend += OPT_REPLY_SIZE;
  1638.         len = opt_replyend - opt_reply;
  1639.         opt_reply = (unsigned char *)realloc(opt_reply, len);
  1640.         if (opt_reply == NULL) {
  1641. /*@*/            printf("env_opt_add: realloc() failed!!!\n");
  1642.             opt_reply = opt_replyp = opt_replyend = NULL;
  1643.             return;
  1644.         }
  1645.         opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
  1646.         opt_replyend = opt_reply + len;
  1647.     }
  1648.     if (opt_welldefined(ep))
  1649. #ifdef    OLD_ENVIRON
  1650.         if (telopt_environ == TELOPT_OLD_ENVIRON)
  1651.             *opt_replyp++ = old_env_var;
  1652.         else
  1653. #endif
  1654.             *opt_replyp++ = NEW_ENV_VAR;
  1655.     else
  1656.         *opt_replyp++ = ENV_USERVAR;
  1657.     for (;;) {
  1658.         while (c = *ep++) {
  1659.             switch(c&0xff) {
  1660.             case IAC:
  1661.                 *opt_replyp++ = IAC;
  1662.                 break;
  1663.             case NEW_ENV_VAR:
  1664.             case NEW_ENV_VALUE:
  1665.             case ENV_ESC:
  1666.             case ENV_USERVAR:
  1667.                 *opt_replyp++ = ENV_ESC;
  1668.                 break;
  1669.             }
  1670.             *opt_replyp++ = c;
  1671.         }
  1672.         if (ep = vp) {
  1673. #ifdef    OLD_ENVIRON
  1674.             if (telopt_environ == TELOPT_OLD_ENVIRON)
  1675.                 *opt_replyp++ = old_env_value;
  1676.             else
  1677. #endif
  1678.                 *opt_replyp++ = NEW_ENV_VALUE;
  1679.             vp = NULL;
  1680.         } else
  1681.             break;
  1682.     }
  1683. }
  1684.  
  1685.     int
  1686. opt_welldefined(ep)
  1687.     char *ep;
  1688. {
  1689.     if ((strcmp(ep, "USER") == 0) ||
  1690.         (strcmp(ep, "DISPLAY") == 0) ||
  1691.         (strcmp(ep, "PRINTER") == 0) ||
  1692.         (strcmp(ep, "SYSTEMTYPE") == 0) ||
  1693.         (strcmp(ep, "JOB") == 0) ||
  1694.         (strcmp(ep, "ACCT") == 0))
  1695.         return(1);
  1696.     return(0);
  1697. }
  1698.     void
  1699. env_opt_end(emptyok)
  1700.     register int emptyok;
  1701. {
  1702.     register int len;
  1703.  
  1704.     len = opt_replyp - opt_reply + 2;
  1705.     if (emptyok || len > 6) {
  1706.         *opt_replyp++ = IAC;
  1707.         *opt_replyp++ = SE;
  1708.         if (NETROOM() > len) {
  1709.             ring_supply_data(&netoring, opt_reply, len);
  1710.             printsub('>', &opt_reply[2], len - 2);
  1711.         }
  1712. /*@*/        else printf("slc_end_reply: not enough room\n");
  1713.     }
  1714.     if (opt_reply) {
  1715.         free(opt_reply);
  1716.         opt_reply = opt_replyp = opt_replyend = NULL;
  1717.     }
  1718. }
  1719.  
  1720.  
  1721.  
  1722.     int
  1723. telrcv()
  1724. {
  1725.     register int c;
  1726.     register int scc;
  1727.     register unsigned char *sbp;
  1728.     int count;
  1729.     int returnValue = 0;
  1730.  
  1731.     scc = 0;
  1732.     count = 0;
  1733.     while (TTYROOM() > 2) {
  1734.     if (scc == 0) {
  1735.         if (count) {
  1736.         ring_consumed(&netiring, count);
  1737.         returnValue = 1;
  1738.         count = 0;
  1739.         }
  1740.         sbp = netiring.consume;
  1741.         scc = ring_full_consecutive(&netiring);
  1742.         if (scc == 0) {
  1743.         /* No more data coming in */
  1744.         break;
  1745.         }
  1746.     }
  1747.  
  1748.     c = *sbp++ & 0xff, scc--; count++;
  1749. #ifdef    ENCRYPTION
  1750.     if (decrypt_input)
  1751.         c = (*decrypt_input)(c);
  1752. #endif    /* ENCRYPTION */
  1753.  
  1754.     switch (telrcv_state) {
  1755.  
  1756.     case TS_CR:
  1757.         telrcv_state = TS_DATA;
  1758.         if (c == '\0') {
  1759.         break;    /* Ignore \0 after CR */
  1760.         }
  1761.         else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
  1762.         TTYADD(c);
  1763.         break;
  1764.         }
  1765.         /* Else, fall through */
  1766.  
  1767.     case TS_DATA:
  1768.         if (c == IAC) {
  1769.         telrcv_state = TS_IAC;
  1770.         break;
  1771.         }
  1772. #        if defined(TN3270)
  1773.         if (In3270) {
  1774.         *Ifrontp++ = c;
  1775.         while (scc > 0) {
  1776.             c = *sbp++ & 0377, scc--; count++;
  1777. #ifdef    ENCRYPTION
  1778.             if (decrypt_input)
  1779.             c = (*decrypt_input)(c);
  1780. #endif    /* ENCRYPTION */
  1781.             if (c == IAC) {
  1782.             telrcv_state = TS_IAC;
  1783.             break;
  1784.             }
  1785.             *Ifrontp++ = c;
  1786.         }
  1787.         } else
  1788. #        endif /* defined(TN3270) */
  1789.             /*
  1790.              * The 'crmod' hack (see following) is needed
  1791.              * since we can't * set CRMOD on output only.
  1792.              * Machines like MULTICS like to send \r without
  1793.              * \n; since we must turn off CRMOD to get proper
  1794.              * input, the mapping is done here (sigh).
  1795.              */
  1796.         if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
  1797.         if (scc > 0) {
  1798.             c = *sbp&0xff;
  1799. #ifdef    ENCRYPTION
  1800.             if (decrypt_input)
  1801.             c = (*decrypt_input)(c);
  1802. #endif    /* ENCRYPTION */
  1803.             if (c == 0) {
  1804.             sbp++, scc--; count++;
  1805.             /* a "true" CR */
  1806.             TTYADD('\r');
  1807.             } else if (my_want_state_is_dont(TELOPT_ECHO) &&
  1808.                     (c == '\n')) {
  1809.             sbp++, scc--; count++;
  1810.             TTYADD('\n');
  1811.             } else {
  1812. #ifdef    ENCRYPTION
  1813.                 if (decrypt_input)
  1814.                 (*decrypt_input)(-1);
  1815. #endif    /* ENCRYPTION */
  1816.  
  1817.             TTYADD('\r');
  1818.             if (crmod) {
  1819.                 TTYADD('\n');
  1820.             }
  1821.             }
  1822.         } else {
  1823.             telrcv_state = TS_CR;
  1824.             TTYADD('\r');
  1825.             if (crmod) {
  1826.                 TTYADD('\n');
  1827.             }
  1828.         }
  1829.         } else {
  1830.         TTYADD(c);
  1831.         }
  1832.         continue;
  1833.  
  1834.     case TS_IAC:
  1835. process_iac:
  1836.         switch (c) {
  1837.         
  1838.         case WILL:
  1839.         telrcv_state = TS_WILL;
  1840.         continue;
  1841.  
  1842.         case WONT:
  1843.         telrcv_state = TS_WONT;
  1844.         continue;
  1845.  
  1846.         case DO:
  1847.         telrcv_state = TS_DO;
  1848.         continue;
  1849.  
  1850.         case DONT:
  1851.         telrcv_state = TS_DONT;
  1852.         continue;
  1853.  
  1854.         case DM:
  1855.             /*
  1856.              * We may have missed an urgent notification,
  1857.              * so make sure we flush whatever is in the
  1858.              * buffer currently.
  1859.              */
  1860.         printoption("RCVD", IAC, DM);
  1861.         SYNCHing = 1;
  1862.         (void) ttyflush(1);
  1863.         SYNCHing = stilloob();
  1864.         settimer(gotDM);
  1865.         break;
  1866.  
  1867.         case SB:
  1868.         SB_CLEAR();
  1869.         telrcv_state = TS_SB;
  1870.         continue;
  1871.  
  1872. #        if defined(TN3270)
  1873.         case EOR:
  1874.         if (In3270) {
  1875.             if (Ibackp == Ifrontp) {
  1876.             Ibackp = Ifrontp = Ibuf;
  1877.             ISend = 0;    /* should have been! */
  1878.             } else {
  1879.             Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
  1880.             ISend = 1;
  1881.             }
  1882.         }
  1883.         printoption("RCVD", IAC, EOR);
  1884.         break;
  1885. #        endif /* defined(TN3270) */
  1886.  
  1887.         case IAC:
  1888. #        if !defined(TN3270)
  1889.         TTYADD(IAC);
  1890. #        else /* !defined(TN3270) */
  1891.         if (In3270) {
  1892.             *Ifrontp++ = IAC;
  1893.         } else {
  1894.             TTYADD(IAC);
  1895.         }
  1896. #        endif /* !defined(TN3270) */
  1897.         break;
  1898.  
  1899.         case NOP:
  1900.         case GA:
  1901.         default:
  1902.         printoption("RCVD", IAC, c);
  1903.         break;
  1904.         }
  1905.         telrcv_state = TS_DATA;
  1906.         continue;
  1907.  
  1908.     case TS_WILL:
  1909.         printoption("RCVD", WILL, c);
  1910.         willoption(c);
  1911.         SetIn3270();
  1912.         telrcv_state = TS_DATA;
  1913.         continue;
  1914.  
  1915.     case TS_WONT:
  1916.         printoption("RCVD", WONT, c);
  1917.         wontoption(c);
  1918.         SetIn3270();
  1919.         telrcv_state = TS_DATA;
  1920.         continue;
  1921.  
  1922.     case TS_DO:
  1923.         printoption("RCVD", DO, c);
  1924.         dooption(c);
  1925.         SetIn3270();
  1926.         if (c == TELOPT_NAWS) {
  1927.         sendnaws();
  1928.         } else if (c == TELOPT_LFLOW) {
  1929.         localflow = 1;
  1930.         setcommandmode();
  1931.         setconnmode(0);
  1932.         }
  1933.         telrcv_state = TS_DATA;
  1934.         continue;
  1935.  
  1936.     case TS_DONT:
  1937.         printoption("RCVD", DONT, c);
  1938.         dontoption(c);
  1939.         flushline = 1;
  1940.         setconnmode(0);    /* set new tty mode (maybe) */
  1941.         SetIn3270();
  1942.         telrcv_state = TS_DATA;
  1943.         continue;
  1944.  
  1945.     case TS_SB:
  1946.         if (c == IAC) {
  1947.         telrcv_state = TS_SE;
  1948.         } else {
  1949.         SB_ACCUM(c);
  1950.         }
  1951.         continue;
  1952.  
  1953.     case TS_SE:
  1954.         if (c != SE) {
  1955.         if (c != IAC) {
  1956.             /*
  1957.              * This is an error.  We only expect to get
  1958.              * "IAC IAC" or "IAC SE".  Several things may
  1959.              * have happend.  An IAC was not doubled, the
  1960.              * IAC SE was left off, or another option got
  1961.              * inserted into the suboption are all possibilities.
  1962.              * If we assume that the IAC was not doubled,
  1963.              * and really the IAC SE was left off, we could
  1964.              * get into an infinate loop here.  So, instead,
  1965.              * we terminate the suboption, and process the
  1966.              * partial suboption if we can.
  1967.              */
  1968.             SB_ACCUM(IAC);
  1969.             SB_ACCUM(c);
  1970.             subpointer -= 2;
  1971.             SB_TERM();
  1972.  
  1973.             printoption("In SUBOPTION processing, RCVD", IAC, c);
  1974.             suboption();    /* handle sub-option */
  1975.             SetIn3270();
  1976.             telrcv_state = TS_IAC;
  1977.             goto process_iac;
  1978.         }
  1979.         SB_ACCUM(c);
  1980.         telrcv_state = TS_SB;
  1981.         } else {
  1982.         SB_ACCUM(IAC);
  1983.         SB_ACCUM(SE);
  1984.         subpointer -= 2;
  1985.         SB_TERM();
  1986.         suboption();    /* handle sub-option */
  1987.         SetIn3270();
  1988.         telrcv_state = TS_DATA;
  1989.         }
  1990.     }
  1991.     }
  1992.     if (count)
  1993.     ring_consumed(&netiring, count);
  1994.     return returnValue||count;
  1995. }
  1996.  
  1997. static int bol = 1, local = 0;
  1998.  
  1999.     int
  2000. rlogin_susp()
  2001. {
  2002.     if (local) {
  2003.     local = 0;
  2004.     bol = 1;
  2005.     command(0, "z\n", 2);
  2006.     return(1);
  2007.     }
  2008.     return(0);
  2009. }
  2010.  
  2011.     static int
  2012. telsnd()
  2013. {
  2014.     int tcc;
  2015.     int count;
  2016.     int returnValue = 0;
  2017.     unsigned char *tbp;
  2018.  
  2019.     tcc = 0;
  2020.     count = 0;
  2021.     while (NETROOM() > 2) {
  2022.     register int sc;
  2023.     register int c;
  2024.  
  2025.     if (tcc == 0) {
  2026.         if (count) {
  2027.         ring_consumed(&ttyiring, count);
  2028.         returnValue = 1;
  2029.         count = 0;
  2030.         }
  2031.         tbp = ttyiring.consume;
  2032.         tcc = ring_full_consecutive(&ttyiring);
  2033.         if (tcc == 0) {
  2034.         break;
  2035.         }
  2036.     }
  2037.     c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
  2038.     if (rlogin != _POSIX_VDISABLE) {
  2039.         if (bol) {
  2040.             bol = 0;
  2041.             if (sc == rlogin) {
  2042.                 local = 1;
  2043.                 continue;
  2044.             }
  2045.         } else if (local) {
  2046.             local = 0;
  2047.             if (sc == '.' || c == termEofChar) {
  2048.                 bol = 1;
  2049.                 command(0, "close\n", 6);
  2050.                 continue;
  2051.             }
  2052.             if (sc == termSuspChar) {
  2053.                 bol = 1;
  2054.                 command(0, "z\n", 2);
  2055.                 continue;
  2056.             }
  2057.             if (sc == escape) {
  2058.                 command(0, (char *)tbp, tcc);
  2059.                 bol = 1;
  2060.                 count += tcc;
  2061.                 tcc = 0;
  2062.                 flushline = 1;
  2063.                 break;
  2064.             }
  2065.             if (sc != rlogin) {
  2066.                 ++tcc;
  2067.                 --tbp;
  2068.                 --count;
  2069.                 c = sc = rlogin;
  2070.             }
  2071.         }
  2072.         if ((sc == '\n') || (sc == '\r'))
  2073.             bol = 1;
  2074.     } else if (sc == escape) {
  2075.         /*
  2076.          * Double escape is a pass through of a single escape character.
  2077.          */
  2078.         if (tcc && strip(*tbp) == escape) {
  2079.         tbp++;
  2080.         tcc--;
  2081.         count++;
  2082.         bol = 0;
  2083.         } else {
  2084.         command(0, (char *)tbp, tcc);
  2085.         bol = 1;
  2086.         count += tcc;
  2087.         tcc = 0;
  2088.         flushline = 1;
  2089.         break;
  2090.         }
  2091.     } else
  2092.         bol = 0;
  2093. #ifdef    KLUDGELINEMODE
  2094.     if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
  2095.         if (tcc > 0 && strip(*tbp) == echoc) {
  2096.         tcc--; tbp++; count++;
  2097.         } else {
  2098.         dontlecho = !dontlecho;
  2099.         settimer(echotoggle);
  2100.         setconnmode(0);
  2101.         flushline = 1;
  2102.         break;
  2103.         }
  2104.     }
  2105. #endif
  2106.     if (MODE_LOCAL_CHARS(globalmode)) {
  2107.         if (TerminalSpecialChars(sc) == 0) {
  2108.         bol = 1;
  2109.         break;
  2110.         }
  2111.     }
  2112.     if (my_want_state_is_wont(TELOPT_BINARY)) {
  2113.         switch (c) {
  2114.         case '\n':
  2115.             /*
  2116.              * If we are in CRMOD mode (\r ==> \n)
  2117.              * on our local machine, then probably
  2118.              * a newline (unix) is CRLF (TELNET).
  2119.              */
  2120.         if (MODE_LOCAL_CHARS(globalmode)) {
  2121.             NETADD('\r');
  2122.         }
  2123.         NETADD('\n');
  2124.         bol = flushline = 1;
  2125.         break;
  2126.         case '\r':
  2127.         if (!crlf) {
  2128.             NET2ADD('\r', '\0');
  2129.         } else {
  2130.             NET2ADD('\r', '\n');
  2131.         }
  2132.         bol = flushline = 1;
  2133.         break;
  2134.         case IAC:
  2135.         NET2ADD(IAC, IAC);
  2136.         break;
  2137.         default:
  2138.         NETADD(c);
  2139.         break;
  2140.         }
  2141.     } else if (c == IAC) {
  2142.         NET2ADD(IAC, IAC);
  2143.     } else {
  2144.         NETADD(c);
  2145.     }
  2146.     }
  2147.     if (count)
  2148.     ring_consumed(&ttyiring, count);
  2149.     return returnValue||count;        /* Non-zero if we did anything */
  2150. }
  2151.  
  2152. /*
  2153.  * Scheduler()
  2154.  *
  2155.  * Try to do something.
  2156.  *
  2157.  * If we do something useful, return 1; else return 0.
  2158.  *
  2159.  */
  2160.  
  2161.  
  2162.     int
  2163. Scheduler(block)
  2164.     int    block;            /* should we block in the select ? */
  2165. {
  2166.         /* One wants to be a bit careful about setting returnValue
  2167.          * to one, since a one implies we did some useful work,
  2168.          * and therefore probably won't be called to block next
  2169.          * time (TN3270 mode only).
  2170.          */
  2171.     int returnValue;
  2172.     int netin, netout, netex, ttyin, ttyout;
  2173.  
  2174.     /* Decide which rings should be processed */
  2175.  
  2176.     netout = ring_full_count(&netoring) &&
  2177.         (flushline ||
  2178.         (my_want_state_is_wont(TELOPT_LINEMODE)
  2179. #ifdef    KLUDGELINEMODE
  2180.             && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
  2181. #endif
  2182.         ) ||
  2183.             my_want_state_is_will(TELOPT_BINARY));
  2184.     ttyout = ring_full_count(&ttyoring);
  2185.  
  2186. #if    defined(TN3270)
  2187.     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
  2188. #else    /* defined(TN3270) */
  2189.     ttyin = ring_empty_count(&ttyiring);
  2190. #endif    /* defined(TN3270) */
  2191.  
  2192. #if    defined(TN3270)
  2193.     netin = ring_empty_count(&netiring);
  2194. #   else /* !defined(TN3270) */
  2195.     netin = !ISend && ring_empty_count(&netiring);
  2196. #   endif /* !defined(TN3270) */
  2197.  
  2198.     netex = !SYNCHing;
  2199.  
  2200.     /* If we have seen a signal recently, reset things */
  2201. #   if defined(TN3270) && defined(unix)
  2202.     if (HaveInput) {
  2203.     HaveInput = 0;
  2204.     (void) signal(SIGIO, inputAvailable);
  2205.     }
  2206. #endif    /* defined(TN3270) && defined(unix) */
  2207.  
  2208.     /* Call to system code to process rings */
  2209.  
  2210.     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
  2211.  
  2212.     /* Now, look at the input rings, looking for work to do. */
  2213.  
  2214.     if (ring_full_count(&ttyiring)) {
  2215. #   if defined(TN3270)
  2216.     if (In3270) {
  2217.         int c;
  2218.  
  2219.         c = DataFromTerminal(ttyiring.consume,
  2220.                     ring_full_consecutive(&ttyiring));
  2221.         if (c) {
  2222.         returnValue = 1;
  2223.             ring_consumed(&ttyiring, c);
  2224.         }
  2225.     } else {
  2226. #   endif /* defined(TN3270) */
  2227.         returnValue |= telsnd();
  2228. #   if defined(TN3270)
  2229.     }
  2230. #   endif /* defined(TN3270) */
  2231.     }
  2232.  
  2233.     if (ring_full_count(&netiring)) {
  2234. #    if !defined(TN3270)
  2235.     returnValue |= telrcv();
  2236. #    else /* !defined(TN3270) */
  2237.     returnValue = Push3270();
  2238. #    endif /* !defined(TN3270) */
  2239.     }
  2240.     return returnValue;
  2241. }
  2242.  
  2243. /*
  2244.  * Select from tty and network...
  2245.  */
  2246.     void
  2247. telnet(user)
  2248.     char *user;
  2249. {
  2250.     sys_telnet_init();
  2251.  
  2252. #if    defined(AUTHENTICATION) || defined(ENCRYPTION) 
  2253.     {
  2254.     extern char *localhost ();
  2255.     static char *local_host = 0;
  2256.  
  2257.     if (!local_host)
  2258.         local_host = localhost ();
  2259.  
  2260.     auth_encrypt_init(local_host, hostname, "TELNET", 0);
  2261.     auth_encrypt_user(user);
  2262.     }
  2263. #endif    /* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
  2264. #   if !defined(TN3270)
  2265.     if (telnetport) {
  2266. #if    defined(AUTHENTICATION)
  2267.     if (autologin)
  2268.         send_will(TELOPT_AUTHENTICATION, 1);
  2269. #endif
  2270. #ifdef    ENCRYPTION
  2271.     send_do(TELOPT_ENCRYPT, 1);
  2272.     send_will(TELOPT_ENCRYPT, 1);
  2273. #endif    /* ENCRYPTION */
  2274.     send_do(TELOPT_SGA, 1);
  2275.     send_will(TELOPT_TTYPE, 1);
  2276.     send_will(TELOPT_NAWS, 1);
  2277.     send_will(TELOPT_TSPEED, 1);
  2278.     send_will(TELOPT_LFLOW, 1);
  2279.     send_will(TELOPT_LINEMODE, 1);
  2280.     send_will(TELOPT_NEW_ENVIRON, 1);
  2281.     send_do(TELOPT_STATUS, 1);
  2282.     if (env_getvalue((unsigned char *)"DISPLAY"))
  2283.         send_will(TELOPT_XDISPLOC, 1);
  2284.     if (eight)
  2285.         tel_enter_binary(eight);
  2286.     }
  2287. #   endif /* !defined(TN3270) */
  2288.  
  2289. #   if !defined(TN3270)
  2290.     for (;;) {
  2291.     int schedValue;
  2292.  
  2293.     while ((schedValue = Scheduler(0)) != 0) {
  2294.         if (schedValue == -1) {
  2295.         setcommandmode();
  2296.         return;
  2297.         }
  2298.     }
  2299.  
  2300.     if (Scheduler(1) == -1) {
  2301.         setcommandmode();
  2302.         return;
  2303.     }
  2304.     }
  2305. #   else /* !defined(TN3270) */
  2306.     for (;;) {
  2307.     int schedValue;
  2308.  
  2309.     while (!In3270 && !shell_active) {
  2310.         if (Scheduler(1) == -1) {
  2311.         setcommandmode();
  2312.         return;
  2313.         }
  2314.     }
  2315.  
  2316.     while ((schedValue = Scheduler(0)) != 0) {
  2317.         if (schedValue == -1) {
  2318.         setcommandmode();
  2319.         return;
  2320.         }
  2321.     }
  2322.         /* If there is data waiting to go out to terminal, don't
  2323.          * schedule any more data for the terminal.
  2324.          */
  2325.     if (ring_full_count(&ttyoring)) {
  2326.         schedValue = 1;
  2327.     } else {
  2328.         if (shell_active) {
  2329.         if (shell_continue() == 0) {
  2330.             ConnectScreen();
  2331.         }
  2332.         } else if (In3270) {
  2333.         schedValue = DoTerminalOutput();
  2334.         }
  2335.     }
  2336.     if (schedValue && (shell_active == 0)) {
  2337.         if (Scheduler(1) == -1) {
  2338.         setcommandmode();
  2339.         return;
  2340.         }
  2341.     }
  2342.     }
  2343. #   endif /* !defined(TN3270) */
  2344. }
  2345.  
  2346. #if    0    /* XXX - this not being in is a bug */
  2347. /*
  2348.  * nextitem()
  2349.  *
  2350.  *    Return the address of the next "item" in the TELNET data
  2351.  * stream.  This will be the address of the next character if
  2352.  * the current address is a user data character, or it will
  2353.  * be the address of the character following the TELNET command
  2354.  * if the current address is a TELNET IAC ("I Am a Command")
  2355.  * character.
  2356.  */
  2357.  
  2358.     static char *
  2359. nextitem(current)
  2360.     char *current;
  2361. {
  2362.     if ((*current&0xff) != IAC) {
  2363.     return current+1;
  2364.     }
  2365.     switch (*(current+1)&0xff) {
  2366.     case DO:
  2367.     case DONT:
  2368.     case WILL:
  2369.     case WONT:
  2370.     return current+3;
  2371.     case SB:        /* loop forever looking for the SE */
  2372.     {
  2373.         register char *look = current+2;
  2374.  
  2375.         for (;;) {
  2376.         if ((*look++&0xff) == IAC) {
  2377.             if ((*look++&0xff) == SE) {
  2378.             return look;
  2379.             }
  2380.         }
  2381.         }
  2382.     }
  2383.     default:
  2384.     return current+2;
  2385.     }
  2386. }
  2387. #endif    /* 0 */
  2388.  
  2389. /*
  2390.  * netclear()
  2391.  *
  2392.  *    We are about to do a TELNET SYNCH operation.  Clear
  2393.  * the path to the network.
  2394.  *
  2395.  *    Things are a bit tricky since we may have sent the first
  2396.  * byte or so of a previous TELNET command into the network.
  2397.  * So, we have to scan the network buffer from the beginning
  2398.  * until we are up to where we want to be.
  2399.  *
  2400.  *    A side effect of what we do, just to keep things
  2401.  * simple, is to clear the urgent data pointer.  The principal
  2402.  * caller should be setting the urgent data pointer AFTER calling
  2403.  * us in any case.
  2404.  */
  2405.  
  2406.     static void
  2407. netclear()
  2408. {
  2409. #if    0    /* XXX */
  2410.     register char *thisitem, *next;
  2411.     char *good;
  2412. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  2413.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  2414.  
  2415.     thisitem = netobuf;
  2416.  
  2417.     while ((next = nextitem(thisitem)) <= netobuf.send) {
  2418.     thisitem = next;
  2419.     }
  2420.  
  2421.     /* Now, thisitem is first before/at boundary. */
  2422.  
  2423.     good = netobuf;    /* where the good bytes go */
  2424.  
  2425.     while (netoring.add > thisitem) {
  2426.     if (wewant(thisitem)) {
  2427.         int length;
  2428.  
  2429.         next = thisitem;
  2430.         do {
  2431.         next = nextitem(next);
  2432.         } while (wewant(next) && (nfrontp > next));
  2433.         length = next-thisitem;
  2434.         memmove(good, thisitem, length);
  2435.         good += length;
  2436.         thisitem = next;
  2437.     } else {
  2438.         thisitem = nextitem(thisitem);
  2439.     }
  2440.     }
  2441.  
  2442. #endif    /* 0 */
  2443. }
  2444.  
  2445. /*
  2446.  * These routines add various telnet commands to the data stream.
  2447.  */
  2448.  
  2449.     static void
  2450. doflush()
  2451. {
  2452.     NET2ADD(IAC, DO);
  2453.     NETADD(TELOPT_TM);
  2454.     flushline = 1;
  2455.     flushout = 1;
  2456.     (void) ttyflush(1);            /* Flush/drop output */
  2457.     /* do printoption AFTER flush, otherwise the output gets tossed... */
  2458.     printoption("SENT", DO, TELOPT_TM);
  2459. }
  2460.  
  2461.     void
  2462. xmitAO()
  2463. {
  2464.     NET2ADD(IAC, AO);
  2465.     printoption("SENT", IAC, AO);
  2466.     if (autoflush) {
  2467.     doflush();
  2468.     }
  2469. }
  2470.  
  2471.  
  2472.     void
  2473. xmitEL()
  2474. {
  2475.     NET2ADD(IAC, EL);
  2476.     printoption("SENT", IAC, EL);
  2477. }
  2478.  
  2479.     void
  2480. xmitEC()
  2481. {
  2482.     NET2ADD(IAC, EC);
  2483.     printoption("SENT", IAC, EC);
  2484. }
  2485.  
  2486.  
  2487.     int
  2488. dosynch()
  2489. {
  2490.     netclear();            /* clear the path to the network */
  2491.     NETADD(IAC);
  2492.     setneturg();
  2493.     NETADD(DM);
  2494.     printoption("SENT", IAC, DM);
  2495.     return 1;
  2496. }
  2497.  
  2498. int want_status_response = 0;
  2499.  
  2500.     int
  2501. get_status()
  2502. {
  2503.     unsigned char tmp[16];
  2504.     register unsigned char *cp;
  2505.  
  2506.     if (my_want_state_is_dont(TELOPT_STATUS)) {
  2507.     printf("Remote side does not support STATUS option\n");
  2508.     return 0;
  2509.     }
  2510.     cp = tmp;
  2511.  
  2512.     *cp++ = IAC;
  2513.     *cp++ = SB;
  2514.     *cp++ = TELOPT_STATUS;
  2515.     *cp++ = TELQUAL_SEND;
  2516.     *cp++ = IAC;
  2517.     *cp++ = SE;
  2518.     if (NETROOM() >= cp - tmp) {
  2519.     ring_supply_data(&netoring, tmp, cp-tmp);
  2520.     printsub('>', tmp+2, cp - tmp - 2);
  2521.     }
  2522.     ++want_status_response;
  2523.     return 1;
  2524. }
  2525.  
  2526.     void
  2527. intp()
  2528. {
  2529.     NET2ADD(IAC, IP);
  2530.     printoption("SENT", IAC, IP);
  2531.     flushline = 1;
  2532.     if (autoflush) {
  2533.     doflush();
  2534.     }
  2535.     if (autosynch) {
  2536.     dosynch();
  2537.     }
  2538. }
  2539.  
  2540.     void
  2541. sendbrk()
  2542. {
  2543.     NET2ADD(IAC, BREAK);
  2544.     printoption("SENT", IAC, BREAK);
  2545.     flushline = 1;
  2546.     if (autoflush) {
  2547.     doflush();
  2548.     }
  2549.     if (autosynch) {
  2550.     dosynch();
  2551.     }
  2552. }
  2553.  
  2554.     void
  2555. sendabort()
  2556. {
  2557.     NET2ADD(IAC, ABORT);
  2558.     printoption("SENT", IAC, ABORT);
  2559.     flushline = 1;
  2560.     if (autoflush) {
  2561.     doflush();
  2562.     }
  2563.     if (autosynch) {
  2564.     dosynch();
  2565.     }
  2566. }
  2567.  
  2568.     void
  2569. sendsusp()
  2570. {
  2571.     NET2ADD(IAC, SUSP);
  2572.     printoption("SENT", IAC, SUSP);
  2573.     flushline = 1;
  2574.     if (autoflush) {
  2575.     doflush();
  2576.     }
  2577.     if (autosynch) {
  2578.     dosynch();
  2579.     }
  2580. }
  2581.  
  2582.     void
  2583. sendeof()
  2584. {
  2585.     NET2ADD(IAC, xEOF);
  2586.     printoption("SENT", IAC, xEOF);
  2587. }
  2588.  
  2589.     void
  2590. sendayt()
  2591. {
  2592.     NET2ADD(IAC, AYT);
  2593.     printoption("SENT", IAC, AYT);
  2594. }
  2595.  
  2596. /*
  2597.  * Send a window size update to the remote system.
  2598.  */
  2599.  
  2600.     void
  2601. sendnaws()
  2602. {
  2603.     long rows, cols;
  2604.     unsigned char tmp[16];
  2605.     register unsigned char *cp;
  2606.  
  2607.     if (my_state_is_wont(TELOPT_NAWS))
  2608.     return;
  2609.  
  2610. #define    PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
  2611.                 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
  2612.  
  2613.     if (TerminalWindowSize(&rows, &cols) == 0) {    /* Failed */
  2614.     return;
  2615.     }
  2616.  
  2617.     cp = tmp;
  2618.  
  2619.     *cp++ = IAC;
  2620.     *cp++ = SB;
  2621.     *cp++ = TELOPT_NAWS;
  2622.     PUTSHORT(cp, cols);
  2623.     PUTSHORT(cp, rows);
  2624.     *cp++ = IAC;
  2625.     *cp++ = SE;
  2626.     if (NETROOM() >= cp - tmp) {
  2627.     ring_supply_data(&netoring, tmp, cp-tmp);
  2628.     printsub('>', tmp+2, cp - tmp - 2);
  2629.     }
  2630. }
  2631.  
  2632.     void
  2633. tel_enter_binary(rw)
  2634.     int rw;
  2635. {
  2636.     if (rw&1)
  2637.     send_do(TELOPT_BINARY, 1);
  2638.     if (rw&2)
  2639.     send_will(TELOPT_BINARY, 1);
  2640. }
  2641.  
  2642.     void
  2643. tel_leave_binary(rw)
  2644.     int rw;
  2645. {
  2646.     if (rw&1)
  2647.     send_dont(TELOPT_BINARY, 1);
  2648.     if (rw&2)
  2649.     send_wont(TELOPT_BINARY, 1);
  2650. }
  2651.