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