home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / telnet / commands.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  64.0 KB  |  2,823 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[] = "@(#)commands.c    5.5 (Berkeley) 3/22/91";
  36. #endif /* not lint */
  37.  
  38. #if    defined(unix)
  39. #include <sys/param.h>
  40. #ifdef    CRAY
  41. #include <sys/types.h>
  42. #endif
  43. #include <sys/file.h>
  44. #else
  45. #include <sys/types.h>
  46. #endif    /* defined(unix) */
  47. #include <sys/socket.h>
  48. #include <netinet/in.h>
  49. #ifdef    CRAY
  50. #include <fcntl.h>
  51. #endif    /* CRAY */
  52.  
  53. #include <signal.h>
  54. #include <netdb.h>
  55. #include <ctype.h>
  56. #include <pwd.h>
  57. #include <varargs.h>
  58. #include <errno.h>
  59.  
  60. #include <arpa/telnet.h>
  61.  
  62. #include "general.h"
  63.  
  64. #include "ring.h"
  65.  
  66. #include "externs.h"
  67. #include "defines.h"
  68. #include "types.h"
  69.  
  70. #ifndef CRAY
  71. #include <netinet/in_systm.h>
  72. # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
  73. # include <machine/endian.h>
  74. # endif /* vax */
  75. #endif /* CRAY */
  76. #include <netinet/ip.h>
  77.  
  78.  
  79. #ifndef       MAXHOSTNAMELEN
  80. #define       MAXHOSTNAMELEN 64
  81. #endif        MAXHOSTNAMELEN
  82.  
  83. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  84. int tos = -1;
  85. #endif    /* defined(IPPROTO_IP) && defined(IP_TOS) */
  86.  
  87. char    *hostname;
  88. static char _hostname[MAXHOSTNAMELEN];
  89.  
  90. extern char *getenv();
  91.  
  92. extern int isprefix();
  93. extern char **genget();
  94. extern int Ambiguous();
  95.  
  96. static call();
  97.  
  98. typedef struct {
  99.     char    *name;        /* command name */
  100.     char    *help;        /* help string (NULL for no help) */
  101.     int    (*handler)();    /* routine which executes command */
  102.     int    needconnect;    /* Do we need to be connected to execute? */
  103. } Command;
  104.  
  105. static char line[256];
  106. static char saveline[256];
  107. static int margc;
  108. static char *margv[20];
  109.  
  110.     static void
  111. makeargv()
  112. {
  113.     register char *cp, *cp2, c;
  114.     register char **argp = margv;
  115.  
  116.     margc = 0;
  117.     cp = line;
  118.     if (*cp == '!') {        /* Special case shell escape */
  119.     strcpy(saveline, line);    /* save for shell command */
  120.     *argp++ = "!";        /* No room in string to get this */
  121.     margc++;
  122.     cp++;
  123.     }
  124.     while (c = *cp) {
  125.     register int inquote = 0;
  126.     while (isspace(c))
  127.         c = *++cp;
  128.     if (c == '\0')
  129.         break;
  130.     *argp++ = cp;
  131.     margc += 1;
  132.     for (cp2 = cp; c != '\0'; c = *++cp) {
  133.         if (inquote) {
  134.         if (c == inquote) {
  135.             inquote = 0;
  136.             continue;
  137.         }
  138.         } else {
  139.         if (c == '\\') {
  140.             if ((c = *++cp) == '\0')
  141.             break;
  142.         } else if (c == '"') {
  143.             inquote = '"';
  144.             continue;
  145.         } else if (c == '\'') {
  146.             inquote = '\'';
  147.             continue;
  148.         } else if (isspace(c))
  149.             break;
  150.         }
  151.         *cp2++ = c;
  152.     }
  153.     *cp2 = '\0';
  154.     if (c == '\0')
  155.         break;
  156.     cp++;
  157.     }
  158.     *argp++ = 0;
  159. }
  160.  
  161. /*
  162.  * Make a character string into a number.
  163.  *
  164.  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
  165.  */
  166.  
  167.     static
  168. special(s)
  169.     register char *s;
  170. {
  171.     register char c;
  172.     char b;
  173.  
  174.     switch (*s) {
  175.     case '^':
  176.         b = *++s;
  177.         if (b == '?') {
  178.             c = b | 0x40;        /* DEL */
  179.         } else {
  180.             c = b & 0x1f;
  181.         }
  182.         break;
  183.     default:
  184.         c = *s;
  185.         break;
  186.     }
  187.     return c;
  188. }
  189.  
  190. /*
  191.  * Construct a control character sequence
  192.  * for a special character.
  193.  */
  194.     static char *
  195. control(c)
  196.     register cc_t c;
  197. {
  198.     static char buf[5];
  199.     /*
  200.      * The only way I could get the Sun 3.5 compiler
  201.      * to shut up about
  202.      *    if ((unsigned int)c >= 0x80)
  203.      * was to assign "c" to an unsigned int variable...
  204.      * Arggg....
  205.      */
  206.     register unsigned int uic = (unsigned int)c;
  207.  
  208.     if (uic == 0x7f)
  209.         return ("^?");
  210.     if (c == (cc_t)_POSIX_VDISABLE) {
  211.         return "off";
  212.     }
  213.     if (uic >= 0x80) {
  214.         buf[0] = '\\';
  215.         buf[1] = ((c>>6)&07) + '0';
  216.         buf[2] = ((c>>3)&07) + '0';
  217.         buf[3] = (c&07) + '0';
  218.         buf[4] = 0;
  219.     } else if (uic >= 0x20) {
  220.         buf[0] = c;
  221.         buf[1] = 0;
  222.     } else {
  223.         buf[0] = '^';
  224.         buf[1] = '@'+c;
  225.         buf[2] = 0;
  226.     }
  227.     return (buf);
  228. }
  229.  
  230.  
  231.  
  232. /*
  233.  *    The following are data structures and routines for
  234.  *    the "send" command.
  235.  *
  236.  */
  237.  
  238. struct sendlist {
  239.     char    *name;        /* How user refers to it (case independent) */
  240.     char    *help;        /* Help information (0 ==> no help) */
  241.     int        needconnect;    /* Need to be connected */
  242.     int        narg;        /* Number of arguments */
  243.     int        (*handler)();    /* Routine to perform (for special ops) */
  244.     int        nbyte;        /* Number of bytes to send this command */
  245.     int        what;        /* Character to be sent (<0 ==> special) */
  246. };
  247.  
  248.  
  249. extern int
  250.     send_esc P((void)),
  251.     send_help P((void)),
  252.     send_docmd P((char *)),
  253.     send_dontcmd P((char *)),
  254.     send_willcmd P((char *)),
  255.     send_wontcmd P((char *));
  256.  
  257. static struct sendlist Sendlist[] = {
  258.     { "ao",    "Send Telnet Abort output",        1, 0, 0, 2, AO },
  259.     { "ayt",    "Send Telnet 'Are You There'",        1, 0, 0, 2, AYT },
  260.     { "brk",    "Send Telnet Break",            1, 0, 0, 2, BREAK },
  261.     { "break",    0,                    1, 0, 0, 2, BREAK },
  262.     { "ec",    "Send Telnet Erase Character",        1, 0, 0, 2, EC },
  263.     { "el",    "Send Telnet Erase Line",        1, 0, 0, 2, EL },
  264.     { "escape",    "Send current escape character",    1, 0, send_esc, 1, 0 },
  265.     { "ga",    "Send Telnet 'Go Ahead' sequence",    1, 0, 0, 2, GA },
  266.     { "ip",    "Send Telnet Interrupt Process",    1, 0, 0, 2, IP },
  267.     { "intp",    0,                    1, 0, 0, 2, IP },
  268.     { "interrupt", 0,                    1, 0, 0, 2, IP },
  269.     { "intr",    0,                    1, 0, 0, 2, IP },
  270.     { "nop",    "Send Telnet 'No operation'",        1, 0, 0, 2, NOP },
  271.     { "eor",    "Send Telnet 'End of Record'",        1, 0, 0, 2, EOR },
  272.     { "abort",    "Send Telnet 'Abort Process'",        1, 0, 0, 2, ABORT },
  273.     { "susp",    "Send Telnet 'Suspend Process'",    1, 0, 0, 2, SUSP },
  274.     { "eof",    "Send Telnet End of File Character",    1, 0, 0, 2, xEOF },
  275.     { "synch",    "Perform Telnet 'Synch operation'",    1, 0, dosynch, 2, 0 },
  276.     { "getstatus", "Send request for STATUS",        1, 0, get_status, 6, 0 },
  277.     { "?",    "Display send options",            0, 0, send_help, 0, 0 },
  278.     { "help",    0,                    0, 0, send_help, 0, 0 },
  279.     { "do",    0,                    0, 1, send_docmd, 3, 0 },
  280.     { "dont",    0,                    0, 1, send_dontcmd, 3, 0 },
  281.     { "will",    0,                    0, 1, send_willcmd, 3, 0 },
  282.     { "wont",    0,                    0, 1, send_wontcmd, 3, 0 },
  283.     { 0 }
  284. };
  285.  
  286. #define    GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
  287.                 sizeof(struct sendlist)))
  288.  
  289.     static int
  290. sendcmd(argc, argv)
  291.     int  argc;
  292.     char **argv;
  293. {
  294.     int what;        /* what we are sending this time */
  295.     int count;        /* how many bytes we are going to need to send */
  296.     int i;
  297.     int question = 0;    /* was at least one argument a question */
  298.     struct sendlist *s;    /* pointer to current command */
  299.     int success = 0;
  300.     int needconnect = 0;
  301.  
  302.     if (argc < 2) {
  303.     printf("need at least one argument for 'send' command\n");
  304.     printf("'send ?' for help\n");
  305.     return 0;
  306.     }
  307.     /*
  308.      * First, validate all the send arguments.
  309.      * In addition, we see how much space we are going to need, and
  310.      * whether or not we will be doing a "SYNCH" operation (which
  311.      * flushes the network queue).
  312.      */
  313.     count = 0;
  314.     for (i = 1; i < argc; i++) {
  315.     s = GETSEND(argv[i]);
  316.     if (s == 0) {
  317.         printf("Unknown send argument '%s'\n'send ?' for help.\n",
  318.             argv[i]);
  319.         return 0;
  320.     } else if (Ambiguous(s)) {
  321.         printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
  322.             argv[i]);
  323.         return 0;
  324.     }
  325.     if (i + s->narg >= argc) {
  326.         fprintf(stderr,
  327.         "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
  328.         s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
  329.         return 0;
  330.     }
  331.     count += s->nbyte;
  332.     if (s->handler == send_help) {
  333.         send_help();
  334.         return 0;
  335.     }
  336.  
  337.     i += s->narg;
  338.     needconnect += s->needconnect;
  339.     }
  340.     if (!connected && needconnect) {
  341.     printf("?Need to be connected first.\n");
  342.     printf("'send ?' for help\n");
  343.     return 0;
  344.     }
  345.     /* Now, do we have enough room? */
  346.     if (NETROOM() < count) {
  347.     printf("There is not enough room in the buffer TO the network\n");
  348.     printf("to process your request.  Nothing will be done.\n");
  349.     printf("('send synch' will throw away most data in the network\n");
  350.     printf("buffer, if this might help.)\n");
  351.     return 0;
  352.     }
  353.     /* OK, they are all OK, now go through again and actually send */
  354.     count = 0;
  355.     for (i = 1; i < argc; i++) {
  356.     if ((s = GETSEND(argv[i])) == 0) {
  357.         fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
  358.         (void) quit();
  359.         /*NOTREACHED*/
  360.     }
  361.     if (s->handler) {
  362.         count++;
  363.         success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
  364.                   (s->narg > 1) ? argv[i+2] : 0);
  365.         i += s->narg;
  366.     } else {
  367.         NET2ADD(IAC, what);
  368.         printoption("SENT", IAC, what);
  369.     }
  370.     }
  371.     return (count == success);
  372. }
  373.  
  374.     static int
  375. send_esc()
  376. {
  377.     NETADD(escape);
  378.     return 1;
  379. }
  380.  
  381.     static int
  382. send_docmd(name)
  383.     char *name;
  384. {
  385.     void send_do();
  386.     return(send_tncmd(send_do, "do", name));
  387. }
  388.  
  389.     static int
  390. send_dontcmd(name)
  391.     char *name;
  392. {
  393.     void send_dont();
  394.     return(send_tncmd(send_dont, "dont", name));
  395. }
  396.     static int
  397. send_willcmd(name)
  398.     char *name;
  399. {
  400.     void send_will();
  401.     return(send_tncmd(send_will, "will", name));
  402. }
  403.     static int
  404. send_wontcmd(name)
  405.     char *name;
  406. {
  407.     void send_wont();
  408.     return(send_tncmd(send_wont, "wont", name));
  409. }
  410.  
  411.     int
  412. send_tncmd(func, cmd, name)
  413.     void    (*func)();
  414.     char    *cmd, *name;
  415. {
  416.     char **cpp;
  417.     extern char *telopts[];
  418.  
  419.     if (isprefix(name, "help") || isprefix(name, "?")) {
  420.     register int col, len;
  421.  
  422.     printf("Usage: send %s <option>\n", cmd);
  423.     printf("Valid options are:\n\t");
  424.  
  425.     col = 8;
  426.     for (cpp = telopts; *cpp; cpp++) {
  427.         len = strlen(*cpp) + 1;
  428.         if (col + len > 65) {
  429.         printf("\n\t");
  430.         col = 8;
  431.         }
  432.         printf(" %s", *cpp);
  433.         col += len;
  434.     }
  435.     printf("\n");
  436.     return 0;
  437.     }
  438.     cpp = (char **)genget(name, telopts, sizeof(char *));
  439.     if (Ambiguous(cpp)) {
  440.     fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
  441.                     name, cmd);
  442.     return 0;
  443.     }
  444.     if (cpp == 0) {
  445.     fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
  446.                     name, cmd);
  447.     return 0;
  448.     }
  449.     if (!connected) {
  450.     printf("?Need to be connected first.\n");
  451.     return 0;
  452.     }
  453.     (*func)(cpp - telopts, 1);
  454.     return 1;
  455. }
  456.  
  457.     static int
  458. send_help()
  459. {
  460.     struct sendlist *s;    /* pointer to current command */
  461.     for (s = Sendlist; s->name; s++) {
  462.     if (s->help)
  463.         printf("%-15s %s\n", s->name, s->help);
  464.     }
  465.     return(0);
  466. }
  467.  
  468. /*
  469.  * The following are the routines and data structures referred
  470.  * to by the arguments to the "toggle" command.
  471.  */
  472.  
  473.     static int
  474. lclchars()
  475. {
  476.     donelclchars = 1;
  477.     return 1;
  478. }
  479.  
  480.     static int
  481. togdebug()
  482. {
  483. #ifndef    NOT43
  484.     if (net > 0 &&
  485.     (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
  486.         perror("setsockopt (SO_DEBUG)");
  487.     }
  488. #else    /* NOT43 */
  489.     if (debug) {
  490.     if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
  491.         perror("setsockopt (SO_DEBUG)");
  492.     } else
  493.     printf("Cannot turn off socket debugging\n");
  494. #endif    /* NOT43 */
  495.     return 1;
  496. }
  497.  
  498.  
  499.     static int
  500. togcrlf()
  501. {
  502.     if (crlf) {
  503.     printf("Will send carriage returns as telnet <CR><LF>.\n");
  504.     } else {
  505.     printf("Will send carriage returns as telnet <CR><NUL>.\n");
  506.     }
  507.     return 1;
  508. }
  509.  
  510. int binmode;
  511.  
  512.     static int
  513. togbinary(val)
  514.     int val;
  515. {
  516.     donebinarytoggle = 1;
  517.  
  518.     if (val >= 0) {
  519.     binmode = val;
  520.     } else {
  521.     if (my_want_state_is_will(TELOPT_BINARY) &&
  522.                 my_want_state_is_do(TELOPT_BINARY)) {
  523.         binmode = 1;
  524.     } else if (my_want_state_is_wont(TELOPT_BINARY) &&
  525.                 my_want_state_is_dont(TELOPT_BINARY)) {
  526.         binmode = 0;
  527.     }
  528.     val = binmode ? 0 : 1;
  529.     }
  530.  
  531.     if (val == 1) {
  532.     if (my_want_state_is_will(TELOPT_BINARY) &&
  533.                     my_want_state_is_do(TELOPT_BINARY)) {
  534.         printf("Already operating in binary mode with remote host.\n");
  535.     } else {
  536.         printf("Negotiating binary mode with remote host.\n");
  537.         tel_enter_binary(3);
  538.     }
  539.     } else {
  540.     if (my_want_state_is_wont(TELOPT_BINARY) &&
  541.                     my_want_state_is_dont(TELOPT_BINARY)) {
  542.         printf("Already in network ascii mode with remote host.\n");
  543.     } else {
  544.         printf("Negotiating network ascii mode with remote host.\n");
  545.         tel_leave_binary(3);
  546.     }
  547.     }
  548.     return 1;
  549. }
  550.  
  551.     static int
  552. togrbinary(val)
  553.     int val;
  554. {
  555.     donebinarytoggle = 1;
  556.  
  557.     if (val == -1)
  558.     val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
  559.  
  560.     if (val == 1) {
  561.     if (my_want_state_is_do(TELOPT_BINARY)) {
  562.         printf("Already receiving in binary mode.\n");
  563.     } else {
  564.         printf("Negotiating binary mode on input.\n");
  565.         tel_enter_binary(1);
  566.     }
  567.     } else {
  568.     if (my_want_state_is_dont(TELOPT_BINARY)) {
  569.         printf("Already receiving in network ascii mode.\n");
  570.     } else {
  571.         printf("Negotiating network ascii mode on input.\n");
  572.         tel_leave_binary(1);
  573.     }
  574.     }
  575.     return 1;
  576. }
  577.  
  578.     static int
  579. togxbinary(val)
  580.     int val;
  581. {
  582.     donebinarytoggle = 1;
  583.  
  584.     if (val == -1)
  585.     val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
  586.  
  587.     if (val == 1) {
  588.     if (my_want_state_is_will(TELOPT_BINARY)) {
  589.         printf("Already transmitting in binary mode.\n");
  590.     } else {
  591.         printf("Negotiating binary mode on output.\n");
  592.         tel_enter_binary(2);
  593.     }
  594.     } else {
  595.     if (my_want_state_is_wont(TELOPT_BINARY)) {
  596.         printf("Already transmitting in network ascii mode.\n");
  597.     } else {
  598.         printf("Negotiating network ascii mode on output.\n");
  599.         tel_leave_binary(2);
  600.     }
  601.     }
  602.     return 1;
  603. }
  604.  
  605.  
  606. extern int togglehelp P((void));
  607. #if    defined(AUTHENTICATE)
  608. extern int auth_togdebug P((int));
  609. #endif
  610. #if    defined(ENCRYPT)
  611. extern int EncryptAutoEnc P((int));
  612. extern int EncryptAutoDec P((int));
  613. extern int EncryptDebug P((int));
  614. extern int EncryptVerbose P((int));
  615. #endif
  616.  
  617. struct togglelist {
  618.     char    *name;        /* name of toggle */
  619.     char    *help;        /* help message */
  620.     int        (*handler)();    /* routine to do actual setting */
  621.     int        *variable;
  622.     char    *actionexplanation;
  623. };
  624.  
  625. static struct togglelist Togglelist[] = {
  626.     { "autoflush",
  627.     "flushing of output when sending interrupt characters",
  628.         0,
  629.         &autoflush,
  630.             "flush output when sending interrupt characters" },
  631.     { "autosynch",
  632.     "automatic sending of interrupt characters in urgent mode",
  633.         0,
  634.         &autosynch,
  635.             "send interrupt characters in urgent mode" },
  636. #if    defined(AUTHENTICATE)
  637.     { "autologin",
  638.     "automatic sending of login and/or authentication info",
  639.         0,
  640.         &autologin,
  641.             "send login name and/or authentication information" },
  642.     { "authdebug",
  643.     "Toggle authentication debugging",
  644.         auth_togdebug,
  645.         0,
  646.              "print authentication debugging information" },
  647. #endif
  648. #if    defined(ENCRYPT)
  649.     { "autoencrypt",
  650.     "automatic encryption of data stream",
  651.         EncryptAutoEnc,
  652.         0,
  653.             "automatically encrypt output" },
  654.     { "autodecrypt",
  655.     "automatic decryption of data stream",
  656.         EncryptAutoDec,
  657.         0,
  658.             "automatically decrypt input" },
  659.     { "verbose_encrypt",
  660.     "Toggle verbose encryption output",
  661.         EncryptVerbose,
  662.         0,
  663.             "print verbose encryption output" },
  664.     { "encdebug",
  665.     "Toggle encryption debugging",
  666.         EncryptDebug,
  667.         0,
  668.             "print encryption debugging information" },
  669. #endif
  670.     { "skiprc",
  671.     "don't read ~/.telnetrc file",
  672.         0,
  673.         &skiprc,
  674.             "read ~/.telnetrc file" },
  675.     { "binary",
  676.     "sending and receiving of binary data",
  677.         togbinary,
  678.         0,
  679.             0 },
  680.     { "inbinary",
  681.     "receiving of binary data",
  682.         togrbinary,
  683.         0,
  684.             0 },
  685.     { "outbinary",
  686.     "sending of binary data",
  687.         togxbinary,
  688.         0,
  689.             0 },
  690.     { "crlf",
  691.     "sending carriage returns as telnet <CR><LF>",
  692.         togcrlf,
  693.         &crlf,
  694.             0 },
  695.     { "crmod",
  696.     "mapping of received carriage returns",
  697.         0,
  698.         &crmod,
  699.             "map carriage return on output" },
  700.     { "localchars",
  701.     "local recognition of certain control characters",
  702.         lclchars,
  703.         &localchars,
  704.             "recognize certain control characters" },
  705.     { " ", "", 0 },        /* empty line */
  706. #if    defined(unix) && defined(TN3270)
  707.     { "apitrace",
  708.     "(debugging) toggle tracing of API transactions",
  709.         0,
  710.         &apitrace,
  711.             "trace API transactions" },
  712.     { "cursesdata",
  713.     "(debugging) toggle printing of hexadecimal curses data",
  714.         0,
  715.         &cursesdata,
  716.             "print hexadecimal representation of curses data" },
  717. #endif    /* defined(unix) && defined(TN3270) */
  718.     { "debug",
  719.     "debugging",
  720.         togdebug,
  721.         &debug,
  722.             "turn on socket level debugging" },
  723.     { "netdata",
  724.     "printing of hexadecimal network data (debugging)",
  725.         0,
  726.         &netdata,
  727.             "print hexadecimal representation of network traffic" },
  728.     { "prettydump",
  729.     "output of \"netdata\" to user readable format (debugging)",
  730.         0,
  731.         &prettydump,
  732.             "print user readable output for \"netdata\"" },
  733.     { "options",
  734.     "viewing of options processing (debugging)",
  735.         0,
  736.         &showoptions,
  737.             "show option processing" },
  738. #if    defined(unix)
  739.     { "termdata",
  740.     "(debugging) toggle printing of hexadecimal terminal data",
  741.         0,
  742.         &termdata,
  743.             "print hexadecimal representation of terminal traffic" },
  744. #endif    /* defined(unix) */
  745.     { "?",
  746.     0,
  747.         togglehelp },
  748.     { "help",
  749.     0,
  750.         togglehelp },
  751.     { 0 }
  752. };
  753.  
  754.     static int
  755. togglehelp()
  756. {
  757.     struct togglelist *c;
  758.  
  759.     for (c = Togglelist; c->name; c++) {
  760.     if (c->help) {
  761.         if (*c->help)
  762.         printf("%-15s toggle %s\n", c->name, c->help);
  763.         else
  764.         printf("\n");
  765.     }
  766.     }
  767.     printf("\n");
  768.     printf("%-15s %s\n", "?", "display help information");
  769.     return 0;
  770. }
  771.  
  772.     static void
  773. settogglehelp(set)
  774.     int set;
  775. {
  776.     struct togglelist *c;
  777.  
  778.     for (c = Togglelist; c->name; c++) {
  779.     if (c->help) {
  780.         if (*c->help)
  781.         printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
  782.                         c->help);
  783.         else
  784.         printf("\n");
  785.     }
  786.     }
  787. }
  788.  
  789. #define    GETTOGGLE(name) (struct togglelist *) \
  790.         genget(name, (char **) Togglelist, sizeof(struct togglelist))
  791.  
  792.     static int
  793. toggle(argc, argv)
  794.     int  argc;
  795.     char *argv[];
  796. {
  797.     int retval = 1;
  798.     char *name;
  799.     struct togglelist *c;
  800.  
  801.     if (argc < 2) {
  802.     fprintf(stderr,
  803.         "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
  804.     return 0;
  805.     }
  806.     argc--;
  807.     argv++;
  808.     while (argc--) {
  809.     name = *argv++;
  810.     c = GETTOGGLE(name);
  811.     if (Ambiguous(c)) {
  812.         fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
  813.                     name);
  814.         return 0;
  815.     } else if (c == 0) {
  816.         fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
  817.                     name);
  818.         return 0;
  819.     } else {
  820.         if (c->variable) {
  821.         *c->variable = !*c->variable;        /* invert it */
  822.         if (c->actionexplanation) {
  823.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  824.                             c->actionexplanation);
  825.         }
  826.         }
  827.         if (c->handler) {
  828.         retval &= (*c->handler)(-1);
  829.         }
  830.     }
  831.     }
  832.     return retval;
  833. }
  834.  
  835. /*
  836.  * The following perform the "set" command.
  837.  */
  838.  
  839. #ifdef    USE_TERMIO
  840. struct termio new_tc = { 0 };
  841. #endif
  842.  
  843. struct setlist {
  844.     char *name;                /* name */
  845.     char *help;                /* help information */
  846.     void (*handler)();
  847.     cc_t *charp;            /* where it is located at */
  848. };
  849.  
  850. static struct setlist Setlist[] = {
  851. #ifdef    KLUDGELINEMODE
  852.     { "echo",     "character to toggle local echoing on/off", 0, &echoc },
  853. #endif
  854.     { "escape",    "character to escape back to telnet command mode", 0, &escape },
  855.     { "rlogin", "rlogin escape character", 0, &rlogin },
  856.     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
  857.     { " ", "" },
  858.     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
  859.     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
  860.     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
  861.     { "quit",    "character to cause an Abort process", 0, termQuitCharp },
  862.     { "eof",    "character to cause an EOF ", 0, termEofCharp },
  863.     { " ", "" },
  864.     { " ", "The following are for local editing in linemode", 0, 0 },
  865.     { "erase",    "character to use to erase a character", 0, termEraseCharp },
  866.     { "kill",    "character to use to erase a line", 0, termKillCharp },
  867.     { "lnext",    "character to use for literal next", 0, termLiteralNextCharp },
  868.     { "susp",    "character to cause a Suspend Process", 0, termSuspCharp },
  869.     { "reprint", "character to use for line reprint", 0, termRprntCharp },
  870.     { "worderase", "character to use to erase a word", 0, termWerasCharp },
  871.     { "start",    "character to use for XON", 0, termStartCharp },
  872.     { "stop",    "character to use for XOFF", 0, termStopCharp },
  873.     { "forw1",    "alternate end of line character", 0, termForw1Charp },
  874.     { "forw2",    "alternate end of line character", 0, termForw2Charp },
  875.     { "ayt",    "alternate AYT character", 0, termAytCharp },
  876.     { 0 }
  877. };
  878.  
  879. #if    defined(CRAY) && !defined(__STDC__)
  880. /* Work around compiler bug in pcc 4.1.5 */
  881.     void
  882. _setlist_init()
  883. {
  884. #ifndef    KLUDGELINEMODE
  885. #define    N 5
  886. #else
  887. #define    N 6
  888. #endif
  889.     Setlist[N+0].charp = &termFlushChar;
  890.     Setlist[N+1].charp = &termIntChar;
  891.     Setlist[N+2].charp = &termQuitChar;
  892.     Setlist[N+3].charp = &termEofChar;
  893.     Setlist[N+6].charp = &termEraseChar;
  894.     Setlist[N+7].charp = &termKillChar;
  895.     Setlist[N+8].charp = &termLiteralNextChar;
  896.     Setlist[N+9].charp = &termSuspChar;
  897.     Setlist[N+10].charp = &termRprntChar;
  898.     Setlist[N+11].charp = &termWerasChar;
  899.     Setlist[N+12].charp = &termStartChar;
  900.     Setlist[N+13].charp = &termStopChar;
  901.     Setlist[N+14].charp = &termForw1Char;
  902.     Setlist[N+15].charp = &termForw2Char;
  903.     Setlist[N+16].charp = &termAytChar;
  904. #undef    N
  905. }
  906. #endif    /* defined(CRAY) && !defined(__STDC__) */
  907.  
  908.     static struct setlist *
  909. getset(name)
  910.     char *name;
  911. {
  912.     return (struct setlist *)
  913.         genget(name, (char **) Setlist, sizeof(struct setlist));
  914. }
  915.  
  916.     void
  917. set_escape_char(s)
  918.     char *s;
  919. {
  920.     if (rlogin != _POSIX_VDISABLE) {
  921.         rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
  922.         printf("Telnet rlogin escape character is '%s'.\n",
  923.                     control(rlogin));
  924.     } else {
  925.         escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
  926.         printf("Telnet escape character is '%s'.\n", control(escape));
  927.     }
  928. }
  929.  
  930.     static int
  931. setcmd(argc, argv)
  932.     int  argc;
  933.     char *argv[];
  934. {
  935.     int value;
  936.     struct setlist *ct;
  937.     struct togglelist *c;
  938.  
  939.     if (argc < 2 || argc > 3) {
  940.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  941.     return 0;
  942.     }
  943.     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
  944.     for (ct = Setlist; ct->name; ct++)
  945.         printf("%-15s %s\n", ct->name, ct->help);
  946.     printf("\n");
  947.     settogglehelp(1);
  948.     printf("%-15s %s\n", "?", "display help information");
  949.     return 0;
  950.     }
  951.  
  952.     ct = getset(argv[1]);
  953.     if (ct == 0) {
  954.     c = GETTOGGLE(argv[1]);
  955.     if (c == 0) {
  956.         fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
  957.             argv[1]);
  958.         return 0;
  959.     } else if (Ambiguous(c)) {
  960.         fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  961.             argv[1]);
  962.         return 0;
  963.     }
  964.     if (c->variable) {
  965.         if ((argc == 2) || (strcmp("on", argv[2]) == 0))
  966.         *c->variable = 1;
  967.         else if (strcmp("off", argv[2]) == 0)
  968.         *c->variable = 0;
  969.         else {
  970.         printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
  971.         return 0;
  972.         }
  973.         if (c->actionexplanation) {
  974.         printf("%s %s.\n", *c->variable? "Will" : "Won't",
  975.                             c->actionexplanation);
  976.         }
  977.     }
  978.     if (c->handler)
  979.         (*c->handler)(1);
  980.     } else if (argc != 3) {
  981.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  982.     return 0;
  983.     } else if (Ambiguous(ct)) {
  984.     fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  985.             argv[1]);
  986.     return 0;
  987.     } else if (ct->handler) {
  988.     (*ct->handler)(argv[2]);
  989.     printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
  990.     } else {
  991.     if (strcmp("off", argv[2])) {
  992.         value = special(argv[2]);
  993.     } else {
  994.         value = _POSIX_VDISABLE;
  995.     }
  996.     *(ct->charp) = (cc_t)value;
  997.     printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  998.     }
  999.     slc_check();
  1000.     return 1;
  1001. }
  1002.  
  1003.     static int
  1004. unsetcmd(argc, argv)
  1005.     int  argc;
  1006.     char *argv[];
  1007. {
  1008.     struct setlist *ct;
  1009.     struct togglelist *c;
  1010.     register char *name;
  1011.  
  1012.     if (argc < 2) {
  1013.     fprintf(stderr,
  1014.         "Need an argument to 'unset' command.  'unset ?' for help.\n");
  1015.     return 0;
  1016.     }
  1017.     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
  1018.     for (ct = Setlist; ct->name; ct++)
  1019.         printf("%-15s %s\n", ct->name, ct->help);
  1020.     printf("\n");
  1021.     settogglehelp(0);
  1022.     printf("%-15s %s\n", "?", "display help information");
  1023.     return 0;
  1024.     }
  1025.  
  1026.     argc--;
  1027.     argv++;
  1028.     while (argc--) {
  1029.     name = *argv++;
  1030.     ct = getset(name);
  1031.     if (ct == 0) {
  1032.         c = GETTOGGLE(name);
  1033.         if (c == 0) {
  1034.         fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
  1035.             name);
  1036.         return 0;
  1037.         } else if (Ambiguous(c)) {
  1038.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  1039.             name);
  1040.         return 0;
  1041.         }
  1042.         if (c->variable) {
  1043.         *c->variable = 0;
  1044.         if (c->actionexplanation) {
  1045.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  1046.                             c->actionexplanation);
  1047.         }
  1048.         }
  1049.         if (c->handler)
  1050.         (*c->handler)(0);
  1051.     } else if (Ambiguous(ct)) {
  1052.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  1053.             name);
  1054.         return 0;
  1055.     } else if (ct->handler) {
  1056.         (*ct->handler)(0);
  1057.         printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
  1058.     } else {
  1059.         *(ct->charp) = _POSIX_VDISABLE;
  1060.         printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  1061.     }
  1062.     }
  1063.     return 1;
  1064. }
  1065.  
  1066. /*
  1067.  * The following are the data structures and routines for the
  1068.  * 'mode' command.
  1069.  */
  1070. #ifdef    KLUDGELINEMODE
  1071. extern int kludgelinemode;
  1072.  
  1073.     static int
  1074. dokludgemode()
  1075. {
  1076.     kludgelinemode = 1;
  1077.     send_wont(TELOPT_LINEMODE, 1);
  1078.     send_dont(TELOPT_SGA, 1);
  1079.     send_dont(TELOPT_ECHO, 1);
  1080. }
  1081. #endif
  1082.  
  1083.     static int
  1084. dolinemode()
  1085. {
  1086. #ifdef    KLUDGELINEMODE
  1087.     if (kludgelinemode)
  1088.     send_dont(TELOPT_SGA, 1);
  1089. #endif
  1090.     send_will(TELOPT_LINEMODE, 1);
  1091.     send_dont(TELOPT_ECHO, 1);
  1092.     return 1;
  1093. }
  1094.  
  1095.     static int
  1096. docharmode()
  1097. {
  1098. #ifdef    KLUDGELINEMODE
  1099.     if (kludgelinemode)
  1100.     send_do(TELOPT_SGA, 1);
  1101.     else
  1102. #endif
  1103.     send_wont(TELOPT_LINEMODE, 1);
  1104.     send_do(TELOPT_ECHO, 1);
  1105.     return 1;
  1106. }
  1107.  
  1108.     static int
  1109. dolmmode(bit, on)
  1110.     int bit, on;
  1111. {
  1112.     unsigned char c;
  1113.     extern int linemode;
  1114.  
  1115.     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
  1116.     printf("?Need to have LINEMODE option enabled first.\n");
  1117.     printf("'mode ?' for help.\n");
  1118.     return 0;
  1119.     }
  1120.  
  1121.     if (on)
  1122.     c = (linemode | bit);
  1123.     else
  1124.     c = (linemode & ~bit);
  1125.     lm_mode(&c, 1, 1);
  1126.     return 1;
  1127. }
  1128.  
  1129.     int
  1130. setmode(bit)
  1131. {
  1132.     return dolmmode(bit, 1);
  1133. }
  1134.  
  1135.     int
  1136. clearmode(bit)
  1137. {
  1138.     return dolmmode(bit, 0);
  1139. }
  1140.  
  1141. struct modelist {
  1142.     char    *name;        /* command name */
  1143.     char    *help;        /* help string */
  1144.     int    (*handler)();    /* routine which executes command */
  1145.     int    needconnect;    /* Do we need to be connected to execute? */
  1146.     int    arg1;
  1147. };
  1148.  
  1149. extern int modehelp();
  1150.  
  1151. static struct modelist ModeList[] = {
  1152.     { "character", "Disable LINEMODE option",    docharmode, 1 },
  1153. #ifdef    KLUDGELINEMODE
  1154.     { "",    "(or disable obsolete line-by-line mode)", 0 },
  1155. #endif
  1156.     { "line",    "Enable LINEMODE option",    dolinemode, 1 },
  1157. #ifdef    KLUDGELINEMODE
  1158.     { "",    "(or enable obsolete line-by-line mode)", 0 },
  1159. #endif
  1160.     { "", "", 0 },
  1161.     { "",    "These require the LINEMODE option to be enabled", 0 },
  1162.     { "isig",    "Enable signal trapping",    setmode, 1, MODE_TRAPSIG },
  1163.     { "+isig",    0,                setmode, 1, MODE_TRAPSIG },
  1164.     { "-isig",    "Disable signal trapping",    clearmode, 1, MODE_TRAPSIG },
  1165.     { "edit",    "Enable character editing",    setmode, 1, MODE_EDIT },
  1166.     { "+edit",    0,                setmode, 1, MODE_EDIT },
  1167.     { "-edit",    "Disable character editing",    clearmode, 1, MODE_EDIT },
  1168.     { "softtabs", "Enable tab expansion",    setmode, 1, MODE_SOFT_TAB },
  1169.     { "+softtabs", 0,                setmode, 1, MODE_SOFT_TAB },
  1170.     { "-softtabs", "Disable character editing",    clearmode, 1, MODE_SOFT_TAB },
  1171.     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
  1172.     { "+litecho", 0,                setmode, 1, MODE_LIT_ECHO },
  1173.     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
  1174.     { "help",    0,                modehelp, 0 },
  1175. #ifdef    KLUDGELINEMODE
  1176.     { "kludgeline", 0,                dokludgemode, 1 },
  1177. #endif
  1178.     { "", "", 0 },
  1179.     { "?",    "Print help information",    modehelp, 0 },
  1180.     { 0 },
  1181. };
  1182.  
  1183.  
  1184.     int
  1185. modehelp()
  1186. {
  1187.     struct modelist *mt;
  1188.  
  1189.     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
  1190.     for (mt = ModeList; mt->name; mt++) {
  1191.     if (mt->help) {
  1192.         if (*mt->help)
  1193.         printf("%-15s %s\n", mt->name, mt->help);
  1194.         else
  1195.         printf("\n");
  1196.     }
  1197.     }
  1198.     return 0;
  1199. }
  1200.  
  1201. #define    GETMODECMD(name) (struct modelist *) \
  1202.         genget(name, (char **) ModeList, sizeof(struct modelist))
  1203.  
  1204.     static int
  1205. modecmd(argc, argv)
  1206.     int  argc;
  1207.     char *argv[];
  1208. {
  1209.     struct modelist *mt;
  1210.  
  1211.     if (argc != 2) {
  1212.     printf("'mode' command requires an argument\n");
  1213.     printf("'mode ?' for help.\n");
  1214.     } else if ((mt = GETMODECMD(argv[1])) == 0) {
  1215.     fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
  1216.     } else if (Ambiguous(mt)) {
  1217.     fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
  1218.     } else if (mt->needconnect && !connected) {
  1219.     printf("?Need to be connected first.\n");
  1220.     printf("'mode ?' for help.\n");
  1221.     } else if (mt->handler) {
  1222.     return (*mt->handler)(mt->arg1);
  1223.     }
  1224.     return 0;
  1225. }
  1226.  
  1227. /*
  1228.  * The following data structures and routines implement the
  1229.  * "display" command.
  1230.  */
  1231.  
  1232.     static int
  1233. display(argc, argv)
  1234.     int  argc;
  1235.     char *argv[];
  1236. {
  1237.     struct togglelist *tl;
  1238.     struct setlist *sl;
  1239.  
  1240. #define    dotog(tl)    if (tl->variable && tl->actionexplanation) { \
  1241.                 if (*tl->variable) { \
  1242.                 printf("will"); \
  1243.                 } else { \
  1244.                 printf("won't"); \
  1245.                 } \
  1246.                 printf(" %s.\n", tl->actionexplanation); \
  1247.             }
  1248.  
  1249. #define    doset(sl)   if (sl->name && *sl->name != ' ') { \
  1250.             if (sl->handler == 0) \
  1251.                 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
  1252.             else \
  1253.                 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
  1254.             }
  1255.  
  1256.     if (argc == 1) {
  1257.     for (tl = Togglelist; tl->name; tl++) {
  1258.         dotog(tl);
  1259.     }
  1260.     printf("\n");
  1261.     for (sl = Setlist; sl->name; sl++) {
  1262.         doset(sl);
  1263.     }
  1264.     } else {
  1265.     int i;
  1266.  
  1267.     for (i = 1; i < argc; i++) {
  1268.         sl = getset(argv[i]);
  1269.         tl = GETTOGGLE(argv[i]);
  1270.         if (Ambiguous(sl) || Ambiguous(tl)) {
  1271.         printf("?Ambiguous argument '%s'.\n", argv[i]);
  1272.         return 0;
  1273.         } else if (!sl && !tl) {
  1274.         printf("?Unknown argument '%s'.\n", argv[i]);
  1275.         return 0;
  1276.         } else {
  1277.         if (tl) {
  1278.             dotog(tl);
  1279.         }
  1280.         if (sl) {
  1281.             doset(sl);
  1282.         }
  1283.         }
  1284.     }
  1285.     }
  1286. /*@*/optionstatus();
  1287. #if    defined(ENCRYPT)
  1288.     EncryptStatus();
  1289. #endif
  1290.     return 1;
  1291. #undef    doset
  1292. #undef    dotog
  1293. }
  1294.  
  1295. /*
  1296.  * The following are the data structures, and many of the routines,
  1297.  * relating to command processing.
  1298.  */
  1299.  
  1300. /*
  1301.  * Set the escape character.
  1302.  */
  1303.     static int
  1304. setescape(argc, argv)
  1305.     int argc;
  1306.     char *argv[];
  1307. {
  1308.     register char *arg;
  1309.     char buf[50];
  1310.  
  1311.     printf(
  1312.         "Deprecated usage - please use 'set escape%s%s' in the future.\n",
  1313.                 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
  1314.     if (argc > 2)
  1315.         arg = argv[1];
  1316.     else {
  1317.         printf("new escape character: ");
  1318.         (void) fgets(buf, sizeof(buf), stdin);
  1319.         arg = buf;
  1320.     }
  1321.     if (arg[0] != '\0')
  1322.         escape = arg[0];
  1323.     if (!In3270) {
  1324.         printf("Escape character is '%s'.\n", control(escape));
  1325.     }
  1326.     (void) fflush(stdout);
  1327.     return 1;
  1328. }
  1329.  
  1330.     /*VARARGS*/
  1331.     static int
  1332. togcrmod()
  1333. {
  1334.     crmod = !crmod;
  1335.     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
  1336.     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
  1337.     (void) fflush(stdout);
  1338.     return 1;
  1339. }
  1340.  
  1341.     /*VARARGS*/
  1342.     int
  1343. suspend()
  1344. {
  1345. #ifdef    SIGTSTP
  1346.     setcommandmode();
  1347.     {
  1348.     long oldrows, oldcols, newrows, newcols, err;
  1349.  
  1350.     err = TerminalWindowSize(&oldrows, &oldcols);
  1351.     (void) kill(0, SIGTSTP);
  1352.     err += TerminalWindowSize(&newrows, &newcols);
  1353.     if (connected && !err &&
  1354.         ((oldrows != newrows) || (oldcols != newcols))) {
  1355.         sendnaws();
  1356.     }
  1357.     }
  1358.     /* reget parameters in case they were changed */
  1359.     TerminalSaveState();
  1360.     setconnmode(0);
  1361. #else
  1362.     printf("Suspend is not supported.  Try the '!' command instead\n");
  1363. #endif
  1364.     return 1;
  1365. }
  1366.  
  1367. #if    !defined(TN3270)
  1368.     /*ARGSUSED*/
  1369.     int
  1370. shell(argc, argv)
  1371.     int argc;
  1372.     char *argv[];
  1373. {
  1374.     setcommandmode();
  1375.     switch(vfork()) {
  1376.     case -1:
  1377.     perror("Fork failed\n");
  1378.     break;
  1379.  
  1380.     case 0:
  1381.     {
  1382.         /*
  1383.          * Fire up the shell in the child.
  1384.          */
  1385.         register char *shellp, *shellname;
  1386.         extern char *rindex();
  1387.  
  1388.         shellp = getenv("SHELL");
  1389.         if (shellp == NULL)
  1390.         shellp = "/bin/sh";
  1391.         if ((shellname = rindex(shellp, '/')) == 0)
  1392.         shellname = shellp;
  1393.         else
  1394.         shellname++;
  1395.         if (argc > 1)
  1396.         execl(shellp, shellname, "-c", &saveline[1], 0);
  1397.         else
  1398.         execl(shellp, shellname, 0);
  1399.         perror("Execl");
  1400.         _exit(1);
  1401.     }
  1402.     default:
  1403.         (void)wait((int *)0);    /* Wait for the shell to complete */
  1404.     }
  1405.     return 1;
  1406. }
  1407. #endif    /* !defined(TN3270) */
  1408.  
  1409.     /*VARARGS*/
  1410.     static
  1411. bye(argc, argv)
  1412.     int  argc;        /* Number of arguments */
  1413.     char *argv[];    /* arguments */
  1414. {
  1415.     extern int resettermname;
  1416.  
  1417.     if (connected) {
  1418.     (void) shutdown(net, 2);
  1419.     printf("Connection closed.\n");
  1420.     (void) NetClose(net);
  1421.     connected = 0;
  1422.     resettermname = 1;
  1423. #if    defined(AUTHENTICATE) || defined(ENCRYPT)
  1424.     auth_encrypt_connect(connected);
  1425. #endif
  1426.     /* reset options */
  1427.     tninit();
  1428. #if    defined(TN3270)
  1429.     SetIn3270();        /* Get out of 3270 mode */
  1430. #endif    /* defined(TN3270) */
  1431.     }
  1432.     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
  1433.     longjmp(toplevel, 1);
  1434.     /* NOTREACHED */
  1435.     }
  1436.     return 1;            /* Keep lint, etc., happy */
  1437. }
  1438.  
  1439. /*VARARGS*/
  1440. quit()
  1441. {
  1442.     (void) call(bye, "bye", "fromquit", 0);
  1443.     Exit(0);
  1444.     /*NOTREACHED*/
  1445. }
  1446.  
  1447. /*VARARGS*/
  1448.     int
  1449. logout()
  1450. {
  1451.     send_do(TELOPT_LOGOUT, 1);
  1452.     (void) netflush();
  1453.     return 1;
  1454. }
  1455.  
  1456.  
  1457. /*
  1458.  * The SLC command.
  1459.  */
  1460.  
  1461. struct slclist {
  1462.     char    *name;
  1463.     char    *help;
  1464.     void    (*handler)();
  1465.     int    arg;
  1466. };
  1467.  
  1468. extern void slc_help();
  1469.  
  1470. struct slclist SlcList[] = {
  1471.     { "export",    "Use local special character definitions",
  1472.                         slc_mode_export,    0 },
  1473.     { "import",    "Use remote special character definitions",
  1474.                         slc_mode_import,    1 },
  1475.     { "check",    "Verify remote special character definitions",
  1476.                         slc_mode_import,    0 },
  1477.     { "help",    0,                slc_help,        0 },
  1478.     { "?",    "Print help information",    slc_help,        0 },
  1479.     { 0 },
  1480. };
  1481.  
  1482.     static void
  1483. slc_help()
  1484. {
  1485.     struct slclist *c;
  1486.  
  1487.     for (c = SlcList; c->name; c++) {
  1488.     if (c->help) {
  1489.         if (*c->help)
  1490.         printf("%-15s %s\n", c->name, c->help);
  1491.         else
  1492.         printf("\n");
  1493.     }
  1494.     }
  1495. }
  1496.  
  1497.     static struct slclist *
  1498. getslc(name)
  1499.     char *name;
  1500. {
  1501.     return (struct slclist *)
  1502.         genget(name, (char **) SlcList, sizeof(struct slclist));
  1503. }
  1504.  
  1505.     static
  1506. slccmd(argc, argv)
  1507.     int  argc;
  1508.     char *argv[];
  1509. {
  1510.     struct slclist *c;
  1511.  
  1512.     if (argc != 2) {
  1513.     fprintf(stderr,
  1514.         "Need an argument to 'slc' command.  'slc ?' for help.\n");
  1515.     return 0;
  1516.     }
  1517.     c = getslc(argv[1]);
  1518.     if (c == 0) {
  1519.         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
  1520.                     argv[1]);
  1521.         return 0;
  1522.     }
  1523.     if (Ambiguous(c)) {
  1524.         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
  1525.                     argv[1]);
  1526.         return 0;
  1527.     }
  1528.     (*c->handler)(c->arg);
  1529.     slcstate();
  1530.     return 1;
  1531. }
  1532.  
  1533. /*
  1534.  * The ENVIRON command.
  1535.  */
  1536.  
  1537. struct envlist {
  1538.     char    *name;
  1539.     char    *help;
  1540.     void    (*handler)();
  1541.     int    narg;
  1542. };
  1543.  
  1544. extern struct env_lst *
  1545.     env_define P((unsigned char *, unsigned char *));
  1546. extern void
  1547.     env_undefine P((unsigned char *)),
  1548.     env_export P((unsigned char *)),
  1549.     env_unexport P((unsigned char *)),
  1550.     env_send P((unsigned char *)),
  1551.     env_list P((void)),
  1552.     env_help P((void));
  1553.  
  1554. struct envlist EnvList[] = {
  1555.     { "define",    "Define an environment variable",
  1556.                         (void (*)())env_define,    2 },
  1557.     { "undefine", "Undefine an environment variable",
  1558.                         env_undefine,    1 },
  1559.     { "export",    "Mark an environment variable for automatic export",
  1560.                         env_export,    1 },
  1561.     { "unexport", "Don't mark an environment variable for automatic export",
  1562.                         env_unexport,    1 },
  1563.     { "send",    "Send an environment variable", env_send,    1 },
  1564.     { "list",    "List the current environment variables",
  1565.                         env_list,    0 },
  1566.     { "help",    0,                env_help,        0 },
  1567.     { "?",    "Print help information",    env_help,        0 },
  1568.     { 0 },
  1569. };
  1570.  
  1571.     static void
  1572. env_help()
  1573. {
  1574.     struct envlist *c;
  1575.  
  1576.     for (c = EnvList; c->name; c++) {
  1577.     if (c->help) {
  1578.         if (*c->help)
  1579.         printf("%-15s %s\n", c->name, c->help);
  1580.         else
  1581.         printf("\n");
  1582.     }
  1583.     }
  1584. }
  1585.  
  1586.     static struct envlist *
  1587. getenvcmd(name)
  1588.     char *name;
  1589. {
  1590.     return (struct envlist *)
  1591.         genget(name, (char **) EnvList, sizeof(struct envlist));
  1592. }
  1593.  
  1594. env_cmd(argc, argv)
  1595.     int  argc;
  1596.     char *argv[];
  1597. {
  1598.     struct envlist *c;
  1599.  
  1600.     if (argc < 2) {
  1601.     fprintf(stderr,
  1602.         "Need an argument to 'environ' command.  'environ ?' for help.\n");
  1603.     return 0;
  1604.     }
  1605.     c = getenvcmd(argv[1]);
  1606.     if (c == 0) {
  1607.         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
  1608.                     argv[1]);
  1609.         return 0;
  1610.     }
  1611.     if (Ambiguous(c)) {
  1612.         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
  1613.                     argv[1]);
  1614.         return 0;
  1615.     }
  1616.     if (c->narg + 2 != argc) {
  1617.     fprintf(stderr,
  1618.         "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
  1619.         c->narg < argc + 2 ? "only " : "",
  1620.         c->narg, c->narg == 1 ? "" : "s", c->name);
  1621.     return 0;
  1622.     }
  1623.     (*c->handler)(argv[2], argv[3]);
  1624.     return 1;
  1625. }
  1626.  
  1627. struct env_lst {
  1628.     struct env_lst *next;    /* pointer to next structure */
  1629.     struct env_lst *prev;    /* pointer to next structure */
  1630.     unsigned char *var;    /* pointer to variable name */
  1631.     unsigned char *value;    /* pointer to varialbe value */
  1632.     int export;        /* 1 -> export with default list of variables */
  1633. };
  1634.  
  1635. struct env_lst envlisthead;
  1636.  
  1637.     struct env_lst *
  1638. env_find(var)
  1639.     unsigned char *var;
  1640. {
  1641.     register struct env_lst *ep;
  1642.  
  1643.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1644.         if (strcmp((char *)ep->var, (char *)var) == 0)
  1645.             return(ep);
  1646.     }
  1647.     return(NULL);
  1648. }
  1649.  
  1650.     void
  1651. env_init()
  1652. {
  1653.     extern char **environ;
  1654.     register char **epp, *cp;
  1655.     register struct env_lst *ep;
  1656.     extern char *index();
  1657.  
  1658.     for (epp = environ; *epp; epp++) {
  1659.         if (cp = index(*epp, '=')) {
  1660.             *cp = '\0';
  1661.             ep = env_define((unsigned char *)*epp,
  1662.                     (unsigned char *)cp+1);
  1663.             ep->export = 0;
  1664.             *cp = '=';
  1665.         }
  1666.     }
  1667.     /*
  1668.      * Special case for DISPLAY variable.  If it is ":0.0" or
  1669.      * "unix:0.0", we have to get rid of "unix" and insert our
  1670.      * hostname.
  1671.      */
  1672.     if ((ep = env_find("DISPLAY"))
  1673.         && ((*ep->value == ':')
  1674.             || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
  1675.         char hbuf[256+1];
  1676.         char *cp2 = index((char *)ep->value, ':');
  1677.  
  1678.         gethostname(hbuf, 256);
  1679.         hbuf[256] = '\0';
  1680.         cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
  1681.         sprintf((char *)cp, "%s%s", hbuf, cp2);
  1682.         free(ep->value);
  1683.         ep->value = (unsigned char *)cp;
  1684.     }
  1685.     /*
  1686.      * If USER is not defined, but LOGNAME is, then add
  1687.      * USER with the value from LOGNAME.  By default, we
  1688.      * don't export the USER variable.
  1689.      */
  1690.     if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
  1691.         env_define((unsigned char *)"USER", ep->value);
  1692.         env_unexport((unsigned char *)"USER");
  1693.     }
  1694.     env_export((unsigned char *)"DISPLAY");
  1695.     env_export((unsigned char *)"PRINTER");
  1696. }
  1697.  
  1698.     struct env_lst *
  1699. env_define(var, value)
  1700.     unsigned char *var, *value;
  1701. {
  1702.     register struct env_lst *ep;
  1703.  
  1704.     if (ep = env_find(var)) {
  1705.         if (ep->var)
  1706.             free(ep->var);
  1707.         if (ep->value)
  1708.             free(ep->value);
  1709.     } else {
  1710.         ep = (struct env_lst *)malloc(sizeof(struct env_lst));
  1711.         ep->next = envlisthead.next;
  1712.         envlisthead.next = ep;
  1713.         ep->prev = &envlisthead;
  1714.         if (ep->next)
  1715.             ep->next->prev = ep;
  1716.     }
  1717.     ep->export = 1;
  1718.     ep->var = (unsigned char *)strdup((char *)var);
  1719.     ep->value = (unsigned char *)strdup((char *)value);
  1720.     return(ep);
  1721. }
  1722.  
  1723.     void
  1724. env_undefine(var)
  1725.     unsigned char *var;
  1726. {
  1727.     register struct env_lst *ep;
  1728.  
  1729.     if (ep = env_find(var)) {
  1730.         ep->prev->next = ep->next;
  1731.         if (ep->next)
  1732.             ep->next->prev = ep->prev;
  1733.         if (ep->var)
  1734.             free(ep->var);
  1735.         if (ep->value)
  1736.             free(ep->value);
  1737.         free(ep);
  1738.     }
  1739. }
  1740.  
  1741.     void
  1742. env_export(var)
  1743.     unsigned char *var;
  1744. {
  1745.     register struct env_lst *ep;
  1746.  
  1747.     if (ep = env_find(var))
  1748.         ep->export = 1;
  1749. }
  1750.  
  1751.     void
  1752. env_unexport(var)
  1753.     unsigned char *var;
  1754. {
  1755.     register struct env_lst *ep;
  1756.  
  1757.     if (ep = env_find(var))
  1758.         ep->export = 0;
  1759. }
  1760.  
  1761.     void
  1762. env_send(var)
  1763.     unsigned char *var;
  1764. {
  1765.     register struct env_lst *ep;
  1766.  
  1767.         if (my_state_is_wont(TELOPT_ENVIRON)) {
  1768.         fprintf(stderr,
  1769.             "Cannot send '%s': Telnet ENVIRON option not enabled\n",
  1770.                                     var);
  1771.         return;
  1772.     }
  1773.     ep = env_find(var);
  1774.     if (ep == 0) {
  1775.         fprintf(stderr, "Cannot send '%s': variable not defined\n",
  1776.                                     var);
  1777.         return;
  1778.     }
  1779.     env_opt_start_info();
  1780.     env_opt_add(ep->var);
  1781.     env_opt_end(0);
  1782. }
  1783.  
  1784.     void
  1785. env_list()
  1786. {
  1787.     register struct env_lst *ep;
  1788.  
  1789.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1790.         printf("%c %-20s %s\n", ep->export ? '*' : ' ',
  1791.                     ep->var, ep->value);
  1792.     }
  1793. }
  1794.  
  1795.     unsigned char *
  1796. env_default(init)
  1797.     int init;
  1798. {
  1799.     static struct env_lst *nep = NULL;
  1800.  
  1801.     if (init) {
  1802.         nep = &envlisthead;
  1803.         return;
  1804.     }
  1805.     if (nep) {
  1806.         while (nep = nep->next) {
  1807.             if (nep->export)
  1808.                 return(nep->var);
  1809.         }
  1810.     }
  1811.     return(NULL);
  1812. }
  1813.  
  1814.     unsigned char *
  1815. env_getvalue(var)
  1816.     unsigned char *var;
  1817. {
  1818.     register struct env_lst *ep;
  1819.  
  1820.     if (ep = env_find(var))
  1821.         return(ep->value);
  1822.     return(NULL);
  1823. }
  1824.  
  1825. #if    defined(AUTHENTICATE)
  1826. /*
  1827.  * The AUTHENTICATE command.
  1828.  */
  1829.  
  1830. struct authlist {
  1831.     char    *name;
  1832.     char    *help;
  1833.     int    (*handler)();
  1834.     int    narg;
  1835. };
  1836.  
  1837. extern int
  1838.     auth_enable P((int)),
  1839.     auth_disable P((int)),
  1840.     auth_status P((void)),
  1841.     auth_help P((void));
  1842.  
  1843. struct authlist AuthList[] = {
  1844.     { "status",    "Display current status of authentication information",
  1845.                         auth_status,    0 },
  1846.     { "disable", "Disable an authentication type ('auth disable ?' for more)",
  1847.                         auth_disable,    1 },
  1848.     { "enable", "Enable an authentication type ('auth enable ?' for more)",
  1849.                         auth_enable,    1 },
  1850.     { "help",    0,                auth_help,        0 },
  1851.     { "?",    "Print help information",    auth_help,        0 },
  1852.     { 0 },
  1853. };
  1854.  
  1855.     static int
  1856. auth_help()
  1857. {
  1858.     struct authlist *c;
  1859.  
  1860.     for (c = AuthList; c->name; c++) {
  1861.     if (c->help) {
  1862.         if (*c->help)
  1863.         printf("%-15s %s\n", c->name, c->help);
  1864.         else
  1865.         printf("\n");
  1866.     }
  1867.     }
  1868.     return 0;
  1869. }
  1870.  
  1871. auth_cmd(argc, argv)
  1872.     int  argc;
  1873.     char *argv[];
  1874. {
  1875.     struct authlist *c;
  1876.  
  1877.     c = (struct authlist *)
  1878.         genget(argv[1], (char **) AuthList, sizeof(struct authlist));
  1879.     if (c == 0) {
  1880.         fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
  1881.                     argv[1]);
  1882.         return 0;
  1883.     }
  1884.     if (Ambiguous(c)) {
  1885.         fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
  1886.                     argv[1]);
  1887.         return 0;
  1888.     }
  1889.     if (c->narg + 2 != argc) {
  1890.     fprintf(stderr,
  1891.         "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
  1892.         c->narg < argc + 2 ? "only " : "",
  1893.         c->narg, c->narg == 1 ? "" : "s", c->name);
  1894.     return 0;
  1895.     }
  1896.     return((*c->handler)(argv[2], argv[3]));
  1897. }
  1898. #endif
  1899.  
  1900. #if    defined(ENCRYPT)
  1901. /*
  1902.  * The ENCRYPT command.
  1903.  */
  1904.  
  1905. struct encryptlist {
  1906.     char    *name;
  1907.     char    *help;
  1908.     int    (*handler)();
  1909.     int    needconnect;
  1910.     int    minarg;
  1911.     int    maxarg;
  1912. };
  1913.  
  1914. extern int
  1915.     EncryptEnable P((char *, char *)),
  1916.     EncryptDisable P((char *, char *)),
  1917.     EncryptType P((char *, char *)),
  1918.     EncryptStart P((char *)),
  1919.     EncryptStartInput P((void)),
  1920.     EncryptStartOutput P((void)),
  1921.     EncryptStop P((char *)),
  1922.     EncryptStopInput P((void)),
  1923.     EncryptStopOutput P((void)),
  1924.     EncryptStatus P((void)),
  1925.     EncryptHelp P((void));
  1926.  
  1927. struct encryptlist EncryptList[] = {
  1928.     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
  1929.                         EncryptEnable, 1, 1, 2 },
  1930.     { "disable", "Disable encryption. ('encrypt enable ?' for more)",
  1931.                         EncryptDisable, 0, 1, 2 },
  1932.     { "type", "Set encryptiong type. ('encrypt type ?' for more)",
  1933.                         EncryptType, 0, 1, 1 },
  1934.     { "start", "Start encryption. ('encrypt start ?' for more)",
  1935.                         EncryptStart, 1, 0, 1 },
  1936.     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
  1937.                         EncryptStop, 1, 0, 1 },
  1938.     { "input", "Start encrypting the input stream",
  1939.                         EncryptStartInput, 1, 0, 0 },
  1940.     { "-input", "Stop encrypting the input stream",
  1941.                         EncryptStopInput, 1, 0, 0 },
  1942.     { "output", "Start encrypting the output stream",
  1943.                         EncryptStartOutput, 1, 0, 0 },
  1944.     { "-output", "Stop encrypting the output stream",
  1945.                         EncryptStopOutput, 1, 0, 0 },
  1946.  
  1947.     { "status",    "Display current status of authentication information",
  1948.                         EncryptStatus,    0, 0, 0 },
  1949.     { "help",    0,                EncryptHelp,    0, 0, 0 },
  1950.     { "?",    "Print help information",    EncryptHelp,    0, 0, 0 },
  1951.     { 0 },
  1952. };
  1953.  
  1954.     static int
  1955. EncryptHelp()
  1956. {
  1957.     struct encryptlist *c;
  1958.  
  1959.     for (c = EncryptList; c->name; c++) {
  1960.     if (c->help) {
  1961.         if (*c->help)
  1962.         printf("%-15s %s\n", c->name, c->help);
  1963.         else
  1964.         printf("\n");
  1965.     }
  1966.     }
  1967.     return 0;
  1968. }
  1969.  
  1970. encrypt_cmd(argc, argv)
  1971.     int  argc;
  1972.     char *argv[];
  1973. {
  1974.     struct encryptlist *c;
  1975.  
  1976.     c = (struct encryptlist *)
  1977.         genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
  1978.     if (c == 0) {
  1979.         fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
  1980.                     argv[1]);
  1981.         return 0;
  1982.     }
  1983.     if (Ambiguous(c)) {
  1984.         fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
  1985.                     argv[1]);
  1986.         return 0;
  1987.     }
  1988.     argc -= 2;
  1989.     if (argc < c->minarg || argc > c->maxarg) {
  1990.     if (c->minarg == c->maxarg) {
  1991.         fprintf(stderr, "Need %s%d argument%s ",
  1992.         c->minarg < argc ? "only " : "", c->minarg,
  1993.         c->minarg == 1 ? "" : "s");
  1994.     } else {
  1995.         fprintf(stderr, "Need %s%d-%d arguments ",
  1996.         c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
  1997.     }
  1998.     fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
  1999.         c->name);
  2000.     return 0;
  2001.     }
  2002.     if (c->needconnect && !connected) {
  2003.     if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
  2004.         printf("?Need to be connected first.\n");
  2005.         return 0;
  2006.     }
  2007.     }
  2008.     return ((*c->handler)(argc > 0 ? argv[2] : 0,
  2009.             argc > 1 ? argv[3] : 0,
  2010.             argc > 2 ? argv[4] : 0));
  2011. }
  2012. #endif
  2013.  
  2014. #if    defined(unix) && defined(TN3270)
  2015.     static void
  2016. filestuff(fd)
  2017.     int fd;
  2018. {
  2019.     int res;
  2020.  
  2021. #ifdef    F_GETOWN
  2022.     setconnmode(0);
  2023.     res = fcntl(fd, F_GETOWN, 0);
  2024.     setcommandmode();
  2025.  
  2026.     if (res == -1) {
  2027.     perror("fcntl");
  2028.     return;
  2029.     }
  2030.     printf("\tOwner is %d.\n", res);
  2031. #endif
  2032.  
  2033.     setconnmode(0);
  2034.     res = fcntl(fd, F_GETFL, 0);
  2035.     setcommandmode();
  2036.  
  2037.     if (res == -1) {
  2038.     perror("fcntl");
  2039.     return;
  2040.     }
  2041.     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
  2042. }
  2043. #endif /* defined(unix) && defined(TN3270) */
  2044.  
  2045. /*
  2046.  * Print status about the connection.
  2047.  */
  2048.     /*ARGSUSED*/
  2049.     static
  2050. status(argc, argv)
  2051.     int     argc;
  2052.     char *argv[];
  2053. {
  2054.     if (connected) {
  2055.     printf("Connected to %s.\n", hostname);
  2056.     if ((argc < 2) || strcmp(argv[1], "notmuch")) {
  2057.         int mode = getconnmode();
  2058.  
  2059.         if (my_want_state_is_will(TELOPT_LINEMODE)) {
  2060.         printf("Operating with LINEMODE option\n");
  2061.         printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
  2062.         printf("%s catching of signals\n",
  2063.                     (mode&MODE_TRAPSIG) ? "Local" : "No");
  2064.         slcstate();
  2065. #ifdef    KLUDGELINEMODE
  2066.         } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
  2067.         printf("Operating in obsolete linemode\n");
  2068. #endif
  2069.         } else {
  2070.         printf("Operating in single character mode\n");
  2071.         if (localchars)
  2072.             printf("Catching signals locally\n");
  2073.         }
  2074.         printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
  2075.         if (my_want_state_is_will(TELOPT_LFLOW))
  2076.         printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
  2077. #if    defined(ENCRYPT)
  2078.         encrypt_display();
  2079. #endif
  2080.     }
  2081.     } else {
  2082.     printf("No connection.\n");
  2083.     }
  2084. #   if !defined(TN3270)
  2085.     printf("Escape character is '%s'.\n", control(escape));
  2086.     (void) fflush(stdout);
  2087. #   else /* !defined(TN3270) */
  2088.     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
  2089.     printf("Escape character is '%s'.\n", control(escape));
  2090.     }
  2091. #   if defined(unix)
  2092.     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
  2093.     printf("SIGIO received %d time%s.\n",
  2094.                 sigiocount, (sigiocount == 1)? "":"s");
  2095.     if (In3270) {
  2096.         printf("Process ID %d, process group %d.\n",
  2097.                         getpid(), getpgrp(getpid()));
  2098.         printf("Terminal input:\n");
  2099.         filestuff(tin);
  2100.         printf("Terminal output:\n");
  2101.         filestuff(tout);
  2102.         printf("Network socket:\n");
  2103.         filestuff(net);
  2104.     }
  2105.     }
  2106.     if (In3270 && transcom) {
  2107.        printf("Transparent mode command is '%s'.\n", transcom);
  2108.     }
  2109. #   endif /* defined(unix) */
  2110.     (void) fflush(stdout);
  2111.     if (In3270) {
  2112.     return 0;
  2113.     }
  2114. #   endif /* defined(TN3270) */
  2115.     return 1;
  2116. }
  2117.  
  2118. #ifdef    SIGINFO
  2119. /*
  2120.  * Function that gets called when SIGINFO is received.
  2121.  */
  2122. ayt_status()
  2123. {
  2124.     (void) call(status, "status", "notmuch", 0);
  2125. }
  2126. #endif
  2127.  
  2128.     int
  2129. tn(argc, argv)
  2130.     int argc;
  2131.     char *argv[];
  2132. {
  2133.     register struct hostent *host = 0;
  2134.     struct sockaddr_in sin;
  2135.     struct servent *sp = 0;
  2136.     unsigned long temp, inet_addr();
  2137.     extern char *inet_ntoa();
  2138. #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2139.     char *srp = 0, *strrchr();
  2140.     unsigned long sourceroute(), srlen;
  2141. #endif
  2142.     char *cmd, *hostp = 0, *portp = 0, *user = 0;
  2143.  
  2144.     /* clear the socket address prior to use */
  2145.     bzero((char *)&sin, sizeof(sin));
  2146.  
  2147.     if (connected) {
  2148.     printf("?Already connected to %s\n", hostname);
  2149.     setuid(getuid());
  2150.     return 0;
  2151.     }
  2152.     if (argc < 2) {
  2153.     (void) strcpy(line, "open ");
  2154.     printf("(to) ");
  2155.     (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
  2156.     makeargv();
  2157.     argc = margc;
  2158.     argv = margv;
  2159.     }
  2160.     cmd = *argv;
  2161.     --argc; ++argv;
  2162.     while (argc) {
  2163.     if (isprefix(*argv, "help") || isprefix(*argv, "?"))
  2164.         goto usage;
  2165.     if (strcmp(*argv, "-l") == 0) {
  2166.         --argc; ++argv;
  2167.         if (argc == 0)
  2168.         goto usage;
  2169.         user = *argv++;
  2170.         --argc;
  2171.         continue;
  2172.     }
  2173.     if (strcmp(*argv, "-a") == 0) {
  2174.         --argc; ++argv;
  2175.         autologin = 1;
  2176.         continue;
  2177.     }
  2178.     if (hostp == 0) {
  2179.         hostp = *argv++;
  2180.         --argc;
  2181.         continue;
  2182.     }
  2183.     if (portp == 0) {
  2184.         portp = *argv++;
  2185.         --argc;
  2186.         continue;
  2187.     }
  2188.     usage:
  2189.     printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
  2190.     setuid(getuid());
  2191.     return 0;
  2192.     }
  2193.     if (hostp == 0)
  2194.     goto usage;
  2195.  
  2196. #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2197.     if (hostp[0] == '@' || hostp[0] == '!') {
  2198.     if ((hostname = strrchr(hostp, ':')) == NULL)
  2199.         hostname = strrchr(hostp, '@');
  2200.     hostname++;
  2201.     srp = 0;
  2202.     temp = sourceroute(hostp, &srp, &srlen);
  2203.     if (temp == 0) {
  2204.         herror(srp);
  2205.         setuid(getuid());
  2206.         return 0;
  2207.     } else if (temp == -1) {
  2208.         printf("Bad source route option: %s\n", hostp);
  2209.         setuid(getuid());
  2210.         return 0;
  2211.     } else {
  2212.         sin.sin_addr.s_addr = temp;
  2213.         sin.sin_family = AF_INET;
  2214.     }
  2215.     } else {
  2216. #endif
  2217.     temp = inet_addr(hostp);
  2218.     if (temp != (unsigned long) -1) {
  2219.         sin.sin_addr.s_addr = temp;
  2220.         sin.sin_family = AF_INET;
  2221.         (void) strcpy(_hostname, hostp);
  2222.         hostname = _hostname;
  2223.     } else {
  2224.         host = gethostbyname(hostp);
  2225.         if (host) {
  2226.         sin.sin_family = host->h_addrtype;
  2227. #if    defined(h_addr)        /* In 4.3, this is a #define */
  2228.         memcpy((caddr_t)&sin.sin_addr,
  2229.                 host->h_addr_list[0], host->h_length);
  2230. #else    /* defined(h_addr) */
  2231.         memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
  2232. #endif    /* defined(h_addr) */
  2233.         strncpy(_hostname, host->h_name, sizeof(_hostname));
  2234.         _hostname[sizeof(_hostname)-1] = '\0';
  2235.         hostname = _hostname;
  2236.         } else {
  2237.         herror(hostp);
  2238.             setuid(getuid());
  2239.         return 0;
  2240.         }
  2241.     }
  2242. #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2243.     }
  2244. #endif
  2245.     if (portp) {
  2246.     if (*portp == '-') {
  2247.         portp++;
  2248.         telnetport = 1;
  2249.     } else
  2250.         telnetport = 0;
  2251.     sin.sin_port = atoi(portp);
  2252.     if (sin.sin_port == 0) {
  2253.         sp = getservbyname(portp, "tcp");
  2254.         if (sp)
  2255.         sin.sin_port = sp->s_port;
  2256.         else {
  2257.         printf("%s: bad port number\n", portp);
  2258.             setuid(getuid());
  2259.         return 0;
  2260.         }
  2261.     } else {
  2262. #if    !defined(htons)
  2263.         u_short htons();
  2264. #endif    /* !defined(htons) */
  2265.         sin.sin_port = htons(sin.sin_port);
  2266.     }
  2267.     } else {
  2268.     if (sp == 0) {
  2269.         sp = getservbyname("telnet", "tcp");
  2270.         if (sp == 0) {
  2271.         fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
  2272.             setuid(getuid());
  2273.         return 0;
  2274.         }
  2275.         sin.sin_port = sp->s_port;
  2276.     }
  2277.     telnetport = 1;
  2278.     }
  2279.     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
  2280.     do {
  2281.     net = socket(AF_INET, SOCK_STREAM, 0);
  2282.     setuid(getuid());
  2283.     if (net < 0) {
  2284.         perror("telnet: socket");
  2285.         return 0;
  2286.     }
  2287. #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2288.     if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
  2289.         perror("setsockopt (IP_OPTIONS)");
  2290. #endif
  2291. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  2292.     {
  2293. # if    defined(HAS_GETTOS)
  2294.         struct tosent *tp;
  2295.         if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
  2296.         tos = tp->t_tos;
  2297. # endif
  2298.         if (tos < 0)
  2299.         tos = 020;    /* Low Delay bit */
  2300.         if (tos
  2301.         && (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
  2302.         && (errno != ENOPROTOOPT))
  2303.             perror("telnet: setsockopt (IP_TOS) (ignored)");
  2304.     }
  2305. #endif    /* defined(IPPROTO_IP) && defined(IP_TOS) */
  2306.  
  2307.     if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
  2308.         perror("setsockopt (SO_DEBUG)");
  2309.     }
  2310.  
  2311.     if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  2312. #if    defined(h_addr)        /* In 4.3, this is a #define */
  2313.         if (host && host->h_addr_list[1]) {
  2314.         int oerrno = errno;
  2315.  
  2316.         fprintf(stderr, "telnet: connect to address %s: ",
  2317.                         inet_ntoa(sin.sin_addr));
  2318.         errno = oerrno;
  2319.         perror((char *)0);
  2320.         host->h_addr_list++;
  2321.         memcpy((caddr_t)&sin.sin_addr, 
  2322.             host->h_addr_list[0], host->h_length);
  2323.         (void) NetClose(net);
  2324.         continue;
  2325.         }
  2326. #endif    /* defined(h_addr) */
  2327.         perror("telnet: Unable to connect to remote host");
  2328.         return 0;
  2329.     }
  2330.     connected++;
  2331. #if    defined(AUTHENTICATE) || defined(ENCRYPT)
  2332.     auth_encrypt_connect(connected);
  2333. #endif
  2334.     } while (connected == 0);
  2335.     cmdrc(hostp, hostname);
  2336.     if (autologin && user == NULL) {
  2337.     struct passwd *pw;
  2338.  
  2339.     user = getenv("USER");
  2340.     if (user == NULL ||
  2341.         (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
  2342.         if (pw = getpwuid(getuid()))
  2343.             user = pw->pw_name;
  2344.         else
  2345.             user = NULL;
  2346.     }
  2347.     }
  2348.     if (user) {
  2349.     env_define((unsigned char *)"USER", (unsigned char *)user);
  2350.     env_export((unsigned char *)"USER");
  2351.     }
  2352.     (void) call(status, "status", "notmuch", 0);
  2353.     if (setjmp(peerdied) == 0)
  2354.     telnet(user);
  2355.     (void) NetClose(net);
  2356.     ExitString("Connection closed by foreign host.\n",1);
  2357.     /*NOTREACHED*/
  2358. }
  2359.  
  2360. #define HELPINDENT (sizeof ("connect"))
  2361.  
  2362. static char
  2363.     openhelp[] =    "connect to a site",
  2364.     closehelp[] =    "close current connection",
  2365.     logouthelp[] =    "forcibly logout remote user and close the connection",
  2366.     quithelp[] =    "exit telnet",
  2367.     statushelp[] =    "print status information",
  2368.     helphelp[] =    "print help information",
  2369.     sendhelp[] =    "transmit special characters ('send ?' for more)",
  2370.     sethelp[] =     "set operating parameters ('set ?' for more)",
  2371.     unsethelp[] =     "unset operating parameters ('unset ?' for more)",
  2372.     togglestring[] ="toggle operating parameters ('toggle ?' for more)",
  2373.     slchelp[] =    "change state of special charaters ('slc ?' for more)",
  2374.     displayhelp[] =    "display operating parameters",
  2375. #if    defined(TN3270) && defined(unix)
  2376.     transcomhelp[] = "specify Unix command for transparent mode pipe",
  2377. #endif    /* defined(TN3270) && defined(unix) */
  2378. #if    defined(AUTHENTICATE)
  2379.     authhelp[] =    "turn on (off) authentication ('auth ?' for more)",
  2380. #endif
  2381. #if    defined(ENCRYPT)
  2382.     encrypthelp[] =    "turn on (off) encryption ('encrypt ?' for more)",
  2383. #endif
  2384. #if    defined(unix)
  2385.     zhelp[] =    "suspend telnet",
  2386. #endif    /* defined(unix) */
  2387.     shellhelp[] =    "invoke a subshell",
  2388.     envhelp[] =    "change environment variables ('environ ?' for more)",
  2389.     modestring[] = "try to enter line or character mode ('mode ?' for more)";
  2390.  
  2391. extern int    help();
  2392.  
  2393. static Command cmdtab[] = {
  2394.     { "close",    closehelp,    bye,        1 },
  2395.     { "logout",    logouthelp,    logout,        1 },
  2396.     { "display",    displayhelp,    display,    0 },
  2397.     { "mode",    modestring,    modecmd,    0 },
  2398.     { "open",    openhelp,    tn,        0 },
  2399.     { "quit",    quithelp,    quit,        0 },
  2400.     { "send",    sendhelp,    sendcmd,    0 },
  2401.     { "set",    sethelp,    setcmd,        0 },
  2402.     { "unset",    unsethelp,    unsetcmd,    0 },
  2403.     { "status",    statushelp,    status,        0 },
  2404.     { "toggle",    togglestring,    toggle,        0 },
  2405.     { "slc",    slchelp,    slccmd,        0 },
  2406. #if    defined(TN3270) && defined(unix)
  2407.     { "transcom",    transcomhelp,    settranscom,    0 },
  2408. #endif    /* defined(TN3270) && defined(unix) */
  2409. #if    defined(AUTHENTICATE)
  2410.     { "auth",    authhelp,    auth_cmd,    0 },
  2411. #endif
  2412. #if    defined(ENCRYPT)
  2413.     { "encrypt",    encrypthelp,    encrypt_cmd,    0 },
  2414. #endif
  2415. #if    defined(unix)
  2416.     { "z",        zhelp,        suspend,    0 },
  2417. #endif    /* defined(unix) */
  2418. #if    defined(TN3270)
  2419.     { "!",        shellhelp,    shell,        1 },
  2420. #else
  2421.     { "!",        shellhelp,    shell,        0 },
  2422. #endif
  2423.     { "environ",    envhelp,    env_cmd,    0 },
  2424.     { "?",        helphelp,    help,        0 },
  2425.     0
  2426. };
  2427.  
  2428. static char    crmodhelp[] =    "deprecated command -- use 'toggle crmod' instead";
  2429. static char    escapehelp[] =    "deprecated command -- use 'set escape' instead";
  2430.  
  2431. static Command cmdtab2[] = {
  2432.     { "help",    0,        help,        0 },
  2433.     { "escape",    escapehelp,    setescape,    0 },
  2434.     { "crmod",    crmodhelp,    togcrmod,    0 },
  2435.     0
  2436. };
  2437.  
  2438.  
  2439. /*
  2440.  * Call routine with argc, argv set from args (terminated by 0).
  2441.  */
  2442.  
  2443.     /*VARARGS1*/
  2444.     static
  2445. call(va_alist)
  2446.     va_dcl
  2447. {
  2448.     va_list ap;
  2449.     typedef int (*intrtn_t)();
  2450.     intrtn_t routine;
  2451.     char *args[100];
  2452.     int argno = 0;
  2453.  
  2454.     va_start(ap);
  2455.     routine = (va_arg(ap, intrtn_t));
  2456.     while ((args[argno++] = va_arg(ap, char *)) != 0) {
  2457.     ;
  2458.     }
  2459.     va_end(ap);
  2460.     return (*routine)(argno-1, args);
  2461. }
  2462.  
  2463.  
  2464.     static Command *
  2465. getcmd(name)
  2466.     char *name;
  2467. {
  2468.     Command *cm;
  2469.  
  2470.     if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))
  2471.     return cm;
  2472.     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
  2473. }
  2474.  
  2475.     void
  2476. command(top, tbuf, cnt)
  2477.     int top;
  2478.     char *tbuf;
  2479.     int cnt;
  2480. {
  2481.     register Command *c;
  2482.  
  2483.     setcommandmode();
  2484.     if (!top) {
  2485.     putchar('\n');
  2486. #if    defined(unix)
  2487.     } else {
  2488.     (void) signal(SIGINT, SIG_DFL);
  2489.     (void) signal(SIGQUIT, SIG_DFL);
  2490. #endif    /* defined(unix) */
  2491.     }
  2492.     for (;;) {
  2493.     if (rlogin == _POSIX_VDISABLE)
  2494.         printf("%s> ", prompt);
  2495.     if (tbuf) {
  2496.         register char *cp;
  2497.         cp = line;
  2498.         while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
  2499.         cnt--;
  2500.         tbuf = 0;
  2501.         if (cp == line || *--cp != '\n' || cp == line)
  2502.         goto getline;
  2503.         *cp = '\0';
  2504.         if (rlogin == _POSIX_VDISABLE)
  2505.             printf("%s\n", line);
  2506.     } else {
  2507.     getline:
  2508.         if (rlogin != _POSIX_VDISABLE)
  2509.         printf("%s> ", prompt);
  2510.         if (fgets(line, sizeof(line), stdin) == NULL) {
  2511.         if (feof(stdin) || ferror(stdin)) {
  2512.             (void) quit();
  2513.             /*NOTREACHED*/
  2514.         }
  2515.         break;
  2516.         }
  2517.     }
  2518.     if (line[0] == 0)
  2519.         break;
  2520.     makeargv();
  2521.     if (margv[0] == 0) {
  2522.         break;
  2523.     }
  2524.     c = getcmd(margv[0]);
  2525.     if (Ambiguous(c)) {
  2526.         printf("?Ambiguous command\n");
  2527.         continue;
  2528.     }
  2529.     if (c == 0) {
  2530.         printf("?Invalid command\n");
  2531.         continue;
  2532.     }
  2533.     if (c->needconnect && !connected) {
  2534.         printf("?Need to be connected first.\n");
  2535.         continue;
  2536.     }
  2537.     if ((*c->handler)(margc, margv)) {
  2538.         break;
  2539.     }
  2540.     }
  2541.     if (!top) {
  2542.     if (!connected) {
  2543.         longjmp(toplevel, 1);
  2544.         /*NOTREACHED*/
  2545.     }
  2546. #if    defined(TN3270)
  2547.     if (shell_active == 0) {
  2548.         setconnmode(0);
  2549.     }
  2550. #else    /* defined(TN3270) */
  2551.     setconnmode(0);
  2552. #endif    /* defined(TN3270) */
  2553.     }
  2554. }
  2555.  
  2556. /*
  2557.  * Help command.
  2558.  */
  2559.     static
  2560. help(argc, argv)
  2561.     int argc;
  2562.     char *argv[];
  2563. {
  2564.     register Command *c;
  2565.  
  2566.     if (argc == 1) {
  2567.         printf("Commands may be abbreviated.  Commands are:\n\n");
  2568.         for (c = cmdtab; c->name; c++)
  2569.             if (c->help) {
  2570.                 printf("%-*s\t%s\n", HELPINDENT, c->name,
  2571.                                     c->help);
  2572.             }
  2573.         return 0;
  2574.     }
  2575.     while (--argc > 0) {
  2576.         register char *arg;
  2577.         arg = *++argv;
  2578.         c = getcmd(arg);
  2579.         if (Ambiguous(c))
  2580.             printf("?Ambiguous help command %s\n", arg);
  2581.         else if (c == (Command *)0)
  2582.             printf("?Invalid help command %s\n", arg);
  2583.         else
  2584.             printf("%s\n", c->help);
  2585.     }
  2586.     return 0;
  2587. }
  2588.  
  2589. static char *rcname = 0;
  2590. static char rcbuf[128];
  2591.  
  2592. cmdrc(m1, m2)
  2593.     char *m1, *m2;
  2594. {
  2595.     register Command *c;
  2596.     FILE *rcfile;
  2597.     int gotmachine = 0;
  2598.     int l1 = strlen(m1);
  2599.     int l2 = strlen(m2);
  2600.     char m1save[64];
  2601.  
  2602.     if (skiprc)
  2603.     return;
  2604.  
  2605.     strcpy(m1save, m1);
  2606.     m1 = m1save;
  2607.  
  2608.     if (rcname == 0) {
  2609.     rcname = getenv("HOME");
  2610.     if (rcname)
  2611.         strcpy(rcbuf, rcname);
  2612.     else
  2613.         rcbuf[0] = '\0';
  2614.     strcat(rcbuf, "/.telnetrc");
  2615.     rcname = rcbuf;
  2616.     }
  2617.  
  2618.     if ((rcfile = fopen(rcname, "r")) == 0) {
  2619.     return;
  2620.     }
  2621.  
  2622.     for (;;) {
  2623.     if (fgets(line, sizeof(line), rcfile) == NULL)
  2624.         break;
  2625.     if (line[0] == 0)
  2626.         break;
  2627.     if (line[0] == '#')
  2628.         continue;
  2629.     if (gotmachine) {
  2630.         if (!isspace(line[0]))
  2631.         gotmachine = 0;
  2632.     }
  2633.     if (gotmachine == 0) {
  2634.         if (isspace(line[0]))
  2635.         continue;
  2636.         if (strncasecmp(line, m1, l1) == 0)
  2637.         strncpy(line, &line[l1], sizeof(line) - l1);
  2638.         else if (strncasecmp(line, m2, l2) == 0)
  2639.         strncpy(line, &line[l2], sizeof(line) - l2);
  2640.         else if (strncasecmp(line, "DEFAULT", 7) == 0)
  2641.         strncpy(line, &line[7], sizeof(line) - 7);
  2642.         else
  2643.         continue;
  2644.         if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
  2645.         continue;
  2646.         gotmachine = 1;
  2647.     }
  2648.     makeargv();
  2649.     if (margv[0] == 0)
  2650.         continue;
  2651.     c = getcmd(margv[0]);
  2652.     if (Ambiguous(c)) {
  2653.         printf("?Ambiguous command: %s\n", margv[0]);
  2654.         continue;
  2655.     }
  2656.     if (c == 0) {
  2657.         printf("?Invalid command: %s\n", margv[0]);
  2658.         continue;
  2659.     }
  2660.     /*
  2661.      * This should never happen...
  2662.      */
  2663.     if (c->needconnect && !connected) {
  2664.         printf("?Need to be connected first for %s.\n", margv[0]);
  2665.         continue;
  2666.     }
  2667.     (*c->handler)(margc, margv);
  2668.     }
  2669.     fclose(rcfile);
  2670. }
  2671.  
  2672. #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2673.  
  2674. /*
  2675.  * Source route is handed in as
  2676.  *    [!]@hop1@hop2...[@|:]dst
  2677.  * If the leading ! is present, it is a
  2678.  * strict source route, otherwise it is
  2679.  * assmed to be a loose source route.
  2680.  *
  2681.  * We fill in the source route option as
  2682.  *    hop1,hop2,hop3...dest
  2683.  * and return a pointer to hop1, which will
  2684.  * be the address to connect() to.
  2685.  *
  2686.  * Arguments:
  2687.  *    arg:    pointer to route list to decipher
  2688.  *
  2689.  *    cpp:     If *cpp is not equal to NULL, this is a
  2690.  *        pointer to a pointer to a character array
  2691.  *        that should be filled in with the option.
  2692.  *
  2693.  *    lenp:    pointer to an integer that contains the
  2694.  *        length of *cpp if *cpp != NULL.
  2695.  *
  2696.  * Return values:
  2697.  *
  2698.  *    Returns the address of the host to connect to.  If the
  2699.  *    return value is -1, there was a syntax error in the
  2700.  *    option, either unknown characters, or too many hosts.
  2701.  *    If the return value is 0, one of the hostnames in the
  2702.  *    path is unknown, and *cpp is set to point to the bad
  2703.  *    hostname.
  2704.  *
  2705.  *    *cpp:    If *cpp was equal to NULL, it will be filled
  2706.  *        in with a pointer to our static area that has
  2707.  *        the option filled in.  This will be 32bit aligned.
  2708.  * 
  2709.  *    *lenp:    This will be filled in with how long the option
  2710.  *        pointed to by *cpp is.
  2711.  *    
  2712.  */
  2713.     unsigned long
  2714. sourceroute(arg, cpp, lenp)
  2715.     char    *arg;
  2716.     char    **cpp;
  2717.     int    *lenp;
  2718. {
  2719.     static char lsr[44];
  2720.     char *cp, *cp2, *lsrp, *lsrep;
  2721.     register int tmp;
  2722.     struct in_addr sin_addr;
  2723.     register struct hostent *host = 0;
  2724.     register char c;
  2725.  
  2726.     /*
  2727.      * Verify the arguments, and make sure we have
  2728.      * at least 7 bytes for the option.
  2729.      */
  2730.     if (cpp == NULL || lenp == NULL)
  2731.         return((unsigned long)-1);
  2732.     if (*cpp != NULL && *lenp < 7)
  2733.         return((unsigned long)-1);
  2734.     /*
  2735.      * Decide whether we have a buffer passed to us,
  2736.      * or if we need to use our own static buffer.
  2737.      */
  2738.     if (*cpp) {
  2739.         lsrp = *cpp;
  2740.         lsrep = lsrp + *lenp;
  2741.     } else {
  2742.         *cpp = lsrp = lsr;
  2743.         lsrep = lsrp + 44;
  2744.     }
  2745.  
  2746.     cp = arg;
  2747.  
  2748.     /*
  2749.      * Next, decide whether we have a loose source
  2750.      * route or a strict source route, and fill in
  2751.      * the begining of the option.
  2752.      */
  2753.     if (*cp == '!') {
  2754.         cp++;
  2755.         *lsrp++ = IPOPT_SSRR;
  2756.     } else
  2757.         *lsrp++ = IPOPT_LSRR;
  2758.  
  2759.     if (*cp != '@')
  2760.         return((unsigned long)-1);
  2761.  
  2762.     lsrp++;        /* skip over length, we'll fill it in later */
  2763.     *lsrp++ = 4;
  2764.  
  2765.     cp++;
  2766.  
  2767.     sin_addr.s_addr = 0;
  2768.  
  2769.     for (c = 0;;) {
  2770.         if (c == ':')
  2771.             cp2 = 0;
  2772.         else for (cp2 = cp; c = *cp2; cp2++) {
  2773.             if (c == ',') {
  2774.                 *cp2++ = '\0';
  2775.                 if (*cp2 == '@')
  2776.                     cp2++;
  2777.             } else if (c == '@') {
  2778.                 *cp2++ = '\0';
  2779.             } else if (c == ':') {
  2780.                 *cp2++ = '\0';
  2781.             } else
  2782.                 continue;
  2783.             break;
  2784.         }
  2785.         if (!c)
  2786.             cp2 = 0;
  2787.  
  2788.         if ((tmp = inet_addr(cp)) != -1) {
  2789.             sin_addr.s_addr = tmp;
  2790.         } else if (host = gethostbyname(cp)) {
  2791. #if    defined(h_addr)
  2792.             memcpy((caddr_t)&sin_addr,
  2793.                 host->h_addr_list[0], host->h_length);
  2794. #else
  2795.             memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
  2796. #endif
  2797.         } else {
  2798.             *cpp = cp;
  2799.             return(0);
  2800.         }
  2801.         memcpy(lsrp, (char *)&sin_addr, 4);
  2802.         lsrp += 4;
  2803.         if (cp2)
  2804.             cp = cp2;
  2805.         else
  2806.             break;
  2807.         /*
  2808.          * Check to make sure there is space for next address
  2809.          */
  2810.         if (lsrp + 4 > lsrep)
  2811.             return((unsigned long)-1);
  2812.     }
  2813.     if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
  2814.         *cpp = 0;
  2815.         *lenp = 0;
  2816.         return((unsigned long)-1);
  2817.     }
  2818.     *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
  2819.     *lenp = lsrp - *cpp;
  2820.     return(sin_addr.s_addr);
  2821. }
  2822. #endif
  2823.