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