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