commands.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:63k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1988, 1990, 1993                                            */
  2. /* The Regents of the University of California.  All rights reserved.        */
  3. /*                                                                           */
  4. /* Redistribution and use in source and binary forms, with or without        */
  5. /* modification, are permitted provided that the following conditions        */
  6. /* are met:                                                                  */
  7. /* 1. Redistributions of source code must retain the above copyright         */
  8. /* notice, this list of conditions and the following disclaimer.             */
  9. /* 2. Redistributions in binary form must reproduce the above copyright      */
  10. /* notice, this list of conditions and the following disclaimer in the       */
  11. /* documentation and/or other materials provided with the distribution.      */
  12. /* 3. All advertising materials mentioning features or use of this           */
  13. /* software must display the following acknowledgement:                      */
  14. /*   This product includes software developed by the University of           */
  15. /*   California, Berkeley and its contributors.                              */
  16. /* 4. Neither the name of the University nor the names of its contributors   */
  17. /* may be used to endorse or promote products derived from this software     */
  18. /* without specific prior written permission.                                */
  19. /*                                                                           */
  20. /* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
  21. /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
  22. /* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
  23. /* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE */
  24. /* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR       */
  25. /* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
  26. /* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
  27. /* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
  28. /* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
  29. /* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
  30. /* THE POSSIBILITY OF SUCH DAMAGE.                                           */
  31. #ifdef SHOW_SCCIDS
  32. static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
  33. #endif
  34. #include "config.h"
  35. #ifdef HAVE_SYS_PARAM_H
  36. #include <sys/param.h>
  37. #endif
  38. #ifdef HAVE_SYS_TYPES_H
  39. #include <sys/types.h>
  40. #endif
  41. #ifdef HAVE_SYS_FILE_H
  42. #include <sys/file.h>
  43. #endif
  44. #ifdef HAVE_UNISTD_H
  45. #include <unistd.h>
  46. #endif
  47. #include <sys/socket.h>
  48. #include <netinet/in.h>
  49. #ifdef HAVE_SYS_FCNTL_H
  50. #include <sys/fcntl.h>
  51. #endif
  52. #ifdef HAVE_FCNTL_H
  53. #include <fcntl.h>
  54. #endif
  55. #include <stdio.h>
  56. #ifdef HAVE_STRING_H
  57. #include <string.h>
  58. #endif
  59. #ifdef HAVE_STRINGS_H
  60. #include <strings.h>
  61. #endif
  62. #ifdef HAVE_UNISTD_H
  63. #include <unistd.h>
  64. #endif
  65. #ifdef HAVE_STDLIB_H
  66. #include <stdlib.h>
  67. #endif
  68. #include <signal.h>
  69. #include <ctype.h>
  70. #include <pwd.h>
  71. #include <varargs.h>
  72. #include <errno.h>
  73. #include <arpa/telnet.h>
  74. #include "general.h"
  75. #include "ring.h"
  76. #include "externs.h"
  77. #include "defines.h"
  78. #include "types.h"
  79. #ifdef HAVE_MACHINE_ENDIAN_H
  80. #include <machine/endian.h>
  81. #endif
  82. #include <netinet/ip.h>
  83. #define DONT_NEED_SIGBLOCK
  84. #define DONT_NEED_SIGUNBLOCK
  85. #define DONT_NEED_SIGPAUSE
  86. #define DONT_NEED_SIGPENDING
  87. #include "sigfix.h"
  88. #ifndef MAXHOSTNAMELEN
  89. #define MAXHOSTNAMELEN 64
  90. #endif
  91. #if defined(IPPROTO_IP) && defined(IP_TOS)
  92. int tos = -1;
  93. #endif
  94. char *hostname;
  95. static char _hostname[MAXHOSTNAMELEN];
  96. extern int isprefix();
  97. extern char **genget();
  98. extern int Ambiguous();
  99. extern void herror();
  100. static call();
  101. typedef struct {
  102.     char *name; /* command name */
  103.     char *help; /* help string (NULL for no help) */
  104.     int (*handler)(); /* routine which executes command */
  105.     int needconnect; /* Do we need to be connected to execute? */
  106. } Command;
  107. static char line[256];
  108. static char saveline[256];
  109. static int margc;
  110. static char *margv[20];
  111. void cmdrc P((char *, char *));
  112. static void makeargv() {
  113.     register char *cp, *cp2, c;
  114.     register char **argp = margv;
  115.     margc = 0;
  116.     cp = line;
  117.     if (*cp == '!') { /* Special case shell escape */
  118. strcpy(saveline, line); /* save for shell command */
  119. *argp++ = "!"; /* No room in string to get this */
  120. margc++;
  121. cp++;
  122.     }
  123.     while ((c = *cp)) {
  124. register int inquote = 0;
  125. while (isspace(c))
  126.     c = *++cp;
  127. if (c == '')
  128.     break;
  129. *argp++ = cp;
  130. margc += 1;
  131. for (cp2 = cp; c != ''; c = *++cp) {
  132.     if (inquote) {
  133. if (c == inquote) {
  134.     inquote = 0;
  135.     continue;
  136. }
  137.     } else {
  138. if (c == '\') {
  139.     if ((c = *++cp) == '')
  140. break;
  141. } else if (c == '"') {
  142.     inquote = '"';
  143.     continue;
  144. } else if (c == ''') {
  145.     inquote = ''';
  146.     continue;
  147. } else if (isspace(c))
  148.     break;
  149.     }
  150.     *cp2++ = c;
  151. }
  152. *cp2 = '';
  153. if (c == '')
  154.     break;
  155. cp++;
  156.     }
  157.     *argp++ = 0;
  158. }
  159. /* Make a character string into a number.                                    */
  160. /* Todo: 1.  Could take random integers (12, 0x12, 012, 0b1).                */
  161. static char special(register char *s) {
  162.     register char c;
  163.     char b;
  164.     
  165.     switch (*s) {
  166. case '^':
  167.     b = *++s;
  168.     if (b == '?') {
  169. c = b | 0x40; /* DEL */
  170.     } else {
  171. c = b & 0x1f;
  172.     }
  173.     break;
  174. default:
  175.     c = *s;
  176.     break;
  177.     }
  178.     return c;
  179. }
  180. /* Construct a control character sequence for a special character.           */
  181. static char *control(register cc_t c) {
  182.     static char buf[5];
  183.     /* The only way I could get the Sun 3.5 compiler to shut up about "if    */
  184.     /* ((unsigned int)c >= 0x80)" was to assign "c" to an unsigned int       */
  185.     /* variable...  Arggg....                                                */
  186.     register unsigned int uic = (unsigned int)c;
  187.     if (uic == 0x7f) {
  188. return ("^?");
  189.     }
  190.     if (c == (cc_t)_POSIX_VDISABLE) {
  191. return "off";
  192.     }
  193.     if (uic >= 0x80) {
  194. buf[0] = '\';
  195. buf[1] = ((c>>6)&07) + '0';
  196. buf[2] = ((c>>3)&07) + '0';
  197. buf[3] = (c&07) + '0';
  198. buf[4] = 0;
  199.     } else if (uic >= 0x20) {
  200. buf[0] = c;
  201. buf[1] = 0;
  202.     } else {
  203. buf[0] = '^';
  204. buf[1] = '@'+c;
  205. buf[2] = 0;
  206.     }
  207.     return (buf);
  208. }
  209. /* The following are data structures and routines for                        */
  210. /* the "send" command.                                                       */
  211. struct sendlist {
  212.     char *name; /* How user refers to it (case independent) */
  213.     char *help; /* Help information (0 ==> no help) */
  214.     int needconnect; /* Need to be connected */
  215.     int narg; /* Number of arguments */
  216.     int (*handler)(); /* Routine to perform (for special ops) */
  217.     int nbyte; /* Number of bytes to send this command */
  218.     int what; /* Character to be sent (<0 ==> special) */
  219. };
  220. static int
  221. send_esc P((void)),
  222. send_help P((void)),
  223. send_docmd P((char *)),
  224. send_dontcmd P((char *)),
  225. send_willcmd P((char *)),
  226. send_wontcmd P((char *));
  227. static struct sendlist Sendlist[] = {
  228.     { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO },
  229.     { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT },
  230.     { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK },
  231.     { "break", 0, 1, 0, 0, 2, BREAK },
  232.     { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC },
  233.     { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL },
  234.     { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 },
  235.     { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA },
  236.     { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP },
  237.     { "intp", 0, 1, 0, 0, 2, IP },
  238.     { "interrupt", 0, 1, 0, 0, 2, IP },
  239.     { "intr", 0, 1, 0, 0, 2, IP },
  240.     { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP },
  241.     { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR },
  242.     { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT },
  243.     { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP },
  244.     { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF },
  245.     { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 },
  246.     { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 },
  247.     { "?", "Display send options", 0, 0, send_help, 0, 0 },
  248.     { "help", 0, 0, 0, send_help, 0, 0 },
  249.     { "do", 0, 0, 1, send_docmd, 3, 0 },
  250.     { "dont", 0, 0, 1, send_dontcmd, 3, 0 },
  251.     { "will", 0, 0, 1, send_willcmd, 3, 0 },
  252.     { "wont", 0, 0, 1, send_wontcmd, 3, 0 },
  253.     { 0 }
  254. };
  255. #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, 
  256. sizeof(struct sendlist)))
  257. /*VARARGS*/
  258. static int bye(int argc, char *argv[]) {
  259.     extern int resettermname;
  260.     if (connected) {
  261. (void) shutdown(net, 2);
  262. printf("Connection closed.n");
  263. (void) NetClose(net);
  264. connected = 0;
  265. resettermname = 1;
  266. /* reset options */
  267. tninit();
  268. #ifdef TN3270
  269. SetIn3270(); /* Get out of 3270 mode */
  270. #endif /* defined(TN3270) */
  271.     }
  272.     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
  273. longjmp(toplevel, 1);
  274. /* NOTREACHED */
  275.     }
  276.     return 1; /* Keep lint, etc., happy */
  277. }
  278. int quit() {
  279.     call(bye, "bye", "fromquit", 0);
  280.     Exit(0);
  281.     /*NOTREACHED*/
  282.     return 0;
  283. }
  284. int logout() {
  285.     send_do(TELOPT_LOGOUT, 1);
  286.     netflush();
  287.     return 1;
  288. }
  289. static int sendcmd(int argc, char **argv) { 
  290.     int count; /* how many bytes we are going to need to send */
  291.     int i;
  292.     struct sendlist *s; /* pointer to current command */
  293.     int success = 0;
  294.     int needconnect = 0;
  295.     if (argc < 2) {
  296. printf("need at least one argument for 'send' commandn");
  297. printf("'send ?' for helpn");
  298. return 0;
  299.     }
  300.     /* First, validate all the send arguments.  In addition, we see how much */
  301.     /* space we are going to need, and whether or not we will be doing a     */
  302.     /* "SYNCH" operation (which flushes the network queue).                  */
  303.     count = 0;
  304.     for (i = 1; i < argc; i++) {
  305. s = GETSEND(argv[i]);
  306. if (s == 0) {
  307.     printf("Unknown send argument '%s'n'send ?' for help.n", argv[i]);
  308.     return 0;
  309. } else if (Ambiguous(s)) {
  310.     printf("Ambiguous send argument '%s'n'send ?' for help.n", argv[i]);
  311.     return 0;
  312. }
  313. if (i + s->narg >= argc) {
  314.     fprintf(stderr, "Need %d argument%s to 'send %s' command.  'send %s ?' for help.n",
  315.     s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
  316.     return 0;
  317. }
  318. count += s->nbyte;
  319. if (s->handler == send_help) {
  320.     send_help();
  321.     return 0;
  322. }
  323. i += s->narg;
  324. needconnect += s->needconnect;
  325.     }
  326.     if (!connected && needconnect) {
  327. printf("?Need to be connected first.n");
  328. printf("'send ?' for helpn");
  329. return 0;
  330.     }
  331.     /* Now, do we have enough room? */
  332.     if (NETROOM() < count) {
  333. printf("There is not enough room in the buffer TO the networkn");
  334. printf("to process your request.  Nothing will be done.n");
  335. printf("('send synch' will throw away most data in the networkn");
  336. printf("buffer, if this might help.)n");
  337. return 0;
  338.     }
  339.     /* OK, they are all OK, now go through again and actually send */
  340.     count = 0;
  341.     for (i = 1; i < argc; i++) {
  342. if ((s = GETSEND(argv[i])) == 0) {
  343.     fprintf(stderr, "Telnet 'send' error - argument disappeared!n");
  344.     (void) quit();
  345.     /*NOTREACHED*/
  346. }
  347. if (s->handler) {
  348.     count++;
  349.     success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
  350.   (s->narg > 1) ? argv[i+2] : 0);
  351.     i += s->narg;
  352. } else {
  353.     NET2ADD(IAC, s->what);
  354.     printoption("SENT", IAC, s->what);
  355. }
  356.     }
  357.     return (count == success);
  358. }
  359. static int send_esc() {
  360.     NETADD(escape);
  361.     return 1;
  362. }
  363. static int send_tncmd(void (*func)(), char *cmd, char *name) {
  364.     char **cpp;
  365.     extern char *telopts[];
  366.     register int val = 0;
  367.     if (isprefix(name, "help") || isprefix(name, "?")) {
  368. register int col, len;
  369. printf("Usage: send %s <value|option>n", cmd);
  370. printf(""value" must be from 0 to 255n");
  371. printf("Valid options are:nt");
  372. col = 8;
  373. for (cpp = telopts; *cpp; cpp++) {
  374.     len = strlen(*cpp) + 3;
  375.     if (col + len > 65) {
  376. printf("nt");
  377. col = 8;
  378.     }
  379.     printf(" "%s"", *cpp);
  380.     col += len;
  381. }
  382. printf("n");
  383. return 0;
  384.     }
  385.     cpp = (char **)genget(name, telopts, sizeof(char *));
  386.     if (Ambiguous(cpp)) {
  387. fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).n", name, cmd);
  388. return 0;
  389.     }
  390.     if (cpp) {
  391. val = cpp - telopts;
  392.     } else {
  393. register char *cp = name;
  394. while (*cp >= '0' && *cp <= '9') {
  395.     val *= 10;
  396.     val += *cp - '0';
  397.     cp++;
  398. }
  399. if (*cp != 0) {
  400.     fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).n", name, cmd);
  401.     return 0;
  402. } else if (val < 0 || val > 255) {
  403.     fprintf(stderr, "'%s': bad value ('send %s ?' for help).n", name, cmd);
  404.     return 0;
  405. }
  406.     }
  407.     if (!connected) {
  408. printf("?Need to be connected first.n");
  409. return 0;
  410.     }
  411.     (*func)(val, 1);
  412.     return 1;
  413. }
  414. static int send_docmd(char *name) {
  415.     return(send_tncmd(send_do, "do", name));
  416. }
  417. static int send_dontcmd(char *name) {
  418.     return(send_tncmd(send_dont, "dont", name));
  419. }
  420. static int send_willcmd(char *name) {
  421.     return(send_tncmd(send_will, "will", name));
  422. }
  423. static int send_wontcmd(char *name) {
  424.     return(send_tncmd(send_wont, "wont", name));
  425. }
  426. static int send_help() {
  427.     struct sendlist *s; /* pointer to current command */
  428.     for (s = Sendlist; s->name; s++) {
  429. if (s->help) printf("%-15s %sn", s->name, s->help);
  430.     }
  431.     return(0);
  432. }
  433. /* The following are the routines and data structures referred to by the     */
  434. /* arguments to the "toggle" command.                                        */
  435. static int lclchars() {
  436.     donelclchars = 1;
  437.     return 1;
  438. }
  439. static int togdebug() {
  440. #ifdef NOT43
  441.     if (!debug) {
  442. printf("Cannot turn off socket debuggingn");
  443. return 1;
  444.     }
  445. #endif
  446.     if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0) < 0)
  447. perror("setsockopt (SO_DEBUG)");
  448.     return 1;
  449. }
  450. static int togcrlf() {
  451.     if (crlf) {
  452. printf("Will send carriage returns as telnet <CR><LF>.n");
  453.     } else {
  454. printf("Will send carriage returns as telnet <CR><NUL>.n");
  455.     }
  456.     return 1;
  457. }
  458. int binmode;
  459. static int togbinary(int val) {
  460.     donebinarytoggle = 1;
  461.     if (val >= 0) {
  462. binmode = val;
  463.     } else {
  464. if (my_want_state_is_will(TELOPT_BINARY) &&
  465.     my_want_state_is_do(TELOPT_BINARY)) {
  466.     binmode = 1;
  467. } else if (my_want_state_is_wont(TELOPT_BINARY) &&
  468.    my_want_state_is_dont(TELOPT_BINARY)) {
  469.     binmode = 0;
  470. }
  471. val = binmode ? 0 : 1;
  472.     }
  473.     if (val == 1) {
  474. if (my_want_state_is_will(TELOPT_BINARY) &&
  475.     my_want_state_is_do(TELOPT_BINARY)) {
  476.     printf("Already operating in binary mode with remote host.n");
  477. } else {
  478.     printf("Negotiating binary mode with remote host.n");
  479.     tel_enter_binary(3);
  480. }
  481.     } else {
  482. if (my_want_state_is_wont(TELOPT_BINARY) &&
  483.     my_want_state_is_dont(TELOPT_BINARY)) {
  484.     printf("Already in network ascii mode with remote host.n");
  485. } else {
  486.     printf("Negotiating network ascii mode with remote host.n");
  487.     tel_leave_binary(3);
  488. }
  489.     }
  490.     return 1;
  491. }
  492. static int togrbinary(int val) {
  493.     donebinarytoggle = 1;
  494.     
  495.     if (val == -1) {
  496. val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
  497.     }
  498.     if (val == 1) {
  499. if (my_want_state_is_do(TELOPT_BINARY)) {
  500.     printf("Already receiving in binary mode.n");
  501. } else {
  502.     printf("Negotiating binary mode on input.n");
  503.     tel_enter_binary(1);
  504. }
  505.     } else {
  506. if (my_want_state_is_dont(TELOPT_BINARY)) {
  507.     printf("Already receiving in network ascii mode.n");
  508. } else {
  509.     printf("Negotiating network ascii mode on input.n");
  510.     tel_leave_binary(1);
  511. }
  512.     }
  513.     return 1;
  514. }
  515. static int togxbinary(int val) {
  516.     donebinarytoggle = 1;
  517.     if (val == -1) {
  518. val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
  519.     }
  520.     if (val == 1) {
  521. if (my_want_state_is_will(TELOPT_BINARY)) {
  522.     printf("Already transmitting in binary mode.n");
  523. } else {
  524.     printf("Negotiating binary mode on output.n");
  525.     tel_enter_binary(2);
  526. }
  527.     } else {
  528. if (my_want_state_is_wont(TELOPT_BINARY)) {
  529.     printf("Already transmitting in network ascii mode.n");
  530. } else {
  531.     printf("Negotiating network ascii mode on output.n");
  532.     tel_leave_binary(2);
  533. }
  534.     }
  535.     return 1;
  536. }
  537. static int togglehelp P((void));
  538. struct togglelist {
  539.     char *name; /* name of toggle */
  540.     char *help; /* help message */
  541.     int (*handler)(); /* routine to do actual setting */
  542.     int *variable;
  543.     char *actionexplanation;
  544. };
  545. static struct togglelist Togglelist[] = {
  546.     { "autoflush", 
  547.       "flushing of output when sending interrupt characters",
  548.       0,
  549.       &autoflush,
  550.       "flush output when sending interrupt characters" },
  551.     { "autosynch",
  552.       "automatic sending of interrupt characters in urgent mode",
  553.       0,
  554.       &autosynch,
  555.       "send interrupt characters in urgent mode" },
  556.     { "skiprc",
  557.       "don't read ~/.telnetrc file",
  558.       0,
  559.       &skiprc,
  560.       "skip reading of ~/.telnetrc file" },
  561.     { "binary",
  562.       "sending and receiving of binary data",
  563.       togbinary,
  564.       0,
  565.       0 },
  566.     { "inbinary",
  567.       "receiving of binary data",
  568.       togrbinary,
  569.       0,
  570.       0 },
  571.     { "outbinary",
  572.       "sending of binary data",
  573.       togxbinary,
  574.       0,
  575.       0 },
  576.     { "crlf",
  577.       "sending carriage returns as telnet <CR><LF>",
  578.       togcrlf,
  579.       &crlf,
  580.       0 },
  581.     { "crmod",
  582.       "mapping of received carriage returns",
  583.       0,
  584.       &crmod,
  585.       "map carriage return on output" },
  586.     { "localchars",
  587.       "local recognition of certain control characters",
  588.       lclchars,
  589.       &localchars,
  590.       "recognize certain control characters" },
  591.     { " ", "", 0 }, /* empty line */
  592. #ifdef TN3270
  593.     { "apitrace",
  594.       "(debugging) toggle tracing of API transactions",
  595.       0,
  596.       &apitrace,
  597.       "trace API transactions" },
  598.     { "cursesdata",
  599.       "(debugging) toggle printing of hexadecimal curses data",
  600.       0,
  601.       &cursesdata,
  602.       "print hexadecimal representation of curses data" },
  603. #endif
  604.     { "debug",
  605.       "debugging",
  606.       togdebug,
  607.       &debug,
  608.       "turn on socket level debugging" },
  609.     { "netdata",
  610.       "printing of hexadecimal network data (debugging)",
  611.       0,
  612.       &netdata,
  613.       "print hexadecimal representation of network traffic" },
  614.     { "prettydump",
  615.       "output of "netdata" to user readable format (debugging)",
  616.       0,
  617.       &prettydump,
  618.       "print user readable output for "netdata"" },
  619.     { "options",
  620.       "viewing of options processing (debugging)",
  621.       0,
  622.       &showoptions,
  623.       "show option processing" },
  624.     { "termdata",
  625.       "(debugging) toggle printing of hexadecimal terminal data",
  626.       0,
  627.       &termdata,
  628.       "print hexadecimal representation of terminal traffic" },
  629.     { "?",
  630.       0,
  631.       togglehelp },
  632.     { "help",
  633.       0,
  634.       togglehelp },
  635.     { 0 }
  636. };
  637. static int togglehelp() {
  638.     struct togglelist *c;
  639.     for (c = Togglelist; c->name; c++) {
  640. if (c->help) {
  641.     if (*c->help) printf("%-15s toggle %sn", c->name, c->help);
  642.     else printf("n");
  643. }
  644.     }
  645.     printf("n");
  646.     printf("%-15s %sn", "?", "display help information");
  647.     return 0;
  648. }
  649. static void settogglehelp(int set) {
  650.     struct togglelist *c;
  651.     for (c = Togglelist; c->name; c++) {
  652. if (c->help) {
  653.     if (*c->help) printf("%-15s %s %sn", c->name, set ? "enable" : "disable", c->help);
  654.     else printf("n");
  655. }
  656.     }
  657. }
  658. #define GETTOGGLE(name) (struct togglelist *) genget(name, (char **) Togglelist, sizeof(struct togglelist))
  659. static int toggle(int argc, char *argv[]) {
  660.     int retval = 1;
  661.     char *name;
  662.     struct togglelist *c;
  663.     if (argc < 2) {
  664. fprintf(stderr, "Need an argument to 'toggle' command.  'toggle ?' for help.n");
  665. return 0;
  666.     }
  667.     argc--;
  668.     argv++;
  669.     while (argc--) {
  670. name = *argv++;
  671. c = GETTOGGLE(name);
  672. if (Ambiguous(c)) {
  673.     fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).n", name);
  674.     return 0;
  675. } else if (c == 0) {
  676.     fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).n", name);
  677.     return 0;
  678. } else {
  679.     if (c->variable) {
  680. *c->variable = !*c->variable; /* invert it */
  681. if (c->actionexplanation) {
  682.     printf("%s %s.n", *c->variable? "Will" : "Won't", c->actionexplanation);
  683. }
  684.     }
  685.     if (c->handler) {
  686. retval &= (*c->handler)(-1);
  687.     }
  688. }
  689.     }
  690.     return retval;
  691. }
  692. /* The following perform the "set" command.                                  */
  693. #ifdef USE_TERMIO
  694. struct termio new_tc = { 0 };
  695. #endif
  696. struct setlist {
  697.     char *name; /* name */
  698.     char *help; /* help information */
  699.     void (*handler)();
  700.     cc_t *charp; /* where it is located at */
  701. };
  702. static struct setlist Setlist[] = {
  703. #ifdef KLUDGELINEMODE
  704.     { "echo",  "character to toggle local echoing on/off", 0, &echoc },
  705. #endif
  706.     { "escape", "character to escape back to telnet command mode", 0, &escape },
  707.     { "rlogin", "rlogin escape character", 0, &rlogin },
  708.     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
  709.     { " ", "" },
  710.     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
  711.     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
  712.     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
  713.     { "quit", "character to cause an Abort process", 0, termQuitCharp },
  714.     { "eof", "character to cause an EOF ", 0, termEofCharp },
  715.     { " ", "" },
  716.     { " ", "The following are for local editing in linemode", 0, 0 },
  717.     { "erase", "character to use to erase a character", 0, termEraseCharp },
  718.     { "kill", "character to use to erase a line", 0, termKillCharp },
  719.     { "lnext", "character to use for literal next", 0, termLiteralNextCharp },
  720.     { "susp", "character to cause a Suspend Process", 0, termSuspCharp },
  721.     { "reprint", "character to use for line reprint", 0, termRprntCharp },
  722.     { "worderase", "character to use to erase a word", 0, termWerasCharp },
  723.     { "start", "character to use for XON", 0, termStartCharp },
  724.     { "stop", "character to use for XOFF", 0, termStopCharp },
  725.     { "forw1", "alternate end of line character", 0, termForw1Charp },
  726.     { "forw2", "alternate end of line character", 0, termForw2Charp },
  727.     { "ayt", "alternate AYT character", 0, termAytCharp },
  728.     { 0 }
  729. };
  730. #if defined(CRAY) && !defined(__STDC__)
  731. /* Work around compiler bug in pcc 4.1.5 */
  732. void _setlist_init() {
  733. #ifndef KLUDGELINEMODE
  734. #define N 5
  735. #else
  736. #define N 6
  737. #endif
  738. Setlist[N+0].charp = &termFlushChar;
  739. Setlist[N+1].charp = &termIntChar;
  740. Setlist[N+2].charp = &termQuitChar;
  741. Setlist[N+3].charp = &termEofChar;
  742. Setlist[N+6].charp = &termEraseChar;
  743. Setlist[N+7].charp = &termKillChar;
  744. Setlist[N+8].charp = &termLiteralNextChar;
  745. Setlist[N+9].charp = &termSuspChar;
  746. Setlist[N+10].charp = &termRprntChar;
  747. Setlist[N+11].charp = &termWerasChar;
  748. Setlist[N+12].charp = &termStartChar;
  749. Setlist[N+13].charp = &termStopChar;
  750. Setlist[N+14].charp = &termForw1Char;
  751. Setlist[N+15].charp = &termForw2Char;
  752. Setlist[N+16].charp = &termAytChar;
  753. #undef N
  754. }
  755. #endif /* defined(CRAY) && !defined(__STDC__) */
  756. static struct setlist *getset(char *name) {
  757.     return (struct setlist *)genget(name, (char **) Setlist, sizeof(struct setlist));
  758. }
  759. void set_escape_char(char *s) {
  760.     if (rlogin != _POSIX_VDISABLE) {
  761. rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
  762. printf("Telnet rlogin escape character is '%s'.n", control(rlogin));
  763.     } else {
  764. escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
  765. printf("Telnet escape character is '%s'.n", control(escape));
  766.     }
  767. }
  768. static int setcmd(int argc, char *argv[]) {
  769.     int value;
  770.     struct setlist *ct;
  771.     struct togglelist *c;
  772.     if (argc < 2 || argc > 3) {
  773. printf("Format is 'set Name Value'n'set ?' for help.n");
  774. return 0;
  775.     }
  776.     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
  777. for (ct = Setlist; ct->name; ct++) printf("%-15s %sn", ct->name, ct->help);
  778. printf("n");
  779. settogglehelp(1);
  780. printf("%-15s %sn", "?", "display help information");
  781. return 0;
  782.     }
  783.     ct = getset(argv[1]);
  784.     if (ct == 0) {
  785. c = GETTOGGLE(argv[1]);
  786. if (c == 0) { 
  787.     fprintf(stderr, "'%s': unknown argument ('set ?' for help).n", argv[1]);
  788.     return 0;
  789. } else if (Ambiguous(c)) {
  790.     fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).n", argv[1]);
  791.     return 0;
  792. }
  793. if (c->variable) {
  794.     if ((argc == 2) || (strcmp("on", argv[2]) == 0))
  795. *c->variable = 1;
  796.     else if (strcmp("off", argv[2]) == 0)
  797. *c->variable = 0;
  798.     else {
  799. printf("Format is 'set togglename [on|off]'n'set ?' for help.n");
  800. return 0;
  801.     }
  802.     if (c->actionexplanation) {
  803. printf("%s %s.n", *c->variable? "Will" : "Won't", c->actionexplanation);
  804.     }
  805. }
  806. if (c->handler) (*c->handler)(1);
  807.     } else if (argc != 3) {
  808. printf("Format is 'set Name Value'n'set ?' for help.n");
  809. return 0;
  810.     } else if (Ambiguous(ct)) {
  811. fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).n", argv[1]);
  812. return 0;
  813.     } else if (ct->handler) {
  814. (*ct->handler)(argv[2]);
  815. printf("%s set to "%s".n", ct->name, (char *)ct->charp);
  816.     } else {
  817. if (strcmp("off", argv[2])) {
  818.     value = special(argv[2]);
  819. } else {
  820.     value = _POSIX_VDISABLE;
  821. }
  822. *(ct->charp) = (cc_t)value;
  823. printf("%s character is '%s'.n", ct->name, control(*(ct->charp)));
  824.     }
  825.     slc_check();
  826.     return 1;
  827. }
  828. static int unsetcmd(int argc, char *argv[]) {
  829.     struct setlist *ct;
  830.     struct togglelist *c;
  831.     register char *name;
  832.     if (argc < 2) {
  833. fprintf(stderr, "Need an argument to 'unset' command.  'unset ?' for help.n");
  834. return 0;
  835.     }
  836.     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
  837. for (ct = Setlist; ct->name; ct++) printf("%-15s %sn", ct->name, ct->help);
  838. printf("n");
  839. settogglehelp(0);
  840. printf("%-15s %sn", "?", "display help information");
  841. return 0;
  842.     }
  843.     argc--;
  844.     argv++;
  845.     while (argc--) {
  846. name = *argv++;
  847. ct = getset(name);
  848. if (ct == 0) {
  849.     c = GETTOGGLE(name);
  850.     if (c == 0) {
  851. fprintf(stderr, "'%s': unknown argument ('unset ?' for help).n", name);
  852. return 0;
  853.     } else if (Ambiguous(c)) {
  854. fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).n", name);
  855. return 0;
  856.     }
  857.     if (c->variable) {
  858. *c->variable = 0;
  859. if (c->actionexplanation) {
  860.     printf("%s %s.n", *c->variable? "Will" : "Won't", c->actionexplanation);
  861. }
  862.     }
  863.     if (c->handler) (*c->handler)(0);
  864. } else if (Ambiguous(ct)) {
  865.     fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).n", name);
  866.     return 0;
  867. } else if (ct->handler) {
  868.     (*ct->handler)(0);
  869.     printf("%s reset to "%s".n", ct->name, (char *)ct->charp);
  870. } else {
  871.     *(ct->charp) = _POSIX_VDISABLE;
  872.     printf("%s character is '%s'.n", ct->name, control(*(ct->charp)));
  873. }
  874.     }
  875.     return 1;
  876. }
  877. /* The following are the data structures and routines for the 'mode'         */
  878. /* command.                                                                  */
  879. #ifdef KLUDGELINEMODE
  880. extern int kludgelinemode;
  881. static int dokludgemode() {
  882.     kludgelinemode = 1;
  883.     send_wont(TELOPT_LINEMODE, 1);
  884.     send_dont(TELOPT_SGA, 1);
  885.     send_dont(TELOPT_ECHO, 1);
  886.     return 1;
  887. }
  888. #endif
  889. static int dolinemode() {
  890. #ifdef KLUDGELINEMODE
  891.     if (kludgelinemode) send_dont(TELOPT_SGA, 1);
  892. #endif
  893.     send_will(TELOPT_LINEMODE, 1);
  894.     send_dont(TELOPT_ECHO, 1);
  895.     return 1;
  896. }
  897. static int docharmode() {
  898. #ifdef KLUDGELINEMODE
  899.     if (kludgelinemode) send_do(TELOPT_SGA, 1);
  900.     else
  901. #endif
  902.     send_wont(TELOPT_LINEMODE, 1);
  903.     send_do(TELOPT_ECHO, 1);
  904.     return 1;
  905. }
  906. static int dolmmode(int bit, int on) {
  907.     unsigned char c;
  908.     extern int linemode;
  909.     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
  910. printf("?Need to have LINEMODE option enabled first.n");
  911. printf("'mode ?' for help.n");
  912. return 0;
  913.     }
  914.     if (on) c = (linemode | bit);
  915.     else    c = (linemode & ~bit);
  916.     lm_mode(&c, 1, 1);
  917.     return 1;
  918. }
  919. static int tn_setmode(int bit) {
  920.     return dolmmode(bit, 1);
  921. }
  922. static int clearmode(int bit) {
  923.     return dolmmode(bit, 0);
  924. }
  925. struct modelist {
  926.     char *name; /* command name */
  927.     char *help; /* help string */
  928.     int (*handler)(); /* routine which executes command */
  929.     int needconnect; /* Do we need to be connected to execute? */
  930.     int arg1;
  931. };
  932. extern int modehelp();
  933. static struct modelist ModeList[] = {
  934.     { "character", "Disable LINEMODE option",      docharmode, 1 },
  935. #ifdef KLUDGELINEMODE
  936.     { "",    "(or disable obsolete line-by-line mode)", 0 },
  937. #endif
  938.     { "line",    "Enable LINEMODE option",      dolinemode, 1 },
  939. #ifdef KLUDGELINEMODE
  940.     { "", "(or enable obsolete line-by-line mode)", 0 },
  941. #endif
  942.     { "", "", 0 },
  943.     { "",    "These require the LINEMODE option to be enabled", 0 },
  944.     { "isig",    "Enable signal trapping",      tn_setmode, 1, MODE_TRAPSIG },
  945.     { "+isig",    NULL,      tn_setmode, 1, MODE_TRAPSIG },
  946.     { "-isig",    "Disable signal trapping",      clearmode,  1, MODE_TRAPSIG },
  947.     { "edit",    "Enable character editing",      tn_setmode, 1, MODE_EDIT },
  948.     { "+edit",    NULL,      tn_setmode, 1, MODE_EDIT },
  949.     { "-edit",    "Disable character editing",      clearmode,  1, MODE_EDIT },
  950.     { "softtabs",  "Enable tab expansion",      tn_setmode, 1, MODE_SOFT_TAB },
  951.     { "+softtabs", NULL,      tn_setmode, 1, MODE_SOFT_TAB },
  952.     { "-softtabs", "Disable character editing",      clearmode,  1, MODE_SOFT_TAB },
  953.     { "litecho",   "Enable literal character echo",  tn_setmode, 1, MODE_LIT_ECHO },
  954.     { "+litecho",  NULL,      tn_setmode, 1, MODE_LIT_ECHO },
  955.     { "-litecho",  "Disable literal character echo", clearmode,  1, MODE_LIT_ECHO },
  956.     { "help",    NULL,      modehelp,   0 },
  957. #ifdef KLUDGELINEMODE
  958.     { "kludgeline", 0,      dokludgemode, 1 },
  959. #endif
  960.     { "", "", 0 },
  961.     { "?",     "Print help information",      modehelp, 0 },
  962.     { 0 },
  963. };
  964. int modehelp() {
  965.     struct modelist *mt;
  966.     printf("format is:  'mode Mode', where 'Mode' is one of:nn");
  967.     for (mt = ModeList; mt->name; mt++) {
  968. if (mt->help) {
  969.     if (*mt->help) printf("%-15s %sn", mt->name, mt->help);
  970.     else printf("n");
  971. }
  972.     }
  973.     return 0;
  974. }
  975. #define GETMODECMD(name) (struct modelist *) genget(name, (char **) ModeList, sizeof(struct modelist))
  976. static int modecmd(int argc, char *argv[]) {
  977.     struct modelist *mt;
  978.     if (argc != 2) {
  979. printf("'mode' command requires an argumentn");
  980. printf("'mode ?' for help.n");
  981.     } else if ((mt = GETMODECMD(argv[1])) == 0) {
  982. fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).n", argv[1]);
  983.     } else if (Ambiguous(mt)) {
  984. fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).n", argv[1]);
  985.     } else if (mt->needconnect && !connected) {
  986. printf("?Need to be connected first.n");
  987. printf("'mode ?' for help.n");
  988.     } else if (mt->handler) {
  989. return (*mt->handler)(mt->arg1);
  990.     }
  991.     return 0;
  992. }
  993. /* The following data structures and routines implement the "display"        */
  994. /* command.                                                                  */
  995. static int display(int argc, char *argv[]) {
  996.     struct togglelist *tl;
  997.     struct setlist *sl;
  998. #define dotog(tl) if (tl->variable && tl->actionexplanation) { 
  999.     if (*tl->variable) { 
  1000. printf("will"); 
  1001.     } else { 
  1002. printf("won't"); 
  1003.     } 
  1004.     printf(" %s.n", tl->actionexplanation); 
  1005. }
  1006. #define doset(sl)   if (sl->name && *sl->name != ' ') { 
  1007. if (sl->handler == 0) 
  1008.     printf("%-15s [%s]n", sl->name, control(*sl->charp)); 
  1009. else 
  1010.     printf("%-15s "%s"n", sl->name, (char *)sl->charp); 
  1011.     }
  1012.     if (argc == 1) {
  1013. for (tl = Togglelist; tl->name; tl++) {
  1014.     dotog(tl);
  1015. }
  1016. printf("n");
  1017. for (sl = Setlist; sl->name; sl++) {
  1018.     doset(sl);
  1019. }
  1020.     } else {
  1021. int i;
  1022. for (i = 1; i < argc; i++) {
  1023.     sl = getset(argv[i]);
  1024.     tl = GETTOGGLE(argv[i]);
  1025.     if (Ambiguous(sl) || Ambiguous(tl)) {
  1026. printf("?Ambiguous argument '%s'.n", argv[i]);
  1027. return 0;
  1028.     } else if (!sl && !tl) {
  1029. printf("?Unknown argument '%s'.n", argv[i]);
  1030. return 0;
  1031.     } else {
  1032. if (tl) {
  1033.     dotog(tl);
  1034. }
  1035. if (sl) {
  1036.     doset(sl);
  1037. }
  1038.     }
  1039. }
  1040.     }
  1041.     /*@*/optionstatus();
  1042.     return 1;
  1043. #undef doset
  1044. #undef dotog
  1045. }
  1046. /* The following are the data structures, and many of the routines, relating */
  1047. /* to command processing.                                                    */
  1048. /*                                                                           */
  1049. /* Set the escape character.                                                 */
  1050. static int setescape(int argc, char *argv[]) {
  1051.     register char *arg;
  1052.     char buf[50];
  1053.     
  1054.     printf("Deprecated usage - please use 'set escape%s%s' in the future.n",
  1055.    (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
  1056.     if (argc > 2) arg = argv[1];
  1057.     else {
  1058. printf("new escape character: ");
  1059. fgets(buf, sizeof(buf), stdin);
  1060. arg = buf;
  1061.     }
  1062.     if (arg[0] != '') escape = arg[0];
  1063.     if (!In3270) {
  1064. printf("Escape character is '%s'.n", control(escape));
  1065.     }
  1066.     fflush(stdout);
  1067.     return 1;
  1068. }
  1069. static int togcrmod() {
  1070.     crmod = !crmod;
  1071.     printf("Deprecated usage - please use 'toggle crmod' in the future.n");
  1072.     printf("%s map carriage return on output.n", crmod ? "Will" : "Won't");
  1073.     fflush(stdout);
  1074.     return 1;
  1075. }
  1076. int suspend() {
  1077. #ifdef SIGTSTP
  1078.     long oldrows, oldcols, newrows, newcols, err;
  1079.     setcommandmode();
  1080.     err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
  1081.     kill(0, SIGTSTP);
  1082.     /* If we didn't get the window size before the SUSPEND, but we can get   */
  1083.     /* them now (?), then send the NAWS to make sure that we are set up for  */
  1084.     /* the right window size.                                                                       */
  1085.     if (TerminalWindowSize(&newrows, &newcols) && connected &&
  1086. (err || ((oldrows != newrows) || (oldcols != newcols)))) {
  1087. sendnaws();
  1088.     }
  1089.     /* reget parameters in case they were changed */
  1090.     TerminalSaveState();
  1091.     setconnmode(0);
  1092. #else
  1093.     printf("Suspend is not supported.  Try the '!' command insteadn");
  1094. #endif
  1095.     return 1;
  1096. }
  1097. #ifndef TN3270
  1098. int shell(int argc, char *argv[]) {
  1099.     long oldrows, oldcols, newrows, newcols, err;
  1100.     setcommandmode();
  1101.     err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
  1102.     switch(vfork()) {
  1103.     case -1:
  1104. perror("Fork failedn");
  1105. break;
  1106.     case 0:
  1107. {
  1108.     /* Fire up the shell in the child. */
  1109.     register char *shellp, *shellname;
  1110.     shellp = getenv("SHELL");
  1111.     if (shellp == NULL) shellp = "/bin/sh";
  1112.     if ((shellname = strrchr(shellp, '/')) == 0) shellname = shellp;
  1113.     else shellname++;
  1114.     if (argc > 1) execl(shellp, shellname, "-c", &saveline[1], 0);
  1115.     else execl(shellp, shellname, 0);
  1116.     perror("Execl");
  1117.     _exit(1);
  1118. }
  1119.     default:
  1120. wait(NULL); /* Wait for the shell to complete */
  1121. if (TerminalWindowSize(&newrows, &newcols) && connected &&
  1122.     (err || ((oldrows != newrows) || (oldcols != newcols)))) {
  1123.     sendnaws();
  1124. }
  1125. break;
  1126.     }
  1127.     return 1;
  1128. }
  1129. #else
  1130. extern int shell();
  1131. #endif
  1132. /* The SLC command.                                                          */
  1133. struct slclist {
  1134. char *name;
  1135. char *help;
  1136. void (*handler)();
  1137. int arg;
  1138. };
  1139. static void slc_help();
  1140. struct slclist SlcList[] = {
  1141.     { "export", "Use local special character definitions",     slc_mode_export, 0 },
  1142.     { "import", "Use remote special character definitions",    slc_mode_import, 1 },
  1143.     { "check", "Verify remote special character definitions", slc_mode_import, 0 },
  1144.     { "help", 0,                slc_help, 0 },
  1145.     { "?", "Print help information",                slc_help, 0 },
  1146.     { 0 },
  1147. };
  1148. static void slc_help() {
  1149.     struct slclist *c;
  1150.     for (c = SlcList; c->name; c++) {
  1151. if (c->help) {
  1152.     if (*c->help) printf("%-15s %sn", c->name, c->help);
  1153.     else printf("n");
  1154. }
  1155.     }
  1156. }
  1157. static struct slclist *getslc(char *name) {
  1158.     return (struct slclist *) genget(name, (char **) SlcList, sizeof(struct slclist));
  1159. }
  1160. static int slccmd(int argc, char *argv[]) {
  1161.     struct slclist *c;
  1162.     if (argc != 2) {
  1163. fprintf(stderr, "Need an argument to 'slc' command.  'slc ?' for help.n");
  1164. return 0;
  1165.     }
  1166.     
  1167.     c = getslc(argv[1]);
  1168.     if (c == 0) {
  1169. fprintf(stderr, "'%s': unknown argument ('slc ?' for help).n", argv[1]);
  1170. return 0;
  1171.     }
  1172.     
  1173.     if (Ambiguous(c)) {
  1174. fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).n", argv[1]);
  1175. return 0;
  1176.     }
  1177.     
  1178.     (*c->handler)(c->arg);
  1179.     slcstate();
  1180.     return 1;
  1181. }
  1182. /* The ENVIRON command. */
  1183. struct envlist {
  1184. char *name;
  1185. char *help;
  1186. void (*handler)();
  1187. int narg;
  1188. };
  1189. extern struct env_lst *
  1190. env_define P((unsigned char *, unsigned char *));
  1191. extern void
  1192. env_undefine P((unsigned char *)),
  1193. env_export P((unsigned char *)),
  1194. env_unexport P((unsigned char *)),
  1195. env_send P((unsigned char *)),
  1196. #if defined(OLD_ENVIRON) && defined(ENV_HACK)
  1197. env_varval P((unsigned char *)),
  1198. #endif
  1199. env_list P((void));
  1200. static void
  1201. env_help P((void));
  1202. struct envlist EnvList[] = {
  1203.     { "define", "Define an environment variable",
  1204. (void (*)())env_define, 2 },
  1205.     { "undefine", "Undefine an environment variable",
  1206. env_undefine, 1 },
  1207.     { "export", "Mark an environment variable for automatic export",
  1208. env_export, 1 },
  1209.     { "unexport", "Don't mark an environment variable for automatic export",
  1210. env_unexport, 1 },
  1211.     { "send", "Send an environment variable", env_send, 1 },
  1212.     { "list", "List the current environment variables",
  1213. env_list, 0 },
  1214. #if defined(OLD_ENVIRON) && defined(ENV_HACK)
  1215.     { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
  1216. env_varval,    1 },
  1217. #endif
  1218.     { "help", 0, env_help, 0 },
  1219.     { "?", "Print help information", env_help, 0 },
  1220.     { 0 },
  1221. };
  1222. static void env_help() {
  1223.     struct envlist *c;
  1224.     for (c = EnvList; c->name; c++) {
  1225. if (c->help) {
  1226.     if (*c->help) printf("%-15s %sn", c->name, c->help);
  1227.     else printf("n");
  1228. }
  1229.     }
  1230. }
  1231. static struct envlist *getenvcmd(char *name) {
  1232.     return (struct envlist *)genget(name, (char **) EnvList, sizeof(struct envlist));
  1233. }
  1234. int env_cmd(int argc, char *argv[]) {
  1235.     struct envlist *c;
  1236.     if (argc < 2) {
  1237. fprintf(stderr, "Need an argument to 'environ' command.  'environ ?' for help.n");
  1238. return 0;
  1239.     }
  1240.     c = getenvcmd(argv[1]);
  1241.     if (c == 0) {
  1242. fprintf(stderr, "'%s': unknown argument ('environ ?' for help).n", argv[1]);
  1243. return 0;
  1244.     }
  1245.     if (Ambiguous(c)) {
  1246. fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).n", argv[1]);
  1247. return 0;
  1248.     }
  1249.     
  1250.     if (c->narg + 2 != argc) {
  1251. fprintf(stderr, "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.n",
  1252. c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name);
  1253. return 0;
  1254.     }
  1255.     (*c->handler)(argv[2], argv[3]);
  1256.     return 1;
  1257. }
  1258. struct env_lst {
  1259. struct env_lst *next; /* pointer to next structure */
  1260. struct env_lst *prev; /* pointer to previous structure */
  1261. unsigned char *var; /* pointer to variable name */
  1262. unsigned char *value; /* pointer to variable value */
  1263. int export; /* 1 -> export with default list of variables */
  1264. int welldefined; /* A well defined variable */
  1265. };
  1266. struct env_lst envlisthead;
  1267. struct env_lst *env_find(unsigned char *var) {
  1268.     register struct env_lst *ep;
  1269.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1270. if (strcmp((char *)ep->var, (char *)var) == 0)
  1271.     return(ep);
  1272.     }
  1273.     return(NULL);
  1274. }
  1275. void env_init() {
  1276.     extern char **environ;
  1277.     register char **epp, *cp;
  1278.     register struct env_lst *ep;
  1279.     for (epp = environ; *epp; epp++) {
  1280. if ((cp = strchr(*epp, '='))) {
  1281.     *cp = '';
  1282.     ep = env_define((unsigned char *)*epp, (unsigned char *)cp+1);
  1283.     ep->export = 0;
  1284.     *cp = '=';
  1285. }
  1286.     }
  1287.     /* Special case for DISPLAY variable.  If it is ":0.0" or "unix:0.0", we */
  1288.     /* have to get rid of "unix" and insert our hostname.                    */
  1289.     if ((ep = env_find("DISPLAY")) && ((*ep->value == ':') || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
  1290. char hbuf[256+1];
  1291. char *cp2 = strchr((char *)ep->value, ':');
  1292. gethostname(hbuf, 256);
  1293. hbuf[256] = '';
  1294. cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
  1295. sprintf((char *)cp, "%s%s", hbuf, cp2);
  1296. free(ep->value);
  1297. ep->value = (unsigned char *)cp;
  1298.     }
  1299.     /* If USER is not defined, but LOGNAME is, then add USER with the value  */
  1300.     /* from LOGNAME.  By default, we don't export the USER variable.         */
  1301.     if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
  1302. env_define((unsigned char *)"USER", ep->value);
  1303. env_unexport((unsigned char *)"USER");
  1304.     }
  1305.     env_export((unsigned char *)"DISPLAY");
  1306.     env_export((unsigned char *)"PRINTER");
  1307. }
  1308. struct env_lst *env_define(unsigned char *var, unsigned char *value) {
  1309.     register struct env_lst *ep;
  1310.     if ((ep = env_find(var))) {
  1311. if (ep->var)   free(ep->var);
  1312. if (ep->value) free(ep->value);
  1313.     } else {
  1314. ep = (struct env_lst *)malloc(sizeof(struct env_lst));
  1315. ep->next = envlisthead.next;
  1316. envlisthead.next = ep;
  1317. ep->prev = &envlisthead;
  1318. if (ep->next) ep->next->prev = ep;
  1319.     }
  1320.     ep->welldefined = opt_welldefined((char *)var);
  1321.     ep->export = 1;
  1322.     ep->var = (unsigned char *)strdup((char *)var);
  1323.     ep->value = (unsigned char *)strdup((char *)value);
  1324.     return(ep);
  1325. }
  1326. void env_undefine(unsigned char *var) {
  1327.     register struct env_lst *ep;
  1328.     if ((ep = env_find(var))) {
  1329. ep->prev->next = ep->next;
  1330. if (ep->next)  ep->next->prev = ep->prev;
  1331. if (ep->var)   free(ep->var);
  1332. if (ep->value) free(ep->value);
  1333. free(ep);
  1334.     }
  1335. }
  1336. void env_export(unsigned char *var) {
  1337.     register struct env_lst *ep;
  1338.     
  1339.     if ((ep = env_find(var))) ep->export = 1;
  1340. }
  1341. void env_unexport(unsigned char *var) {
  1342.     register struct env_lst *ep;
  1343.     if ((ep = env_find(var))) ep->export = 0;
  1344. }
  1345. void env_send(unsigned char *var) {
  1346.     register struct env_lst *ep;
  1347.     if (my_state_is_wont(TELOPT_NEW_ENVIRON)
  1348. #ifdef OLD_ENVIRON
  1349. && my_state_is_wont(TELOPT_OLD_ENVIRON)
  1350. #endif
  1351. ) {
  1352. fprintf(stderr, "Cannot send '%s': Telnet ENVIRON option not enabledn", var);
  1353. return;
  1354.     }
  1355.     ep = env_find(var);
  1356.     
  1357.     if (ep == 0) {
  1358. fprintf(stderr, "Cannot send '%s': variable not definedn", var);
  1359. return;
  1360.     }
  1361.     env_opt_start_info();
  1362.     env_opt_add(ep->var);
  1363.     env_opt_end(0);
  1364. }
  1365. void env_list() {
  1366.     register struct env_lst *ep;
  1367.     
  1368.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1369. printf("%c %-20s %sn", ep->export ? '*' : ' ', ep->var, ep->value);
  1370.     }
  1371. }
  1372. unsigned char *
  1373. env_default(init, welldefined)
  1374.     int init, welldefined;
  1375. {
  1376. static struct env_lst *nep = NULL;
  1377. if (init) {
  1378. nep = &envlisthead;
  1379. return NULL;
  1380. }
  1381. if (nep) {
  1382. while ((nep = nep->next)) {
  1383. if (nep->export && (nep->welldefined == welldefined))
  1384. return(nep->var);
  1385. }
  1386. }
  1387. return(NULL);
  1388. }
  1389. unsigned char *
  1390. env_getvalue(var)
  1391. unsigned char *var;
  1392. {
  1393. register struct env_lst *ep;
  1394. if ((ep = env_find(var)))
  1395. return(ep->value);
  1396. return(NULL);
  1397. }
  1398. #if defined(OLD_ENVIRON) && defined(ENV_HACK)
  1399. void
  1400. env_varval(what)
  1401. unsigned char *what;
  1402. {
  1403. extern int old_env_var, old_env_value, env_auto;
  1404. int len = strlen((char *)what);
  1405. if (len == 0)
  1406. goto unknown;
  1407. if (strncasecmp((char *)what, "status", len) == 0) {
  1408. if (env_auto)
  1409. printf("%s%s", "VAR and VALUE are/will be ",
  1410. "determined automaticallyn");
  1411. if (old_env_var == OLD_ENV_VAR)
  1412. printf("VAR and VALUE set to correct definitionsn");
  1413. else
  1414. printf("VAR and VALUE definitions are reversedn");
  1415. } else if (strncasecmp((char *)what, "auto", len) == 0) {
  1416. env_auto = 1;
  1417. old_env_var = OLD_ENV_VALUE;
  1418. old_env_value = OLD_ENV_VAR;
  1419. } else if (strncasecmp((char *)what, "right", len) == 0) {
  1420. env_auto = 0;
  1421. old_env_var = OLD_ENV_VAR;
  1422. old_env_value = OLD_ENV_VALUE;
  1423. } else if (strncasecmp((char *)what, "wrong", len) == 0) {
  1424. env_auto = 0;
  1425. old_env_var = OLD_ENV_VALUE;
  1426. old_env_value = OLD_ENV_VAR;
  1427. } else {
  1428. unknown:
  1429. printf("Unknown "varval" command. ("auto", "right", "wrong", "status")n");
  1430. }
  1431. }
  1432. #endif
  1433. #ifdef TN3270
  1434.     static void
  1435. filestuff(fd)
  1436.     int fd;
  1437. {
  1438.     int res;
  1439. #ifdef F_GETOWN
  1440.     setconnmode(0);
  1441.     res = fcntl(fd, F_GETOWN, 0);
  1442.     setcommandmode();
  1443.     if (res == -1) {
  1444. perror("fcntl");
  1445. return;
  1446.     }
  1447.     printf("tOwner is %d.n", res);
  1448. #endif
  1449.     setconnmode(0);
  1450.     res = fcntl(fd, F_GETFL, 0);
  1451.     setcommandmode();
  1452.     if (res == -1) {
  1453. perror("fcntl");
  1454. return;
  1455.     }
  1456. #ifdef notdef
  1457.     printf("tFlags are 0x%x: %sn", res, decodeflags(res));
  1458. #endif
  1459. }
  1460. #endif
  1461. /*
  1462.  * Print status about the connection.
  1463.  */
  1464.     /*ARGSUSED*/
  1465.     static int 
  1466. status(argc, argv)
  1467.     int  argc;
  1468.     char *argv[];
  1469. {
  1470.     if (connected) {
  1471. printf("Connected to %s.n", hostname);
  1472. if ((argc < 2) || strcmp(argv[1], "notmuch")) {
  1473.     int mode = getconnmode();
  1474.     if (my_want_state_is_will(TELOPT_LINEMODE)) {
  1475. printf("Operating with LINEMODE optionn");
  1476. printf("%s line editingn", (mode&MODE_EDIT) ? "Local" : "No");
  1477. printf("%s catching of signalsn",
  1478. (mode&MODE_TRAPSIG) ? "Local" : "No");
  1479. slcstate();
  1480. #ifdef KLUDGELINEMODE
  1481.     } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
  1482. printf("Operating in obsolete linemoden");
  1483. #endif
  1484.     } else {
  1485. printf("Operating in single character moden");
  1486. if (localchars)
  1487.     printf("Catching signals locallyn");
  1488.     }
  1489.     printf("%s character echon", (mode&MODE_ECHO) ? "Local" : "Remote");
  1490.     if (my_want_state_is_will(TELOPT_LFLOW))
  1491. printf("%s flow controln", (mode&MODE_FLOW) ? "Local" : "No");
  1492. }
  1493.     } else {
  1494. printf("No connection.n");
  1495.     }
  1496. #ifndef TN3270
  1497.     printf("Escape character is '%s'.n", control(escape));
  1498.     (void) fflush(stdout);
  1499. #   else /* !defined(TN3270) */
  1500.     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
  1501. printf("Escape character is '%s'.n", control(escape));
  1502.     }
  1503.     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
  1504. printf("SIGIO received %d time%s.n",
  1505. sigiocount, (sigiocount == 1)? "":"s");
  1506. if (In3270) {
  1507.     printf("Process ID %d, process group %d.n",
  1508.     getpid(), getpgrp(getpid()));
  1509.     printf("Terminal input:n");
  1510.     filestuff(tin);
  1511.     printf("Terminal output:n");
  1512.     filestuff(tout);
  1513.     printf("Network socket:n");
  1514.     filestuff(net);
  1515. }
  1516.     }
  1517.     if (In3270 && transcom) {
  1518.        printf("Transparent mode command is '%s'.n", transcom);
  1519.     }
  1520.     fflush(stdout);
  1521.     if (In3270) return 0;
  1522. #   endif /* defined(TN3270) */
  1523.     return 1;
  1524. }
  1525. #ifdef SIGINFO
  1526. /*
  1527.  * Function that gets called when SIGINFO is received.
  1528.  */
  1529.      void
  1530. ayt_status()
  1531. {
  1532.     (void) call(status, "status", "notmuch", 0);
  1533. }
  1534. #endif
  1535.     int
  1536. tn(argc, argv)
  1537.     int argc;
  1538.     char *argv[];
  1539. {
  1540.     register struct hostent *host = 0;
  1541.     struct sockaddr_in sin;
  1542.     struct servent *sp = 0;
  1543.     unsigned int temp;
  1544. #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
  1545.     char *srp = 0;
  1546.     unsigned int sourceroute(), srlen;
  1547. #endif
  1548.     char *cmd, *hostp = 0, *portp = 0, *user = 0;
  1549.     /* clear the socket address prior to use */
  1550.     memset((char *)&sin, 0, sizeof(sin));
  1551.     if (connected) {
  1552. printf("?Already connected to %sn", hostname);
  1553. setuid(getuid());
  1554. return 0;
  1555.     }
  1556.     if (argc < 2) {
  1557. (void) strcpy(line, "open ");
  1558. printf("(to) ");
  1559. (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
  1560. makeargv();
  1561. argc = margc;
  1562. argv = margv;
  1563.     }
  1564.     cmd = *argv;
  1565.     --argc; ++argv;
  1566.     while (argc) {
  1567. if (isprefix(*argv, "help") || isprefix(*argv, "?"))
  1568.     goto usage;
  1569. if (strcmp(*argv, "-l") == 0) {
  1570.     --argc; ++argv;
  1571.     if (argc == 0)
  1572. goto usage;
  1573.     user = *argv++;
  1574.     --argc;
  1575.     continue;
  1576. }
  1577. if (strcmp(*argv, "-a") == 0) {
  1578.     --argc; ++argv;
  1579.     autologin = 1;
  1580.     continue;
  1581. }
  1582. if (hostp == 0) {
  1583.     hostp = *argv++;
  1584.     --argc;
  1585.     continue;
  1586. }
  1587. if (portp == 0) {
  1588.     portp = *argv++;
  1589.     --argc;
  1590.     continue;
  1591. }
  1592.     usage:
  1593. printf("usage: %s [-l user] [-a] host-name [port]n", cmd);
  1594. setuid(getuid());
  1595. return 0;
  1596.     }
  1597.     if (hostp == 0)
  1598. goto usage;
  1599. #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
  1600.     if (hostp[0] == '@' || hostp[0] == '!') {
  1601. if ((hostname = strrchr(hostp, ':')) == NULL)
  1602.     hostname = strrchr(hostp, '@');
  1603. hostname++;
  1604. srp = 0;
  1605. temp = sourceroute(hostp, &srp, &srlen);
  1606. if (temp == 0) {
  1607.     herror(srp);
  1608.     setuid(getuid());
  1609.     return 0;
  1610. } else if (temp == -1) {
  1611.     printf("Bad source route option: %sn", hostp);
  1612.     setuid(getuid());
  1613.     return 0;
  1614. } else {
  1615.     sin.sin_addr.s_addr = temp;
  1616.     sin.sin_family = AF_INET;
  1617. }
  1618.     } else {
  1619. #endif
  1620. temp = (unsigned int)inet_addr(hostp);
  1621. if (temp != (unsigned int) -1) {
  1622.     sin.sin_addr.s_addr = temp;
  1623.     sin.sin_family = AF_INET;
  1624.     (void) strcpy(_hostname, hostp);
  1625.     hostname = _hostname;
  1626. } else {
  1627.     host = gethostbyname(hostp);
  1628.     if (host) {
  1629. sin.sin_family = host->h_addrtype;
  1630. #ifdef h_addr /* In 4.3, this is a #define */
  1631. memmove((caddr_t)&sin.sin_addr,
  1632. host->h_addr_list[0], host->h_length);
  1633. #else /* defined(h_addr) */
  1634. memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
  1635. #endif /* defined(h_addr) */
  1636. strncpy(_hostname, host->h_name, sizeof(_hostname));
  1637. _hostname[sizeof(_hostname)-1] = '';
  1638. hostname = _hostname;
  1639.     } else {
  1640. herror(hostp);
  1641. setuid(getuid());
  1642. return 0;
  1643.     }
  1644. }
  1645. #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
  1646.     }
  1647. #endif
  1648.     if (portp) {
  1649. if (*portp == '-') {
  1650.     portp++;
  1651.     telnetport = 1;
  1652. } else
  1653.     telnetport = 0;
  1654. sin.sin_port = atoi(portp);
  1655. if (sin.sin_port == 0) {
  1656.     sp = getservbyname(portp, "tcp");
  1657.     if (sp)
  1658. sin.sin_port = sp->s_port;
  1659.     else {
  1660. printf("%s: bad port numbern", portp);
  1661. setuid(getuid());
  1662. return 0;
  1663.     }
  1664. } else {
  1665.     sin.sin_port = htons(sin.sin_port);
  1666. }
  1667.     } else {
  1668. if (sp == 0) {
  1669.     sp = getservbyname("telnet", "tcp");
  1670.     if (sp == 0) {
  1671. fprintf(stderr, "telnet: tcp/telnet: unknown servicen");
  1672. setuid(getuid());
  1673. return 0;
  1674.     }
  1675.     sin.sin_port = sp->s_port;
  1676. }
  1677. telnetport = 1;
  1678.     }
  1679.     printf("Trying %s...n", inet_ntoa(sin.sin_addr));
  1680.     do {
  1681. net = socket(AF_INET, SOCK_STREAM, 0);
  1682. setuid(getuid());
  1683. if (net < 0) {
  1684.     perror("telnet: socket");
  1685.     return 0;
  1686. }
  1687. #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
  1688. if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
  1689. perror("setsockopt (IP_OPTIONS)");
  1690. #endif
  1691. #if defined(IPPROTO_IP) && defined(IP_TOS)
  1692. {
  1693. #ifdef HAS_GETTOS
  1694.     struct tosent *tp;
  1695.     if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
  1696. tos = tp->t_tos;
  1697. # endif
  1698.     if (tos < 0)
  1699. tos = 020; /* Low Delay bit */
  1700.     if (tos
  1701. && (setsockopt(net, IPPROTO_IP, IP_TOS,
  1702.     (char *)&tos, sizeof(int)) < 0)
  1703. && (errno != ENOPROTOOPT))
  1704.     perror("telnet: setsockopt (IP_TOS) (ignored)");
  1705. }
  1706. #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
  1707. if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
  1708. perror("setsockopt (SO_DEBUG)");
  1709. }
  1710. if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  1711. #ifdef h_addr /* In 4.3, this is a #define */
  1712.     if (host && host->h_addr_list[1]) {
  1713. int oerrno = errno;
  1714. fprintf(stderr, "telnet: connect to address %s: ",
  1715. inet_ntoa(sin.sin_addr));
  1716. errno = oerrno;
  1717. perror((char *)0);
  1718. host->h_addr_list++;
  1719. memmove((caddr_t)&sin.sin_addr,
  1720. host->h_addr_list[0], host->h_length);
  1721. NetClose(net);
  1722. continue;
  1723.     }
  1724. #endif /* defined(h_addr) */
  1725.     perror("telnet: Unable to connect to remote host");
  1726.     return 0;
  1727. }
  1728. connected++;
  1729.     } while (connected == 0);
  1730.     cmdrc(hostp, hostname);
  1731.     if (autologin && user == NULL) {
  1732. struct passwd *pw;
  1733. user = getenv("USER");
  1734. if (user == NULL ||
  1735.     (((pw = getpwnam(user))) && pw->pw_uid != getuid())) {
  1736. if ((pw = getpwuid(getuid())))
  1737. user = pw->pw_name;
  1738. else
  1739. user = NULL;
  1740. }
  1741.     }
  1742.     if (user) {
  1743. env_define((unsigned char *)"USER", (unsigned char *)user);
  1744. env_export((unsigned char *)"USER");
  1745.     }
  1746.     (void) call(status, "status", "notmuch", 0);
  1747.     if (setjmp(peerdied) == 0)
  1748. telnet(user);
  1749.     NetClose(net);
  1750.     ExitString("Connection closed by foreign host.n",1);
  1751.     /*NOTREACHED*/
  1752.     return 0;
  1753. }
  1754. #define HELPINDENT (sizeof ("connect"))
  1755. static char
  1756. openhelp[] = "connect to a site",
  1757. closehelp[] = "close current connection",
  1758. logouthelp[] = "forcibly logout remote user and close the connection",
  1759. quithelp[] = "exit telnet",
  1760. statushelp[] = "print status information",
  1761. helphelp[] = "print help information",
  1762. sendhelp[] = "transmit special characters ('send ?' for more)",
  1763. sethelp[] =  "set operating parameters ('set ?' for more)",
  1764. unsethelp[] =  "unset operating parameters ('unset ?' for more)",
  1765. togglestring[] ="toggle operating parameters ('toggle ?' for more)",
  1766. slchelp[] = "change state of special charaters ('slc ?' for more)",
  1767. displayhelp[] = "display operating parameters",
  1768. #ifdef TN3270
  1769. transcomhelp[] = "specify Unix command for transparent mode pipe",
  1770. #endif /* defined(TN3270) */
  1771. zhelp[] = "suspend telnet",
  1772. shellhelp[] = "invoke a subshell",
  1773. envhelp[] = "change environment variables ('environ ?' for more)",
  1774. modestring[] = "try to enter line or character mode ('mode ?' for more)";
  1775. static int help();
  1776. static Command cmdtab[] = {
  1777. { "close", closehelp, bye, 1 },
  1778. { "logout", logouthelp, logout, 1 },
  1779. { "display", displayhelp, display, 0 },
  1780. { "mode", modestring, modecmd, 0 },
  1781. { "open", openhelp, tn, 0 },
  1782. { "quit", quithelp, quit, 0 },
  1783. { "send", sendhelp, sendcmd, 0 },
  1784. { "set", sethelp, setcmd, 0 },
  1785. { "unset", unsethelp, unsetcmd, 0 },
  1786. { "status", statushelp, status, 0 },
  1787. { "toggle", togglestring, toggle, 0 },
  1788. { "slc", slchelp, slccmd, 0 },
  1789. #ifdef TN3270
  1790. { "transcom", transcomhelp, settranscom, 0 },
  1791. #endif /* defined(TN3270) */
  1792. { "z", zhelp, suspend, 0 },
  1793. #ifdef TN3270
  1794. { "!", shellhelp, shell, 1 },
  1795. #else
  1796. { "!", shellhelp, shell, 0 },
  1797. #endif
  1798. { "environ", envhelp, env_cmd, 0 },
  1799. { "?", helphelp, help, 0 },
  1800. { 0 } 
  1801. };
  1802. static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
  1803. static char escapehelp[] = "deprecated command -- use 'set escape' instead";
  1804. static Command cmdtab2[] = {
  1805. { "help", 0, help, 0 },
  1806. { "escape", escapehelp, setescape, 0 },
  1807. { "crmod", crmodhelp, togcrmod, 0 },
  1808. { 0 }
  1809. };
  1810. /*
  1811.  * Call routine with argc, argv set from args (terminated by 0).
  1812.  */
  1813.     /*VARARGS1*/
  1814.     static int
  1815. call(va_alist)
  1816.     va_dcl
  1817. {
  1818.     va_list ap;
  1819.     typedef int (*intrtn_t)();
  1820.     intrtn_t routine;
  1821.     char *args[100];
  1822.     int argno = 0;
  1823.     va_start(ap);
  1824.     routine = (va_arg(ap, intrtn_t));
  1825.     while ((args[argno++] = va_arg(ap, char *)) != 0) {
  1826. ;
  1827.     }
  1828.     va_end(ap);
  1829.     return (*routine)(argno-1, args);
  1830. }
  1831.     static Command *
  1832. getcmd(name)
  1833.     char *name;
  1834. {
  1835.     Command *cm;
  1836.     
  1837.     if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 
  1838. return cm;
  1839.     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
  1840. }
  1841.     void
  1842. command(top, tbuf, cnt)
  1843.     int top;
  1844.     char *tbuf;
  1845.     int cnt;
  1846. {
  1847.     register Command *c;
  1848.     setcommandmode();
  1849.     if (!top) {
  1850. putchar('n');
  1851.     } else {
  1852. Signal(SIGINT, SIG_DFL);
  1853. Signal(SIGQUIT, SIG_DFL);
  1854.     }
  1855.     for (;;) {
  1856. if (rlogin == _POSIX_VDISABLE)
  1857. printf("%s> ", prompt);
  1858. if (tbuf) {
  1859.     register char *cp;
  1860.     cp = line;
  1861.     while (cnt > 0 && (*cp++ = *tbuf++) != 'n')
  1862. cnt--;
  1863.     tbuf = 0;
  1864.     if (cp == line || *--cp != 'n' || cp == line)
  1865. goto getline;
  1866.     *cp = '';
  1867.     if (rlogin == _POSIX_VDISABLE)
  1868. printf("%sn", line);
  1869. } else {
  1870. getline:
  1871.     if (rlogin != _POSIX_VDISABLE)
  1872. printf("%s> ", prompt);
  1873.     if (fgets(line, sizeof(line), stdin) == NULL) {
  1874. if (feof(stdin) || ferror(stdin)) {
  1875.     (void) quit();
  1876.     /*NOTREACHED*/
  1877. }
  1878. break;
  1879.     }
  1880. }
  1881. if (line[0] == 0)
  1882.     break;
  1883. makeargv();
  1884. if (margv[0] == 0) {
  1885.     break;
  1886. }
  1887. c = getcmd(margv[0]);
  1888. if (Ambiguous(c)) {
  1889.     printf("?Ambiguous commandn");
  1890.     continue;
  1891. }
  1892. if (c == 0) {
  1893.     printf("?Invalid commandn");
  1894.     continue;
  1895. }
  1896. if (c->needconnect && !connected) {
  1897.     printf("?Need to be connected first.n");
  1898.     continue;
  1899. }
  1900. if ((*c->handler)(margc, margv)) {
  1901.     break;
  1902. }
  1903.     }
  1904.     if (!top) {
  1905. if (!connected) {
  1906.     longjmp(toplevel, 1);
  1907.     /*NOTREACHED*/
  1908. }
  1909. #ifdef TN3270
  1910. if (shell_active == 0) {
  1911.     setconnmode(0);
  1912. }
  1913. #else /* defined(TN3270) */
  1914. setconnmode(0);
  1915. #endif /* defined(TN3270) */
  1916.     }
  1917. }
  1918. /*
  1919.  * Help command.
  1920.  */
  1921. static int
  1922. help(argc, argv)
  1923. int argc;
  1924. char *argv[];
  1925. {
  1926. register Command *c;
  1927. if (argc == 1) {
  1928. printf("Commands may be abbreviated.  Commands are:nn");
  1929. for (c = cmdtab; c->name; c++)
  1930. if (c->help) {
  1931.     printf("%-*st%sn", (int)HELPINDENT, c->name, c->help);
  1932. }
  1933. return 0;
  1934. }
  1935. while (--argc > 0) {
  1936. register char *arg;
  1937. arg = *++argv;
  1938. c = getcmd(arg);
  1939. if (Ambiguous(c))
  1940. printf("?Ambiguous help command %sn", arg);
  1941. else if (c == (Command *)0)
  1942. printf("?Invalid help command %sn", arg);
  1943. else
  1944. printf("%sn", c->help);
  1945. }
  1946. return 0;
  1947. }
  1948. static char *rcname = 0;
  1949. static char rcbuf[128];
  1950.     void
  1951. cmdrc(m1, m2)
  1952.     char *m1, *m2;
  1953. {
  1954.     register Command *c;
  1955.     FILE *rcfile;
  1956.     int gotmachine = 0;
  1957.     int l1 = strlen(m1);
  1958.     int l2 = strlen(m2);
  1959.     char m1save[64];
  1960.     
  1961.     if (skiprc)
  1962. return;
  1963.     strcpy(m1save, m1);
  1964.     m1 = m1save;
  1965.     if (rcname == 0) {
  1966. rcname = getenv("HOME");
  1967. if (rcname)
  1968.     strcpy(rcbuf, rcname);
  1969. else
  1970.     rcbuf[0] = '';
  1971. strcat(rcbuf, "/.telnetrc");
  1972. rcname = rcbuf;
  1973.     }
  1974.     if ((rcfile = fopen(rcname, "r")) == 0) {
  1975. return;
  1976.     }
  1977.     for (;;) {
  1978. if (fgets(line, sizeof(line), rcfile) == NULL)
  1979.     break;
  1980. if (line[0] == 0)
  1981.     break;
  1982. if (line[0] == '#')
  1983.     continue;
  1984. if (gotmachine) {
  1985.     if (!isspace(line[0]))
  1986. gotmachine = 0;
  1987. }
  1988. if (gotmachine == 0) {
  1989.     if (isspace(line[0]))
  1990. continue;
  1991.     if (strncasecmp(line, m1, l1) == 0)
  1992. strncpy(line, &line[l1], sizeof(line) - l1);
  1993.     else if (strncasecmp(line, m2, l2) == 0)
  1994. strncpy(line, &line[l2], sizeof(line) - l2);
  1995.     else if (strncasecmp(line, "DEFAULT", 7) == 0)
  1996. strncpy(line, &line[7], sizeof(line) - 7);
  1997.     else
  1998. continue;
  1999.     if (line[0] != ' ' && line[0] != 't' && line[0] != 'n')
  2000. continue;
  2001.     gotmachine = 1;
  2002. }
  2003. makeargv();
  2004. if (margv[0] == 0)
  2005.     continue;
  2006. c = getcmd(margv[0]);
  2007. if (Ambiguous(c)) {
  2008.     printf("?Ambiguous command: %sn", margv[0]);
  2009.     continue;
  2010. }
  2011. if (c == 0) {
  2012.     printf("?Invalid command: %sn", margv[0]);
  2013.     continue;
  2014. }
  2015. /*
  2016.  * This should never happen...
  2017.  */
  2018. if (c->needconnect && !connected) {
  2019.     printf("?Need to be connected first for %s.n", margv[0]);
  2020.     continue;
  2021. }
  2022. (*c->handler)(margc, margv);
  2023.     }
  2024.     fclose(rcfile);
  2025. }
  2026. #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
  2027. /*
  2028.  * Source route is handed in as
  2029.  * [!]@hop1@hop2...[@|:]dst
  2030.  * If the leading ! is present, it is a
  2031.  * strict source route, otherwise it is
  2032.  * assmed to be a loose source route.
  2033.  *
  2034.  * We fill in the source route option as
  2035.  * hop1,hop2,hop3...dest
  2036.  * and return a pointer to hop1, which will
  2037.  * be the address to connect() to.
  2038.  *
  2039.  * Arguments:
  2040.  * arg: pointer to route list to decipher
  2041.  *
  2042.  * cpp:  If *cpp is not equal to NULL, this is a
  2043.  * pointer to a pointer to a character array
  2044.  * that should be filled in with the option.
  2045.  *
  2046.  * lenp: pointer to an integer that contains the
  2047.  * length of *cpp if *cpp != NULL.
  2048.  *
  2049.  * Return values:
  2050.  *
  2051.  * Returns the address of the host to connect to.  If the
  2052.  * return value is -1, there was a syntax error in the
  2053.  * option, either unknown characters, or too many hosts.
  2054.  * If the return value is 0, one of the hostnames in the
  2055.  * path is unknown, and *cpp is set to point to the bad
  2056.  * hostname.
  2057.  *
  2058.  * *cpp: If *cpp was equal to NULL, it will be filled
  2059.  * in with a pointer to our static area that has
  2060.  * the option filled in.  This will be 32bit aligned.
  2061.  *
  2062.  * *lenp: This will be filled in with how long the option
  2063.  * pointed to by *cpp is.
  2064.  *
  2065.  */
  2066. unsigned int
  2067. sourceroute(arg, cpp, lenp)
  2068. char *arg;
  2069. char **cpp;
  2070. int *lenp;
  2071. {
  2072. static char lsr[44];
  2073. #ifdef sysV88
  2074. static IOPTN ipopt;
  2075. #endif
  2076. char *cp, *cp2, *lsrp, *lsrep;
  2077. register int tmp;
  2078. struct in_addr sin_addr;
  2079. register struct hostent *host = 0;
  2080. register char c;
  2081. /*
  2082.  * Verify the arguments, and make sure we have
  2083.  * at least 7 bytes for the option.
  2084.  */
  2085. if (cpp == NULL || lenp == NULL)
  2086. return((unsigned int)-1);
  2087. if (*cpp != NULL && *lenp < 7)
  2088. return((unsigned int)-1);
  2089. /*
  2090.  * Decide whether we have a buffer passed to us,
  2091.  * or if we need to use our own static buffer.
  2092.  */
  2093. if (*cpp) {
  2094. lsrp = *cpp;
  2095. lsrep = lsrp + *lenp;
  2096. } else {
  2097. *cpp = lsrp = lsr;
  2098. lsrep = lsrp + 44;
  2099. }
  2100. cp = arg;
  2101. /*
  2102.  * Next, decide whether we have a loose source
  2103.  * route or a strict source route, and fill in
  2104.  * the begining of the option.
  2105.  */
  2106. #ifndef sysV88
  2107. if (*cp == '!') {
  2108. cp++;
  2109. *lsrp++ = IPOPT_SSRR;
  2110. } else
  2111. *lsrp++ = IPOPT_LSRR;
  2112. #else
  2113. if (*cp == '!') {
  2114. cp++;
  2115. ipopt.io_type = IPOPT_SSRR;
  2116. } else
  2117. ipopt.io_type = IPOPT_LSRR;
  2118. #endif
  2119. if (*cp != '@')
  2120. return((unsigned int)-1);
  2121. #ifndef sysV88
  2122. lsrp++; /* skip over length, we'll fill it in later */
  2123. *lsrp++ = 4;
  2124. #endif
  2125. cp++;
  2126. sin_addr.s_addr = 0;
  2127. for (c = 0;;) {
  2128. if (c == ':')
  2129. cp2 = 0;
  2130. else for (cp2 = cp; (c = *cp2); cp2++) {
  2131. if (c == ',') {
  2132. *cp2++ = '';
  2133. if (*cp2 == '@')
  2134. cp2++;
  2135. } else if (c == '@') {
  2136. *cp2++ = '';
  2137. } else if (c == ':') {
  2138. *cp2++ = '';
  2139. } else
  2140. continue;
  2141. break;
  2142. }
  2143. if (!c)
  2144. cp2 = 0;
  2145. if ((tmp = inet_addr(cp)) != -1) {
  2146. sin_addr.s_addr = tmp;
  2147. } else if ((host = gethostbyname(cp))) {
  2148. #ifdef h_addr
  2149. memmove((caddr_t)&sin_addr,
  2150. host->h_addr_list[0], host->h_length);
  2151. #else
  2152. memmove((caddr_t)&sin_addr, host->h_addr, host->h_length);
  2153. #endif
  2154. } else {
  2155. *cpp = cp;
  2156. return(0);
  2157. }
  2158. memmove(lsrp, (char *)&sin_addr, 4);
  2159. lsrp += 4;
  2160. if (cp2)
  2161. cp = cp2;
  2162. else
  2163. break;
  2164. /*
  2165.  * Check to make sure there is space for next address
  2166.  */
  2167. if (lsrp + 4 > lsrep)
  2168. return((unsigned int)-1);
  2169. }
  2170. #ifndef sysV88
  2171. if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
  2172. *cpp = 0;
  2173. *lenp = 0;
  2174. return((unsigned int)-1);
  2175. }
  2176. *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
  2177. *lenp = lsrp - *cpp;
  2178. #else
  2179. ipopt.io_len = lsrp - *cpp;
  2180. if (ipopt.io_len <= 5) { /* Is 3 better ? */
  2181. *cpp = 0;
  2182. *lenp = 0;
  2183. return((unsigned int)-1);
  2184. }
  2185. *lenp = sizeof(ipopt);
  2186. *cpp = (char *) &ipopt;
  2187. #endif
  2188. return(sin_addr.s_addr);
  2189. }
  2190. #endif