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