1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)commands.c 1.10 (Berkeley) 09/14/88"; 20 #endif /* not lint */ 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 26 #include <signal.h> 27 #include <netdb.h> 28 #include <ctype.h> 29 #include <varargs.h> 30 31 #include <arpa/telnet.h> 32 33 #include "general.h" 34 35 #include "ring.h" 36 37 #include "externs.h" 38 #include "defines.h" 39 #include "types.h" 40 41 char *hostname; 42 43 #define Ambiguous(s) ((char *)s == ambiguous) 44 static char *ambiguous; /* special return value for command routines */ 45 46 typedef struct { 47 char *name; /* command name */ 48 char *help; /* help string */ 49 int (*handler)(); /* routine which executes command */ 50 int dohelp; /* Should we give general help information? */ 51 int needconnect; /* Do we need to be connected to execute? */ 52 } Command; 53 54 static char line[200]; 55 static int margc; 56 static char *margv[20]; 57 58 /* 59 * Various utility routines. 60 */ 61 62 static void 63 makeargv() 64 { 65 register char *cp; 66 register char **argp = margv; 67 68 margc = 0; 69 cp = line; 70 if (*cp == '!') { /* Special case shell escape */ 71 *argp++ = "!"; /* No room in string to get this */ 72 margc++; 73 cp++; 74 } 75 while (*cp) { 76 while (isspace(*cp)) 77 cp++; 78 if (*cp == '\0') 79 break; 80 *argp++ = cp; 81 margc += 1; 82 while (*cp != '\0' && !isspace(*cp)) 83 cp++; 84 if (*cp == '\0') 85 break; 86 *cp++ = '\0'; 87 } 88 *argp++ = 0; 89 } 90 91 92 static char ** 93 genget(name, table, next) 94 char *name; /* name to match */ 95 char **table; /* name entry in table */ 96 char **(*next)(); /* routine to return next entry in table */ 97 { 98 register char *p, *q; 99 register char **c, **found; 100 register int nmatches, longest; 101 102 if (name == 0) { 103 return 0; 104 } 105 longest = 0; 106 nmatches = 0; 107 found = 0; 108 for (c = table; (p = *c) != 0; c = (*next)(c)) { 109 for (q = name; 110 (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 111 if (*q == 0) /* exact match? */ 112 return (c); 113 if (!*q) { /* the name was a prefix */ 114 if (q - name > longest) { 115 longest = q - name; 116 nmatches = 1; 117 found = c; 118 } else if (q - name == longest) 119 nmatches++; 120 } 121 } 122 if (nmatches > 1) 123 return (char **)ambiguous; 124 return (found); 125 } 126 127 /* 128 * Make a character string into a number. 129 * 130 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 131 */ 132 133 static 134 special(s) 135 register char *s; 136 { 137 register char c; 138 char b; 139 140 switch (*s) { 141 case '^': 142 b = *++s; 143 if (b == '?') { 144 c = b | 0x40; /* DEL */ 145 } else { 146 c = b & 0x1f; 147 } 148 break; 149 default: 150 c = *s; 151 break; 152 } 153 return c; 154 } 155 156 /* 157 * Construct a control character sequence 158 * for a special character. 159 */ 160 static char * 161 control(c) 162 register int c; 163 { 164 static char buf[3]; 165 166 if (c == 0x7f) 167 return ("^?"); 168 if (c == '\377') { 169 return "off"; 170 } 171 if (c >= 0x20) { 172 buf[0] = c; 173 buf[1] = 0; 174 } else { 175 buf[0] = '^'; 176 buf[1] = '@'+c; 177 buf[2] = 0; 178 } 179 return (buf); 180 } 181 182 183 184 /* 185 * The following are data structures and routines for 186 * the "send" command. 187 * 188 */ 189 190 struct sendlist { 191 char *name; /* How user refers to it (case independent) */ 192 int what; /* Character to be sent (<0 ==> special) */ 193 char *help; /* Help information (0 ==> no help) */ 194 #if defined(NOT43) 195 int (*routine)(); /* Routine to perform (for special ops) */ 196 #else /* defined(NOT43) */ 197 void (*routine)(); /* Routine to perform (for special ops) */ 198 #endif /* defined(NOT43) */ 199 }; 200 201 #define SENDQUESTION -1 202 #define SENDESCAPE -3 203 204 static struct sendlist Sendlist[] = { 205 { "ao", AO, "Send Telnet Abort output" }, 206 { "ayt", AYT, "Send Telnet 'Are You There'" }, 207 { "brk", BREAK, "Send Telnet Break" }, 208 { "ec", EC, "Send Telnet Erase Character" }, 209 { "el", EL, "Send Telnet Erase Line" }, 210 { "escape", SENDESCAPE, "Send current escape character" }, 211 { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 212 { "ip", IP, "Send Telnet Interrupt Process" }, 213 { "nop", NOP, "Send Telnet 'No operation'" }, 214 { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 215 { "?", SENDQUESTION, "Display send options" }, 216 { 0 } 217 }; 218 219 static struct sendlist Sendlist2[] = { /* some synonyms */ 220 { "break", BREAK, 0 }, 221 222 { "intp", IP, 0 }, 223 { "interrupt", IP, 0 }, 224 { "intr", IP, 0 }, 225 226 { "help", SENDQUESTION, 0 }, 227 228 { 0 } 229 }; 230 231 static char ** 232 getnextsend(name) 233 char *name; 234 { 235 struct sendlist *c = (struct sendlist *) name; 236 237 return (char **) (c+1); 238 } 239 240 static struct sendlist * 241 getsend(name) 242 char *name; 243 { 244 struct sendlist *sl; 245 246 if ((sl = (struct sendlist *) 247 genget(name, (char **) Sendlist, getnextsend)) != 0) { 248 return sl; 249 } else { 250 return (struct sendlist *) 251 genget(name, (char **) Sendlist2, getnextsend); 252 } 253 } 254 255 static 256 sendcmd(argc, argv) 257 int argc; 258 char **argv; 259 { 260 int what; /* what we are sending this time */ 261 int count; /* how many bytes we are going to need to send */ 262 int i; 263 int question = 0; /* was at least one argument a question */ 264 struct sendlist *s; /* pointer to current command */ 265 266 if (argc < 2) { 267 printf("need at least one argument for 'send' command\n"); 268 printf("'send ?' for help\n"); 269 return 0; 270 } 271 /* 272 * First, validate all the send arguments. 273 * In addition, we see how much space we are going to need, and 274 * whether or not we will be doing a "SYNCH" operation (which 275 * flushes the network queue). 276 */ 277 count = 0; 278 for (i = 1; i < argc; i++) { 279 s = getsend(argv[i]); 280 if (s == 0) { 281 printf("Unknown send argument '%s'\n'send ?' for help.\n", 282 argv[i]); 283 return 0; 284 } else if (Ambiguous(s)) { 285 printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 286 argv[i]); 287 return 0; 288 } 289 switch (s->what) { 290 case SENDQUESTION: 291 break; 292 case SENDESCAPE: 293 count += 1; 294 break; 295 case SYNCH: 296 count += 2; 297 break; 298 default: 299 count += 2; 300 break; 301 } 302 } 303 /* Now, do we have enough room? */ 304 if (NETROOM() < count) { 305 printf("There is not enough room in the buffer TO the network\n"); 306 printf("to process your request. Nothing will be done.\n"); 307 printf("('send synch' will throw away most data in the network\n"); 308 printf("buffer, if this might help.)\n"); 309 return 0; 310 } 311 /* OK, they are all OK, now go through again and actually send */ 312 for (i = 1; i < argc; i++) { 313 if ((s = getsend(argv[i])) == 0) { 314 fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 315 quit(); 316 /*NOTREACHED*/ 317 } 318 if (s->routine) { 319 (*s->routine)(s); 320 } else { 321 switch (what = s->what) { 322 case SYNCH: 323 dosynch(); 324 break; 325 case SENDQUESTION: 326 for (s = Sendlist; s->name; s++) { 327 if (s->help) { 328 printf(s->name); 329 if (s->help) { 330 printf("\t%s", s->help); 331 } 332 printf("\n"); 333 } 334 } 335 question = 1; 336 break; 337 case SENDESCAPE: 338 NETADD(escape); 339 break; 340 default: 341 NET2ADD(IAC, what); 342 break; 343 } 344 } 345 } 346 return !question; 347 } 348 349 /* 350 * The following are the routines and data structures referred 351 * to by the arguments to the "toggle" command. 352 */ 353 354 static 355 lclchars() 356 { 357 donelclchars = 1; 358 return 1; 359 } 360 361 static 362 togdebug() 363 { 364 #ifndef NOT43 365 if (net > 0 && 366 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 367 perror("setsockopt (SO_DEBUG)"); 368 } 369 #else /* NOT43 */ 370 if (debug) { 371 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 372 perror("setsockopt (SO_DEBUG)"); 373 } else 374 printf("Cannot turn off socket debugging\n"); 375 #endif /* NOT43 */ 376 return 1; 377 } 378 379 380 static int 381 togcrlf() 382 { 383 if (crlf) { 384 printf("Will send carriage returns as telnet <CR><LF>.\n"); 385 } else { 386 printf("Will send carriage returns as telnet <CR><NUL>.\n"); 387 } 388 return 1; 389 } 390 391 392 static int 393 togbinary() 394 { 395 donebinarytoggle = 1; 396 397 if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 398 NET2ADD(IAC, DO); 399 NETADD(TELOPT_BINARY); 400 printoption("<SENT", doopt, TELOPT_BINARY, 0); 401 NET2ADD(IAC, WILL); 402 NETADD(TELOPT_BINARY); 403 printoption("<SENT", doopt, TELOPT_BINARY, 0); 404 hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 405 printf("Negotiating binary mode with remote host.\n"); 406 } else { /* Turn off binary mode */ 407 NET2ADD(IAC, DONT); 408 NETADD(TELOPT_BINARY); 409 printoption("<SENT", dont, TELOPT_BINARY, 0); 410 NET2ADD(IAC, DONT); 411 NETADD(TELOPT_BINARY); 412 printoption("<SENT", dont, TELOPT_BINARY, 0); 413 hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 414 printf("Negotiating network ascii mode with remote host.\n"); 415 } 416 return 1; 417 } 418 419 420 421 extern int togglehelp(); 422 423 struct togglelist { 424 char *name; /* name of toggle */ 425 char *help; /* help message */ 426 int (*handler)(); /* routine to do actual setting */ 427 int dohelp; /* should we display help information */ 428 int *variable; 429 char *actionexplanation; 430 }; 431 432 static struct togglelist Togglelist[] = { 433 { "autoflush", 434 "toggle flushing of output when sending interrupt characters", 435 0, 436 1, 437 &autoflush, 438 "flush output when sending interrupt characters" }, 439 { "autosynch", 440 "toggle automatic sending of interrupt characters in urgent mode", 441 0, 442 1, 443 &autosynch, 444 "send interrupt characters in urgent mode" }, 445 { "binary", 446 "toggle sending and receiving of binary data", 447 togbinary, 448 1, 449 0, 450 0 }, 451 { "crlf", 452 "toggle sending carriage returns as telnet <CR><LF>", 453 togcrlf, 454 1, 455 &crlf, 456 0 }, 457 { "crmod", 458 "toggle mapping of received carriage returns", 459 0, 460 1, 461 &crmod, 462 "map carriage return on output" }, 463 { "localchars", 464 "toggle local recognition of certain control characters", 465 lclchars, 466 1, 467 &localchars, 468 "recognize certain control characters" }, 469 { " ", "", 0, 1 }, /* empty line */ 470 { "debug", 471 "(debugging) toggle debugging", 472 togdebug, 473 1, 474 &debug, 475 "turn on socket level debugging" }, 476 { "netdata", 477 "(debugging) toggle printing of hexadecimal network data", 478 0, 479 1, 480 &netdata, 481 "print hexadecimal representation of network traffic" }, 482 { "options", 483 "(debugging) toggle viewing of options processing", 484 0, 485 1, 486 &showoptions, 487 "show option processing" }, 488 { " ", "", 0, 1 }, /* empty line */ 489 { "?", 490 "display help information", 491 togglehelp, 492 1 }, 493 { "help", 494 "display help information", 495 togglehelp, 496 0 }, 497 { 0 } 498 }; 499 500 static 501 togglehelp() 502 { 503 struct togglelist *c; 504 505 for (c = Togglelist; c->name; c++) { 506 if (c->dohelp) { 507 printf("%s\t%s\n", c->name, c->help); 508 } 509 } 510 return 0; 511 } 512 513 static char ** 514 getnexttoggle(name) 515 char *name; 516 { 517 struct togglelist *c = (struct togglelist *) name; 518 519 return (char **) (c+1); 520 } 521 522 static struct togglelist * 523 gettoggle(name) 524 char *name; 525 { 526 return (struct togglelist *) 527 genget(name, (char **) Togglelist, getnexttoggle); 528 } 529 530 static 531 toggle(argc, argv) 532 int argc; 533 char *argv[]; 534 { 535 int retval = 1; 536 char *name; 537 struct togglelist *c; 538 539 if (argc < 2) { 540 fprintf(stderr, 541 "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 542 return 0; 543 } 544 argc--; 545 argv++; 546 while (argc--) { 547 name = *argv++; 548 c = gettoggle(name); 549 if (Ambiguous(c)) { 550 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 551 name); 552 return 0; 553 } else if (c == 0) { 554 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 555 name); 556 return 0; 557 } else { 558 if (c->variable) { 559 *c->variable = !*c->variable; /* invert it */ 560 if (c->actionexplanation) { 561 printf("%s %s.\n", *c->variable? "Will" : "Won't", 562 c->actionexplanation); 563 } 564 printf("%s %s.\n", *c->variable? "Will" : "Won't", 565 c->actionexplanation); 566 } 567 if (c->handler) { 568 retval &= (*c->handler)(c); 569 } 570 } 571 } 572 return retval; 573 } 574 575 /* 576 * The following perform the "set" command. 577 */ 578 579 struct setlist { 580 char *name; /* name */ 581 char *help; /* help information */ 582 char *charp; /* where it is located at */ 583 }; 584 585 static struct setlist Setlist[] = { 586 { "echo", "character to toggle local echoing on/off", &echoc }, 587 { "escape", "character to escape back to telnet command mode", &escape }, 588 { " ", "" }, 589 { " ", "The following need 'localchars' to be toggled true", 0 }, 590 { "erase", "character to cause an Erase Character", &termEraseChar }, 591 { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 592 { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 593 { "kill", "character to cause an Erase Line", &termKillChar }, 594 { "quit", "character to cause a Break", &termQuitChar }, 595 { "eof", "character to cause an EOF ", &termEofChar }, 596 { 0 } 597 }; 598 599 static char ** 600 getnextset(name) 601 char *name; 602 { 603 struct setlist *c = (struct setlist *)name; 604 605 return (char **) (c+1); 606 } 607 608 static struct setlist * 609 getset(name) 610 char *name; 611 { 612 return (struct setlist *) genget(name, (char **) Setlist, getnextset); 613 } 614 615 static 616 setcmd(argc, argv) 617 int argc; 618 char *argv[]; 619 { 620 int value; 621 struct setlist *ct; 622 623 /* XXX back we go... sigh */ 624 if (argc != 3) { 625 if ((argc == 2) && 626 ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 627 for (ct = Setlist; ct->name; ct++) { 628 printf("%s\t%s\n", ct->name, ct->help); 629 } 630 printf("?\tdisplay help information\n"); 631 } else { 632 printf("Format is 'set Name Value'\n'set ?' for help.\n"); 633 } 634 return 0; 635 } 636 637 ct = getset(argv[1]); 638 if (ct == 0) { 639 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 640 argv[1]); 641 return 0; 642 } else if (Ambiguous(ct)) { 643 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 644 argv[1]); 645 return 0; 646 } else { 647 if (strcmp("off", argv[2])) { 648 value = special(argv[2]); 649 } else { 650 value = -1; 651 } 652 *(ct->charp) = value; 653 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 654 } 655 return 1; 656 } 657 658 /* 659 * The following are the data structures and routines for the 660 * 'mode' command. 661 */ 662 663 static 664 dolinemode() 665 { 666 if (hisopts[TELOPT_SGA]) { 667 wontoption(TELOPT_SGA, 0); 668 } 669 if (hisopts[TELOPT_ECHO]) { 670 wontoption(TELOPT_ECHO, 0); 671 } 672 return 1; 673 } 674 675 static 676 docharmode() 677 { 678 if (!hisopts[TELOPT_SGA]) { 679 willoption(TELOPT_SGA, 0); 680 } 681 if (!hisopts[TELOPT_ECHO]) { 682 willoption(TELOPT_ECHO, 0); 683 } 684 return 1; 685 } 686 687 static Command Mode_commands[] = { 688 { "character", "character-at-a-time mode", docharmode, 1, 1 }, 689 { "line", "line-by-line mode", dolinemode, 1, 1 }, 690 { 0 }, 691 }; 692 693 static char ** 694 getnextmode(name) 695 char *name; 696 { 697 Command *c = (Command *) name; 698 699 return (char **) (c+1); 700 } 701 702 static Command * 703 getmodecmd(name) 704 char *name; 705 { 706 return (Command *) genget(name, (char **) Mode_commands, getnextmode); 707 } 708 709 static 710 modecmd(argc, argv) 711 int argc; 712 char *argv[]; 713 { 714 Command *mt; 715 716 if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 717 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 718 for (mt = Mode_commands; mt->name; mt++) { 719 printf("%s\t%s\n", mt->name, mt->help); 720 } 721 return 0; 722 } 723 mt = getmodecmd(argv[1]); 724 if (mt == 0) { 725 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 726 return 0; 727 } else if (Ambiguous(mt)) { 728 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 729 return 0; 730 } else { 731 (*mt->handler)(); 732 } 733 return 1; 734 } 735 736 /* 737 * The following data structures and routines implement the 738 * "display" command. 739 */ 740 741 static 742 display(argc, argv) 743 int argc; 744 char *argv[]; 745 { 746 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 747 if (*tl->variable) { \ 748 printf("will"); \ 749 } else { \ 750 printf("won't"); \ 751 } \ 752 printf(" %s.\n", tl->actionexplanation); \ 753 } 754 755 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 756 printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 757 } 758 759 struct togglelist *tl; 760 struct setlist *sl; 761 762 if (argc == 1) { 763 for (tl = Togglelist; tl->name; tl++) { 764 dotog(tl); 765 } 766 printf("\n"); 767 for (sl = Setlist; sl->name; sl++) { 768 doset(sl); 769 } 770 } else { 771 int i; 772 773 for (i = 1; i < argc; i++) { 774 sl = getset(argv[i]); 775 tl = gettoggle(argv[i]); 776 if (Ambiguous(sl) || Ambiguous(tl)) { 777 printf("?Ambiguous argument '%s'.\n", argv[i]); 778 return 0; 779 } else if (!sl && !tl) { 780 printf("?Unknown argument '%s'.\n", argv[i]); 781 return 0; 782 } else { 783 if (tl) { 784 dotog(tl); 785 } 786 if (sl) { 787 doset(sl); 788 } 789 } 790 } 791 } 792 return 1; 793 #undef doset 794 #undef dotog 795 } 796 797 /* 798 * The following are the data structures, and many of the routines, 799 * relating to command processing. 800 */ 801 802 /* 803 * Set the escape character. 804 */ 805 static 806 setescape(argc, argv) 807 int argc; 808 char *argv[]; 809 { 810 register char *arg; 811 char buf[50]; 812 813 printf( 814 "Deprecated usage - please use 'set escape%s%s' in the future.\n", 815 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 816 if (argc > 2) 817 arg = argv[1]; 818 else { 819 printf("new escape character: "); 820 (void) gets(buf); 821 arg = buf; 822 } 823 if (arg[0] != '\0') 824 escape = arg[0]; 825 if (!In3270) { 826 printf("Escape character is '%s'.\n", control(escape)); 827 } 828 (void) fflush(stdout); 829 return 1; 830 } 831 832 /*VARARGS*/ 833 static 834 togcrmod() 835 { 836 crmod = !crmod; 837 printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 838 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 839 (void) fflush(stdout); 840 return 1; 841 } 842 843 /*VARARGS*/ 844 suspend() 845 { 846 setcommandmode(); 847 #if defined(unix) 848 (void) kill(0, SIGTSTP); 849 #endif /* defined(unix) */ 850 /* reget parameters in case they were changed */ 851 TerminalSaveState(); 852 setconnmode(); 853 return 1; 854 } 855 856 /*VARARGS*/ 857 static 858 bye(argc, argv) 859 int argc; /* Number of arguments */ 860 char *argv[]; /* arguments */ 861 { 862 if (connected) { 863 (void) shutdown(net, 2); 864 printf("Connection closed.\n"); 865 (void) NetClose(net); 866 connected = 0; 867 /* reset options */ 868 tninit(); 869 #if defined(TN3270) 870 SetIn3270(); /* Get out of 3270 mode */ 871 #endif /* defined(TN3270) */ 872 } 873 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 874 longjmp(toplevel, 1); 875 /* NOTREACHED */ 876 } 877 return 1; /* Keep lint, etc., happy */ 878 } 879 880 /*VARARGS*/ 881 quit() 882 { 883 (void) call(bye, "bye", "fromquit", 0); 884 Exit(0); 885 return 1; /* just to keep lint happy */ 886 } 887 888 /* 889 * Print status about the connection. 890 */ 891 /*ARGSUSED*/ 892 static 893 status(argc, argv) 894 int argc; 895 char *argv[]; 896 { 897 if (connected) { 898 printf("Connected to %s.\n", hostname); 899 if (argc < 2) { 900 printf("Operating in %s.\n", 901 modelist[getconnmode()].modedescriptions); 902 if (localchars) { 903 printf("Catching signals locally.\n"); 904 } 905 } 906 } else { 907 printf("No connection.\n"); 908 } 909 # if !defined(TN3270) 910 printf("Escape character is '%s'.\n", control(escape)); 911 (void) fflush(stdout); 912 # else /* !defined(TN3270) */ 913 if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 914 printf("Escape character is '%s'.\n", control(escape)); 915 } 916 # if defined(unix) 917 if (In3270 && transcom) { 918 printf("Transparent mode command is '%s'.\n", transcom); 919 } 920 # endif /* defined(unix) */ 921 (void) fflush(stdout); 922 if (In3270) { 923 return 0; 924 } 925 # endif /* defined(TN3270) */ 926 return 1; 927 } 928 929 930 931 int 932 tn(argc, argv) 933 int argc; 934 char *argv[]; 935 { 936 register struct hostent *host = 0; 937 struct sockaddr_in sin; 938 struct servent *sp = 0; 939 static char hnamebuf[32]; 940 unsigned long inet_addr(); 941 942 943 #if defined(MSDOS) 944 char *cp; 945 #endif /* defined(MSDOS) */ 946 947 if (connected) { 948 printf("?Already connected to %s\n", hostname); 949 return 0; 950 } 951 if (argc < 2) { 952 (void) strcpy(line, "Connect "); 953 printf("(to) "); 954 (void) gets(&line[strlen(line)]); 955 makeargv(); 956 argc = margc; 957 argv = margv; 958 } 959 if ((argc < 2) || (argc > 3)) { 960 printf("usage: %s host-name [port]\n", argv[0]); 961 return 0; 962 } 963 #if defined(MSDOS) 964 for (cp = argv[1]; *cp; cp++) { 965 if (isupper(*cp)) { 966 *cp = tolower(*cp); 967 } 968 } 969 #endif /* defined(MSDOS) */ 970 sin.sin_addr.s_addr = inet_addr(argv[1]); 971 if (sin.sin_addr.s_addr != -1) { 972 sin.sin_family = AF_INET; 973 (void) strcpy(hnamebuf, argv[1]); 974 hostname = hnamebuf; 975 } else { 976 host = gethostbyname(argv[1]); 977 if (host) { 978 sin.sin_family = host->h_addrtype; 979 #if defined(h_addr) /* In 4.3, this is a #define */ 980 memcpy((caddr_t)&sin.sin_addr, 981 host->h_addr_list[0], host->h_length); 982 #else /* defined(h_addr) */ 983 memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 984 #endif /* defined(h_addr) */ 985 hostname = host->h_name; 986 } else { 987 printf("%s: unknown host\n", argv[1]); 988 return 0; 989 } 990 } 991 if (argc == 3) { 992 sin.sin_port = atoi(argv[2]); 993 if (sin.sin_port == 0) { 994 sp = getservbyname(argv[2], "tcp"); 995 if (sp) 996 sin.sin_port = sp->s_port; 997 else { 998 printf("%s: bad port number\n", argv[2]); 999 return 0; 1000 } 1001 } else { 1002 #if !defined(htons) 1003 u_short htons(); 1004 #endif /* !defined(htons) */ 1005 1006 sin.sin_port = atoi(argv[2]); 1007 sin.sin_port = htons(sin.sin_port); 1008 } 1009 telnetport = 0; 1010 } else { 1011 if (sp == 0) { 1012 sp = getservbyname("telnet", "tcp"); 1013 if (sp == 0) { 1014 fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1015 return 0; 1016 } 1017 sin.sin_port = sp->s_port; 1018 } 1019 telnetport = 1; 1020 } 1021 printf("Trying...\n"); 1022 do { 1023 net = socket(AF_INET, SOCK_STREAM, 0); 1024 if (net < 0) { 1025 perror("telnet: socket"); 1026 return 0; 1027 } 1028 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 1029 perror("setsockopt (SO_DEBUG)"); 1030 } 1031 1032 if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 1033 #if defined(h_addr) /* In 4.3, this is a #define */ 1034 if (host && host->h_addr_list[1]) { 1035 int oerrno = errno; 1036 extern char *inet_ntoa(); 1037 1038 fprintf(stderr, "telnet: connect to address %s: ", 1039 inet_ntoa(sin.sin_addr)); 1040 errno = oerrno; 1041 perror((char *)0); 1042 host->h_addr_list++; 1043 memcpy((caddr_t)&sin.sin_addr, 1044 host->h_addr_list[0], host->h_length); 1045 fprintf(stderr, "Trying %s...\n", 1046 inet_ntoa(sin.sin_addr)); 1047 (void) NetClose(net); 1048 continue; 1049 } 1050 #endif /* defined(h_addr) */ 1051 perror("telnet: Unable to connect to remote host"); 1052 return 0; 1053 } 1054 connected++; 1055 } while (connected == 0); 1056 (void) call(status, "status", "notmuch", 0); 1057 if (setjmp(peerdied) == 0) 1058 telnet(); 1059 (void) NetClose(net); 1060 ExitString("Connection closed by foreign host.\n",1); 1061 /*NOTREACHED*/ 1062 } 1063 1064 1065 #define HELPINDENT (sizeof ("connect")) 1066 1067 static char 1068 openhelp[] = "connect to a site", 1069 closehelp[] = "close current connection", 1070 quithelp[] = "exit telnet", 1071 statushelp[] = "print status information", 1072 helphelp[] = "print help information", 1073 sendhelp[] = "transmit special characters ('send ?' for more)", 1074 sethelp[] = "set operating parameters ('set ?' for more)", 1075 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 1076 displayhelp[] = "display operating parameters", 1077 #if defined(TN3270) && defined(unix) 1078 transcomhelp[] = "specify Unix command for transparent mode pipe", 1079 #endif /* defined(TN3270) && defined(unix) */ 1080 #if defined(unix) 1081 zhelp[] = "suspend telnet", 1082 #endif /* defined(unix */ 1083 #if defined(TN3270) 1084 shellhelp[] = "invoke a subshell", 1085 #endif /* defined(TN3270) */ 1086 modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 1087 1088 extern int help(), shell(); 1089 1090 static Command cmdtab[] = { 1091 { "close", closehelp, bye, 1, 1 }, 1092 { "display", displayhelp, display, 1, 0 }, 1093 { "mode", modehelp, modecmd, 1, 1 }, 1094 { "open", openhelp, tn, 1, 0 }, 1095 { "quit", quithelp, quit, 1, 0 }, 1096 { "send", sendhelp, sendcmd, 1, 1 }, 1097 { "set", sethelp, setcmd, 1, 0 }, 1098 { "status", statushelp, status, 1, 0 }, 1099 { "toggle", togglestring, toggle, 1, 0 }, 1100 #if defined(TN3270) && defined(unix) 1101 { "transcom", transcomhelp, settranscom, 1, 0 }, 1102 #endif /* defined(TN3270) && defined(unix) */ 1103 #if defined(unix) 1104 { "z", zhelp, suspend, 1, 0 }, 1105 #endif /* defined(unix) */ 1106 #if defined(TN3270) 1107 { "!", shellhelp, shell, 1, 1 }, 1108 #endif /* defined(TN3270) */ 1109 { "?", helphelp, help, 1, 0 }, 1110 0 1111 }; 1112 1113 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 1114 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 1115 1116 static Command cmdtab2[] = { 1117 { "help", helphelp, help, 0, 0 }, 1118 { "escape", escapehelp, setescape, 1, 0 }, 1119 { "crmod", crmodhelp, togcrmod, 1, 0 }, 1120 0 1121 }; 1122 1123 1124 /* 1125 * Call routine with argc, argv set from args (terminated by 0). 1126 */ 1127 1128 /*VARARGS1*/ 1129 static 1130 call(va_alist) 1131 va_dcl 1132 { 1133 va_list ap; 1134 typedef int (*intrtn_t)(); 1135 intrtn_t routine; 1136 char *args[100]; 1137 int argno = 0; 1138 1139 va_start(ap); 1140 routine = (va_arg(ap, intrtn_t)); 1141 while ((args[argno++] = va_arg(ap, char *)) != 0) { 1142 ; 1143 } 1144 va_end(ap); 1145 return (*routine)(argno-1, args); 1146 } 1147 1148 1149 static char ** 1150 getnextcmd(name) 1151 char *name; 1152 { 1153 Command *c = (Command *) name; 1154 1155 return (char **) (c+1); 1156 } 1157 1158 static Command * 1159 getcmd(name) 1160 char *name; 1161 { 1162 Command *cm; 1163 1164 if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 1165 return cm; 1166 } else { 1167 return (Command *) genget(name, (char **) cmdtab2, getnextcmd); 1168 } 1169 } 1170 1171 void 1172 command(top) 1173 int top; 1174 { 1175 register Command *c; 1176 1177 setcommandmode(); 1178 if (!top) { 1179 putchar('\n'); 1180 } else { 1181 #if defined(unix) 1182 signal(SIGINT, SIG_DFL); 1183 signal(SIGQUIT, SIG_DFL); 1184 #endif /* defined(unix) */ 1185 } 1186 for (;;) { 1187 printf("%s> ", prompt); 1188 if (gets(line) == NULL) { 1189 if (feof(stdin) || ferror(stdin)) 1190 quit(); 1191 break; 1192 } 1193 if (line[0] == 0) 1194 break; 1195 makeargv(); 1196 c = getcmd(margv[0]); 1197 if (Ambiguous(c)) { 1198 printf("?Ambiguous command\n"); 1199 continue; 1200 } 1201 if (c == 0) { 1202 printf("?Invalid command\n"); 1203 continue; 1204 } 1205 if (c->needconnect && !connected) { 1206 printf("?Need to be connected first.\n"); 1207 continue; 1208 } 1209 if ((*c->handler)(margc, margv)) { 1210 break; 1211 } 1212 } 1213 if (!top) { 1214 if (!connected) { 1215 longjmp(toplevel, 1); 1216 /*NOTREACHED*/ 1217 } 1218 #if defined(TN3270) 1219 if (shell_active == 0) { 1220 setconnmode(); 1221 } 1222 #else /* defined(TN3270) */ 1223 setconnmode(); 1224 #endif /* defined(TN3270) */ 1225 } 1226 } 1227 1228 /* 1229 * Help command. 1230 */ 1231 static 1232 help(argc, argv) 1233 int argc; 1234 char *argv[]; 1235 { 1236 register Command *c; 1237 1238 if (argc == 1) { 1239 printf("Commands may be abbreviated. Commands are:\n\n"); 1240 for (c = cmdtab; c->name; c++) 1241 if (c->dohelp) { 1242 printf("%-*s\t%s\n", HELPINDENT, c->name, 1243 c->help); 1244 } 1245 return 0; 1246 } 1247 while (--argc > 0) { 1248 register char *arg; 1249 arg = *++argv; 1250 c = getcmd(arg); 1251 if (Ambiguous(c)) 1252 printf("?Ambiguous help command %s\n", arg); 1253 else if (c == (Command *)0) 1254 printf("?Invalid help command %s\n", arg); 1255 else 1256 printf("%s\n", c->help); 1257 } 1258 return 0; 1259 } 1260