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