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.15 (Berkeley) 02/06/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 (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 436 NET2ADD(IAC, DO); 437 NETADD(TELOPT_BINARY); 438 printoption("<SENT", doopt, TELOPT_BINARY, 0); 439 NET2ADD(IAC, WILL); 440 NETADD(TELOPT_BINARY); 441 printoption("<SENT", doopt, TELOPT_BINARY, 0); 442 hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 443 printf("Negotiating binary mode with remote host.\n"); 444 } else { /* Turn off binary mode */ 445 NET2ADD(IAC, DONT); 446 NETADD(TELOPT_BINARY); 447 printoption("<SENT", dont, TELOPT_BINARY, 0); 448 NET2ADD(IAC, DONT); 449 NETADD(TELOPT_BINARY); 450 printoption("<SENT", dont, TELOPT_BINARY, 0); 451 hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 452 printf("Negotiating network ascii mode with remote host.\n"); 453 } 454 return 1; 455 } 456 457 458 459 extern int togglehelp(); 460 461 struct togglelist { 462 char *name; /* name of toggle */ 463 char *help; /* help message */ 464 int (*handler)(); /* routine to do actual setting */ 465 int dohelp; /* should we display help information */ 466 int *variable; 467 char *actionexplanation; 468 }; 469 470 static struct togglelist Togglelist[] = { 471 { "autoflush", 472 "toggle flushing of output when sending interrupt characters", 473 0, 474 1, 475 &autoflush, 476 "flush output when sending interrupt characters" }, 477 { "autosynch", 478 "toggle automatic sending of interrupt characters in urgent mode", 479 0, 480 1, 481 &autosynch, 482 "send interrupt characters in urgent mode" }, 483 { "binary", 484 "toggle sending and receiving of binary data", 485 togbinary, 486 1, 487 0, 488 0 }, 489 { "crlf", 490 "toggle sending carriage returns as telnet <CR><LF>", 491 togcrlf, 492 1, 493 &crlf, 494 0 }, 495 { "crmod", 496 "toggle mapping of received carriage returns", 497 0, 498 1, 499 &crmod, 500 "map carriage return on output" }, 501 { "localchars", 502 "toggle local recognition of certain control characters", 503 lclchars, 504 1, 505 &localchars, 506 "recognize certain control characters" }, 507 { " ", "", 0, 1 }, /* empty line */ 508 { "debug", 509 "(debugging) toggle debugging", 510 togdebug, 511 1, 512 &debug, 513 "turn on socket level debugging" }, 514 { "netdata", 515 "(debugging) toggle printing of hexadecimal network data", 516 0, 517 1, 518 &netdata, 519 "print hexadecimal representation of network traffic" }, 520 { "options", 521 "(debugging) toggle viewing of options processing", 522 0, 523 1, 524 &showoptions, 525 "show option processing" }, 526 { " ", "", 0, 1 }, /* empty line */ 527 { "?", 528 "display help information", 529 togglehelp, 530 1 }, 531 { "help", 532 "display help information", 533 togglehelp, 534 0 }, 535 { 0 } 536 }; 537 538 static 539 togglehelp() 540 { 541 struct togglelist *c; 542 543 for (c = Togglelist; c->name; c++) { 544 if (c->dohelp) { 545 printf("%s\t%s\n", c->name, c->help); 546 } 547 } 548 return 0; 549 } 550 551 static char ** 552 getnexttoggle(name) 553 char *name; 554 { 555 struct togglelist *c = (struct togglelist *) name; 556 557 return (char **) (c+1); 558 } 559 560 static struct togglelist * 561 gettoggle(name) 562 char *name; 563 { 564 return (struct togglelist *) 565 genget(name, (char **) Togglelist, getnexttoggle); 566 } 567 568 static 569 toggle(argc, argv) 570 int argc; 571 char *argv[]; 572 { 573 int retval = 1; 574 char *name; 575 struct togglelist *c; 576 577 if (argc < 2) { 578 fprintf(stderr, 579 "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 580 return 0; 581 } 582 argc--; 583 argv++; 584 while (argc--) { 585 name = *argv++; 586 c = gettoggle(name); 587 if (Ambiguous(c)) { 588 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 589 name); 590 return 0; 591 } else if (c == 0) { 592 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 593 name); 594 return 0; 595 } else { 596 if (c->variable) { 597 *c->variable = !*c->variable; /* invert it */ 598 if (c->actionexplanation) { 599 printf("%s %s.\n", *c->variable? "Will" : "Won't", 600 c->actionexplanation); 601 } 602 } 603 if (c->handler) { 604 retval &= (*c->handler)(c); 605 } 606 } 607 } 608 return retval; 609 } 610 611 /* 612 * The following perform the "set" command. 613 */ 614 615 struct setlist { 616 char *name; /* name */ 617 char *help; /* help information */ 618 char *charp; /* where it is located at */ 619 }; 620 621 static struct setlist Setlist[] = { 622 { "echo", "character to toggle local echoing on/off", &echoc }, 623 { "escape", "character to escape back to telnet command mode", &escape }, 624 { " ", "" }, 625 { " ", "The following need 'localchars' to be toggled true", 0 }, 626 { "erase", "character to cause an Erase Character", &termEraseChar }, 627 { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 628 { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 629 { "kill", "character to cause an Erase Line", &termKillChar }, 630 { "quit", "character to cause a Break", &termQuitChar }, 631 { "eof", "character to cause an EOF ", &termEofChar }, 632 { 0 } 633 }; 634 635 static char ** 636 getnextset(name) 637 char *name; 638 { 639 struct setlist *c = (struct setlist *)name; 640 641 return (char **) (c+1); 642 } 643 644 static struct setlist * 645 getset(name) 646 char *name; 647 { 648 return (struct setlist *) genget(name, (char **) Setlist, getnextset); 649 } 650 651 static 652 setcmd(argc, argv) 653 int argc; 654 char *argv[]; 655 { 656 int value; 657 struct setlist *ct; 658 659 /* XXX back we go... sigh */ 660 if (argc != 3) { 661 if ((argc == 2) && 662 ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 663 for (ct = Setlist; ct->name; ct++) { 664 printf("%s\t%s\n", ct->name, ct->help); 665 } 666 printf("?\tdisplay help information\n"); 667 } else { 668 printf("Format is 'set Name Value'\n'set ?' for help.\n"); 669 } 670 return 0; 671 } 672 673 ct = getset(argv[1]); 674 if (ct == 0) { 675 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 676 argv[1]); 677 return 0; 678 } else if (Ambiguous(ct)) { 679 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 680 argv[1]); 681 return 0; 682 } else { 683 if (strcmp("off", argv[2])) { 684 value = special(argv[2]); 685 } else { 686 value = -1; 687 } 688 *(ct->charp) = value; 689 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 690 } 691 return 1; 692 } 693 694 /* 695 * The following are the data structures and routines for the 696 * 'mode' command. 697 */ 698 699 static 700 dolinemode() 701 { 702 if (hisopts[TELOPT_SGA]) { 703 wontoption(TELOPT_SGA, 0); 704 } 705 if (hisopts[TELOPT_ECHO]) { 706 wontoption(TELOPT_ECHO, 0); 707 } 708 return 1; 709 } 710 711 static 712 docharmode() 713 { 714 if (!hisopts[TELOPT_SGA]) { 715 willoption(TELOPT_SGA, 0); 716 } 717 if (!hisopts[TELOPT_ECHO]) { 718 willoption(TELOPT_ECHO, 0); 719 } 720 return 1; 721 } 722 723 static Command Mode_commands[] = { 724 { "character", "character-at-a-time mode", docharmode, 1, 1 }, 725 { "line", "line-by-line mode", dolinemode, 1, 1 }, 726 { 0 }, 727 }; 728 729 static char ** 730 getnextmode(name) 731 char *name; 732 { 733 Command *c = (Command *) name; 734 735 return (char **) (c+1); 736 } 737 738 static Command * 739 getmodecmd(name) 740 char *name; 741 { 742 return (Command *) genget(name, (char **) Mode_commands, getnextmode); 743 } 744 745 static 746 modecmd(argc, argv) 747 int argc; 748 char *argv[]; 749 { 750 Command *mt; 751 752 if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 753 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 754 for (mt = Mode_commands; mt->name; mt++) { 755 printf("%s\t%s\n", mt->name, mt->help); 756 } 757 return 0; 758 } 759 mt = getmodecmd(argv[1]); 760 if (mt == 0) { 761 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 762 return 0; 763 } else if (Ambiguous(mt)) { 764 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 765 return 0; 766 } else { 767 (*mt->handler)(); 768 } 769 return 1; 770 } 771 772 /* 773 * The following data structures and routines implement the 774 * "display" command. 775 */ 776 777 static 778 display(argc, argv) 779 int argc; 780 char *argv[]; 781 { 782 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 783 if (*tl->variable) { \ 784 printf("will"); \ 785 } else { \ 786 printf("won't"); \ 787 } \ 788 printf(" %s.\n", tl->actionexplanation); \ 789 } 790 791 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 792 printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 793 } 794 795 struct togglelist *tl; 796 struct setlist *sl; 797 798 if (argc == 1) { 799 for (tl = Togglelist; tl->name; tl++) { 800 dotog(tl); 801 } 802 printf("\n"); 803 for (sl = Setlist; sl->name; sl++) { 804 doset(sl); 805 } 806 } else { 807 int i; 808 809 for (i = 1; i < argc; i++) { 810 sl = getset(argv[i]); 811 tl = gettoggle(argv[i]); 812 if (Ambiguous(sl) || Ambiguous(tl)) { 813 printf("?Ambiguous argument '%s'.\n", argv[i]); 814 return 0; 815 } else if (!sl && !tl) { 816 printf("?Unknown argument '%s'.\n", argv[i]); 817 return 0; 818 } else { 819 if (tl) { 820 dotog(tl); 821 } 822 if (sl) { 823 doset(sl); 824 } 825 } 826 } 827 } 828 return 1; 829 #undef doset 830 #undef dotog 831 } 832 833 /* 834 * The following are the data structures, and many of the routines, 835 * relating to command processing. 836 */ 837 838 /* 839 * Set the escape character. 840 */ 841 static 842 setescape(argc, argv) 843 int argc; 844 char *argv[]; 845 { 846 register char *arg; 847 char buf[50]; 848 849 printf( 850 "Deprecated usage - please use 'set escape%s%s' in the future.\n", 851 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 852 if (argc > 2) 853 arg = argv[1]; 854 else { 855 printf("new escape character: "); 856 (void) gets(buf); 857 arg = buf; 858 } 859 if (arg[0] != '\0') 860 escape = arg[0]; 861 if (!In3270) { 862 printf("Escape character is '%s'.\n", control(escape)); 863 } 864 (void) fflush(stdout); 865 return 1; 866 } 867 868 /*VARARGS*/ 869 static 870 togcrmod() 871 { 872 crmod = !crmod; 873 printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 874 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 875 (void) fflush(stdout); 876 return 1; 877 } 878 879 /*VARARGS*/ 880 suspend() 881 { 882 setcommandmode(); 883 #if defined(unix) 884 (void) kill(0, SIGTSTP); 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 1083 1084 #if defined(MSDOS) 1085 char *cp; 1086 #endif /* defined(MSDOS) */ 1087 1088 if (connected) { 1089 printf("?Already connected to %s\n", hostname); 1090 return 0; 1091 } 1092 if (argc < 2) { 1093 (void) strcpy(line, "Connect "); 1094 printf("(to) "); 1095 (void) gets(&line[strlen(line)]); 1096 makeargv(); 1097 argc = margc; 1098 argv = margv; 1099 } 1100 if ((argc < 2) || (argc > 3)) { 1101 printf("usage: %s host-name [port]\n", argv[0]); 1102 return 0; 1103 } 1104 #if defined(MSDOS) 1105 for (cp = argv[1]; *cp; cp++) { 1106 if (isupper(*cp)) { 1107 *cp = tolower(*cp); 1108 } 1109 } 1110 #endif /* defined(MSDOS) */ 1111 sin.sin_addr.s_addr = inet_addr(argv[1]); 1112 if (sin.sin_addr.s_addr != (unsigned long) -1) { 1113 sin.sin_family = AF_INET; 1114 (void) strcpy(hnamebuf, argv[1]); 1115 hostname = hnamebuf; 1116 } else { 1117 host = gethostbyname(argv[1]); 1118 if (host) { 1119 sin.sin_family = host->h_addrtype; 1120 #if defined(h_addr) /* In 4.3, this is a #define */ 1121 memcpy((caddr_t)&sin.sin_addr, 1122 host->h_addr_list[0], host->h_length); 1123 #else /* defined(h_addr) */ 1124 memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 1125 #endif /* defined(h_addr) */ 1126 hostname = host->h_name; 1127 } else { 1128 herror(argv[1]); 1129 return 0; 1130 } 1131 } 1132 if (argc == 3) { 1133 sin.sin_port = atoi(argv[2]); 1134 if (sin.sin_port == 0) { 1135 sp = getservbyname(argv[2], "tcp"); 1136 if (sp) 1137 sin.sin_port = sp->s_port; 1138 else { 1139 printf("%s: bad port number\n", argv[2]); 1140 return 0; 1141 } 1142 } else { 1143 #if !defined(htons) 1144 u_short htons(); 1145 #endif /* !defined(htons) */ 1146 1147 sin.sin_port = atoi(argv[2]); 1148 sin.sin_port = htons(sin.sin_port); 1149 } 1150 telnetport = 0; 1151 } else { 1152 if (sp == 0) { 1153 sp = getservbyname("telnet", "tcp"); 1154 if (sp == 0) { 1155 fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1156 return 0; 1157 } 1158 sin.sin_port = sp->s_port; 1159 } 1160 telnetport = 1; 1161 } 1162 printf("Trying...\n"); 1163 do { 1164 net = socket(AF_INET, SOCK_STREAM, 0); 1165 if (net < 0) { 1166 perror("telnet: socket"); 1167 return 0; 1168 } 1169 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 1170 perror("setsockopt (SO_DEBUG)"); 1171 } 1172 1173 if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 1174 #if defined(h_addr) /* In 4.3, this is a #define */ 1175 if (host && host->h_addr_list[1]) { 1176 int oerrno = errno; 1177 extern char *inet_ntoa(); 1178 1179 fprintf(stderr, "telnet: connect to address %s: ", 1180 inet_ntoa(sin.sin_addr)); 1181 errno = oerrno; 1182 perror((char *)0); 1183 host->h_addr_list++; 1184 memcpy((caddr_t)&sin.sin_addr, 1185 host->h_addr_list[0], host->h_length); 1186 fprintf(stderr, "Trying %s...\n", 1187 inet_ntoa(sin.sin_addr)); 1188 (void) NetClose(net); 1189 continue; 1190 } 1191 #endif /* defined(h_addr) */ 1192 perror("telnet: Unable to connect to remote host"); 1193 return 0; 1194 } 1195 connected++; 1196 } while (connected == 0); 1197 (void) call(status, "status", "notmuch", 0); 1198 if (setjmp(peerdied) == 0) 1199 telnet(); 1200 (void) NetClose(net); 1201 ExitString("Connection closed by foreign host.\n",1); 1202 /*NOTREACHED*/ 1203 } 1204 1205 1206 #define HELPINDENT (sizeof ("connect")) 1207 1208 static char 1209 openhelp[] = "connect to a site", 1210 closehelp[] = "close current connection", 1211 quithelp[] = "exit telnet", 1212 statushelp[] = "print status information", 1213 helphelp[] = "print help information", 1214 sendhelp[] = "transmit special characters ('send ?' for more)", 1215 sethelp[] = "set operating parameters ('set ?' for more)", 1216 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 1217 displayhelp[] = "display operating parameters", 1218 #if defined(TN3270) && defined(unix) 1219 transcomhelp[] = "specify Unix command for transparent mode pipe", 1220 #endif /* defined(TN3270) && defined(unix) */ 1221 #if defined(unix) 1222 zhelp[] = "suspend telnet", 1223 #endif /* defined(unix */ 1224 #if defined(TN3270) 1225 shellhelp[] = "invoke a subshell", 1226 #endif /* defined(TN3270) */ 1227 modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 1228 1229 extern int help(), shell(); 1230 1231 static Command cmdtab[] = { 1232 { "close", closehelp, bye, 1, 1 }, 1233 { "display", displayhelp, display, 1, 0 }, 1234 { "mode", modehelp, modecmd, 1, 1 }, 1235 { "open", openhelp, tn, 1, 0 }, 1236 { "quit", quithelp, quit, 1, 0 }, 1237 { "send", sendhelp, sendcmd, 1, 1 }, 1238 { "set", sethelp, setcmd, 1, 0 }, 1239 { "status", statushelp, status, 1, 0 }, 1240 { "toggle", togglestring, toggle, 1, 0 }, 1241 #if defined(TN3270) && defined(unix) 1242 { "transcom", transcomhelp, settranscom, 1, 0 }, 1243 #endif /* defined(TN3270) && defined(unix) */ 1244 #if defined(unix) 1245 { "z", zhelp, suspend, 1, 0 }, 1246 #endif /* defined(unix) */ 1247 #if defined(TN3270) 1248 { "!", shellhelp, shell, 1, 1 }, 1249 #endif /* defined(TN3270) */ 1250 { "?", helphelp, help, 1, 0 }, 1251 0 1252 }; 1253 1254 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 1255 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 1256 1257 static Command cmdtab2[] = { 1258 { "help", helphelp, help, 0, 0 }, 1259 { "escape", escapehelp, setescape, 1, 0 }, 1260 { "crmod", crmodhelp, togcrmod, 1, 0 }, 1261 0 1262 }; 1263 1264 1265 /* 1266 * Call routine with argc, argv set from args (terminated by 0). 1267 */ 1268 1269 /*VARARGS1*/ 1270 static 1271 call(va_alist) 1272 va_dcl 1273 { 1274 va_list ap; 1275 typedef int (*intrtn_t)(); 1276 intrtn_t routine; 1277 char *args[100]; 1278 int argno = 0; 1279 1280 va_start(ap); 1281 routine = (va_arg(ap, intrtn_t)); 1282 while ((args[argno++] = va_arg(ap, char *)) != 0) { 1283 ; 1284 } 1285 va_end(ap); 1286 return (*routine)(argno-1, args); 1287 } 1288 1289 1290 static char ** 1291 getnextcmd(name) 1292 char *name; 1293 { 1294 Command *c = (Command *) name; 1295 1296 return (char **) (c+1); 1297 } 1298 1299 static Command * 1300 getcmd(name) 1301 char *name; 1302 { 1303 Command *cm; 1304 1305 if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 1306 return cm; 1307 } else { 1308 return (Command *) genget(name, (char **) cmdtab2, getnextcmd); 1309 } 1310 } 1311 1312 void 1313 command(top) 1314 int top; 1315 { 1316 register Command *c; 1317 1318 setcommandmode(); 1319 if (!top) { 1320 putchar('\n'); 1321 } else { 1322 #if defined(unix) 1323 signal(SIGINT, SIG_DFL); 1324 signal(SIGQUIT, SIG_DFL); 1325 #endif /* defined(unix) */ 1326 } 1327 for (;;) { 1328 printf("%s> ", prompt); 1329 if (gets(line) == NULL) { 1330 if (feof(stdin) || ferror(stdin)) 1331 quit(); 1332 break; 1333 } 1334 if (line[0] == 0) 1335 break; 1336 makeargv(); 1337 c = getcmd(margv[0]); 1338 if (Ambiguous(c)) { 1339 printf("?Ambiguous command\n"); 1340 continue; 1341 } 1342 if (c == 0) { 1343 printf("?Invalid command\n"); 1344 continue; 1345 } 1346 if (c->needconnect && !connected) { 1347 printf("?Need to be connected first.\n"); 1348 continue; 1349 } 1350 if ((*c->handler)(margc, margv)) { 1351 break; 1352 } 1353 } 1354 if (!top) { 1355 if (!connected) { 1356 longjmp(toplevel, 1); 1357 /*NOTREACHED*/ 1358 } 1359 #if defined(TN3270) 1360 if (shell_active == 0) { 1361 setconnmode(); 1362 } 1363 #else /* defined(TN3270) */ 1364 setconnmode(); 1365 #endif /* defined(TN3270) */ 1366 } 1367 } 1368 1369 /* 1370 * Help command. 1371 */ 1372 static 1373 help(argc, argv) 1374 int argc; 1375 char *argv[]; 1376 { 1377 register Command *c; 1378 1379 if (argc == 1) { 1380 printf("Commands may be abbreviated. Commands are:\n\n"); 1381 for (c = cmdtab; c->name; c++) 1382 if (c->dohelp) { 1383 printf("%-*s\t%s\n", HELPINDENT, c->name, 1384 c->help); 1385 } 1386 return 0; 1387 } 1388 while (--argc > 0) { 1389 register char *arg; 1390 arg = *++argv; 1391 c = getcmd(arg); 1392 if (Ambiguous(c)) 1393 printf("?Ambiguous help command %s\n", arg); 1394 else if (c == (Command *)0) 1395 printf("?Invalid help command %s\n", arg); 1396 else 1397 printf("%s\n", c->help); 1398 } 1399 return 0; 1400 } 1401