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