1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)commands.c 1.27 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #if defined(unix) 14 #include <sys/file.h> 15 #endif /* defined(unix) */ 16 #include <sys/socket.h> 17 #include <netinet/in.h> 18 #ifdef CRAY 19 #include <sys/fcntl.h> 20 #endif /* CRAY */ 21 22 #include <signal.h> 23 #include <netdb.h> 24 #include <ctype.h> 25 #include <varargs.h> 26 27 #include <arpa/telnet.h> 28 29 #include "general.h" 30 31 #include "ring.h" 32 33 #include "externs.h" 34 #include "defines.h" 35 #include "types.h" 36 37 #ifdef SRCRT 38 # ifndef CRAY 39 # include <netinet/in_systm.h> 40 # if defined(vax) || defined(tahoe) || defined(hp300) 41 # include <machine/endian.h> 42 # endif /* vax */ 43 # endif /* CRAY */ 44 #include <netinet/ip.h> 45 #endif /* SRCRT */ 46 47 #if defined(CRAY) && defined(IP_TOS) && !defined(HAS_IP_TOS) 48 # define HAS_IP_TOS 49 #endif 50 51 52 char *hostname; 53 extern char *getenv(); 54 55 #define Ambiguous(s) ((char **)s == &ambiguous) 56 static char *ambiguous; /* special return value for command routines */ 57 58 typedef struct { 59 char *name; /* command name */ 60 char *help; /* help string (NULL for no help) */ 61 int (*handler)(); /* routine which executes command */ 62 int needconnect; /* Do we need to be connected to execute? */ 63 } Command; 64 65 static char line[256]; 66 static char saveline[256]; 67 static int margc; 68 static char *margv[20]; 69 70 /* 71 * Various utility routines. 72 */ 73 74 #if !defined(BSD) || (BSD <= 43) 75 76 char *h_errlist[] = { 77 "Error 0", 78 "Unknown host", /* 1 HOST_NOT_FOUND */ 79 "Host name lookup failure", /* 2 TRY_AGAIN */ 80 "Unknown server error", /* 3 NO_RECOVERY */ 81 "No address associated with name", /* 4 NO_ADDRESS */ 82 }; 83 int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) }; 84 85 int h_errno; /* In some version of SunOS this is necessary */ 86 87 /* 88 * herror -- 89 * print the error indicated by the h_errno value. 90 */ 91 herror(s) 92 char *s; 93 { 94 if (s && *s) { 95 fprintf(stderr, "%s: ", s); 96 } 97 if ((h_errno < 0) || (h_errno >= h_nerr)) { 98 fprintf(stderr, "Unknown error\n"); 99 } else if (h_errno == 0) { 100 #if defined(sun) 101 fprintf(stderr, "Host unknown\n"); 102 #endif /* defined(sun) */ 103 } else { 104 fprintf(stderr, "%s\n", h_errlist[h_errno]); 105 } 106 } 107 #endif /* !define(BSD) || (BSD <= 43) */ 108 109 static void 110 makeargv() 111 { 112 register char *cp; 113 register char **argp = margv; 114 115 margc = 0; 116 cp = line; 117 if (*cp == '!') { /* Special case shell escape */ 118 strcpy(saveline, line); /* save for shell command */ 119 *argp++ = "!"; /* No room in string to get this */ 120 margc++; 121 cp++; 122 } 123 while (*cp) { 124 while (isspace(*cp)) 125 cp++; 126 if (*cp == '\0') 127 break; 128 *argp++ = cp; 129 margc += 1; 130 while (*cp != '\0' && !isspace(*cp)) 131 cp++; 132 if (*cp == '\0') 133 break; 134 *cp++ = '\0'; 135 } 136 *argp++ = 0; 137 } 138 139 140 static char ** 141 genget(name, table, next) 142 char *name; /* name to match */ 143 char **table; /* name entry in table */ 144 char **(*next)(); /* routine to return next entry in table */ 145 { 146 register char *p, *q; 147 register char **c, **found; 148 register int nmatches, longest; 149 150 if (name == 0) { 151 return 0; 152 } 153 longest = 0; 154 nmatches = 0; 155 found = 0; 156 for (c = table; (p = *c) != 0; c = (*next)(c)) { 157 for (q = name; 158 (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 159 if (*q == 0) /* exact match? */ 160 return (c); 161 if (!*q) { /* the name was a prefix */ 162 if (q - name > longest) { 163 longest = q - name; 164 nmatches = 1; 165 found = c; 166 } else if (q - name == longest) 167 nmatches++; 168 } 169 } 170 if (nmatches > 1) 171 return &ambiguous; 172 return (found); 173 } 174 175 /* 176 * Make a character string into a number. 177 * 178 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 179 */ 180 181 static 182 special(s) 183 register char *s; 184 { 185 register char c; 186 char b; 187 188 switch (*s) { 189 case '^': 190 b = *++s; 191 if (b == '?') { 192 c = b | 0x40; /* DEL */ 193 } else { 194 c = b & 0x1f; 195 } 196 break; 197 default: 198 c = *s; 199 break; 200 } 201 return c; 202 } 203 204 /* 205 * Construct a control character sequence 206 * for a special character. 207 */ 208 static char * 209 control(c) 210 register cc_t c; 211 { 212 static char buf[3]; 213 214 if (c == 0x7f) 215 return ("^?"); 216 if (c == (cc_t)-1) { 217 return "off"; 218 } 219 if (c >= 0x20) { 220 buf[0] = c; 221 buf[1] = 0; 222 } else { 223 buf[0] = '^'; 224 buf[1] = '@'+c; 225 buf[2] = 0; 226 } 227 return (buf); 228 } 229 230 231 232 /* 233 * The following are data structures and routines for 234 * the "send" command. 235 * 236 */ 237 238 struct sendlist { 239 char *name; /* How user refers to it (case independent) */ 240 char *help; /* Help information (0 ==> no help) */ 241 #if defined(NOT43) 242 int (*handler)(); /* Routine to perform (for special ops) */ 243 #else /* defined(NOT43) */ 244 void (*handler)(); /* Routine to perform (for special ops) */ 245 #endif /* defined(NOT43) */ 246 int what; /* Character to be sent (<0 ==> special) */ 247 }; 248 249 #define SENDQUESTION -1 250 #define SENDESCAPE -3 251 252 static struct sendlist Sendlist[] = { 253 { "ao", "Send Telnet Abort output", 0, AO }, 254 { "ayt", "Send Telnet 'Are You There'", 0, AYT }, 255 { "brk", "Send Telnet Break", 0, BREAK }, 256 { "ec", "Send Telnet Erase Character", 0, EC }, 257 { "el", "Send Telnet Erase Line", 0, EL }, 258 { "escape", "Send current escape character", 0, SENDESCAPE }, 259 { "ga", "Send Telnet 'Go Ahead' sequence", 0, GA }, 260 { "ip", "Send Telnet Interrupt Process", 0, IP }, 261 { "nop", "Send Telnet 'No operation'", 0, NOP }, 262 { "eor", "Send Telnet 'End of Record'", 0, EOR }, 263 { "abort", "Send Telnet 'Abort Process'", 0, ABORT }, 264 { "susp", "Send Telnet 'Suspend Process'", 0, SUSP }, 265 { "eof", "Send Telnet End of File Character", 0, xEOF }, 266 { "synch", "Perform Telnet 'Synch operation'", dosynch, SYNCH }, 267 { "getstatus", "Send request for STATUS", get_status, 0 }, 268 { "?", "Display send options", 0, SENDQUESTION }, 269 { 0 } 270 }; 271 272 static struct sendlist Sendlist2[] = { /* some synonyms */ 273 { "break", 0, 0, BREAK }, 274 275 { "intp", 0, 0, IP }, 276 { "interrupt", 0, 0, IP }, 277 { "intr", 0, 0, IP }, 278 279 { "help", 0, 0, SENDQUESTION }, 280 281 { 0 } 282 }; 283 284 static char ** 285 getnextsend(name) 286 char *name; 287 { 288 struct sendlist *c = (struct sendlist *) name; 289 290 return (char **) (c+1); 291 } 292 293 static struct sendlist * 294 getsend(name) 295 char *name; 296 { 297 struct sendlist *sl; 298 299 if ((sl = (struct sendlist *) 300 genget(name, (char **) Sendlist, getnextsend)) != 0) { 301 return sl; 302 } else { 303 return (struct sendlist *) 304 genget(name, (char **) Sendlist2, getnextsend); 305 } 306 } 307 308 static 309 sendcmd(argc, argv) 310 int argc; 311 char **argv; 312 { 313 int what; /* what we are sending this time */ 314 int count; /* how many bytes we are going to need to send */ 315 int i; 316 int question = 0; /* was at least one argument a question */ 317 struct sendlist *s; /* pointer to current command */ 318 319 if (argc < 2) { 320 printf("need at least one argument for 'send' command\n"); 321 printf("'send ?' for help\n"); 322 return 0; 323 } 324 /* 325 * First, validate all the send arguments. 326 * In addition, we see how much space we are going to need, and 327 * whether or not we will be doing a "SYNCH" operation (which 328 * flushes the network queue). 329 */ 330 count = 0; 331 for (i = 1; i < argc; i++) { 332 s = getsend(argv[i]); 333 if (s == 0) { 334 printf("Unknown send argument '%s'\n'send ?' for help.\n", 335 argv[i]); 336 return 0; 337 } else if (Ambiguous(s)) { 338 printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 339 argv[i]); 340 return 0; 341 } 342 switch (s->what) { 343 case SENDQUESTION: 344 question = 1; 345 break; 346 case SENDESCAPE: 347 count += 1; 348 break; 349 case SYNCH: 350 count += 2; 351 break; 352 default: 353 count += 2; 354 break; 355 } 356 } 357 if (!connected) { 358 if (count) 359 printf("?Need to be connected first.\n"); 360 if (question) { 361 for (s = Sendlist; s->name; s++) 362 if (s->help) 363 printf("%-15s %s\n", s->name, s->help); 364 } else 365 printf("'send ?' for help\n"); 366 return !question; 367 } 368 /* Now, do we have enough room? */ 369 if (NETROOM() < count) { 370 printf("There is not enough room in the buffer TO the network\n"); 371 printf("to process your request. Nothing will be done.\n"); 372 printf("('send synch' will throw away most data in the network\n"); 373 printf("buffer, if this might help.)\n"); 374 return 0; 375 } 376 /* OK, they are all OK, now go through again and actually send */ 377 for (i = 1; i < argc; i++) { 378 if ((s = getsend(argv[i])) == 0) { 379 fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 380 quit(); 381 /*NOTREACHED*/ 382 } 383 if (s->handler) { 384 (*s->handler)(s); 385 } else { 386 switch (what = s->what) { 387 case SYNCH: 388 dosynch(); 389 break; 390 case SENDQUESTION: 391 for (s = Sendlist; s->name; s++) { 392 if (s->help) 393 printf("%-15s %s\n", s->name, s->help); 394 } 395 question = 1; 396 break; 397 case SENDESCAPE: 398 NETADD(escape); 399 break; 400 default: 401 NET2ADD(IAC, what); 402 break; 403 } 404 } 405 } 406 return !question; 407 } 408 409 /* 410 * The following are the routines and data structures referred 411 * to by the arguments to the "toggle" command. 412 */ 413 414 static 415 lclchars() 416 { 417 donelclchars = 1; 418 return 1; 419 } 420 421 static 422 togdebug() 423 { 424 #ifndef NOT43 425 if (net > 0 && 426 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 427 perror("setsockopt (SO_DEBUG)"); 428 } 429 #else /* NOT43 */ 430 if (debug) { 431 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 432 perror("setsockopt (SO_DEBUG)"); 433 } else 434 printf("Cannot turn off socket debugging\n"); 435 #endif /* NOT43 */ 436 return 1; 437 } 438 439 440 static int 441 togcrlf() 442 { 443 if (crlf) { 444 printf("Will send carriage returns as telnet <CR><LF>.\n"); 445 } else { 446 printf("Will send carriage returns as telnet <CR><NUL>.\n"); 447 } 448 return 1; 449 } 450 451 int binmode; 452 453 static int 454 togbinary(val) 455 int val; 456 { 457 donebinarytoggle = 1; 458 459 if (val >= 0) { 460 binmode = val; 461 } else { 462 if (my_want_state_is_will(TELOPT_BINARY) && 463 my_want_state_is_do(TELOPT_BINARY)) { 464 binmode = 1; 465 } else if (my_want_state_is_wont(TELOPT_BINARY) && 466 my_want_state_is_dont(TELOPT_BINARY)) { 467 binmode = 0; 468 } 469 val = binmode ? 0 : 1; 470 } 471 472 if (val == 1) { 473 if (my_want_state_is_will(TELOPT_BINARY) && 474 my_want_state_is_do(TELOPT_BINARY)) { 475 printf("Already operating in binary mode with remote host.\n"); 476 } else { 477 printf("Negotiating binary mode with remote host.\n"); 478 tel_enter_binary(3); 479 } 480 } else { 481 if (my_want_state_is_wont(TELOPT_BINARY) && 482 my_want_state_is_dont(TELOPT_BINARY)) { 483 printf("Already in network ascii mode with remote host.\n"); 484 } else { 485 printf("Negotiating network ascii mode with remote host.\n"); 486 tel_leave_binary(3); 487 } 488 } 489 return 1; 490 } 491 492 static int 493 togrbinary(val) 494 int val; 495 { 496 donebinarytoggle = 1; 497 498 if (val == -1) 499 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 500 501 if (val == 1) { 502 if (my_want_state_is_do(TELOPT_BINARY)) { 503 printf("Already receiving in binary mode.\n"); 504 } else { 505 printf("Negotiating binary mode on input.\n"); 506 tel_enter_binary(1); 507 } 508 } else { 509 if (my_want_state_is_dont(TELOPT_BINARY)) { 510 printf("Already receiving in network ascii mode.\n"); 511 } else { 512 printf("Negotiating network ascii mode on input.\n"); 513 tel_leave_binary(1); 514 } 515 } 516 return 1; 517 } 518 519 static int 520 togxbinary(val) 521 int val; 522 { 523 donebinarytoggle = 1; 524 525 if (val == -1) 526 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 527 528 if (val == 1) { 529 if (my_want_state_is_will(TELOPT_BINARY)) { 530 printf("Already transmitting in binary mode.\n"); 531 } else { 532 printf("Negotiating binary mode on output.\n"); 533 tel_enter_binary(2); 534 } 535 } else { 536 if (my_want_state_is_wont(TELOPT_BINARY)) { 537 printf("Already transmitting in network ascii mode.\n"); 538 } else { 539 printf("Negotiating network ascii mode on output.\n"); 540 tel_leave_binary(2); 541 } 542 } 543 return 1; 544 } 545 546 547 extern int togglehelp(); 548 extern int slc_check(); 549 550 struct togglelist { 551 char *name; /* name of toggle */ 552 char *help; /* help message */ 553 int (*handler)(); /* routine to do actual setting */ 554 int *variable; 555 char *actionexplanation; 556 }; 557 558 static struct togglelist Togglelist[] = { 559 { "autoflush", 560 "flushing of output when sending interrupt characters", 561 0, 562 &autoflush, 563 "flush output when sending interrupt characters" }, 564 { "autosynch", 565 "automatic sending of interrupt characters in urgent mode", 566 0, 567 &autosynch, 568 "send interrupt characters in urgent mode" }, 569 { "binary", 570 "sending and receiving of binary data", 571 togbinary, 572 0, 573 0 }, 574 { "inbinary", 575 "receiving of binary data", 576 togrbinary, 577 0, 578 0 }, 579 { "outbinary", 580 "sending of binary data", 581 togxbinary, 582 0, 583 0 }, 584 { "crlf", 585 "sending carriage returns as telnet <CR><LF>", 586 togcrlf, 587 &crlf, 588 0 }, 589 { "crmod", 590 "mapping of received carriage returns", 591 0, 592 &crmod, 593 "map carriage return on output" }, 594 { "localchars", 595 "local recognition of certain control characters", 596 lclchars, 597 &localchars, 598 "recognize certain control characters" }, 599 { " ", "", 0 }, /* empty line */ 600 #if defined(unix) && defined(TN3270) 601 { "apitrace", 602 "(debugging) toggle tracing of API transactions", 603 0, 604 &apitrace, 605 "trace API transactions" }, 606 { "cursesdata", 607 "(debugging) toggle printing of hexadecimal curses data", 608 0, 609 &cursesdata, 610 "print hexadecimal representation of curses data" }, 611 #endif /* defined(unix) && defined(TN3270) */ 612 { "debug", 613 "debugging", 614 togdebug, 615 &debug, 616 "turn on socket level debugging" }, 617 { "netdata", 618 "printing of hexadecimal network data (debugging)", 619 0, 620 &netdata, 621 "print hexadecimal representation of network traffic" }, 622 { "prettydump", 623 "output of \"netdata\" to user readable format (debugging)", 624 0, 625 &prettydump, 626 "print user readable output for \"netdata\"" }, 627 { "options", 628 "viewing of options processing (debugging)", 629 0, 630 &showoptions, 631 "show option processing" }, 632 #if defined(unix) 633 { "termdata", 634 "(debugging) toggle printing of hexadecimal terminal data", 635 0, 636 &termdata, 637 "print hexadecimal representation of terminal traffic" }, 638 #endif /* defined(unix) */ 639 { "?", 640 0, 641 togglehelp }, 642 { "help", 643 0, 644 togglehelp }, 645 { 0 } 646 }; 647 648 static 649 togglehelp() 650 { 651 struct togglelist *c; 652 653 for (c = Togglelist; c->name; c++) { 654 if (c->help) { 655 if (*c->help) 656 printf("%-15s toggle %s\n", c->name, c->help); 657 else 658 printf("\n"); 659 } 660 } 661 printf("\n"); 662 printf("%-15s %s\n", "?", "display help information"); 663 return 0; 664 } 665 666 static 667 settogglehelp(set) 668 int set; 669 { 670 struct togglelist *c; 671 672 for (c = Togglelist; c->name; c++) { 673 if (c->help) { 674 if (*c->help) 675 printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", 676 c->help); 677 else 678 printf("\n"); 679 } 680 } 681 } 682 683 static char ** 684 getnexttoggle(name) 685 char *name; 686 { 687 struct togglelist *c = (struct togglelist *) name; 688 689 return (char **) (c+1); 690 } 691 692 static struct togglelist * 693 gettoggle(name) 694 char *name; 695 { 696 return (struct togglelist *) 697 genget(name, (char **) Togglelist, getnexttoggle); 698 } 699 700 static 701 toggle(argc, argv) 702 int argc; 703 char *argv[]; 704 { 705 int retval = 1; 706 char *name; 707 struct togglelist *c; 708 709 if (argc < 2) { 710 fprintf(stderr, 711 "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 712 return 0; 713 } 714 argc--; 715 argv++; 716 while (argc--) { 717 name = *argv++; 718 c = gettoggle(name); 719 if (Ambiguous(c)) { 720 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 721 name); 722 return 0; 723 } else if (c == 0) { 724 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 725 name); 726 return 0; 727 } else { 728 if (c->variable) { 729 *c->variable = !*c->variable; /* invert it */ 730 if (c->actionexplanation) { 731 printf("%s %s.\n", *c->variable? "Will" : "Won't", 732 c->actionexplanation); 733 } 734 } 735 if (c->handler) { 736 retval &= (*c->handler)(-1); 737 } 738 } 739 } 740 return retval; 741 } 742 743 /* 744 * The following perform the "set" command. 745 */ 746 747 #ifdef USE_TERMIO 748 struct termio new_tc = { 0 }; 749 #endif 750 751 struct setlist { 752 char *name; /* name */ 753 char *help; /* help information */ 754 void (*handler)(); 755 cc_t *charp; /* where it is located at */ 756 }; 757 758 static struct setlist Setlist[] = { 759 { "echo", "character to toggle local echoing on/off", 0, &echoc }, 760 { "escape", "character to escape back to telnet command mode", 0, &escape }, 761 { "tracefile", "file to write trace intormation to", SetNetTrace, (cc_t *)NetTraceFile}, 762 { " ", "" }, 763 { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 764 { "flushoutput", "character to cause an Abort Oubput", 0, termFlushCharp }, 765 { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, 766 { "quit", "character to cause an Abort process", 0, termQuitCharp }, 767 { "eof", "character to cause an EOF ", 0, termEofCharp }, 768 { " ", "" }, 769 { " ", "The following are for local editing in linemode", 0, 0 }, 770 { "erase", "character to use to erase a character", 0, termEraseCharp }, 771 { "kill", "character to use to erase a line", 0, termKillCharp }, 772 { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, 773 { "susp", "character to cuase a Suspend Process", 0, termSuspCharp }, 774 { "reprint", "character to use for line reprint", 0, termRprntCharp }, 775 { "worderase", "character to use to erase a word", 0, termWerasCharp }, 776 { "start", "character to use for XON", 0, termStartCharp }, 777 { "stop", "character to sue for XOFF", 0, termStopCharp }, 778 { 0 } 779 }; 780 781 #ifdef CRAY 782 /* Work around compiler bug */ 783 _setlist_init() 784 { 785 Setlist[5].charp = &termFlushChar; 786 Setlist[6].charp = &termIntChar; 787 Setlist[7].charp = &termQuitChar; 788 Setlist[8].charp = &termEofChar; 789 Setlist[11].charp = &termEraseChar; 790 Setlist[12].charp = &termKillChar; 791 Setlist[13].charp = &termLiteralNextChar; 792 Setlist[14].charp = &termSuspChar; 793 Setlist[15].charp = &termRprntChar; 794 Setlist[16].charp = &termWerasChar; 795 Setlist[17].charp = &termStartChar; 796 Setlist[18].charp = &termStopChar; 797 } 798 #endif /* CRAY */ 799 800 static char ** 801 getnextset(name) 802 char *name; 803 { 804 struct setlist *c = (struct setlist *)name; 805 806 return (char **) (c+1); 807 } 808 809 static struct setlist * 810 getset(name) 811 char *name; 812 { 813 return (struct setlist *) genget(name, (char **) Setlist, getnextset); 814 } 815 816 static 817 setcmd(argc, argv) 818 int argc; 819 char *argv[]; 820 { 821 int value; 822 struct setlist *ct; 823 struct togglelist *c; 824 825 if (argc < 2 || argc > 3) { 826 printf("Format is 'set Name Value'\n'set ?' for help.\n"); 827 return 0; 828 } 829 if ((argc == 2) && 830 ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 831 for (ct = Setlist; ct->name; ct++) 832 printf("%-15s %s\n", ct->name, ct->help); 833 printf("\n"); 834 settogglehelp(1); 835 printf("%-15s %s\n", "?", "display help information"); 836 return 0; 837 } 838 839 ct = getset(argv[1]); 840 if (ct == 0) { 841 c = gettoggle(argv[1]); 842 if (c == 0) { 843 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 844 argv[1]); 845 return 0; 846 } else if (Ambiguous(c)) { 847 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 848 argv[1]); 849 return 0; 850 } 851 if (c->variable) { 852 if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 853 *c->variable = 1; 854 else if (strcmp("off", argv[2]) == 0) 855 *c->variable = 0; 856 else { 857 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); 858 return 0; 859 } 860 if (c->actionexplanation) { 861 printf("%s %s.\n", *c->variable? "Will" : "Won't", 862 c->actionexplanation); 863 } 864 } 865 if (c->handler) 866 (*c->handler)(1); 867 } else if (argc != 3) { 868 printf("Format is 'set Name Value'\n'set ?' for help.\n"); 869 return 0; 870 } else if (Ambiguous(ct)) { 871 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 872 argv[1]); 873 return 0; 874 } else if (ct->handler) { 875 (*ct->handler)(argv[2]); 876 printf("%s set to \"%s\".\n", ct->name, (unsigned char *)ct->charp); 877 } else { 878 if (strcmp("off", argv[2])) { 879 value = special(argv[2]); 880 } else { 881 value = -1; 882 } 883 *(ct->charp) = (cc_t)value; 884 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 885 } 886 slc_check(); 887 return 1; 888 } 889 890 static 891 unsetcmd(argc, argv) 892 int argc; 893 char *argv[]; 894 { 895 int value; 896 struct setlist *ct; 897 struct togglelist *c; 898 register char *name; 899 900 if (argc < 2) { 901 fprintf(stderr, 902 "Need an argument to 'unset' command. 'unset ?' for help.\n"); 903 return 0; 904 } 905 if ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help"))) { 906 for (ct = Setlist; ct->name; ct++) 907 printf("%-15s %s\n", ct->name, ct->help); 908 printf("\n"); 909 settogglehelp(0); 910 printf("%-15s %s\n", "?", "display help information"); 911 return 0; 912 } 913 914 argc--; 915 argv++; 916 while (argc--) { 917 name = *argv++; 918 ct = getset(name); 919 if (ct == 0) { 920 c = gettoggle(name); 921 if (c == 0) { 922 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", 923 name); 924 return 0; 925 } else if (Ambiguous(c)) { 926 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", 927 name); 928 return 0; 929 } 930 if (c->variable) { 931 *c->variable = 0; 932 if (c->actionexplanation) { 933 printf("%s %s.\n", *c->variable? "Will" : "Won't", 934 c->actionexplanation); 935 } 936 } 937 if (c->handler) 938 (*c->handler)(0); 939 } else if (Ambiguous(ct)) { 940 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", 941 name); 942 return 0; 943 } else if (ct->handler) { 944 (*ct->handler)(0); 945 printf("%s reset to \"%s\".\n", ct->name, ct->charp); 946 } else { 947 value = -1; 948 *(ct->charp) = -1; 949 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 950 } 951 } 952 return 1; 953 } 954 955 /* 956 * The following are the data structures and routines for the 957 * 'mode' command. 958 */ 959 #ifdef KLUDGELINEMODE 960 extern int kludgelinemode; 961 #endif 962 963 static 964 dolinemode() 965 { 966 #ifdef KLUDGELINEMODE 967 if (kludgelinemode) 968 send_dont(TELOPT_SGA, 1); 969 #endif 970 send_will(TELOPT_LINEMODE, 1); 971 send_dont(TELOPT_ECHO, 1); 972 return 1; 973 } 974 975 static 976 docharmode() 977 { 978 #ifdef KLUDGELINEMODE 979 if (kludgelinemode) 980 send_do(TELOPT_SGA, 1); 981 else 982 #endif 983 send_wont(TELOPT_LINEMODE, 1); 984 send_do(TELOPT_ECHO, 1); 985 return 1; 986 } 987 988 setmode(bit) 989 { 990 return dolmmode(bit, 1); 991 } 992 993 clearmode(bit) 994 { 995 return dolmmode(bit, 0); 996 } 997 998 dolmmode(bit, on) 999 int bit, on; 1000 { 1001 char c; 1002 extern int linemode; 1003 1004 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1005 printf("?Need to have LINEMODE option enabled first.\n"); 1006 printf("'mode ?' for help.\n"); 1007 return 0; 1008 } 1009 1010 if (on) 1011 c = (linemode | bit); 1012 else 1013 c = (linemode & ~bit); 1014 lm_mode(&c, 1, 1); 1015 return 1; 1016 } 1017 1018 struct modelist { 1019 char *name; /* command name */ 1020 char *help; /* help string */ 1021 int (*handler)(); /* routine which executes command */ 1022 int needconnect; /* Do we need to be connected to execute? */ 1023 int arg1; 1024 }; 1025 1026 extern int modehelp(); 1027 1028 static struct modelist ModeList[] = { 1029 { "character", "Disable LINEMODE option", docharmode, 1 }, 1030 #ifdef KLUDGELINEMODE 1031 { "", "(or disable obsolete line-by-line mode)", 0 }, 1032 #endif 1033 { "line", "Enable LINEMODE option", dolinemode, 1 }, 1034 #ifdef KLUDGELINEMODE 1035 { "", "(or enable obsolete line-by-line mode)", 0 }, 1036 #endif 1037 { "", "", 0 }, 1038 { "", "These require the LINEMODE option to be enabled", 0 }, 1039 { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, 1040 { "+isig", 0, setmode, 1, MODE_TRAPSIG }, 1041 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, 1042 { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, 1043 { "+edit", 0, setmode, 1, MODE_EDIT }, 1044 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, 1045 { "help", 0, modehelp, 0 }, 1046 { "?", "Print help information", modehelp, 0 }, 1047 { 0 }, 1048 }; 1049 1050 static char ** 1051 getnextmode(name) 1052 char *name; 1053 { 1054 return (char **) (((struct modelist *)name)+1); 1055 } 1056 1057 static struct modelist * 1058 getmodecmd(name) 1059 char *name; 1060 { 1061 return (struct modelist *) genget(name, (char **) ModeList, getnextmode); 1062 } 1063 1064 modehelp() 1065 { 1066 struct modelist *mt; 1067 1068 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 1069 for (mt = ModeList; mt->name; mt++) { 1070 if (mt->help) { 1071 if (*mt->help) 1072 printf("%-15s %s\n", mt->name, mt->help); 1073 else 1074 printf("\n"); 1075 } 1076 } 1077 return 0; 1078 } 1079 1080 static 1081 modecmd(argc, argv) 1082 int argc; 1083 char *argv[]; 1084 { 1085 struct modelist *mt; 1086 1087 if (argc != 2) { 1088 printf("'mode' command requires an argument\n"); 1089 printf("'mode ?' for help.\n"); 1090 } else if ((mt = getmodecmd(argv[1])) == 0) { 1091 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 1092 } else if (Ambiguous(mt)) { 1093 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 1094 } else if (mt->needconnect && !connected) { 1095 printf("?Need to be connected first.\n"); 1096 printf("'mode ?' for help.\n"); 1097 } else if (mt->handler) { 1098 return (*mt->handler)(mt->arg1); 1099 } 1100 return 0; 1101 } 1102 1103 /* 1104 * The following data structures and routines implement the 1105 * "display" command. 1106 */ 1107 1108 static 1109 display(argc, argv) 1110 int argc; 1111 char *argv[]; 1112 { 1113 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1114 if (*tl->variable) { \ 1115 printf("will"); \ 1116 } else { \ 1117 printf("won't"); \ 1118 } \ 1119 printf(" %s.\n", tl->actionexplanation); \ 1120 } 1121 1122 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1123 if (sl->handler == 0) \ 1124 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ 1125 else \ 1126 printf("%-15s \"%s\"\n", sl->name, sl->charp); \ 1127 } 1128 1129 struct togglelist *tl; 1130 struct setlist *sl; 1131 1132 if (argc == 1) { 1133 for (tl = Togglelist; tl->name; tl++) { 1134 dotog(tl); 1135 } 1136 printf("\n"); 1137 for (sl = Setlist; sl->name; sl++) { 1138 doset(sl); 1139 } 1140 } else { 1141 int i; 1142 1143 for (i = 1; i < argc; i++) { 1144 sl = getset(argv[i]); 1145 tl = gettoggle(argv[i]); 1146 if (Ambiguous(sl) || Ambiguous(tl)) { 1147 printf("?Ambiguous argument '%s'.\n", argv[i]); 1148 return 0; 1149 } else if (!sl && !tl) { 1150 printf("?Unknown argument '%s'.\n", argv[i]); 1151 return 0; 1152 } else { 1153 if (tl) { 1154 dotog(tl); 1155 } 1156 if (sl) { 1157 doset(sl); 1158 } 1159 } 1160 } 1161 } 1162 /*@*/optionstatus(); 1163 return 1; 1164 #undef doset 1165 #undef dotog 1166 } 1167 1168 /* 1169 * The following are the data structures, and many of the routines, 1170 * relating to command processing. 1171 */ 1172 1173 /* 1174 * Set the escape character. 1175 */ 1176 static 1177 setescape(argc, argv) 1178 int argc; 1179 char *argv[]; 1180 { 1181 register char *arg; 1182 char buf[50]; 1183 1184 printf( 1185 "Deprecated usage - please use 'set escape%s%s' in the future.\n", 1186 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 1187 if (argc > 2) 1188 arg = argv[1]; 1189 else { 1190 printf("new escape character: "); 1191 (void) gets(buf); 1192 arg = buf; 1193 } 1194 if (arg[0] != '\0') 1195 escape = arg[0]; 1196 if (!In3270) { 1197 printf("Escape character is '%s'.\n", control(escape)); 1198 } 1199 (void) fflush(stdout); 1200 return 1; 1201 } 1202 1203 /*VARARGS*/ 1204 static 1205 togcrmod() 1206 { 1207 crmod = !crmod; 1208 printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 1209 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 1210 (void) fflush(stdout); 1211 return 1; 1212 } 1213 1214 /*VARARGS*/ 1215 suspend() 1216 { 1217 #ifdef SIGTSTP 1218 setcommandmode(); 1219 { 1220 long oldrows, oldcols, newrows, newcols; 1221 1222 TerminalWindowSize(&oldrows, &oldcols); 1223 (void) kill(0, SIGTSTP); 1224 TerminalWindowSize(&newrows, &newcols); 1225 if ((oldrows != newrows) || (oldcols != newcols)) { 1226 if (connected) { 1227 sendnaws(); 1228 } 1229 } 1230 } 1231 /* reget parameters in case they were changed */ 1232 TerminalSaveState(); 1233 setconnmode(0); 1234 #else 1235 printf("Suspend is not supported. Try the '!' command instead\n"); 1236 #endif 1237 return 1; 1238 } 1239 1240 #if !defined(TN3270) 1241 shell(argc, argv) 1242 int argc; 1243 char *argv[]; 1244 { 1245 extern char *rindex(); 1246 char cmdbuf[256]; 1247 1248 setcommandmode(); 1249 switch(vfork()) { 1250 case -1: 1251 perror("Fork failed\n"); 1252 break; 1253 1254 case 0: 1255 { 1256 /* 1257 * Fire up the shell in the child. 1258 */ 1259 register char *shell, *shellname; 1260 1261 shell = getenv("SHELL"); 1262 if (shell == NULL) 1263 shell = "/bin/sh"; 1264 if ((shellname = rindex(shell, '/')) == 0) 1265 shellname = shell; 1266 else 1267 shellname++; 1268 if (argc > 1) 1269 execl(shell, shellname, "-c", &saveline[1], 0); 1270 else 1271 execl(shell, shellname, 0); 1272 perror("Execl"); 1273 _exit(1); 1274 } 1275 default: 1276 wait((int *)0); /* Wait for the shell to complete */ 1277 } 1278 } 1279 #endif /* !defined(TN3270) */ 1280 1281 /*VARARGS*/ 1282 static 1283 bye(argc, argv) 1284 int argc; /* Number of arguments */ 1285 char *argv[]; /* arguments */ 1286 { 1287 if (connected) { 1288 (void) shutdown(net, 2); 1289 printf("Connection closed.\n"); 1290 (void) NetClose(net); 1291 connected = 0; 1292 /* reset options */ 1293 tninit(); 1294 #if defined(TN3270) 1295 SetIn3270(); /* Get out of 3270 mode */ 1296 #endif /* defined(TN3270) */ 1297 } 1298 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 1299 longjmp(toplevel, 1); 1300 /* NOTREACHED */ 1301 } 1302 return 1; /* Keep lint, etc., happy */ 1303 } 1304 1305 /*VARARGS*/ 1306 quit() 1307 { 1308 (void) call(bye, "bye", "fromquit", 0); 1309 Exit(0); 1310 return 1; /* just to keep lint happy */ 1311 } 1312 1313 /* 1314 * The SLC command. 1315 */ 1316 1317 struct slclist { 1318 char *name; 1319 char *help; 1320 int (*handler)(); 1321 int arg; 1322 }; 1323 1324 extern int slc_help(); 1325 extern int slc_mode_export(), slc_mode_import(), slcstate(); 1326 1327 struct slclist SlcList[] = { 1328 { "export", "Use local special character definitions", 1329 slc_mode_export, 0 }, 1330 { "import", "Use remote special character definitions", 1331 slc_mode_import, 1 }, 1332 { "check", "Verify remote special character definitions", 1333 slc_mode_import, 0 }, 1334 { "help", 0, slc_help, 0 }, 1335 { "?", "Print help information", slc_help, 0 }, 1336 { 0 }, 1337 }; 1338 1339 static 1340 slc_help() 1341 { 1342 struct slclist *c; 1343 1344 for (c = SlcList; c->name; c++) { 1345 if (c->help) { 1346 if (*c->help) 1347 printf("%-15s %s\n", c->name, c->help); 1348 else 1349 printf("\n"); 1350 } 1351 } 1352 } 1353 1354 static char ** 1355 getnextslc(name) 1356 char *name; 1357 { 1358 return (char **)(((struct slclist *)name)+1); 1359 } 1360 1361 static struct slclist * 1362 getslc(name) 1363 char *name; 1364 { 1365 return (struct slclist *)genget(name, (char **) SlcList, getnextslc); 1366 } 1367 1368 static 1369 slccmd(argc, argv) 1370 int argc; 1371 char *argv[]; 1372 { 1373 struct slclist *c; 1374 1375 if (argc != 2) { 1376 fprintf(stderr, 1377 "Need an argument to 'slc' command. 'slc ?' for help.\n"); 1378 return 0; 1379 } 1380 c = getslc(argv[1]); 1381 if (c == 0) { 1382 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", 1383 argv[1]); 1384 return 0; 1385 } 1386 if (Ambiguous(c)) { 1387 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", 1388 argv[1]); 1389 return 0; 1390 } 1391 (*c->handler)(c->arg); 1392 slcstate(); 1393 return 1; 1394 } 1395 1396 #if defined(unix) 1397 /* 1398 * Some information about our file descriptors. 1399 */ 1400 1401 char * 1402 decodeflags(mask) 1403 int mask; 1404 { 1405 static char buffer[100]; 1406 #define do(m,s) \ 1407 if (mask&(m)) { \ 1408 strcat(buffer, (s)); \ 1409 } 1410 1411 buffer[0] = 0; /* Terminate it */ 1412 1413 #ifdef FREAD 1414 do(FREAD, " FREAD"); 1415 #endif 1416 #ifdef FWRITE 1417 do(FWRITE, " FWRITE"); 1418 #endif 1419 #ifdef F_DUPFP 1420 do(F_DUPFD, " F_DUPFD"); 1421 #endif 1422 #ifdef FNDELAY 1423 do(FNDELAY, " FNDELAY"); 1424 #endif 1425 #ifdef FAPPEND 1426 do(FAPPEND, " FAPPEND"); 1427 #endif 1428 #ifdef FMARK 1429 do(FMARK, " FMARK"); 1430 #endif 1431 #ifdef FDEFER 1432 do(FDEFER, " FDEFER"); 1433 #endif 1434 #ifdef FASYNC 1435 do(FASYNC, " FASYNC"); 1436 #endif 1437 #ifdef FSHLOCK 1438 do(FSHLOCK, " FSHLOCK"); 1439 #endif 1440 #ifdef FEXLOCK 1441 do(FEXLOCK, " FEXLOCK"); 1442 #endif 1443 #ifdef FCREAT 1444 do(FCREAT, " FCREAT"); 1445 #endif 1446 #ifdef FTRUNC 1447 do(FTRUNC, " FTRUNC"); 1448 #endif 1449 #ifdef FEXCL 1450 do(FEXCL, " FEXCL"); 1451 #endif 1452 1453 return buffer; 1454 } 1455 #undef do 1456 1457 static void 1458 filestuff(fd) 1459 int fd; 1460 { 1461 int res; 1462 1463 #ifdef F_GETOWN 1464 setconnmode(0); 1465 res = fcntl(fd, F_GETOWN, 0); 1466 setcommandmode(); 1467 1468 if (res == -1) { 1469 perror("fcntl"); 1470 return; 1471 } 1472 printf("\tOwner is %d.\n", res); 1473 #endif 1474 1475 setconnmode(0); 1476 res = fcntl(fd, F_GETFL, 0); 1477 setcommandmode(); 1478 1479 if (res == -1) { 1480 perror("fcntl"); 1481 return; 1482 } 1483 printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); 1484 } 1485 1486 1487 #endif /* defined(unix) */ 1488 1489 /* 1490 * Print status about the connection. 1491 */ 1492 /*ARGSUSED*/ 1493 static 1494 status(argc, argv) 1495 int argc; 1496 char *argv[]; 1497 { 1498 if (connected) { 1499 printf("Connected to %s.\n", hostname); 1500 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 1501 int mode = getconnmode(); 1502 1503 if (my_want_state_is_will(TELOPT_LINEMODE)) { 1504 printf("Operating with LINEMODE option\n"); 1505 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); 1506 printf("%s catching of signals\n", 1507 (mode&MODE_TRAPSIG) ? "Local" : "No"); 1508 slcstate(); 1509 #ifdef KLUDGELINEMODE 1510 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 1511 printf("Operating in obsolete linemode\n"); 1512 #endif 1513 } else { 1514 printf("Operating in single character mode\n"); 1515 if (localchars) 1516 printf("Catching signals locally\n"); 1517 } 1518 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 1519 if (my_want_state_is_will(TELOPT_LFLOW)) 1520 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); 1521 } 1522 } else { 1523 printf("No connection.\n"); 1524 } 1525 # if !defined(TN3270) 1526 printf("Escape character is '%s'.\n", control(escape)); 1527 (void) fflush(stdout); 1528 # else /* !defined(TN3270) */ 1529 if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 1530 printf("Escape character is '%s'.\n", control(escape)); 1531 } 1532 # if defined(unix) 1533 if ((argc >= 2) && !strcmp(argv[1], "everything")) { 1534 printf("SIGIO received %d time%s.\n", 1535 sigiocount, (sigiocount == 1)? "":"s"); 1536 if (In3270) { 1537 printf("Process ID %d, process group %d.\n", 1538 getpid(), getpgrp(getpid())); 1539 printf("Terminal input:\n"); 1540 filestuff(tin); 1541 printf("Terminal output:\n"); 1542 filestuff(tout); 1543 printf("Network socket:\n"); 1544 filestuff(net); 1545 } 1546 } 1547 if (In3270 && transcom) { 1548 printf("Transparent mode command is '%s'.\n", transcom); 1549 } 1550 # endif /* defined(unix) */ 1551 (void) fflush(stdout); 1552 if (In3270) { 1553 return 0; 1554 } 1555 # endif /* defined(TN3270) */ 1556 return 1; 1557 } 1558 1559 1560 #if defined(NEED_GETTOS) 1561 struct tosent { 1562 char *t_name; /* name */ 1563 char **t_aliases; /* alias list */ 1564 char *t_proto; /* protocol */ 1565 int t_tos; /* Type Of Service bits */ 1566 }; 1567 1568 struct tosent * 1569 gettosbyname(name, proto) 1570 char *name, *proto; 1571 { 1572 static struct tosent te; 1573 static char *aliasp = 0; 1574 1575 te.t_name = name; 1576 te.t_aliases = &aliasp; 1577 te.t_proto = proto; 1578 te.t_tos = 020; /* Low Delay bit */ 1579 return(&te); 1580 } 1581 #endif 1582 1583 int 1584 tn(argc, argv) 1585 int argc; 1586 char *argv[]; 1587 { 1588 register struct hostent *host = 0; 1589 struct sockaddr_in sin; 1590 struct servent *sp = 0; 1591 static char hnamebuf[32]; 1592 unsigned long temp, inet_addr(); 1593 extern char *inet_ntoa(); 1594 #if defined(SRCRT) && defined(IPPROTO_IP) 1595 char *srp = 0, *strrchr(); 1596 unsigned long sourceroute(), srlen; 1597 #endif 1598 #if defined(HAS_IP_TOS) || defined(NEED_GETTOS) 1599 struct tosent *tp; 1600 #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */ 1601 1602 1603 if (connected) { 1604 printf("?Already connected to %s\n", hostname); 1605 return 0; 1606 } 1607 if (argc < 2) { 1608 (void) strcpy(line, "Connect "); 1609 printf("(to) "); 1610 (void) gets(&line[strlen(line)]); 1611 makeargv(); 1612 argc = margc; 1613 argv = margv; 1614 } 1615 if ((argc < 2) || (argc > 3)) { 1616 printf("usage: %s host-name [port]\n", argv[0]); 1617 return 0; 1618 } 1619 #if defined(SRCRT) && defined(IPPROTO_IP) 1620 if (argv[1][0] == '@' || argv[1][0] == '!') { 1621 if ((hostname = strrchr(argv[1], ':')) == NULL) 1622 hostname = strrchr(argv[1], '@'); 1623 hostname++; 1624 srp = 0; 1625 temp = sourceroute(argv[1], &srp, &srlen); 1626 if (temp == 0) { 1627 herror(srp); 1628 return 0; 1629 } else if (temp == -1) { 1630 printf("Bad source route option: %s\n", argv[1]); 1631 return 0; 1632 } else { 1633 sin.sin_addr.s_addr = temp; 1634 sin.sin_family = AF_INET; 1635 } 1636 } else { 1637 #endif 1638 temp = inet_addr(argv[1]); 1639 if (temp != (unsigned long) -1) { 1640 sin.sin_addr.s_addr = temp; 1641 sin.sin_family = AF_INET; 1642 (void) strcpy(hnamebuf, argv[1]); 1643 hostname = hnamebuf; 1644 } else { 1645 host = gethostbyname(argv[1]); 1646 if (host) { 1647 sin.sin_family = host->h_addrtype; 1648 #if defined(h_addr) /* In 4.3, this is a #define */ 1649 memcpy((caddr_t)&sin.sin_addr, 1650 host->h_addr_list[0], host->h_length); 1651 #else /* defined(h_addr) */ 1652 memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 1653 #endif /* defined(h_addr) */ 1654 hostname = host->h_name; 1655 } else { 1656 herror(argv[1]); 1657 return 0; 1658 } 1659 } 1660 #if defined(SRCRT) && defined(IPPROTO_IP) 1661 } 1662 #endif 1663 if (argc == 3) { 1664 int tmp; 1665 1666 if (*argv[2] == '-') { 1667 argv[2]++; 1668 telnetport = 1; 1669 } else 1670 telnetport = 0; 1671 sin.sin_port = atoi(argv[2]); 1672 if (sin.sin_port == 0) { 1673 sp = getservbyname(argv[2], "tcp"); 1674 if (sp) 1675 sin.sin_port = sp->s_port; 1676 else { 1677 printf("%s: bad port number\n", argv[2]); 1678 return 0; 1679 } 1680 } else { 1681 #if !defined(htons) 1682 u_short htons(); 1683 #endif /* !defined(htons) */ 1684 sin.sin_port = htons(sin.sin_port); 1685 } 1686 } else { 1687 if (sp == 0) { 1688 sp = getservbyname("telnet", "tcp"); 1689 if (sp == 0) { 1690 fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1691 return 0; 1692 } 1693 sin.sin_port = sp->s_port; 1694 } 1695 telnetport = 1; 1696 } 1697 printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); 1698 do { 1699 net = socket(AF_INET, SOCK_STREAM, 0); 1700 if (net < 0) { 1701 perror("telnet: socket"); 1702 return 0; 1703 } 1704 #if defined(SRCRT) && defined(IPPROTO_IP) 1705 if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) 1706 perror("setsockopt (IP_OPTIONS)"); 1707 #endif 1708 #if defined(HAS_IP_TOS) || defined(NEED_GETTOS) 1709 if ((tp = gettosbyname("telnet", "tcp")) && 1710 (setsockopt(net, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0)) 1711 perror("telnet: setsockopt TOS (ignored)"); 1712 #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */ 1713 1714 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 1715 perror("setsockopt (SO_DEBUG)"); 1716 } 1717 1718 if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 1719 #if defined(h_addr) /* In 4.3, this is a #define */ 1720 if (host && host->h_addr_list[1]) { 1721 int oerrno = errno; 1722 1723 fprintf(stderr, "telnet: connect to address %s: ", 1724 inet_ntoa(sin.sin_addr)); 1725 errno = oerrno; 1726 perror((char *)0); 1727 host->h_addr_list++; 1728 memcpy((caddr_t)&sin.sin_addr, 1729 host->h_addr_list[0], host->h_length); 1730 (void) NetClose(net); 1731 continue; 1732 } 1733 #endif /* defined(h_addr) */ 1734 perror("telnet: Unable to connect to remote host"); 1735 return 0; 1736 } 1737 connected++; 1738 } while (connected == 0); 1739 cmdrc(argv[1], hostname); 1740 (void) call(status, "status", "notmuch", 0); 1741 if (setjmp(peerdied) == 0) 1742 telnet(); 1743 (void) NetClose(net); 1744 ExitString("Connection closed by foreign host.\n",1); 1745 /*NOTREACHED*/ 1746 } 1747 1748 1749 #define HELPINDENT (sizeof ("connect")) 1750 1751 static char 1752 openhelp[] = "connect to a site", 1753 closehelp[] = "close current connection", 1754 quithelp[] = "exit telnet", 1755 statushelp[] = "print status information", 1756 helphelp[] = "print help information", 1757 sendhelp[] = "transmit special characters ('send ?' for more)", 1758 sethelp[] = "set operating parameters ('set ?' for more)", 1759 unsethelp[] = "unset operating parameters ('unset ?' for more)", 1760 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 1761 slchelp[] = "change state of special charaters ('slc ?' for more)", 1762 displayhelp[] = "display operating parameters", 1763 #if defined(TN3270) && defined(unix) 1764 transcomhelp[] = "specify Unix command for transparent mode pipe", 1765 #endif /* defined(TN3270) && defined(unix) */ 1766 #if defined(unix) 1767 zhelp[] = "suspend telnet", 1768 #endif /* defined(unix */ 1769 shellhelp[] = "invoke a subshell", 1770 modestring[] = "try to enter line-by-line or character-at-a-time mode"; 1771 1772 extern int help(), shell(); 1773 1774 static Command cmdtab[] = { 1775 { "close", closehelp, bye, 1 }, 1776 { "display", displayhelp, display, 0 }, 1777 { "mode", modestring, modecmd, 0 }, 1778 { "open", openhelp, tn, 0 }, 1779 { "quit", quithelp, quit, 0 }, 1780 { "send", sendhelp, sendcmd, 0 }, 1781 { "set", sethelp, setcmd, 0 }, 1782 { "unset", unsethelp, unsetcmd, 0 }, 1783 { "status", statushelp, status, 0 }, 1784 { "toggle", togglestring, toggle, 0 }, 1785 { "slc", slchelp, slccmd, 0 }, 1786 #if defined(TN3270) && defined(unix) 1787 { "transcom", transcomhelp, settranscom, 0 }, 1788 #endif /* defined(TN3270) && defined(unix) */ 1789 #if defined(unix) 1790 { "z", zhelp, suspend, 0 }, 1791 #endif /* defined(unix) */ 1792 #if defined(TN3270) 1793 { "!", shellhelp, shell, 1 }, 1794 #else 1795 { "!", shellhelp, shell, 0 }, 1796 #endif 1797 { "?", helphelp, help, 0 }, 1798 0 1799 }; 1800 1801 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 1802 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 1803 1804 static Command cmdtab2[] = { 1805 { "help", 0, help, 0 }, 1806 { "escape", escapehelp, setescape, 0 }, 1807 { "crmod", crmodhelp, togcrmod, 0 }, 1808 0 1809 }; 1810 1811 1812 /* 1813 * Call routine with argc, argv set from args (terminated by 0). 1814 */ 1815 1816 /*VARARGS1*/ 1817 static 1818 call(va_alist) 1819 va_dcl 1820 { 1821 va_list ap; 1822 typedef int (*intrtn_t)(); 1823 intrtn_t routine; 1824 char *args[100]; 1825 int argno = 0; 1826 1827 va_start(ap); 1828 routine = (va_arg(ap, intrtn_t)); 1829 while ((args[argno++] = va_arg(ap, char *)) != 0) { 1830 ; 1831 } 1832 va_end(ap); 1833 return (*routine)(argno-1, args); 1834 } 1835 1836 1837 static char ** 1838 getnextcmd(name) 1839 char *name; 1840 { 1841 Command *c = (Command *) name; 1842 1843 return (char **) (c+1); 1844 } 1845 1846 static Command * 1847 getcmd(name) 1848 char *name; 1849 { 1850 Command *cm; 1851 1852 if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 1853 return cm; 1854 } else { 1855 return (Command *) genget(name, (char **) cmdtab2, getnextcmd); 1856 } 1857 } 1858 1859 void 1860 command(top, tbuf, cnt) 1861 int top; 1862 char *tbuf; 1863 int cnt; 1864 { 1865 register Command *c; 1866 1867 setcommandmode(); 1868 if (!top) { 1869 putchar('\n'); 1870 #if defined(unix) 1871 } else { 1872 signal(SIGINT, SIG_DFL); 1873 signal(SIGQUIT, SIG_DFL); 1874 #endif /* defined(unix) */ 1875 } 1876 for (;;) { 1877 printf("%s> ", prompt); 1878 if (tbuf) { 1879 register char *cp; 1880 cp = line; 1881 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 1882 cnt--; 1883 tbuf = 0; 1884 if (cp == line || *--cp != '\n' || cp == line) 1885 goto getline; 1886 *cp = '\0'; 1887 printf("%s\n", line); 1888 } else { 1889 getline: 1890 if (gets(line) == NULL) { 1891 if (feof(stdin) || ferror(stdin)) 1892 quit(); 1893 break; 1894 } 1895 } 1896 if (line[0] == 0) 1897 break; 1898 makeargv(); 1899 if (margv[0] == 0) { 1900 break; 1901 } 1902 c = getcmd(margv[0]); 1903 if (Ambiguous(c)) { 1904 printf("?Ambiguous command\n"); 1905 continue; 1906 } 1907 if (c == 0) { 1908 printf("?Invalid command\n"); 1909 continue; 1910 } 1911 if (c->needconnect && !connected) { 1912 printf("?Need to be connected first.\n"); 1913 continue; 1914 } 1915 if ((*c->handler)(margc, margv)) { 1916 break; 1917 } 1918 } 1919 if (!top) { 1920 if (!connected) { 1921 longjmp(toplevel, 1); 1922 /*NOTREACHED*/ 1923 } 1924 #if defined(TN3270) 1925 if (shell_active == 0) { 1926 setconnmode(0); 1927 } 1928 #else /* defined(TN3270) */ 1929 setconnmode(0); 1930 #endif /* defined(TN3270) */ 1931 } 1932 } 1933 1934 /* 1935 * Help command. 1936 */ 1937 static 1938 help(argc, argv) 1939 int argc; 1940 char *argv[]; 1941 { 1942 register Command *c; 1943 1944 if (argc == 1) { 1945 printf("Commands may be abbreviated. Commands are:\n\n"); 1946 for (c = cmdtab; c->name; c++) 1947 if (c->help) { 1948 printf("%-*s\t%s\n", HELPINDENT, c->name, 1949 c->help); 1950 } 1951 return 0; 1952 } 1953 while (--argc > 0) { 1954 register char *arg; 1955 arg = *++argv; 1956 c = getcmd(arg); 1957 if (Ambiguous(c)) 1958 printf("?Ambiguous help command %s\n", arg); 1959 else if (c == (Command *)0) 1960 printf("?Invalid help command %s\n", arg); 1961 else 1962 printf("%s\n", c->help); 1963 } 1964 return 0; 1965 } 1966 1967 static char *rcname = 0; 1968 static char rcbuf[128]; 1969 1970 cmdrc(m1, m2) 1971 char *m1, *m2; 1972 { 1973 register Command *c; 1974 FILE *rcfile; 1975 int gotmachine = 0; 1976 int l1 = strlen(m1); 1977 int l2 = strlen(m2); 1978 char m1save[64]; 1979 1980 strcpy(m1save, m1); 1981 m1 = m1save; 1982 1983 if (rcname == 0) { 1984 rcname = getenv("HOME"); 1985 if (rcname) 1986 strcpy(rcbuf, rcname); 1987 else 1988 rcbuf[0] = '\0'; 1989 strcat(rcbuf, "/.telnetrc"); 1990 rcname = rcbuf; 1991 } 1992 1993 if ((rcfile = fopen(rcname, "r")) == 0) { 1994 return; 1995 } 1996 1997 for (;;) { 1998 if (fgets(line, sizeof(line), rcfile) == NULL) 1999 break; 2000 if (line[0] == 0) 2001 break; 2002 if (line[0] == '#') 2003 continue; 2004 if (gotmachine == 0) { 2005 if (isspace(line[0])) 2006 continue; 2007 if (strncasecmp(line, m1, l1) == 0) 2008 strncpy(line, &line[l1], sizeof(line) - l1); 2009 else if (strncasecmp(line, m2, l2) == 0) 2010 strncpy(line, &line[l2], sizeof(line) - l2); 2011 else 2012 continue; 2013 gotmachine = 1; 2014 } else { 2015 if (!isspace(line[0])) { 2016 gotmachine = 0; 2017 continue; 2018 } 2019 } 2020 makeargv(); 2021 if (margv[0] == 0) 2022 continue; 2023 c = getcmd(margv[0]); 2024 if (Ambiguous(c)) { 2025 printf("?Ambiguous command: %s\n", margv[0]); 2026 continue; 2027 } 2028 if (c == 0) { 2029 printf("?Invalid command: %s\n", margv[0]); 2030 continue; 2031 } 2032 /* 2033 * This should never happen... 2034 */ 2035 if (c->needconnect && !connected) { 2036 printf("?Need to be connected first for %s.\n", margv[0]); 2037 continue; 2038 } 2039 (*c->handler)(margc, margv); 2040 } 2041 fclose(rcfile); 2042 } 2043 2044 #if defined(SRCRT) && defined(IPPROTO_IP) 2045 2046 /* 2047 * Source route is handed in as 2048 * [!]@hop1@hop2...[@|:]dst 2049 * If the leading ! is present, it is a 2050 * strict source route, otherwise it is 2051 * assmed to be a loose source route. 2052 * 2053 * We fill in the source route option as 2054 * hop1,hop2,hop3...dest 2055 * and return a pointer to hop1, which will 2056 * be the address to connect() to. 2057 * 2058 * Arguments: 2059 * arg: pointer to route list to decipher 2060 * 2061 * cpp: If *cpp is not equal to NULL, this is a 2062 * pointer to a pointer to a character array 2063 * that should be filled in with the option. 2064 * 2065 * lenp: pointer to an integer that contains the 2066 * length of *cpp if *cpp != NULL. 2067 * 2068 * Return values: 2069 * 2070 * Returns the address of the host to connect to. If the 2071 * return value is -1, there was a syntax error in the 2072 * option, either unknown characters, or too many hosts. 2073 * If the return value is 0, one of the hostnames in the 2074 * path is unknown, and *cpp is set to point to the bad 2075 * hostname. 2076 * 2077 * *cpp: If *cpp was equal to NULL, it will be filled 2078 * in with a pointer to our static area that has 2079 * the option filled in. This will be 32bit aligned. 2080 * 2081 * *lenp: This will be filled in with how long the option 2082 * pointed to by *cpp is. 2083 * 2084 */ 2085 unsigned long 2086 sourceroute(arg, cpp, lenp) 2087 char *arg; 2088 char **cpp; 2089 int *lenp; 2090 { 2091 static char lsr[44]; 2092 char *cp, *cp2, *lsrp, *lsrep, *index(); 2093 register int tmp; 2094 struct in_addr sin_addr; 2095 register struct hostent *host = 0; 2096 register char c; 2097 2098 /* 2099 * Verify the arguments, and make sure we have 2100 * at least 7 bytes for the option. 2101 */ 2102 if (cpp == NULL || lenp == NULL) 2103 return((unsigned long)-1); 2104 if (*cpp != NULL && *lenp < 7) 2105 return((unsigned long)-1); 2106 /* 2107 * Decide whether we have a buffer passed to us, 2108 * or if we need to use our own static buffer. 2109 */ 2110 if (*cpp) { 2111 lsrp = *cpp; 2112 lsrep = lsrp + *lenp; 2113 } else { 2114 *cpp = lsrp = lsr; 2115 lsrep = lsrp + 44; 2116 } 2117 2118 cp = arg; 2119 2120 /* 2121 * Next, decide whether we have a loose source 2122 * route or a strict source route, and fill in 2123 * the begining of the option. 2124 */ 2125 if (*cp == '!') { 2126 cp++; 2127 *lsrp++ = IPOPT_SSRR; 2128 } else 2129 *lsrp++ = IPOPT_LSRR; 2130 2131 if (*cp != '@') 2132 return((unsigned long)-1); 2133 2134 lsrp++; /* skip over length, we'll fill it in later */ 2135 *lsrp++ = 4; 2136 2137 cp++; 2138 2139 sin_addr.s_addr = 0; 2140 2141 for (c = 0;;) { 2142 if (c == ':') 2143 cp2 = 0; 2144 else for (cp2 = cp; c = *cp2; cp2++) { 2145 if (c == ',') { 2146 *cp2++ = '\0'; 2147 if (*cp2 == '@') 2148 cp2++; 2149 } else if (c == '@') { 2150 *cp2++ = '\0'; 2151 } else if (c == ':') { 2152 *cp2++ = '\0'; 2153 } else 2154 continue; 2155 break; 2156 } 2157 if (!c) 2158 cp2 = 0; 2159 2160 if ((tmp = inet_addr(cp)) != -1) { 2161 sin_addr.s_addr = tmp; 2162 } else if (host = gethostbyname(cp)) { 2163 #if defined(h_addr) 2164 memcpy((caddr_t)&sin_addr, 2165 host->h_addr_list[0], host->h_length); 2166 #else 2167 memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length); 2168 #endif 2169 } else { 2170 *cpp = cp; 2171 return(0); 2172 } 2173 memcpy(lsrp, (char *)&sin_addr, 4); 2174 lsrp += 4; 2175 if (cp2) 2176 cp = cp2; 2177 else 2178 break; 2179 /* 2180 * Check to make sure there is space for next address 2181 */ 2182 if (lsrp + 4 > lsrep) 2183 return((unsigned long)-1); 2184 } 2185 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { 2186 *cpp = 0; 2187 *lenp = 0; 2188 return((unsigned long)-1); 2189 } 2190 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ 2191 *lenp = lsrp - *cpp; 2192 return(sin_addr.s_addr); 2193 } 2194 #endif 2195 2196 #if defined(NOSTRNCASECMP) 2197 strncasecmp(p1, p2, len) 2198 register char *p1, *p2; 2199 int len; 2200 { 2201 while (len--) { 2202 if (tolower(*p1) != tolower(*p2)) 2203 return(tolower(*p1) - tolower(*p2)); 2204 if (*p1 == '\0') 2205 return(0); 2206 p1++, p2++; 2207 } 2208 return(0); 2209 } 2210 #endif 2211