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