home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / telnet / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  51.7 KB  |  2,536 lines

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