|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that this notice is preserved and that due credit is given ! 7: * to the University of California at Berkeley. The name of the University ! 8: * may not be used to endorse or promote products derived from this ! 9: * software without specific prior written permission. This software ! 10: * is provided ``as is'' without express or implied warranty. ! 11: */ ! 12: ! 13: #ifndef lint ! 14: char copyright[] = ! 15: "@(#) Copyright (c) 1988 Regents of the University of California.\n\ ! 16: All rights reserved.\n"; ! 17: #endif /* not lint */ ! 18: ! 19: #ifndef lint ! 20: static char sccsid[] = "@(#)telnet.c 6.9 (Berkeley) 3/28/88"; ! 21: #endif /* not lint */ ! 22: ! 23: /* ! 24: * User telnet program, modified for use by tn3270.c. ! 25: * ! 26: * Many of the FUNCTIONAL changes in this newest version of TELNET ! 27: * were suggested by Dave Borman of Cray Research, Inc. ! 28: * ! 29: * Other changes in the tn3270 side come from Alan Crosswell (Columbia), ! 30: * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley). ! 31: * ! 32: * This code is common between telnet(1c) and tn3270(1c). There are the ! 33: * following defines used to generate the various versions: ! 34: * ! 35: * TN3270 - This is to be linked with tn3270. ! 36: * ! 37: * NOT43 - Allows the program to compile and run on ! 38: * a 4.2BSD system. ! 39: * ! 40: * PUTCHAR - Within tn3270, on a NOT43 system, ! 41: * allows the use of the 4.3 curses ! 42: * (greater speed updating the screen). ! 43: * You need the 4.3 curses for this to work. ! 44: * ! 45: * FD_SETSIZE - On whichever system, if this isn't defined, ! 46: * we patch over the FD_SET, etc., macros with ! 47: * some homebrewed ones. ! 48: * ! 49: * SO_OOBINLINE - This is a socket option which we would like ! 50: * to set to allow TCP urgent data to come ! 51: * to us "inline". This is NECESSARY for ! 52: * CORRECT operation, and desireable for ! 53: * simpler operation. ! 54: * ! 55: * LNOFLSH - Detects the presence of the LNOFLSH bit ! 56: * in the tty structure. ! 57: * ! 58: * unix - Compiles in unix specific stuff. ! 59: * ! 60: * MSDOS - Compiles in MSDOS specific stuff. ! 61: * ! 62: */ ! 63: ! 64: #if !defined(TN3270) ! 65: #define ExitString(f,s,r) { fprintf(f, s); exit(r); } ! 66: #define Exit(x) exit(x) ! 67: #define SetIn3270() ! 68: ! 69: void setcommandmode(), command(); /* forward declarations */ ! 70: #endif /* !defined(TN3270) */ ! 71: ! 72: #include <sys/types.h> ! 73: ! 74: #if defined(pyr) ! 75: #define fd_set fdset_t ! 76: #endif /* defined(pyr) */ ! 77: ! 78: #include <sys/socket.h> ! 79: ! 80: #include <netinet/in.h> ! 81: ! 82: #if defined(unix) ! 83: /* By the way, we need to include curses.h before telnet.h since, ! 84: * among other things, telnet.h #defines 'DO', which is a variable ! 85: * declared in curses.h. ! 86: */ ! 87: #include <curses.h> ! 88: #endif /* defined(unix) */ ! 89: ! 90: #define TELOPTS ! 91: #include <arpa/telnet.h> ! 92: ! 93: #if !defined(NOT43) ! 94: #include <arpa/inet.h> ! 95: #else /* !defined(NOT43) */ ! 96: extern unsigned long inet_addr(); ! 97: extern char *inet_ntoa(); ! 98: #endif /* !defined(NOT43) */ ! 99: ! 100: #include <stdio.h> ! 101: #include <ctype.h> ! 102: #include <errno.h> ! 103: #include <setjmp.h> ! 104: #include <netdb.h> ! 105: ! 106: #if defined(unix) ! 107: #include <strings.h> ! 108: #else /* defined(unix) */ ! 109: #include <string.h> ! 110: #endif /* defined(unix) */ ! 111: ! 112: #if defined(TN3270) ! 113: #include "ascii/termin.ext" ! 114: #include "ctlr/screen.h" ! 115: #include "ctlr/oia.h" ! 116: #include "ctlr/options.ext" ! 117: #include "ctlr/outbound.ext" ! 118: #include "general/globals.h" ! 119: #include "telnet.ext" ! 120: #endif /* defined(TN3270) */ ! 121: ! 122: #include "general/general.h" ! 123: ! 124: ! 125: ! 126: #ifndef FD_SETSIZE ! 127: /* ! 128: * The following is defined just in case someone should want to run ! 129: * this telnet on a 4.2 system. ! 130: * ! 131: */ ! 132: ! 133: #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) ! 134: #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) ! 135: #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) ! 136: #define FD_ZERO(p) ((p)->fds_bits[0] = 0) ! 137: ! 138: #endif ! 139: ! 140: #define strip(x) ((x)&0x7f) ! 141: #define min(x,y) ((x<y)? x:y) ! 142: ! 143: #if defined(TN3270) ! 144: static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; ! 145: #endif /* defined(TN3270) */ ! 146: ! 147: static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp; ! 148: #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } ! 149: #define TTYLOC() (tfrontp) ! 150: #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) ! 151: #define TTYMIN() (netobuf) ! 152: #define TTYBYTES() (tfrontp-tbackp) ! 153: #define TTYROOM() (TTYMAX()-TTYLOC()+1) ! 154: ! 155: static char netobuf[2*BUFSIZ], *nfrontp, *nbackp; ! 156: #define NETADD(c) { *nfrontp++ = c; } ! 157: #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } ! 158: #define NETLOC() (nfrontp) ! 159: #define NETMAX() (netobuf+sizeof netobuf-1) ! 160: #define NETBYTES() (nfrontp-nbackp) ! 161: #define NETROOM() (NETMAX()-NETLOC()+1) ! 162: static char *neturg; /* one past last byte of urgent data */ ! 163: ! 164: static char subbuffer[100], ! 165: *subpointer, *subend; /* buffer for sub-options */ ! 166: #define SB_CLEAR() subpointer = subbuffer; ! 167: #define SB_TERM() subend = subpointer; ! 168: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ ! 169: *subpointer++ = (c); \ ! 170: } ! 171: ! 172: static char sb_terminal[] = { IAC, SB, ! 173: TELOPT_TTYPE, TELQUAL_IS, ! 174: 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', ! 175: IAC, SE }; ! 176: #define SBTERMMODEL 13 ! 177: ! 178: ! 179: static char hisopts[256]; ! 180: static char myopts[256]; ! 181: ! 182: static char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 183: static char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 184: static char will[] = { IAC, WILL, '%', 'c', 0 }; ! 185: static char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 186: ! 187: struct cmd { ! 188: char *name; /* command name */ ! 189: char *help; /* help string */ ! 190: int (*handler)(); /* routine which executes command */ ! 191: int dohelp; /* Should we give general help information? */ ! 192: int needconnect; /* Do we need to be connected to execute? */ ! 193: }; ! 194: ! 195: static char sibuf[BUFSIZ], *sbp; ! 196: static char tibuf[BUFSIZ], *tbp; ! 197: static fd_set ibits, obits, xbits; ! 198: ! 199: ! 200: static int ! 201: connected, ! 202: net, ! 203: scc, ! 204: tcc, ! 205: showoptions, ! 206: In3270, /* Are we in 3270 mode? */ ! 207: ISend, /* trying to send network data in */ ! 208: debug = 0, ! 209: crmod, ! 210: netdata, /* Print out network data flow */ ! 211: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ ! 212: noasynch = 0, /* User specified "-noasynch" on command line */ ! 213: askedSGA = 0, /* We have talked about suppress go ahead */ ! 214: telnetport = 1; ! 215: ! 216: static FILE *NetTrace = 0; /* Not in bss, since needs to stay */ ! 217: ! 218: #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ ! 219: ! 220: static char ! 221: *prompt = 0, ! 222: escape, ! 223: echoc; ! 224: ! 225: static int ! 226: SYNCHing, /* we are in TELNET SYNCH mode */ ! 227: flushout, /* flush output */ ! 228: autoflush = 0, /* flush output when interrupting? */ ! 229: autosynch, /* send interrupt characters with SYNCH? */ ! 230: localchars, /* we recognize interrupt/quit */ ! 231: donelclchars, /* the user has set "localchars" */ ! 232: donebinarytoggle, /* the user has put us in binary */ ! 233: dontlecho, /* do we suppress local echoing right now? */ ! 234: globalmode; ! 235: ! 236: /* The following are some tn3270 specific flags */ ! 237: #if defined(TN3270) ! 238: ! 239: static int ! 240: Sent3270TerminalType; /* Have we said we are a 3270? */ ! 241: ! 242: /* Some real, live, globals. */ ! 243: int ! 244: tout, /* Output file descriptor */ ! 245: tin; /* Input file descriptor */ ! 246: ! 247: #else /* defined(TN3270) */ ! 248: static int tin, tout; /* file descriptors */ ! 249: #endif /* defined(TN3270) */ ! 250: ! 251: ! 252: /* ! 253: * Telnet receiver states for fsm ! 254: */ ! 255: #define TS_DATA 0 ! 256: #define TS_IAC 1 ! 257: #define TS_WILL 2 ! 258: #define TS_WONT 3 ! 259: #define TS_DO 4 ! 260: #define TS_DONT 5 ! 261: #define TS_CR 6 ! 262: #define TS_SB 7 /* sub-option collection */ ! 263: #define TS_SE 8 /* looking for sub-option end */ ! 264: ! 265: static int telrcv_state = TS_DATA; ! 266: ! 267: static char line[200]; ! 268: static int margc; ! 269: static char *margv[20]; ! 270: ! 271: static jmp_buf toplevel = { 0 }; ! 272: static jmp_buf peerdied; ! 273: ! 274: extern int errno; ! 275: ! 276: ! 277: static struct sockaddr_in sin; ! 278: ! 279: static struct servent *sp = 0; ! 280: ! 281: static int flushline; ! 282: ! 283: static char *hostname; ! 284: static char hnamebuf[32]; ! 285: ! 286: /* ! 287: * The following are some clocks used to decide how to interpret ! 288: * the relationship between various variables. ! 289: */ ! 290: ! 291: static struct { ! 292: int ! 293: system, /* what the current time is */ ! 294: echotoggle, /* last time user entered echo character */ ! 295: modenegotiated, /* last time operating mode negotiated */ ! 296: didnetreceive, /* last time we read data from network */ ! 297: gotDM; /* when did we last see a data mark */ ! 298: } clocks; ! 299: ! 300: #define settimer(x) clocks.x = clocks.system++ ! 301: ! 302: /* Various modes */ ! 303: #define MODE_LINE(m) (modelist[m].modetype & LINE) ! 304: #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) ! 305: #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO) ! 306: #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE) ! 307: ! 308: #define LOCAL_CHARS 0x01 /* Characters processed locally */ ! 309: #define LINE 0x02 /* Line-by-line mode of operation */ ! 310: #define LOCAL_ECHO 0x04 /* Echoing locally */ ! 311: #define COMMAND_LINE 0x08 /* Command line mode */ ! 312: ! 313: static struct { ! 314: char *modedescriptions; ! 315: char modetype; ! 316: } modelist[] = { ! 317: { "telnet command mode", COMMAND_LINE }, ! 318: { "character-at-a-time mode", 0 }, ! 319: { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, ! 320: { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, ! 321: { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, ! 322: { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, ! 323: { "3270 mode", 0 }, ! 324: }; ! 325: ! 326: ! 327: /* ! 328: * The following routines try to encapsulate what is system dependent ! 329: * (at least between 4.x and dos) which is used in telnet.c. ! 330: */ ! 331: ! 332: #if defined(unix) ! 333: #include <sys/ioctl.h> ! 334: #include <sys/time.h> ! 335: #include <signal.h> ! 336: ! 337: int ! 338: HaveInput; /* There is input available to scan */ ! 339: ! 340: #if defined(TN3270) ! 341: static char tline[200]; ! 342: char *transcom = 0; /* transparent mode command (default: none) */ ! 343: #endif /* defined(TN3270) */ ! 344: ! 345: static struct tchars otc = { 0 }, ntc = { 0 }; ! 346: static struct ltchars oltc = { 0 }, nltc = { 0 }; ! 347: static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; ! 348: ! 349: ! 350: #define TerminalWrite(fd,buf,n) write(fd,buf,n) ! 351: #define TerminalRead(fd,buf,n) read(fd,buf,n) ! 352: ! 353: /* ! 354: * ! 355: */ ! 356: ! 357: static int ! 358: TerminalAutoFlush() /* unix */ ! 359: { ! 360: #if defined(LNOFLSH) ! 361: ioctl(0, TIOCLGET, (char *)&autoflush); ! 362: return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ ! 363: #else /* LNOFLSH */ ! 364: return 1; ! 365: #endif /* LNOFLSH */ ! 366: } ! 367: ! 368: /* ! 369: * TerminalSpecialChars() ! 370: * ! 371: * Look at an input character to see if it is a special character ! 372: * and decide what to do. ! 373: * ! 374: * Output: ! 375: * ! 376: * 0 Don't add this character. ! 377: * 1 Do add this character ! 378: */ ! 379: ! 380: int ! 381: TerminalSpecialChars(c) /* unix */ ! 382: int c; ! 383: { ! 384: void doflush(), intp(), sendbrk(); ! 385: ! 386: if (c == ntc.t_intrc) { ! 387: intp(); ! 388: return 0; ! 389: } else if (c == ntc.t_quitc) { ! 390: sendbrk(); ! 391: return 0; ! 392: } else if (c == nltc.t_flushc) { ! 393: NET2ADD(IAC, AO); ! 394: if (autoflush) { ! 395: doflush(); ! 396: } ! 397: return 0; ! 398: } else if (!MODE_LOCAL_CHARS(globalmode)) { ! 399: if (c == nttyb.sg_kill) { ! 400: NET2ADD(IAC, EL); ! 401: return 0; ! 402: } else if (c == nttyb.sg_erase) { ! 403: NET2ADD(IAC, EC); ! 404: return 0; ! 405: } ! 406: } ! 407: return 1; ! 408: } ! 409: ! 410: ! 411: /* ! 412: * Flush output to the terminal ! 413: */ ! 414: ! 415: static void ! 416: TerminalFlushOutput() /* unix */ ! 417: { ! 418: (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); ! 419: } ! 420: ! 421: static void ! 422: TerminalSaveState() /* unix */ ! 423: { ! 424: ioctl(0, TIOCGETP, (char *)&ottyb); ! 425: ioctl(0, TIOCGETC, (char *)&otc); ! 426: ioctl(0, TIOCGLTC, (char *)&oltc); ! 427: ! 428: ntc = otc; ! 429: nltc = oltc; ! 430: nttyb = ottyb; ! 431: } ! 432: ! 433: static void ! 434: TerminalRestoreState() /* unix */ ! 435: { ! 436: } ! 437: ! 438: /* ! 439: * TerminalNewMode - set up terminal to a specific mode. ! 440: */ ! 441: ! 442: ! 443: static void ! 444: TerminalNewMode(f) /* unix */ ! 445: register int f; ! 446: { ! 447: static int prevmode = 0; ! 448: struct tchars *tc; ! 449: struct tchars tc3; ! 450: struct ltchars *ltc; ! 451: struct sgttyb sb; ! 452: int onoff; ! 453: int old; ! 454: struct tchars notc2; ! 455: struct ltchars noltc2; ! 456: static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 457: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 458: ! 459: globalmode = f; ! 460: if (prevmode == f) ! 461: return; ! 462: old = prevmode; ! 463: prevmode = f; ! 464: sb = nttyb; ! 465: ! 466: switch (f) { ! 467: ! 468: case 0: ! 469: onoff = 0; ! 470: tc = &otc; ! 471: ltc = &oltc; ! 472: break; ! 473: ! 474: case 1: /* remote character processing, remote echo */ ! 475: case 2: /* remote character processing, local echo */ ! 476: case 6: /* 3270 mode - like 1, but with xon/xoff local */ ! 477: /* (might be nice to have "6" in telnet also...) */ ! 478: sb.sg_flags |= CBREAK; ! 479: if ((f == 1) || (f == 6)) { ! 480: sb.sg_flags &= ~(ECHO|CRMOD); ! 481: } else { ! 482: sb.sg_flags |= ECHO|CRMOD; ! 483: } ! 484: sb.sg_erase = sb.sg_kill = -1; ! 485: if (f == 6) { ! 486: tc = &tc3; ! 487: tc3 = notc; ! 488: /* get XON, XOFF characters */ ! 489: tc3.t_startc = otc.t_startc; ! 490: tc3.t_stopc = otc.t_stopc; ! 491: } else { ! 492: /* ! 493: * If user hasn't specified one way or the other, ! 494: * then default to not trapping signals. ! 495: */ ! 496: if (!donelclchars) { ! 497: localchars = 0; ! 498: } ! 499: if (localchars) { ! 500: notc2 = notc; ! 501: notc2.t_intrc = ntc.t_intrc; ! 502: notc2.t_quitc = ntc.t_quitc; ! 503: tc = ¬c2; ! 504: } else { ! 505: tc = ¬c; ! 506: } ! 507: } ! 508: ltc = &noltc; ! 509: onoff = 1; ! 510: break; ! 511: case 3: /* local character processing, remote echo */ ! 512: case 4: /* local character processing, local echo */ ! 513: case 5: /* local character processing, no echo */ ! 514: sb.sg_flags &= ~CBREAK; ! 515: sb.sg_flags |= CRMOD; ! 516: if (f == 4) ! 517: sb.sg_flags |= ECHO; ! 518: else ! 519: sb.sg_flags &= ~ECHO; ! 520: notc2 = ntc; ! 521: tc = ¬c2; ! 522: noltc2 = oltc; ! 523: ltc = &noltc2; ! 524: /* ! 525: * If user hasn't specified one way or the other, ! 526: * then default to trapping signals. ! 527: */ ! 528: if (!donelclchars) { ! 529: localchars = 1; ! 530: } ! 531: if (localchars) { ! 532: notc2.t_brkc = nltc.t_flushc; ! 533: noltc2.t_flushc = -1; ! 534: } else { ! 535: notc2.t_intrc = notc2.t_quitc = -1; ! 536: } ! 537: noltc2.t_suspc = escape; ! 538: noltc2.t_dsuspc = -1; ! 539: onoff = 1; ! 540: break; ! 541: ! 542: default: ! 543: return; ! 544: } ! 545: ioctl(tin, TIOCSLTC, (char *)ltc); ! 546: ioctl(tin, TIOCSETC, (char *)tc); ! 547: ioctl(tin, TIOCSETP, (char *)&sb); ! 548: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) ! 549: ioctl(tin, FIONBIO, (char *)&onoff); ! 550: ioctl(tout, FIONBIO, (char *)&onoff); ! 551: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ ! 552: #if defined(TN3270) ! 553: if (noasynch == 0) { ! 554: ioctl(tin, FIOASYNC, (char *)&onoff); ! 555: } ! 556: #endif /* defined(TN3270) */ ! 557: ! 558: if (MODE_LINE(f)) { ! 559: void doescape(); ! 560: ! 561: signal(SIGTSTP, doescape); ! 562: } else if (MODE_LINE(old)) { ! 563: signal(SIGTSTP, SIG_DFL); ! 564: sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); ! 565: } ! 566: } ! 567: ! 568: ! 569: int ! 570: NetClose(net) ! 571: int net; ! 572: { ! 573: return close(net); ! 574: } ! 575: ! 576: ! 577: static void ! 578: NetNonblockingIO(fd, onoff) /* unix */ ! 579: int ! 580: fd, ! 581: onoff; ! 582: { ! 583: ioctl(net, FIONBIO, (char *)&onoff); ! 584: } ! 585: ! 586: static void ! 587: NetSigIO(fd, onoff) /* unix */ ! 588: int ! 589: fd, ! 590: onoff; ! 591: { ! 592: ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */ ! 593: } ! 594: ! 595: static void ! 596: NetSetPgrp(fd) /* unix */ ! 597: int fd; ! 598: { ! 599: int myPid; ! 600: ! 601: myPid = getpid(); ! 602: #if defined(NOT43) ! 603: myPid = -myPid; ! 604: #endif /* defined(NOT43) */ ! 605: ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ ! 606: } ! 607: ! 608: ! 609: #endif /* defined(unix) */ ! 610: ! 611: #if defined(MSDOS) ! 612: #include <time.h> ! 613: #include <signal.h> ! 614: #include <process.h> ! 615: #include <fcntl.h> ! 616: #include <io.h> ! 617: #include <dos.h> ! 618: ! 619: #if !defined(SO_OOBINLINE) ! 620: #define SO_OOBINLINE ! 621: #endif /* !defined(SO_OOBINLINE) */ ! 622: ! 623: ! 624: static char ! 625: termEofChar, ! 626: termEraseChar, ! 627: termFlushChar, ! 628: termIntChar, ! 629: termKillChar, ! 630: termLiteralNextChar, ! 631: termQuitChar; ! 632: ! 633: static char ! 634: savedInState, savedOutState; ! 635: ! 636: /* ! 637: * MSDOS doesn't have anyway of deciding whether a full-edited line ! 638: * is ready to be read in, so we need to do character-by-character ! 639: * reads, and then do the editing in the program (in the case where ! 640: * we are supporting line-by-line mode). ! 641: * ! 642: * The following routines, which are internal to the MSDOS-specific ! 643: * code, accomplish this miracle. ! 644: */ ! 645: ! 646: #define Hex(c) HEX[(c)&0xff] ! 647: ! 648: static survivorSetup = 0; /* Do we have ^C hooks in? */ ! 649: ! 650: static int ! 651: lineend = 0, /* There is a line terminator */ ! 652: ctrlCCount = 0; ! 653: ! 654: static char linein[200], /* Where input line is assembled */ ! 655: *nextin = linein, /* Next input character */ ! 656: *nextout = linein; /* Next character to be consumed */ ! 657: ! 658: #define consumechar() \ ! 659: if ((++nextout) >= nextin) { \ ! 660: nextout = nextin = linein; \ ! 661: lineend = 0; \ ! 662: } ! 663: ! 664: #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */ ! 665: ! 666: ! 667: /* ! 668: * killone() ! 669: * ! 670: * Erase the last character on the line. ! 671: */ ! 672: ! 673: static void ! 674: killone() ! 675: { ! 676: if (lineend) { ! 677: return; /* ??? XXX */ ! 678: } ! 679: if (nextin == linein) { ! 680: return; /* Nothing to do */ ! 681: } ! 682: nextin--; ! 683: if (!(isspace(*nextin) || isprint(*nextin))) { ! 684: putchar('\b'); ! 685: putchar(' '); ! 686: putchar('\b'); ! 687: } ! 688: putchar('\b'); ! 689: putchar(' '); ! 690: putchar('\b'); ! 691: } ! 692: ! 693: ! 694: /* ! 695: * setlineend() ! 696: * ! 697: * Decide if it's time to send the current line up to the user ! 698: * process. ! 699: */ ! 700: ! 701: static void ! 702: setlineend() ! 703: { ! 704: if (nextin == nextout) { ! 705: return; ! 706: } ! 707: if (characteratatime()) { ! 708: lineend = 1; ! 709: } else if (nextin >= (linein+sizeof linein)) { ! 710: lineend = 1; ! 711: } else { ! 712: int c = *(nextin-1); ! 713: if ((c == termIntChar) ! 714: || (c == termQuitChar) ! 715: || (c == termEofChar)) { ! 716: lineend = 1; ! 717: } else if (c == termFlushChar) { ! 718: lineend = 1; ! 719: } else if ((c == '\n') || (c == '\r')) { ! 720: lineend = 1; ! 721: } ! 722: } ! 723: /* Otherwise, leave it alone (reset by 'consumechar') */ ! 724: } ! 725: ! 726: /* ! 727: * OK, what we do here is: ! 728: * ! 729: * o If we are echoing, then ! 730: * o Look for character erase, line kill characters ! 731: * o Echo the character (using '^' if a control character) ! 732: * o Put the character in the input buffer ! 733: * o Set 'lineend' as necessary ! 734: */ ! 735: ! 736: static void ! 737: DoNextChar(c) ! 738: int c; /* Character to process */ ! 739: { ! 740: static char literalnextcharacter = 0; ! 741: ! 742: if (nextin >= (linein+sizeof linein)) { ! 743: putchar('\7'); /* Ring bell */ ! 744: setlineend(); ! 745: return; ! 746: } ! 747: if (MODE_LOCAL_CHARS(globalmode)) { ! 748: /* Look for some special character */ ! 749: if (!literalnextcharacter) { ! 750: if (c == termEraseChar) { ! 751: killone(); ! 752: setlineend(); ! 753: return; ! 754: } else if (c == termKillChar) { ! 755: while (nextin != linein) { ! 756: killone(); ! 757: } ! 758: setlineend(); ! 759: return; ! 760: } else if (c == termLiteralNextChar) { ! 761: literalnextcharacter = 1; ! 762: return; ! 763: } ! 764: } ! 765: ! 766: if (MODE_LOCAL_ECHO(globalmode)) { ! 767: if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) { ! 768: putchar('\r'); ! 769: putchar('\n'); ! 770: c = '\n'; ! 771: } else if (!isprint(c) && !isspace(c)) { ! 772: putchar('^'); ! 773: putchar(c^0x40); ! 774: } else { ! 775: putchar(c); ! 776: } ! 777: } ! 778: literalnextcharacter = 0; ! 779: } ! 780: *nextin++ = c; ! 781: setlineend(); ! 782: } ! 783: ! 784: static int ! 785: inputExists() ! 786: { ! 787: int input; ! 788: static state = 0; ! 789: ! 790: while (ctrlCCount) { ! 791: DoNextChar(0x03); ! 792: ctrlCCount--; ! 793: } ! 794: if (lineend) { ! 795: return 1; ! 796: } ! 797: #if 1 /* For BIOS variety of calls */ ! 798: if (kbhit() == 0) { ! 799: return lineend; ! 800: } ! 801: input = getch(); /* MSC - get console character */ ! 802: if ((input&0xff) == 0) { ! 803: DoNextChar(0x01); /* ^A */ ! 804: } else { ! 805: DoNextChar(input&0xff); ! 806: } ! 807: #else /* 0 */ ! 808: if ((input = dirconio()) == -1) { ! 809: return lineend; ! 810: } ! 811: if ((input&0xff) == 0) { ! 812: if ((input&0xff00) == 0x0300) { /* Null */ ! 813: DoNextChar(0); ! 814: } else { ! 815: DoNextChar(0x01); ! 816: if (input&0x8000) { ! 817: DoNextChar(0x01); ! 818: DoNextChar((input>>8)&0x7f); ! 819: } else { ! 820: DoNextChar((input>>8)&0xff); ! 821: } ! 822: } ! 823: } else { ! 824: DoNextChar(input&0xff); ! 825: } ! 826: #endif /* 0 */ ! 827: return lineend; ! 828: } ! 829: ! 830: ! 831: void ! 832: CtrlCInterrupt() ! 833: { ! 834: if (!MODE_COMMAND_LINE(globalmode)) { ! 835: char far *Bios_Break = (char far *) (((long)0x40<<16)|0x71); ! 836: ! 837: *Bios_Break = 0; ! 838: ctrlCCount++; /* XXX */ ! 839: signal(SIGINT, CtrlCInterrupt); ! 840: } else { ! 841: closeallsockets(); ! 842: exit(1); ! 843: } ! 844: } ! 845: ! 846: int ! 847: dosbinary(fd, onoff) ! 848: int fd; ! 849: int onoff; ! 850: { ! 851: union REGS regs; ! 852: int oldstate; ! 853: ! 854: /* Get old stuff */ ! 855: regs.h.ah = 0x44; ! 856: regs.h.al = 0; ! 857: regs.x.bx = fd; ! 858: intdos(®s, ®s); ! 859: oldstate = regs.h.dl&(1<<5); /* Save state */ ! 860: ! 861: /* Set correct bits in new mode */ ! 862: regs.h.dh = 0; ! 863: if (onoff) { ! 864: regs.h.dl |= 1<<5; ! 865: } else { ! 866: regs.h.dl &= ~(1<<5); ! 867: } ! 868: ! 869: /* Set in new mode */ ! 870: regs.h.ah = 0x44; ! 871: regs.h.al = 1; ! 872: regs.x.bx = fd; ! 873: intdos(®s, ®s); ! 874: ! 875: return oldstate; ! 876: } ! 877: ! 878: /* ! 879: * The MSDOS routines, called from elsewhere. ! 880: */ ! 881: ! 882: ! 883: static int ! 884: TerminalAutoFlush() /* MSDOS */ ! 885: { ! 886: return 1; ! 887: } ! 888: ! 889: static int ! 890: TerminalCanRead() ! 891: { ! 892: return inputExists(); ! 893: } ! 894: ! 895: ! 896: /* ! 897: * Flush output to the terminal ! 898: */ ! 899: ! 900: static void ! 901: TerminalFlushOutput() /* MSDOS */ ! 902: { ! 903: } ! 904: ! 905: ! 906: static void ! 907: TerminalNewMode(f) /* MSDOS */ ! 908: register int f; ! 909: { ! 910: union REGS inregs; ! 911: struct SREGS segregs; ! 912: static old_1b_offset = 0, old_1b_segment = 0; ! 913: ! 914: globalmode = f; ! 915: if (MODE_COMMAND_LINE(f)) { ! 916: signal(SIGINT, SIG_DFL); ! 917: if (old_1b_segment|old_1b_offset) { ! 918: inregs.h.ah = 0x25; ! 919: inregs.h.al = 0x1b; ! 920: inregs.x.dx = old_1b_offset; ! 921: segregs.ds = old_1b_segment; ! 922: intdosx(&inregs, &inregs, &segregs); ! 923: old_1b_segment = old_1b_offset = 0; ! 924: } ! 925: if (setmode(fileno(stdout), O_TEXT) == -1) { ! 926: ExitPerror("setmode (text)", 1); ! 927: } ! 928: (void) dosbinary(fileno(stdout), 0); ! 929: if (setmode(fileno(stdin), O_TEXT) == -1) { ! 930: ExitPerror("setmode (text)", 1); ! 931: } ! 932: (void) dosbinary(fileno(stdin), 0); ! 933: } else { ! 934: signal(SIGINT, CtrlCInterrupt); ! 935: if ((old_1b_segment|old_1b_offset) == 0) { ! 936: extern void iret_subr(); ! 937: void (far *foo_subr)() = iret_subr; ! 938: ! 939: inregs.h.ah = 0x35; ! 940: inregs.h.al = 0x1b; ! 941: intdosx(&inregs, &inregs, &segregs); ! 942: old_1b_segment = segregs.es; ! 943: old_1b_offset = inregs.x.bx; ! 944: inregs.h.ah = 0x25; ! 945: inregs.h.al = 0x1b; ! 946: inregs.x.dx = FP_OFF(foo_subr); ! 947: segregs.ds = FP_SEG(foo_subr); ! 948: intdosx(&inregs, &inregs, &segregs); ! 949: } ! 950: if (MODE_LOCAL_CHARS(f)) { ! 951: if (setmode(fileno(stdout), O_TEXT) == -1) { ! 952: ExitPerror("setmode (text)", 1); ! 953: } ! 954: (void) dosbinary(fileno(stdout), 0); ! 955: if (setmode(fileno(stdin), O_TEXT) == -1) { ! 956: ExitPerror("setmode (text)", 1); ! 957: } ! 958: (void) dosbinary(fileno(stdin), 0); ! 959: } else { ! 960: if (setmode(fileno(stdout), O_BINARY) == -1) { ! 961: ExitPerror("setmode (binary)", 1); ! 962: } ! 963: (void) dosbinary(fileno(stdout), 1); ! 964: if (setmode(fileno(stdin), O_BINARY) == -1) { ! 965: ExitPerror("setmode (binary)", 1); ! 966: } ! 967: (void) dosbinary(fileno(stdin), 1); ! 968: } ! 969: } ! 970: } ! 971: ! 972: ! 973: int ! 974: TerminalRead(fd, buffer, count) ! 975: int fd; ! 976: char *buffer; ! 977: int count; ! 978: { ! 979: int done = 0; ! 980: ! 981: for (;;) { ! 982: while (inputExists() && (done < count)) { ! 983: *buffer++ = *nextout; ! 984: consumechar(); ! 985: done++; ! 986: } ! 987: if (done) { ! 988: return(done); ! 989: } else { ! 990: return 0; ! 991: } ! 992: } ! 993: } ! 994: ! 995: ! 996: static void ! 997: TerminalSaveState() /* MSDOS */ ! 998: { ! 999: savedInState = dosbinary(fileno(stdin), 0); ! 1000: savedOutState = dosbinary(fileno(stdout), 0); ! 1001: } ! 1002: ! 1003: int ! 1004: TerminalSpecialChars(c) /* MSDOS */ ! 1005: { ! 1006: return 1; ! 1007: } ! 1008: ! 1009: ! 1010: static void ! 1011: TerminalRestoreState() /* MSDOS */ ! 1012: { ! 1013: (void) dosbinary(fileno(stdin), savedInState); ! 1014: (void) dosbinary(fileno(stdout), savedOutState); ! 1015: } ! 1016: ! 1017: ! 1018: static int ! 1019: TerminalWrite(fd, buffer, count) /* MSDOS */ ! 1020: int fd; ! 1021: char *buffer; ! 1022: int count; ! 1023: { ! 1024: return fwrite(buffer, sizeof (char), count, stdout); ! 1025: } ! 1026: ! 1027: ! 1028: static int ! 1029: NetClose(fd) ! 1030: { ! 1031: return closesocket(fd); ! 1032: } ! 1033: ! 1034: static void ! 1035: NetNonblockingIO(fd, onoff) /* MSDOS */ ! 1036: int ! 1037: fd, ! 1038: onoff; ! 1039: { ! 1040: if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { ! 1041: perror("setsockop (SO_NONBLOCKING) "); ! 1042: ExitString(stderr, "exiting\n", 1); ! 1043: } ! 1044: } ! 1045: ! 1046: static void ! 1047: NetSigIO(fd) /* MSDOS */ ! 1048: int fd; ! 1049: { ! 1050: } ! 1051: ! 1052: static void ! 1053: NetSetPgrp(fd) /* MSDOS */ ! 1054: int fd; ! 1055: { ! 1056: } ! 1057: ! 1058: ! 1059: #endif /* defined(MSDOS) */ ! 1060: ! 1061: /* ! 1062: * Initialize variables. ! 1063: */ ! 1064: ! 1065: static void ! 1066: tninit() ! 1067: { ! 1068: #if defined(TN3270) ! 1069: Sent3270TerminalType = 0; ! 1070: Ifrontp = Ibackp = Ibuf; ! 1071: #endif /* defined(TN3270) */ ! 1072: ! 1073: tfrontp = tbackp = ttyobuf; ! 1074: nfrontp = nbackp = netobuf; ! 1075: ! 1076: /* Don't change telnetport */ ! 1077: SB_CLEAR(); ! 1078: ClearArray(hisopts); ! 1079: ClearArray(myopts); ! 1080: sbp = sibuf; ! 1081: tbp = tibuf; ! 1082: ! 1083: connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0; ! 1084: telnetport = 0; ! 1085: #if defined(unix) ! 1086: HaveInput = 0; ! 1087: #endif /* defined(unix) */ ! 1088: ! 1089: SYNCHing = 0; ! 1090: ! 1091: errno = 0; ! 1092: ! 1093: flushline = 0; ! 1094: ! 1095: /* Don't change NetTrace */ ! 1096: ! 1097: escape = CONTROL(']'); ! 1098: echoc = CONTROL('E'); ! 1099: ! 1100: flushline = 1; ! 1101: sp = getservbyname("telnet", "tcp"); ! 1102: if (sp == 0) { ! 1103: ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); ! 1104: /*NOTREACHED*/ ! 1105: } ! 1106: ! 1107: #if defined(TN3270) ! 1108: init_ctlr(); /* Initialize some things */ ! 1109: init_keyboard(); ! 1110: init_screen(); ! 1111: init_system(); ! 1112: #endif /* defined(TN3270) */ ! 1113: } ! 1114: ! 1115: /* ! 1116: * Various utility routines. ! 1117: */ ! 1118: ! 1119: static void ! 1120: makeargv() ! 1121: { ! 1122: register char *cp; ! 1123: register char **argp = margv; ! 1124: ! 1125: margc = 0; ! 1126: cp = line; ! 1127: if (*cp == '!') { /* Special case shell escape */ ! 1128: *argp++ = "!"; /* No room in string to get this */ ! 1129: margc++; ! 1130: cp++; ! 1131: } ! 1132: while (*cp) { ! 1133: while (isspace(*cp)) ! 1134: cp++; ! 1135: if (*cp == '\0') ! 1136: break; ! 1137: *argp++ = cp; ! 1138: margc += 1; ! 1139: while (*cp != '\0' && !isspace(*cp)) ! 1140: cp++; ! 1141: if (*cp == '\0') ! 1142: break; ! 1143: *cp++ = '\0'; ! 1144: } ! 1145: *argp++ = 0; ! 1146: } ! 1147: ! 1148: static char *ambiguous; /* special return value */ ! 1149: #define Ambiguous(t) ((t)&ambiguous) ! 1150: ! 1151: ! 1152: static char ** ! 1153: genget(name, table, next) ! 1154: char *name; /* name to match */ ! 1155: char **table; /* name entry in table */ ! 1156: char **(*next)(); /* routine to return next entry in table */ ! 1157: { ! 1158: register char *p, *q; ! 1159: register char **c, **found; ! 1160: register int nmatches, longest; ! 1161: ! 1162: if (name == 0) { ! 1163: return 0; ! 1164: } ! 1165: longest = 0; ! 1166: nmatches = 0; ! 1167: found = 0; ! 1168: for (c = table; (p = *c) != 0; c = (*next)(c)) { ! 1169: for (q = name; ! 1170: (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) ! 1171: if (*q == 0) /* exact match? */ ! 1172: return (c); ! 1173: if (!*q) { /* the name was a prefix */ ! 1174: if (q - name > longest) { ! 1175: longest = q - name; ! 1176: nmatches = 1; ! 1177: found = c; ! 1178: } else if (q - name == longest) ! 1179: nmatches++; ! 1180: } ! 1181: } ! 1182: if (nmatches > 1) ! 1183: return Ambiguous(char **); ! 1184: return (found); ! 1185: } ! 1186: ! 1187: /* ! 1188: * Make a character string into a number. ! 1189: * ! 1190: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). ! 1191: */ ! 1192: ! 1193: static ! 1194: special(s) ! 1195: register char *s; ! 1196: { ! 1197: register char c; ! 1198: char b; ! 1199: ! 1200: switch (*s) { ! 1201: case '^': ! 1202: b = *++s; ! 1203: if (b == '?') { ! 1204: c = b | 0x40; /* DEL */ ! 1205: } else { ! 1206: c = b & 0x1f; ! 1207: } ! 1208: break; ! 1209: default: ! 1210: c = *s; ! 1211: break; ! 1212: } ! 1213: return c; ! 1214: } ! 1215: ! 1216: /* ! 1217: * Construct a control character sequence ! 1218: * for a special character. ! 1219: */ ! 1220: static char * ! 1221: control(c) ! 1222: register int c; ! 1223: { ! 1224: static char buf[3]; ! 1225: ! 1226: if (c == 0x7f) ! 1227: return ("^?"); ! 1228: if (c == '\377') { ! 1229: return "off"; ! 1230: } ! 1231: if (c >= 0x20) { ! 1232: buf[0] = c; ! 1233: buf[1] = 0; ! 1234: } else { ! 1235: buf[0] = '^'; ! 1236: buf[1] = '@'+c; ! 1237: buf[2] = 0; ! 1238: } ! 1239: return (buf); ! 1240: } ! 1241: ! 1242: ! 1243: /* ! 1244: * upcase() ! 1245: * ! 1246: * Upcase (in place) the argument. ! 1247: */ ! 1248: ! 1249: static void ! 1250: upcase(argument) ! 1251: register char *argument; ! 1252: { ! 1253: register int c; ! 1254: ! 1255: while ((c = *argument) != 0) { ! 1256: if (islower(c)) { ! 1257: *argument = toupper(c); ! 1258: } ! 1259: argument++; ! 1260: } ! 1261: } ! 1262: ! 1263: /* ! 1264: * SetSockOpt() ! 1265: * ! 1266: * Compensate for differences in 4.2 and 4.3 systems. ! 1267: */ ! 1268: ! 1269: static int ! 1270: SetSockOpt(fd, level, option, yesno) ! 1271: int ! 1272: fd, ! 1273: level, ! 1274: option, ! 1275: yesno; ! 1276: { ! 1277: #ifndef NOT43 ! 1278: return setsockopt(fd, level, option, ! 1279: (char *)&yesno, sizeof yesno); ! 1280: #else /* NOT43 */ ! 1281: if (yesno == 0) { /* Can't do that in 4.2! */ ! 1282: fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", ! 1283: option); ! 1284: return -1; ! 1285: } ! 1286: return setsockopt(fd, level, option, 0, 0); ! 1287: #endif /* NOT43 */ ! 1288: } ! 1289: ! 1290: /* ! 1291: * The following are routines used to print out debugging information. ! 1292: */ ! 1293: ! 1294: ! 1295: static void ! 1296: Dump(direction, buffer, length) ! 1297: char direction; ! 1298: char *buffer; ! 1299: int length; ! 1300: { ! 1301: # define BYTES_PER_LINE 32 ! 1302: # define min(x,y) ((x<y)? x:y) ! 1303: char *pThis; ! 1304: int offset; ! 1305: ! 1306: offset = 0; ! 1307: ! 1308: while (length) { ! 1309: /* print one line */ ! 1310: fprintf(NetTrace, "%c 0x%x\t", direction, offset); ! 1311: pThis = buffer; ! 1312: buffer = buffer+min(length, BYTES_PER_LINE); ! 1313: while (pThis < buffer) { ! 1314: fprintf(NetTrace, "%.2x", (*pThis)&0xff); ! 1315: pThis++; ! 1316: } ! 1317: fprintf(NetTrace, "\n"); ! 1318: length -= BYTES_PER_LINE; ! 1319: offset += BYTES_PER_LINE; ! 1320: if (length < 0) { ! 1321: return; ! 1322: } ! 1323: /* find next unique line */ ! 1324: } ! 1325: } ! 1326: ! 1327: ! 1328: /*VARARGS*/ ! 1329: static void ! 1330: printoption(direction, fmt, option, what) ! 1331: char *direction, *fmt; ! 1332: int option, what; ! 1333: { ! 1334: if (!showoptions) ! 1335: return; ! 1336: fprintf(NetTrace, "%s ", direction+1); ! 1337: if (fmt == doopt) ! 1338: fmt = "do"; ! 1339: else if (fmt == dont) ! 1340: fmt = "dont"; ! 1341: else if (fmt == will) ! 1342: fmt = "will"; ! 1343: else if (fmt == wont) ! 1344: fmt = "wont"; ! 1345: else ! 1346: fmt = "???"; ! 1347: if (option < (sizeof telopts/sizeof telopts[0])) ! 1348: fprintf(NetTrace, "%s %s", fmt, telopts[option]); ! 1349: else ! 1350: fprintf(NetTrace, "%s %d", fmt, option); ! 1351: if (*direction == '<') { ! 1352: fprintf(NetTrace, "\r\n"); ! 1353: return; ! 1354: } ! 1355: fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); ! 1356: } ! 1357: ! 1358: static void ! 1359: printsub(direction, pointer, length) ! 1360: char *direction, /* "<" or ">" */ ! 1361: *pointer; /* where suboption data sits */ ! 1362: int length; /* length of suboption data */ ! 1363: { ! 1364: if (showoptions) { ! 1365: fprintf(NetTrace, "%s suboption ", ! 1366: (direction[0] == '<')? "Received":"Sent"); ! 1367: switch (pointer[0]) { ! 1368: case TELOPT_TTYPE: ! 1369: fprintf(NetTrace, "Terminal type "); ! 1370: switch (pointer[1]) { ! 1371: case TELQUAL_IS: ! 1372: { ! 1373: char tmpbuf[sizeof subbuffer]; ! 1374: int minlen = min(length-4, sizeof tmpbuf-1); ! 1375: ! 1376: memcpy(tmpbuf, pointer+2, minlen); ! 1377: tmpbuf[minlen] = 0; ! 1378: fprintf(NetTrace, "is %s.\n", tmpbuf); ! 1379: } ! 1380: break; ! 1381: case TELQUAL_SEND: ! 1382: fprintf(NetTrace, "- request to send.\n"); ! 1383: break; ! 1384: default: ! 1385: fprintf(NetTrace, ! 1386: "- unknown qualifier %d (0x%x).\n", pointer[1]); ! 1387: } ! 1388: break; ! 1389: default: ! 1390: fprintf(NetTrace, "Unknown option %d (0x%x)\n", ! 1391: pointer[0], pointer[0]); ! 1392: } ! 1393: } ! 1394: } ! 1395: ! 1396: /* ! 1397: * Check to see if any out-of-band data exists on a socket (for ! 1398: * Telnet "synch" processing). ! 1399: */ ! 1400: ! 1401: static int ! 1402: stilloob(s) ! 1403: int s; /* socket number */ ! 1404: { ! 1405: static struct timeval timeout = { 0 }; ! 1406: fd_set excepts; ! 1407: int value; ! 1408: ! 1409: do { ! 1410: FD_ZERO(&excepts); ! 1411: FD_SET(s, &excepts); ! 1412: value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); ! 1413: } while ((value == -1) && (errno == EINTR)); ! 1414: ! 1415: if (value < 0) { ! 1416: perror("select"); ! 1417: quit(); ! 1418: } ! 1419: if (FD_ISSET(s, &excepts)) { ! 1420: return 1; ! 1421: } else { ! 1422: return 0; ! 1423: } ! 1424: } ! 1425: ! 1426: ! 1427: /* ! 1428: * netflush ! 1429: * Send as much data as possible to the network, ! 1430: * handling requests for urgent data. ! 1431: * ! 1432: * The return value indicates whether we did any ! 1433: * useful work. ! 1434: */ ! 1435: ! 1436: ! 1437: int ! 1438: netflush() ! 1439: { ! 1440: int n; ! 1441: ! 1442: if ((n = nfrontp - nbackp) > 0) { ! 1443: if (!neturg) { ! 1444: n = send(net, nbackp, n, 0); /* normal write */ ! 1445: } else { ! 1446: n = neturg - nbackp; ! 1447: /* ! 1448: * In 4.2 (and 4.3) systems, there is some question about ! 1449: * what byte in a sendOOB operation is the "OOB" data. ! 1450: * To make ourselves compatible, we only send ONE byte ! 1451: * out of band, the one WE THINK should be OOB (though ! 1452: * we really have more the TCP philosophy of urgent data ! 1453: * rather than the Unix philosophy of OOB data). ! 1454: */ ! 1455: if (n > 1) { ! 1456: n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ ! 1457: } else { ! 1458: n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ ! 1459: } ! 1460: } ! 1461: } ! 1462: if (n < 0) { ! 1463: if (errno != ENOBUFS && errno != EWOULDBLOCK) { ! 1464: setcommandmode(); ! 1465: perror(hostname); ! 1466: NetClose(net); ! 1467: neturg = 0; ! 1468: longjmp(peerdied, -1); ! 1469: /*NOTREACHED*/ ! 1470: } ! 1471: n = 0; ! 1472: } ! 1473: if (netdata && n) { ! 1474: Dump('>', nbackp, n); ! 1475: } ! 1476: nbackp += n; ! 1477: if (nbackp >= neturg) { ! 1478: neturg = 0; ! 1479: } ! 1480: if (nbackp == nfrontp) { ! 1481: nbackp = nfrontp = netobuf; ! 1482: } ! 1483: return n > 0; ! 1484: } ! 1485: ! 1486: /* ! 1487: * nextitem() ! 1488: * ! 1489: * Return the address of the next "item" in the TELNET data ! 1490: * stream. This will be the address of the next character if ! 1491: * the current address is a user data character, or it will ! 1492: * be the address of the character following the TELNET command ! 1493: * if the current address is a TELNET IAC ("I Am a Command") ! 1494: * character. ! 1495: */ ! 1496: ! 1497: static char * ! 1498: nextitem(current) ! 1499: char *current; ! 1500: { ! 1501: if ((*current&0xff) != IAC) { ! 1502: return current+1; ! 1503: } ! 1504: switch (*(current+1)&0xff) { ! 1505: case DO: ! 1506: case DONT: ! 1507: case WILL: ! 1508: case WONT: ! 1509: return current+3; ! 1510: case SB: /* loop forever looking for the SE */ ! 1511: { ! 1512: register char *look = current+2; ! 1513: ! 1514: for (;;) { ! 1515: if ((*look++&0xff) == IAC) { ! 1516: if ((*look++&0xff) == SE) { ! 1517: return look; ! 1518: } ! 1519: } ! 1520: } ! 1521: } ! 1522: default: ! 1523: return current+2; ! 1524: } ! 1525: } ! 1526: /* ! 1527: * netclear() ! 1528: * ! 1529: * We are about to do a TELNET SYNCH operation. Clear ! 1530: * the path to the network. ! 1531: * ! 1532: * Things are a bit tricky since we may have sent the first ! 1533: * byte or so of a previous TELNET command into the network. ! 1534: * So, we have to scan the network buffer from the beginning ! 1535: * until we are up to where we want to be. ! 1536: * ! 1537: * A side effect of what we do, just to keep things ! 1538: * simple, is to clear the urgent data pointer. The principal ! 1539: * caller should be setting the urgent data pointer AFTER calling ! 1540: * us in any case. ! 1541: */ ! 1542: ! 1543: static void ! 1544: netclear() ! 1545: { ! 1546: register char *thisitem, *next; ! 1547: char *good; ! 1548: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ! 1549: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) ! 1550: ! 1551: thisitem = netobuf; ! 1552: ! 1553: while ((next = nextitem(thisitem)) <= nbackp) { ! 1554: thisitem = next; ! 1555: } ! 1556: ! 1557: /* Now, thisitem is first before/at boundary. */ ! 1558: ! 1559: good = netobuf; /* where the good bytes go */ ! 1560: ! 1561: while (nfrontp > thisitem) { ! 1562: if (wewant(thisitem)) { ! 1563: int length; ! 1564: ! 1565: next = thisitem; ! 1566: do { ! 1567: next = nextitem(next); ! 1568: } while (wewant(next) && (nfrontp > next)); ! 1569: length = next-thisitem; ! 1570: memcpy(good, thisitem, length); ! 1571: good += length; ! 1572: thisitem = next; ! 1573: } else { ! 1574: thisitem = nextitem(thisitem); ! 1575: } ! 1576: } ! 1577: ! 1578: nbackp = netobuf; ! 1579: nfrontp = good; /* next byte to be sent */ ! 1580: neturg = 0; ! 1581: } ! 1582: ! 1583: /* ! 1584: * These routines add various telnet commands to the data stream. ! 1585: */ ! 1586: ! 1587: #if defined(NOT43) ! 1588: static int ! 1589: #else /* defined(NOT43) */ ! 1590: static void ! 1591: #endif /* defined(NOT43) */ ! 1592: dosynch() ! 1593: { ! 1594: netclear(); /* clear the path to the network */ ! 1595: NET2ADD(IAC, DM); ! 1596: neturg = NETLOC()-1; /* Some systems are off by one XXX */ ! 1597: ! 1598: #if defined(NOT43) ! 1599: return 0; ! 1600: #endif /* defined(NOT43) */ ! 1601: } ! 1602: ! 1603: static void ! 1604: doflush() ! 1605: { ! 1606: NET2ADD(IAC, DO); ! 1607: NETADD(TELOPT_TM); ! 1608: flushline = 1; ! 1609: flushout = 1; ! 1610: ttyflush(); ! 1611: /* do printoption AFTER flush, otherwise the output gets tossed... */ ! 1612: printoption("<SENT", doopt, TELOPT_TM, 0); ! 1613: } ! 1614: ! 1615: static void ! 1616: intp() ! 1617: { ! 1618: NET2ADD(IAC, IP); ! 1619: if (autoflush) { ! 1620: doflush(); ! 1621: } ! 1622: if (autosynch) { ! 1623: dosynch(); ! 1624: } ! 1625: } ! 1626: ! 1627: static void ! 1628: sendbrk() ! 1629: { ! 1630: NET2ADD(IAC, BREAK); ! 1631: if (autoflush) { ! 1632: doflush(); ! 1633: } ! 1634: if (autosynch) { ! 1635: dosynch(); ! 1636: } ! 1637: } ! 1638: ! 1639: /* ! 1640: * Send as much data as possible to the terminal. ! 1641: * ! 1642: * The return value indicates whether we did any ! 1643: * useful work. ! 1644: */ ! 1645: ! 1646: ! 1647: static int ! 1648: ttyflush() ! 1649: { ! 1650: int n; ! 1651: ! 1652: if ((n = tfrontp - tbackp) > 0) { ! 1653: if (!(SYNCHing||flushout)) { ! 1654: n = TerminalWrite(tout, tbackp, n); ! 1655: } else { ! 1656: TerminalFlushOutput(); ! 1657: /* we leave 'n' alone! */ ! 1658: } ! 1659: } ! 1660: if (n >= 0) { ! 1661: tbackp += n; ! 1662: if (tbackp == tfrontp) { ! 1663: tbackp = tfrontp = ttyobuf; ! 1664: } ! 1665: } ! 1666: return n > 0; ! 1667: } ! 1668: ! 1669: #if defined(TN3270) ! 1670: ! 1671: #if defined(unix) ! 1672: static void ! 1673: inputAvailable() ! 1674: { ! 1675: HaveInput = 1; ! 1676: } ! 1677: #endif /* defined(unix) */ ! 1678: ! 1679: void ! 1680: outputPurge() ! 1681: { ! 1682: int tmp = flushout; ! 1683: ! 1684: flushout = 1; ! 1685: ! 1686: ttyflush(); ! 1687: ! 1688: flushout = tmp; ! 1689: } ! 1690: ! 1691: #endif /* defined(TN3270) */ ! 1692: ! 1693: #if defined(unix) ! 1694: /* ! 1695: * Various signal handling routines. ! 1696: */ ! 1697: ! 1698: static void ! 1699: deadpeer() ! 1700: { ! 1701: setcommandmode(); ! 1702: longjmp(peerdied, -1); ! 1703: } ! 1704: ! 1705: static void ! 1706: intr() ! 1707: { ! 1708: if (localchars) { ! 1709: intp(); ! 1710: return; ! 1711: } ! 1712: setcommandmode(); ! 1713: longjmp(toplevel, -1); ! 1714: } ! 1715: ! 1716: static void ! 1717: intr2() ! 1718: { ! 1719: if (localchars) { ! 1720: sendbrk(); ! 1721: return; ! 1722: } ! 1723: } ! 1724: ! 1725: static void ! 1726: doescape() ! 1727: { ! 1728: command(0); ! 1729: } ! 1730: #endif /* defined(unix) */ ! 1731: ! 1732: /* ! 1733: * These routines decides on what the mode should be (based on the values ! 1734: * of various global variables). ! 1735: */ ! 1736: ! 1737: ! 1738: static ! 1739: getconnmode() ! 1740: { ! 1741: static char newmode[16] = ! 1742: { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; ! 1743: int modeindex = 0; ! 1744: ! 1745: if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { ! 1746: modeindex += 1; ! 1747: } ! 1748: if (hisopts[TELOPT_ECHO]) { ! 1749: modeindex += 2; ! 1750: } ! 1751: if (hisopts[TELOPT_SGA]) { ! 1752: modeindex += 4; ! 1753: } ! 1754: if (In3270) { ! 1755: modeindex += 8; ! 1756: } ! 1757: return newmode[modeindex]; ! 1758: } ! 1759: ! 1760: void ! 1761: setconnmode() ! 1762: { ! 1763: TerminalNewMode(getconnmode()); ! 1764: } ! 1765: ! 1766: ! 1767: void ! 1768: setcommandmode() ! 1769: { ! 1770: TerminalNewMode(0); ! 1771: } ! 1772: ! 1773: static void ! 1774: willoption(option, reply) ! 1775: int option, reply; ! 1776: { ! 1777: char *fmt; ! 1778: ! 1779: switch (option) { ! 1780: ! 1781: case TELOPT_ECHO: ! 1782: # if defined(TN3270) ! 1783: /* ! 1784: * The following is a pain in the rear-end. ! 1785: * Various IBM servers (some versions of Wiscnet, ! 1786: * possibly Fibronics/Spartacus, and who knows who ! 1787: * else) will NOT allow us to send "DO SGA" too early ! 1788: * in the setup proceedings. On the other hand, ! 1789: * 4.2 servers (telnetd) won't set SGA correctly. ! 1790: * So, we are stuck. Empirically (but, based on ! 1791: * a VERY small sample), the IBM servers don't send ! 1792: * out anything about ECHO, so we postpone our sending ! 1793: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers ! 1794: * DO send). ! 1795: */ ! 1796: { ! 1797: if (askedSGA == 0) { ! 1798: askedSGA = 1; ! 1799: if (!hisopts[TELOPT_SGA]) { ! 1800: willoption(TELOPT_SGA, 0); ! 1801: } ! 1802: } ! 1803: } ! 1804: /* Fall through */ ! 1805: case TELOPT_EOR: ! 1806: case TELOPT_BINARY: ! 1807: #endif /* defined(TN3270) */ ! 1808: case TELOPT_SGA: ! 1809: settimer(modenegotiated); ! 1810: hisopts[option] = 1; ! 1811: fmt = doopt; ! 1812: setconnmode(); /* possibly set new tty mode */ ! 1813: break; ! 1814: ! 1815: case TELOPT_TM: ! 1816: return; /* Never reply to TM will's/wont's */ ! 1817: ! 1818: default: ! 1819: fmt = dont; ! 1820: break; ! 1821: } ! 1822: sprintf(nfrontp, fmt, option); ! 1823: nfrontp += sizeof (dont) - 2; ! 1824: if (reply) ! 1825: printoption(">SENT", fmt, option, reply); ! 1826: else ! 1827: printoption("<SENT", fmt, option, reply); ! 1828: } ! 1829: ! 1830: static void ! 1831: wontoption(option, reply) ! 1832: int option, reply; ! 1833: { ! 1834: char *fmt; ! 1835: ! 1836: switch (option) { ! 1837: ! 1838: case TELOPT_ECHO: ! 1839: case TELOPT_SGA: ! 1840: settimer(modenegotiated); ! 1841: hisopts[option] = 0; ! 1842: fmt = dont; ! 1843: setconnmode(); /* Set new tty mode */ ! 1844: break; ! 1845: ! 1846: case TELOPT_TM: ! 1847: return; /* Never reply to TM will's/wont's */ ! 1848: ! 1849: default: ! 1850: fmt = dont; ! 1851: hisopts[option] = 0; ! 1852: break; ! 1853: } ! 1854: sprintf(nfrontp, fmt, option); ! 1855: nfrontp += sizeof (doopt) - 2; ! 1856: if (reply) ! 1857: printoption(">SENT", fmt, option, reply); ! 1858: else ! 1859: printoption("<SENT", fmt, option, reply); ! 1860: } ! 1861: ! 1862: static void ! 1863: dooption(option) ! 1864: int option; ! 1865: { ! 1866: char *fmt; ! 1867: ! 1868: switch (option) { ! 1869: ! 1870: case TELOPT_TM: ! 1871: fmt = will; ! 1872: break; ! 1873: ! 1874: # if defined(TN3270) ! 1875: case TELOPT_EOR: ! 1876: case TELOPT_BINARY: ! 1877: # endif /* defined(TN3270) */ ! 1878: case TELOPT_TTYPE: /* terminal type option */ ! 1879: case TELOPT_SGA: /* no big deal */ ! 1880: fmt = will; ! 1881: myopts[option] = 1; ! 1882: break; ! 1883: ! 1884: case TELOPT_ECHO: /* We're never going to echo... */ ! 1885: default: ! 1886: fmt = wont; ! 1887: break; ! 1888: } ! 1889: sprintf(nfrontp, fmt, option); ! 1890: nfrontp += sizeof (doopt) - 2; ! 1891: printoption(">SENT", fmt, option, 0); ! 1892: } ! 1893: ! 1894: /* ! 1895: * suboption() ! 1896: * ! 1897: * Look at the sub-option buffer, and try to be helpful to the other ! 1898: * side. ! 1899: * ! 1900: * Currently we recognize: ! 1901: * ! 1902: * Terminal type, send request. ! 1903: */ ! 1904: ! 1905: static void ! 1906: suboption() ! 1907: { ! 1908: printsub("<", subbuffer, subend-subbuffer+1); ! 1909: switch (subbuffer[0]&0xff) { ! 1910: case TELOPT_TTYPE: ! 1911: if ((subbuffer[1]&0xff) != TELQUAL_SEND) { ! 1912: ; ! 1913: } else { ! 1914: char *name; ! 1915: char namebuf[41]; ! 1916: extern char *getenv(); ! 1917: int len; ! 1918: ! 1919: #if defined(TN3270) ! 1920: /* ! 1921: * Try to send a 3270 type terminal name. Decide which one based ! 1922: * on the format of our screen, and (in the future) color ! 1923: * capaiblities. ! 1924: */ ! 1925: #if defined(unix) ! 1926: if (initscr() != ERR) { /* Initialize curses to get line size */ ! 1927: MaxNumberLines = LINES; ! 1928: MaxNumberColumns = COLS; ! 1929: } ! 1930: #else /* defined(unix) */ ! 1931: InitTerminal(); ! 1932: #endif /* defined(unix) */ ! 1933: if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { ! 1934: Sent3270TerminalType = 1; ! 1935: if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { ! 1936: MaxNumberLines = 27; ! 1937: MaxNumberColumns = 132; ! 1938: sb_terminal[SBTERMMODEL] = '5'; ! 1939: } else if (MaxNumberLines >= 43) { ! 1940: MaxNumberLines = 43; ! 1941: MaxNumberColumns = 80; ! 1942: sb_terminal[SBTERMMODEL] = '4'; ! 1943: } else if (MaxNumberLines >= 32) { ! 1944: MaxNumberLines = 32; ! 1945: MaxNumberColumns = 80; ! 1946: sb_terminal[SBTERMMODEL] = '3'; ! 1947: } else { ! 1948: MaxNumberLines = 24; ! 1949: MaxNumberColumns = 80; ! 1950: sb_terminal[SBTERMMODEL] = '2'; ! 1951: } ! 1952: NumberLines = 24; /* before we start out... */ ! 1953: NumberColumns = 80; ! 1954: ScreenSize = NumberLines*NumberColumns; ! 1955: if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { ! 1956: ExitString(stderr, ! 1957: "Programming error: MAXSCREENSIZE too small.\n", 1); ! 1958: /*NOTREACHED*/ ! 1959: } ! 1960: memcpy(nfrontp, sb_terminal, sizeof sb_terminal); ! 1961: printsub(">", nfrontp+2, sizeof sb_terminal-2); ! 1962: nfrontp += sizeof sb_terminal; ! 1963: return; ! 1964: } ! 1965: #endif /* defined(TN3270) */ ! 1966: ! 1967: name = getenv("TERM"); ! 1968: if ((name == 0) || ((len = strlen(name)) > 40)) { ! 1969: name = "UNKNOWN"; ! 1970: } ! 1971: if ((len + 4+2) < NETROOM()) { ! 1972: strcpy(namebuf, name); ! 1973: upcase(namebuf); ! 1974: sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, ! 1975: TELQUAL_IS, namebuf, IAC, SE); ! 1976: printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); ! 1977: nfrontp += 4+strlen(namebuf)+2; ! 1978: } else { ! 1979: ExitString(stderr, "No room in buffer for terminal type.\n", ! 1980: 1); ! 1981: /*NOTREACHED*/ ! 1982: } ! 1983: } ! 1984: ! 1985: default: ! 1986: break; ! 1987: } ! 1988: } ! 1989: ! 1990: #if defined(TN3270) ! 1991: static void ! 1992: SetIn3270() ! 1993: { ! 1994: if (Sent3270TerminalType && myopts[TELOPT_BINARY] ! 1995: && hisopts[TELOPT_BINARY] && !donebinarytoggle) { ! 1996: if (!In3270) { ! 1997: In3270 = 1; ! 1998: Init3270(); /* Initialize 3270 functions */ ! 1999: /* initialize terminal key mapping */ ! 2000: InitTerminal(); /* Start terminal going */ ! 2001: LocalClearScreen(); /* Make sure the screen is clear */ ! 2002: setconnmode(); ! 2003: } ! 2004: } else { ! 2005: if (In3270) { ! 2006: StopScreen(1); ! 2007: In3270 = 0; ! 2008: Stop3270(); /* Tell 3270 we aren't here anymore */ ! 2009: setconnmode(); ! 2010: } ! 2011: } ! 2012: } ! 2013: #endif /* defined(TN3270) */ ! 2014: ! 2015: ! 2016: static void ! 2017: telrcv() ! 2018: { ! 2019: register int c; ! 2020: static int telrcv_state = TS_DATA; ! 2021: # if defined(TN3270) ! 2022: register int Scc; ! 2023: register char *Sbp; ! 2024: # endif /* defined(TN3270) */ ! 2025: ! 2026: while ((scc > 0) && (TTYROOM() > 2)) { ! 2027: c = *sbp++ & 0xff, scc--; ! 2028: switch (telrcv_state) { ! 2029: ! 2030: case TS_CR: ! 2031: telrcv_state = TS_DATA; ! 2032: if (c == '\0') { ! 2033: break; /* Ignore \0 after CR */ ! 2034: } else if (c == '\n') { ! 2035: if (hisopts[TELOPT_ECHO] && !crmod) { ! 2036: TTYADD(c); ! 2037: } ! 2038: break; ! 2039: } ! 2040: /* Else, fall through */ ! 2041: ! 2042: case TS_DATA: ! 2043: if (c == IAC) { ! 2044: telrcv_state = TS_IAC; ! 2045: continue; ! 2046: } ! 2047: # if defined(TN3270) ! 2048: if (In3270) { ! 2049: *Ifrontp++ = c; ! 2050: Sbp = sbp; ! 2051: Scc = scc; ! 2052: while (Scc > 0) { ! 2053: c = *Sbp++ & 0377, Scc--; ! 2054: if (c == IAC) { ! 2055: telrcv_state = TS_IAC; ! 2056: break; ! 2057: } ! 2058: *Ifrontp++ = c; ! 2059: } ! 2060: sbp = Sbp; ! 2061: scc = Scc; ! 2062: } else ! 2063: # endif /* defined(TN3270) */ ! 2064: /* ! 2065: * The 'crmod' hack (see following) is needed ! 2066: * since we can't * set CRMOD on output only. ! 2067: * Machines like MULTICS like to send \r without ! 2068: * \n; since we must turn off CRMOD to get proper ! 2069: * input, the mapping is done here (sigh). ! 2070: */ ! 2071: if ((c == '\r') && !hisopts[TELOPT_BINARY]) { ! 2072: if (scc > 0) { ! 2073: c = *sbp&0xff; ! 2074: if (c == 0) { ! 2075: sbp++, scc--; ! 2076: /* a "true" CR */ ! 2077: TTYADD('\r'); ! 2078: } else if (!hisopts[TELOPT_ECHO] && ! 2079: (c == '\n')) { ! 2080: sbp++, scc--; ! 2081: TTYADD('\n'); ! 2082: } else { ! 2083: TTYADD('\r'); ! 2084: if (crmod) { ! 2085: TTYADD('\n'); ! 2086: } ! 2087: } ! 2088: } else { ! 2089: telrcv_state = TS_CR; ! 2090: TTYADD('\r'); ! 2091: if (crmod) { ! 2092: TTYADD('\n'); ! 2093: } ! 2094: } ! 2095: } else { ! 2096: TTYADD(c); ! 2097: } ! 2098: continue; ! 2099: ! 2100: case TS_IAC: ! 2101: switch (c) { ! 2102: ! 2103: case WILL: ! 2104: telrcv_state = TS_WILL; ! 2105: continue; ! 2106: ! 2107: case WONT: ! 2108: telrcv_state = TS_WONT; ! 2109: continue; ! 2110: ! 2111: case DO: ! 2112: telrcv_state = TS_DO; ! 2113: continue; ! 2114: ! 2115: case DONT: ! 2116: telrcv_state = TS_DONT; ! 2117: continue; ! 2118: ! 2119: case DM: ! 2120: /* ! 2121: * We may have missed an urgent notification, ! 2122: * so make sure we flush whatever is in the ! 2123: * buffer currently. ! 2124: */ ! 2125: SYNCHing = 1; ! 2126: ttyflush(); ! 2127: SYNCHing = stilloob(net); ! 2128: settimer(gotDM); ! 2129: break; ! 2130: ! 2131: case NOP: ! 2132: case GA: ! 2133: break; ! 2134: ! 2135: case SB: ! 2136: SB_CLEAR(); ! 2137: telrcv_state = TS_SB; ! 2138: continue; ! 2139: ! 2140: # if defined(TN3270) ! 2141: case EOR: ! 2142: if (In3270) { ! 2143: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); ! 2144: if (Ibackp == Ifrontp) { ! 2145: Ibackp = Ifrontp = Ibuf; ! 2146: ISend = 0; /* should have been! */ ! 2147: } else { ! 2148: ISend = 1; ! 2149: } ! 2150: } ! 2151: break; ! 2152: # endif /* defined(TN3270) */ ! 2153: ! 2154: case IAC: ! 2155: # if !defined(TN3270) ! 2156: TTYADD(IAC); ! 2157: # else /* !defined(TN3270) */ ! 2158: if (In3270) { ! 2159: *Ifrontp++ = IAC; ! 2160: } else { ! 2161: TTYADD(IAC); ! 2162: } ! 2163: # endif /* !defined(TN3270) */ ! 2164: break; ! 2165: ! 2166: default: ! 2167: break; ! 2168: } ! 2169: telrcv_state = TS_DATA; ! 2170: continue; ! 2171: ! 2172: case TS_WILL: ! 2173: printoption(">RCVD", will, c, !hisopts[c]); ! 2174: if (c == TELOPT_TM) { ! 2175: if (flushout) { ! 2176: flushout = 0; ! 2177: } ! 2178: } else if (!hisopts[c]) { ! 2179: willoption(c, 1); ! 2180: } ! 2181: SetIn3270(); ! 2182: telrcv_state = TS_DATA; ! 2183: continue; ! 2184: ! 2185: case TS_WONT: ! 2186: printoption(">RCVD", wont, c, hisopts[c]); ! 2187: if (c == TELOPT_TM) { ! 2188: if (flushout) { ! 2189: flushout = 0; ! 2190: } ! 2191: } else if (hisopts[c]) { ! 2192: wontoption(c, 1); ! 2193: } ! 2194: SetIn3270(); ! 2195: telrcv_state = TS_DATA; ! 2196: continue; ! 2197: ! 2198: case TS_DO: ! 2199: printoption(">RCVD", doopt, c, !myopts[c]); ! 2200: if (!myopts[c]) ! 2201: dooption(c); ! 2202: SetIn3270(); ! 2203: telrcv_state = TS_DATA; ! 2204: continue; ! 2205: ! 2206: case TS_DONT: ! 2207: printoption(">RCVD", dont, c, myopts[c]); ! 2208: if (myopts[c]) { ! 2209: myopts[c] = 0; ! 2210: sprintf(nfrontp, wont, c); ! 2211: nfrontp += sizeof (wont) - 2; ! 2212: flushline = 1; ! 2213: setconnmode(); /* set new tty mode (maybe) */ ! 2214: printoption(">SENT", wont, c, 0); ! 2215: } ! 2216: SetIn3270(); ! 2217: telrcv_state = TS_DATA; ! 2218: continue; ! 2219: ! 2220: case TS_SB: ! 2221: if (c == IAC) { ! 2222: telrcv_state = TS_SE; ! 2223: } else { ! 2224: SB_ACCUM(c); ! 2225: } ! 2226: continue; ! 2227: ! 2228: case TS_SE: ! 2229: if (c != SE) { ! 2230: if (c != IAC) { ! 2231: SB_ACCUM(IAC); ! 2232: } ! 2233: SB_ACCUM(c); ! 2234: telrcv_state = TS_SB; ! 2235: } else { ! 2236: SB_TERM(); ! 2237: suboption(); /* handle sub-option */ ! 2238: SetIn3270(); ! 2239: telrcv_state = TS_DATA; ! 2240: } ! 2241: } ! 2242: } ! 2243: } ! 2244: ! 2245: #if defined(TN3270) ! 2246: ! 2247: /* ! 2248: * The following routines are places where the various tn3270 ! 2249: * routines make calls into telnet.c. ! 2250: */ ! 2251: ! 2252: /* TtyChars() - returns the number of characters in the TTY buffer */ ! 2253: TtyChars() ! 2254: { ! 2255: return(tfrontp-tbackp); ! 2256: } ! 2257: ! 2258: /* ! 2259: * DataToNetwork - queue up some data to go to network. If "done" is set, ! 2260: * then when last byte is queued, we add on an IAC EOR sequence (so, ! 2261: * don't call us with "done" until you want that done...) ! 2262: * ! 2263: * We actually do send all the data to the network buffer, since our ! 2264: * only client needs for us to do that. ! 2265: */ ! 2266: ! 2267: int ! 2268: DataToNetwork(buffer, count, done) ! 2269: register char *buffer; /* where the data is */ ! 2270: register int count; /* how much to send */ ! 2271: int done; /* is this the last of a logical block */ ! 2272: { ! 2273: register int c; ! 2274: int origCount; ! 2275: fd_set o; ! 2276: ! 2277: origCount = count; ! 2278: FD_ZERO(&o); ! 2279: ! 2280: while (count) { ! 2281: if ((netobuf+sizeof netobuf - nfrontp) < 6) { ! 2282: netflush(); ! 2283: while ((netobuf+sizeof netobuf - nfrontp) < 6) { ! 2284: FD_SET(net, &o); ! 2285: (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, ! 2286: (struct timeval *) 0); ! 2287: netflush(); ! 2288: } ! 2289: } ! 2290: c = *buffer++; ! 2291: count--; ! 2292: if (c == IAC) { ! 2293: *nfrontp++ = IAC; ! 2294: *nfrontp++ = IAC; ! 2295: } else { ! 2296: *nfrontp++ = c; ! 2297: } ! 2298: } ! 2299: ! 2300: if (done && !count) { ! 2301: *nfrontp++ = IAC; ! 2302: *nfrontp++ = EOR; ! 2303: netflush(); /* try to move along as quickly as ... */ ! 2304: } ! 2305: return(origCount - count); ! 2306: } ! 2307: ! 2308: /* DataToTerminal - queue up some data to go to terminal. */ ! 2309: ! 2310: int ! 2311: DataToTerminal(buffer, count) ! 2312: register char *buffer; /* where the data is */ ! 2313: register int count; /* how much to send */ ! 2314: { ! 2315: int origCount; ! 2316: #if defined(unix) ! 2317: fd_set o; ! 2318: ! 2319: FD_ZERO(&o); ! 2320: #endif /* defined(unix) */ ! 2321: origCount = count; ! 2322: ! 2323: while (count) { ! 2324: if (tfrontp >= ttyobuf+sizeof ttyobuf) { ! 2325: ttyflush(); ! 2326: while (tfrontp >= ttyobuf+sizeof ttyobuf) { ! 2327: #if defined(unix) ! 2328: FD_SET(tout, &o); ! 2329: (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, ! 2330: (struct timeval *) 0); ! 2331: #endif /* defined(unix) */ ! 2332: ttyflush(); ! 2333: } ! 2334: } ! 2335: *tfrontp++ = *buffer++; ! 2336: count--; ! 2337: } ! 2338: return(origCount - count); ! 2339: } ! 2340: ! 2341: /* EmptyTerminal - called to make sure that the terminal buffer is empty. ! 2342: * Note that we consider the buffer to run all the ! 2343: * way to the kernel (thus the select). ! 2344: */ ! 2345: ! 2346: void ! 2347: EmptyTerminal() ! 2348: { ! 2349: #if defined(unix) ! 2350: fd_set o; ! 2351: ! 2352: FD_ZERO(&o); ! 2353: #endif /* defined(unix) */ ! 2354: ! 2355: if (tfrontp == tbackp) { ! 2356: #if defined(unix) ! 2357: FD_SET(tout, &o); ! 2358: (void) select(tout+1, (int *) 0, &o, (int *) 0, ! 2359: (struct timeval *) 0); /* wait for TTLOWAT */ ! 2360: #endif /* defined(unix) */ ! 2361: } else { ! 2362: while (tfrontp != tbackp) { ! 2363: ttyflush(); ! 2364: #if defined(unix) ! 2365: FD_SET(tout, &o); ! 2366: (void) select(tout+1, (int *) 0, &o, (int *) 0, ! 2367: (struct timeval *) 0); /* wait for TTLOWAT */ ! 2368: #endif /* defined(unix) */ ! 2369: } ! 2370: } ! 2371: } ! 2372: ! 2373: /* ! 2374: * Push3270 - Try to send data along the 3270 output (to screen) direction. ! 2375: */ ! 2376: ! 2377: static int ! 2378: Push3270() ! 2379: { ! 2380: int save = scc; ! 2381: ! 2382: if (scc) { ! 2383: if (Ifrontp+scc > Ibuf+sizeof Ibuf) { ! 2384: if (Ibackp != Ibuf) { ! 2385: memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); ! 2386: Ifrontp -= (Ibackp-Ibuf); ! 2387: Ibackp = Ibuf; ! 2388: } ! 2389: } ! 2390: if (Ifrontp+scc < Ibuf+sizeof Ibuf) { ! 2391: telrcv(); ! 2392: } ! 2393: } ! 2394: return save != scc; ! 2395: } ! 2396: ! 2397: ! 2398: /* ! 2399: * Finish3270 - get the last dregs of 3270 data out to the terminal ! 2400: * before quitting. ! 2401: */ ! 2402: ! 2403: static void ! 2404: Finish3270() ! 2405: { ! 2406: while (Push3270() || !DoTerminalOutput()) { ! 2407: #if defined(unix) ! 2408: HaveInput = 0; ! 2409: #endif /* defined(unix) */ ! 2410: ; ! 2411: } ! 2412: } ! 2413: ! 2414: ! 2415: ! 2416: /* StringToTerminal - output a null terminated string to the terminal */ ! 2417: ! 2418: void ! 2419: StringToTerminal(s) ! 2420: char *s; ! 2421: { ! 2422: int count; ! 2423: ! 2424: count = strlen(s); ! 2425: if (count) { ! 2426: (void) DataToTerminal(s, count); /* we know it always goes... */ ! 2427: } ! 2428: } ! 2429: ! 2430: ! 2431: #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) ! 2432: /* _putchar - output a single character to the terminal. This name is so that ! 2433: * curses(3x) can call us to send out data. ! 2434: */ ! 2435: ! 2436: void ! 2437: _putchar(c) ! 2438: char c; ! 2439: { ! 2440: if (tfrontp >= ttyobuf+sizeof ttyobuf) { ! 2441: (void) DataToTerminal(&c, 1); ! 2442: } else { ! 2443: *tfrontp++ = c; /* optimize if possible. */ ! 2444: } ! 2445: } ! 2446: #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ ! 2447: ! 2448: static void ! 2449: SetForExit() ! 2450: { ! 2451: setconnmode(); ! 2452: if (In3270) { ! 2453: Finish3270(); ! 2454: } ! 2455: setcommandmode(); ! 2456: fflush(stdout); ! 2457: fflush(stderr); ! 2458: if (In3270) { ! 2459: StopScreen(1); ! 2460: } ! 2461: setconnmode(); ! 2462: setcommandmode(); ! 2463: } ! 2464: ! 2465: static void ! 2466: Exit(returnCode) ! 2467: int returnCode; ! 2468: { ! 2469: SetForExit(); ! 2470: exit(returnCode); ! 2471: } ! 2472: ! 2473: void ! 2474: ExitString(file, string, returnCode) ! 2475: FILE *file; ! 2476: char *string; ! 2477: int returnCode; ! 2478: { ! 2479: SetForExit(); ! 2480: fwrite(string, 1, strlen(string), file); ! 2481: exit(returnCode); ! 2482: } ! 2483: ! 2484: void ! 2485: ExitPerror(string, returnCode) ! 2486: char *string; ! 2487: int returnCode; ! 2488: { ! 2489: SetForExit(); ! 2490: perror(string); ! 2491: exit(returnCode); ! 2492: } ! 2493: ! 2494: #endif /* defined(TN3270) */ ! 2495: ! 2496: /* ! 2497: * Scheduler() ! 2498: * ! 2499: * Try to do something. ! 2500: * ! 2501: * If we do something useful, return 1; else return 0. ! 2502: * ! 2503: */ ! 2504: ! 2505: ! 2506: int ! 2507: Scheduler(block) ! 2508: int block; /* should we block in the select ? */ ! 2509: { ! 2510: register int c; ! 2511: /* One wants to be a bit careful about setting returnValue ! 2512: * to one, since a one implies we did some useful work, ! 2513: * and therefore probably won't be called to block next ! 2514: * time (TN3270 mode only). ! 2515: */ ! 2516: int returnValue = 0; ! 2517: static struct timeval TimeValue = { 0 }; ! 2518: ! 2519: if (scc < 0 && tcc < 0) { ! 2520: return -1; ! 2521: } ! 2522: ! 2523: if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { ! 2524: FD_SET(net, &obits); ! 2525: } ! 2526: #if !defined(MSDOS) ! 2527: if (TTYBYTES()) { ! 2528: FD_SET(tout, &obits); ! 2529: } ! 2530: #if defined(TN3270) ! 2531: if ((tcc == 0) && NETROOM() && (shell_active == 0)) { ! 2532: FD_SET(tin, &ibits); ! 2533: } ! 2534: #else /* defined(TN3270) */ ! 2535: if ((tcc == 0) && NETROOM()) { ! 2536: FD_SET(tin, &ibits); ! 2537: } ! 2538: #endif /* defined(TN3270) */ ! 2539: #endif /* !defined(MSDOS) */ ! 2540: # if !defined(TN3270) ! 2541: if (TTYROOM()) { ! 2542: FD_SET(net, &ibits); ! 2543: } ! 2544: # else /* !defined(TN3270) */ ! 2545: if (!ISend && TTYROOM()) { ! 2546: FD_SET(net, &ibits); ! 2547: } ! 2548: # endif /* !defined(TN3270) */ ! 2549: if (!SYNCHing) { ! 2550: FD_SET(net, &xbits); ! 2551: } ! 2552: # if defined(TN3270) && defined(unix) ! 2553: if (HaveInput) { ! 2554: HaveInput = 0; ! 2555: signal(SIGIO, inputAvailable); ! 2556: } ! 2557: #endif /* defined(TN3270) && defined(unix) */ ! 2558: if ((c = select(16, &ibits, &obits, &xbits, ! 2559: block? (struct timeval *)0 : &TimeValue)) < 0) { ! 2560: if (c == -1) { ! 2561: /* ! 2562: * we can get EINTR if we are in line mode, ! 2563: * and the user does an escape (TSTP), or ! 2564: * some other signal generator. ! 2565: */ ! 2566: if (errno == EINTR) { ! 2567: return 0; ! 2568: } ! 2569: # if defined(TN3270) ! 2570: /* ! 2571: * we can get EBADF if we were in transparent ! 2572: * mode, and the transcom process died. ! 2573: */ ! 2574: if (errno == EBADF) { ! 2575: /* ! 2576: * zero the bits (even though kernel does it) ! 2577: * to make sure we are selecting on the right ! 2578: * ones. ! 2579: */ ! 2580: FD_ZERO(&ibits); ! 2581: FD_ZERO(&obits); ! 2582: FD_ZERO(&xbits); ! 2583: return 0; ! 2584: } ! 2585: # endif /* defined(TN3270) */ ! 2586: /* I don't like this, does it ever happen? */ ! 2587: printf("sleep(5) from telnet, after select\r\n"); ! 2588: #if defined(unix) ! 2589: sleep(5); ! 2590: #endif /* defined(unix) */ ! 2591: } ! 2592: return 0; ! 2593: } ! 2594: ! 2595: /* ! 2596: * Any urgent data? ! 2597: */ ! 2598: if (FD_ISSET(net, &xbits)) { ! 2599: FD_CLR(net, &xbits); ! 2600: SYNCHing = 1; ! 2601: ttyflush(); /* flush already enqueued data */ ! 2602: } ! 2603: ! 2604: /* ! 2605: * Something to read from the network... ! 2606: */ ! 2607: if (FD_ISSET(net, &ibits)) { ! 2608: int canread; ! 2609: ! 2610: FD_CLR(net, &ibits); ! 2611: if (scc == 0) { ! 2612: sbp = sibuf; ! 2613: } ! 2614: canread = sibuf + sizeof sibuf - (sbp+scc); ! 2615: #if !defined(SO_OOBINLINE) ! 2616: /* ! 2617: * In 4.2 (and some early 4.3) systems, the ! 2618: * OOB indication and data handling in the kernel ! 2619: * is such that if two separate TCP Urgent requests ! 2620: * come in, one byte of TCP data will be overlaid. ! 2621: * This is fatal for Telnet, but we try to live ! 2622: * with it. ! 2623: * ! 2624: * In addition, in 4.2 (and...), a special protocol ! 2625: * is needed to pick up the TCP Urgent data in ! 2626: * the correct sequence. ! 2627: * ! 2628: * What we do is: if we think we are in urgent ! 2629: * mode, we look to see if we are "at the mark". ! 2630: * If we are, we do an OOB receive. If we run ! 2631: * this twice, we will do the OOB receive twice, ! 2632: * but the second will fail, since the second ! 2633: * time we were "at the mark", but there wasn't ! 2634: * any data there (the kernel doesn't reset ! 2635: * "at the mark" until we do a normal read). ! 2636: * Once we've read the OOB data, we go ahead ! 2637: * and do normal reads. ! 2638: * ! 2639: * There is also another problem, which is that ! 2640: * since the OOB byte we read doesn't put us ! 2641: * out of OOB state, and since that byte is most ! 2642: * likely the TELNET DM (data mark), we would ! 2643: * stay in the TELNET SYNCH (SYNCHing) state. ! 2644: * So, clocks to the rescue. If we've "just" ! 2645: * received a DM, then we test for the ! 2646: * presence of OOB data when the receive OOB ! 2647: * fails (and AFTER we did the normal mode read ! 2648: * to clear "at the mark"). ! 2649: */ ! 2650: if (SYNCHing) { ! 2651: int atmark; ! 2652: ! 2653: ioctl(net, SIOCATMARK, (char *)&atmark); ! 2654: if (atmark) { ! 2655: c = recv(net, sbp+scc, canread, MSG_OOB); ! 2656: if ((c == -1) && (errno == EINVAL)) { ! 2657: c = recv(net, sbp+scc, canread, 0); ! 2658: if (clocks.didnetreceive < clocks.gotDM) { ! 2659: SYNCHing = stilloob(net); ! 2660: } ! 2661: } ! 2662: } else { ! 2663: c = recv(net, sbp+scc, canread, 0); ! 2664: } ! 2665: } else { ! 2666: c = recv(net, sbp+scc, canread, 0); ! 2667: } ! 2668: settimer(didnetreceive); ! 2669: #else /* !defined(SO_OOBINLINE) */ ! 2670: c = recv(net, sbp+scc, canread, 0); ! 2671: #endif /* !defined(SO_OOBINLINE) */ ! 2672: if (c < 0 && errno == EWOULDBLOCK) { ! 2673: c = 0; ! 2674: } else if (c <= 0) { ! 2675: return -1; ! 2676: } ! 2677: if (netdata) { ! 2678: Dump('<', sbp+scc, c); ! 2679: } ! 2680: scc += c; ! 2681: returnValue = 1; ! 2682: } ! 2683: ! 2684: /* ! 2685: * Something to read from the tty... ! 2686: */ ! 2687: #if defined(MSDOS) ! 2688: if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) ! 2689: #else /* defined(MSDOS) */ ! 2690: if (FD_ISSET(tin, &ibits)) ! 2691: #endif /* defined(MSDOS) */ ! 2692: { ! 2693: FD_CLR(tin, &ibits); ! 2694: if (tcc == 0) { ! 2695: tbp = tibuf; /* nothing left, reset */ ! 2696: } ! 2697: c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); ! 2698: if (c < 0 && errno == EWOULDBLOCK) { ! 2699: c = 0; ! 2700: } else { ! 2701: #if defined(unix) ! 2702: /* EOF detection for line mode!!!! */ ! 2703: if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { ! 2704: /* must be an EOF... */ ! 2705: *tbp = ntc.t_eofc; ! 2706: c = 1; ! 2707: } ! 2708: #endif /* defined(unix) */ ! 2709: if (c <= 0) { ! 2710: tcc = c; ! 2711: return -1; ! 2712: } ! 2713: } ! 2714: tcc += c; ! 2715: returnValue = 1; /* did something useful */ ! 2716: } ! 2717: ! 2718: # if defined(TN3270) ! 2719: if (tcc > 0) { ! 2720: if (In3270) { ! 2721: c = DataFromTerminal(tbp, tcc); ! 2722: if (c) { ! 2723: returnValue = 1; ! 2724: } ! 2725: tcc -= c; ! 2726: tbp += c; ! 2727: } else { ! 2728: # endif /* defined(TN3270) */ ! 2729: returnValue = 1; ! 2730: while (tcc > 0) { ! 2731: register int sc; ! 2732: ! 2733: if (NETROOM() < 2) { ! 2734: flushline = 1; ! 2735: break; ! 2736: } ! 2737: c = *tbp++ & 0xff, sc = strip(c), tcc--; ! 2738: if (sc == escape) { ! 2739: command(0); ! 2740: tcc = 0; ! 2741: flushline = 1; ! 2742: break; ! 2743: } else if (MODE_LINE(globalmode) && (sc == echoc)) { ! 2744: if (tcc > 0 && strip(*tbp) == echoc) { ! 2745: tbp++; ! 2746: tcc--; ! 2747: } else { ! 2748: dontlecho = !dontlecho; ! 2749: settimer(echotoggle); ! 2750: setconnmode(); ! 2751: tcc = 0; ! 2752: flushline = 1; ! 2753: break; ! 2754: } ! 2755: } ! 2756: if (localchars) { ! 2757: if (TerminalSpecialChars(sc) == 0) { ! 2758: break; ! 2759: } ! 2760: } ! 2761: if (!myopts[TELOPT_BINARY]) { ! 2762: switch (c) { ! 2763: case '\n': ! 2764: /* ! 2765: * If we are in CRMOD mode (\r ==> \n) ! 2766: * on our local machine, then probably ! 2767: * a newline (unix) is CRLF (TELNET). ! 2768: */ ! 2769: if (MODE_LOCAL_CHARS(globalmode)) { ! 2770: NETADD('\r'); ! 2771: } ! 2772: NETADD('\n'); ! 2773: flushline = 1; ! 2774: break; ! 2775: case '\r': ! 2776: if (!crlf) { ! 2777: NET2ADD('\r', '\0'); ! 2778: } else { ! 2779: NET2ADD('\r', '\n'); ! 2780: } ! 2781: flushline = 1; ! 2782: break; ! 2783: case IAC: ! 2784: NET2ADD(IAC, IAC); ! 2785: break; ! 2786: default: ! 2787: NETADD(c); ! 2788: break; ! 2789: } ! 2790: } else if (c == IAC) { ! 2791: NET2ADD(IAC, IAC); ! 2792: } else { ! 2793: NETADD(c); ! 2794: } ! 2795: } ! 2796: # if defined(TN3270) ! 2797: } ! 2798: } ! 2799: # endif /* defined(TN3270) */ ! 2800: ! 2801: if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) && ! 2802: FD_ISSET(net, &obits) && (NETBYTES() > 0)) { ! 2803: FD_CLR(net, &obits); ! 2804: returnValue = netflush(); ! 2805: } ! 2806: if (scc > 0) { ! 2807: # if !defined(TN3270) ! 2808: telrcv(); ! 2809: returnValue = 1; ! 2810: # else /* !defined(TN3270) */ ! 2811: returnValue = Push3270(); ! 2812: # endif /* !defined(TN3270) */ ! 2813: } ! 2814: #if defined(MSDOS) ! 2815: if (TTYBYTES()) ! 2816: #else /* defined(MSDOS) */ ! 2817: if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) ! 2818: #endif /* defined(MSDOS) */ ! 2819: { ! 2820: FD_CLR(tout, &obits); ! 2821: returnValue = ttyflush(); ! 2822: } ! 2823: return returnValue; ! 2824: } ! 2825: ! 2826: /* ! 2827: * Select from tty and network... ! 2828: */ ! 2829: static void ! 2830: telnet() ! 2831: { ! 2832: #if defined(MSDOS) ! 2833: #define SCHED_BLOCK 0 /* Don't block in MSDOS */ ! 2834: #else /* defined(MSDOS) */ ! 2835: #define SCHED_BLOCK 1 ! 2836: #endif /* defined(MSDOS) */ ! 2837: ! 2838: #if defined(TN3270) && defined(unix) ! 2839: int myPid; ! 2840: #endif /* defined(TN3270) */ ! 2841: ! 2842: tout = fileno(stdout); ! 2843: tin = fileno(stdin); ! 2844: setconnmode(); ! 2845: scc = 0; ! 2846: tcc = 0; ! 2847: FD_ZERO(&ibits); ! 2848: FD_ZERO(&obits); ! 2849: FD_ZERO(&xbits); ! 2850: ! 2851: NetNonblockingIO(net, 1); ! 2852: ! 2853: #if defined(TN3270) ! 2854: if (noasynch == 0) { /* DBX can't handle! */ ! 2855: NetSigIO(net, 1); ! 2856: } ! 2857: NetSetPgrp(net); ! 2858: #endif /* defined(TN3270) */ ! 2859: ! 2860: ! 2861: #if defined(SO_OOBINLINE) && !defined(MSDOS) ! 2862: SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); ! 2863: #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ ! 2864: ! 2865: # if !defined(TN3270) ! 2866: if (telnetport) { ! 2867: if (!hisopts[TELOPT_SGA]) { ! 2868: willoption(TELOPT_SGA, 0); ! 2869: } ! 2870: if (!myopts[TELOPT_TTYPE]) { ! 2871: dooption(TELOPT_TTYPE, 0); ! 2872: } ! 2873: } ! 2874: # endif /* !defined(TN3270) */ ! 2875: ! 2876: # if !defined(TN3270) ! 2877: for (;;) { ! 2878: if (Scheduler(SCHED_BLOCK) == -1) { ! 2879: setcommandmode(); ! 2880: return; ! 2881: } ! 2882: } ! 2883: # else /* !defined(TN3270) */ ! 2884: for (;;) { ! 2885: int schedValue; ! 2886: ! 2887: while (!In3270 && !shell_active) { ! 2888: if (Scheduler(SCHED_BLOCK) == -1) { ! 2889: setcommandmode(); ! 2890: return; ! 2891: } ! 2892: } ! 2893: ! 2894: while ((schedValue = Scheduler(0)) != 0) { ! 2895: if (schedValue == -1) { ! 2896: setcommandmode(); ! 2897: return; ! 2898: } ! 2899: } ! 2900: /* If there is data waiting to go out to terminal, don't ! 2901: * schedule any more data for the terminal. ! 2902: */ ! 2903: if (tfrontp-tbackp) { ! 2904: schedValue = 1; ! 2905: } else { ! 2906: if (shell_active) { ! 2907: if (shell_continue() == 0) { ! 2908: ConnectScreen(); ! 2909: } ! 2910: } else if (In3270) { ! 2911: schedValue = DoTerminalOutput(); ! 2912: } ! 2913: } ! 2914: if (schedValue && (shell_active == 0)) { ! 2915: if (Scheduler(SCHED_BLOCK) == -1) { ! 2916: setcommandmode(); ! 2917: return; ! 2918: } ! 2919: } ! 2920: } ! 2921: # endif /* !defined(TN3270) */ ! 2922: } ! 2923: ! 2924: /* ! 2925: * The following are data structures and routines for ! 2926: * the "send" command. ! 2927: * ! 2928: */ ! 2929: ! 2930: struct sendlist { ! 2931: char *name; /* How user refers to it (case independent) */ ! 2932: int what; /* Character to be sent (<0 ==> special) */ ! 2933: char *help; /* Help information (0 ==> no help) */ ! 2934: #if defined(NOT43) ! 2935: int (*routine)(); /* Routine to perform (for special ops) */ ! 2936: #else /* defined(NOT43) */ ! 2937: void (*routine)(); /* Routine to perform (for special ops) */ ! 2938: #endif /* defined(NOT43) */ ! 2939: }; ! 2940: ! 2941: #define SENDQUESTION -1 ! 2942: #define SENDESCAPE -3 ! 2943: ! 2944: static struct sendlist Sendlist[] = { ! 2945: { "ao", AO, "Send Telnet Abort output" }, ! 2946: { "ayt", AYT, "Send Telnet 'Are You There'" }, ! 2947: { "brk", BREAK, "Send Telnet Break" }, ! 2948: { "ec", EC, "Send Telnet Erase Character" }, ! 2949: { "el", EL, "Send Telnet Erase Line" }, ! 2950: { "escape", SENDESCAPE, "Send current escape character" }, ! 2951: { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, ! 2952: { "ip", IP, "Send Telnet Interrupt Process" }, ! 2953: { "nop", NOP, "Send Telnet 'No operation'" }, ! 2954: { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, ! 2955: { "?", SENDQUESTION, "Display send options" }, ! 2956: { 0 } ! 2957: }; ! 2958: ! 2959: static struct sendlist Sendlist2[] = { /* some synonyms */ ! 2960: { "break", BREAK, 0 }, ! 2961: ! 2962: { "intp", IP, 0 }, ! 2963: { "interrupt", IP, 0 }, ! 2964: { "intr", IP, 0 }, ! 2965: ! 2966: { "help", SENDQUESTION, 0 }, ! 2967: ! 2968: { 0 } ! 2969: }; ! 2970: ! 2971: static char ** ! 2972: getnextsend(name) ! 2973: char *name; ! 2974: { ! 2975: struct sendlist *c = (struct sendlist *) name; ! 2976: ! 2977: return (char **) (c+1); ! 2978: } ! 2979: ! 2980: static struct sendlist * ! 2981: getsend(name) ! 2982: char *name; ! 2983: { ! 2984: struct sendlist *sl; ! 2985: ! 2986: if ((sl = (struct sendlist *) ! 2987: genget(name, (char **) Sendlist, getnextsend)) != 0) { ! 2988: return sl; ! 2989: } else { ! 2990: return (struct sendlist *) ! 2991: genget(name, (char **) Sendlist2, getnextsend); ! 2992: } ! 2993: } ! 2994: ! 2995: static ! 2996: sendcmd(argc, argv) ! 2997: int argc; ! 2998: char **argv; ! 2999: { ! 3000: int what; /* what we are sending this time */ ! 3001: int count; /* how many bytes we are going to need to send */ ! 3002: int i; ! 3003: int question = 0; /* was at least one argument a question */ ! 3004: struct sendlist *s; /* pointer to current command */ ! 3005: ! 3006: if (argc < 2) { ! 3007: printf("need at least one argument for 'send' command\n"); ! 3008: printf("'send ?' for help\n"); ! 3009: return 0; ! 3010: } ! 3011: /* ! 3012: * First, validate all the send arguments. ! 3013: * In addition, we see how much space we are going to need, and ! 3014: * whether or not we will be doing a "SYNCH" operation (which ! 3015: * flushes the network queue). ! 3016: */ ! 3017: count = 0; ! 3018: for (i = 1; i < argc; i++) { ! 3019: s = getsend(argv[i]); ! 3020: if (s == 0) { ! 3021: printf("Unknown send argument '%s'\n'send ?' for help.\n", ! 3022: argv[i]); ! 3023: return 0; ! 3024: } else if (s == Ambiguous(struct sendlist *)) { ! 3025: printf("Ambiguous send argument '%s'\n'send ?' for help.\n", ! 3026: argv[i]); ! 3027: return 0; ! 3028: } ! 3029: switch (s->what) { ! 3030: case SENDQUESTION: ! 3031: break; ! 3032: case SENDESCAPE: ! 3033: count += 1; ! 3034: break; ! 3035: case SYNCH: ! 3036: count += 2; ! 3037: break; ! 3038: default: ! 3039: count += 2; ! 3040: break; ! 3041: } ! 3042: } ! 3043: /* Now, do we have enough room? */ ! 3044: if (NETROOM() < count) { ! 3045: printf("There is not enough room in the buffer TO the network\n"); ! 3046: printf("to process your request. Nothing will be done.\n"); ! 3047: printf("('send synch' will throw away most data in the network\n"); ! 3048: printf("buffer, if this might help.)\n"); ! 3049: return 0; ! 3050: } ! 3051: /* OK, they are all OK, now go through again and actually send */ ! 3052: for (i = 1; i < argc; i++) { ! 3053: if ((s = getsend(argv[i])) == 0) { ! 3054: fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); ! 3055: quit(); ! 3056: /*NOTREACHED*/ ! 3057: } ! 3058: if (s->routine) { ! 3059: (*s->routine)(s); ! 3060: } else { ! 3061: switch (what = s->what) { ! 3062: case SYNCH: ! 3063: dosynch(); ! 3064: break; ! 3065: case SENDQUESTION: ! 3066: for (s = Sendlist; s->name; s++) { ! 3067: if (s->help) { ! 3068: printf(s->name); ! 3069: if (s->help) { ! 3070: printf("\t%s", s->help); ! 3071: } ! 3072: printf("\n"); ! 3073: } ! 3074: } ! 3075: question = 1; ! 3076: break; ! 3077: case SENDESCAPE: ! 3078: NETADD(escape); ! 3079: break; ! 3080: default: ! 3081: NET2ADD(IAC, what); ! 3082: break; ! 3083: } ! 3084: } ! 3085: } ! 3086: return !question; ! 3087: } ! 3088: ! 3089: /* ! 3090: * The following are the routines and data structures referred ! 3091: * to by the arguments to the "toggle" command. ! 3092: */ ! 3093: ! 3094: static ! 3095: lclchars() ! 3096: { ! 3097: donelclchars = 1; ! 3098: return 1; ! 3099: } ! 3100: ! 3101: static ! 3102: togdebug() ! 3103: { ! 3104: #ifndef NOT43 ! 3105: if (net > 0 && ! 3106: (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { ! 3107: perror("setsockopt (SO_DEBUG)"); ! 3108: } ! 3109: #else /* NOT43 */ ! 3110: if (debug) { ! 3111: if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 3112: perror("setsockopt (SO_DEBUG)"); ! 3113: } else ! 3114: printf("Cannot turn off socket debugging\n"); ! 3115: #endif /* NOT43 */ ! 3116: return 1; ! 3117: } ! 3118: ! 3119: ! 3120: static int ! 3121: togcrlf() ! 3122: { ! 3123: if (crlf) { ! 3124: printf("Will send carriage returns as telnet <CR><LF>.\n"); ! 3125: } else { ! 3126: printf("Will send carriage returns as telnet <CR><NUL>.\n"); ! 3127: } ! 3128: return 1; ! 3129: } ! 3130: ! 3131: ! 3132: static int ! 3133: togbinary() ! 3134: { ! 3135: donebinarytoggle = 1; ! 3136: ! 3137: if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ ! 3138: NET2ADD(IAC, DO); ! 3139: NETADD(TELOPT_BINARY); ! 3140: printoption("<SENT", doopt, TELOPT_BINARY, 0); ! 3141: NET2ADD(IAC, WILL); ! 3142: NETADD(TELOPT_BINARY); ! 3143: printoption("<SENT", doopt, TELOPT_BINARY, 0); ! 3144: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; ! 3145: printf("Negotiating binary mode with remote host.\n"); ! 3146: } else { /* Turn off binary mode */ ! 3147: NET2ADD(IAC, DONT); ! 3148: NETADD(TELOPT_BINARY); ! 3149: printoption("<SENT", dont, TELOPT_BINARY, 0); ! 3150: NET2ADD(IAC, DONT); ! 3151: NETADD(TELOPT_BINARY); ! 3152: printoption("<SENT", dont, TELOPT_BINARY, 0); ! 3153: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; ! 3154: printf("Negotiating network ascii mode with remote host.\n"); ! 3155: } ! 3156: return 1; ! 3157: } ! 3158: ! 3159: ! 3160: ! 3161: extern int togglehelp(); ! 3162: ! 3163: struct togglelist { ! 3164: char *name; /* name of toggle */ ! 3165: char *help; /* help message */ ! 3166: int (*handler)(); /* routine to do actual setting */ ! 3167: int dohelp; /* should we display help information */ ! 3168: int *variable; ! 3169: char *actionexplanation; ! 3170: }; ! 3171: ! 3172: static struct togglelist Togglelist[] = { ! 3173: { "autoflush", ! 3174: "toggle flushing of output when sending interrupt characters", ! 3175: 0, ! 3176: 1, ! 3177: &autoflush, ! 3178: "flush output when sending interrupt characters" }, ! 3179: { "autosynch", ! 3180: "toggle automatic sending of interrupt characters in urgent mode", ! 3181: 0, ! 3182: 1, ! 3183: &autosynch, ! 3184: "send interrupt characters in urgent mode" }, ! 3185: { "binary", ! 3186: "toggle sending and receiving of binary data", ! 3187: togbinary, ! 3188: 1, ! 3189: 0, ! 3190: 0 }, ! 3191: { "crlf", ! 3192: "toggle sending carriage returns as telnet <CR><LF>", ! 3193: togcrlf, ! 3194: 1, ! 3195: &crlf, ! 3196: 0 }, ! 3197: { "crmod", ! 3198: "toggle mapping of received carriage returns", ! 3199: 0, ! 3200: 1, ! 3201: &crmod, ! 3202: "map carriage return on output" }, ! 3203: { "localchars", ! 3204: "toggle local recognition of certain control characters", ! 3205: lclchars, ! 3206: 1, ! 3207: &localchars, ! 3208: "recognize certain control characters" }, ! 3209: { " ", "", 0, 1 }, /* empty line */ ! 3210: { "debug", ! 3211: "(debugging) toggle debugging", ! 3212: togdebug, ! 3213: 1, ! 3214: &debug, ! 3215: "turn on socket level debugging" }, ! 3216: { "netdata", ! 3217: "(debugging) toggle printing of hexadecimal network data", ! 3218: 0, ! 3219: 1, ! 3220: &netdata, ! 3221: "print hexadecimal representation of network traffic" }, ! 3222: { "options", ! 3223: "(debugging) toggle viewing of options processing", ! 3224: 0, ! 3225: 1, ! 3226: &showoptions, ! 3227: "show option processing" }, ! 3228: { " ", "", 0, 1 }, /* empty line */ ! 3229: { "?", ! 3230: "display help information", ! 3231: togglehelp, ! 3232: 1 }, ! 3233: { "help", ! 3234: "display help information", ! 3235: togglehelp, ! 3236: 0 }, ! 3237: { 0 } ! 3238: }; ! 3239: ! 3240: static ! 3241: togglehelp() ! 3242: { ! 3243: struct togglelist *c; ! 3244: ! 3245: for (c = Togglelist; c->name; c++) { ! 3246: if (c->dohelp) { ! 3247: printf("%s\t%s\n", c->name, c->help); ! 3248: } ! 3249: } ! 3250: return 0; ! 3251: } ! 3252: ! 3253: static char ** ! 3254: getnexttoggle(name) ! 3255: char *name; ! 3256: { ! 3257: struct togglelist *c = (struct togglelist *) name; ! 3258: ! 3259: return (char **) (c+1); ! 3260: } ! 3261: ! 3262: static struct togglelist * ! 3263: gettoggle(name) ! 3264: char *name; ! 3265: { ! 3266: return (struct togglelist *) ! 3267: genget(name, (char **) Togglelist, getnexttoggle); ! 3268: } ! 3269: ! 3270: static ! 3271: toggle(argc, argv) ! 3272: int argc; ! 3273: char *argv[]; ! 3274: { ! 3275: int retval = 1; ! 3276: char *name; ! 3277: struct togglelist *c; ! 3278: ! 3279: if (argc < 2) { ! 3280: fprintf(stderr, ! 3281: "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); ! 3282: return 0; ! 3283: } ! 3284: argc--; ! 3285: argv++; ! 3286: while (argc--) { ! 3287: name = *argv++; ! 3288: c = gettoggle(name); ! 3289: if (c == Ambiguous(struct togglelist *)) { ! 3290: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", ! 3291: name); ! 3292: return 0; ! 3293: } else if (c == 0) { ! 3294: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", ! 3295: name); ! 3296: return 0; ! 3297: } else { ! 3298: if (c->variable) { ! 3299: *c->variable = !*c->variable; /* invert it */ ! 3300: if (c->actionexplanation) { ! 3301: printf("%s %s.\n", *c->variable? "Will" : "Won't", ! 3302: c->actionexplanation); ! 3303: } ! 3304: } ! 3305: if (c->handler) { ! 3306: retval &= (*c->handler)(c); ! 3307: } ! 3308: } ! 3309: } ! 3310: return retval; ! 3311: } ! 3312: ! 3313: /* ! 3314: * The following perform the "set" command. ! 3315: */ ! 3316: ! 3317: struct setlist { ! 3318: char *name; /* name */ ! 3319: char *help; /* help information */ ! 3320: char *charp; /* where it is located at */ ! 3321: }; ! 3322: ! 3323: static struct setlist Setlist[] = { ! 3324: { "echo", "character to toggle local echoing on/off", &echoc }, ! 3325: { "escape", "character to escape back to telnet command mode", &escape }, ! 3326: { " ", "" }, ! 3327: { " ", "The following need 'localchars' to be toggled true", 0 }, ! 3328: #if defined(unix) ! 3329: { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, ! 3330: { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, ! 3331: { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, ! 3332: { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, ! 3333: { "quit", "character to cause a Break", &ntc.t_quitc }, ! 3334: { "eof", "character to cause an EOF ", &ntc.t_eofc }, ! 3335: #endif /* defined(unix) */ ! 3336: #if defined(MSDOS) ! 3337: { "erase", "character to cause an Erase Character", &termEraseChar }, ! 3338: { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, ! 3339: { "interrupt", "character to cause an Interrupt Process", &termIntChar }, ! 3340: { "kill", "character to cause an Erase Line", &termKillChar }, ! 3341: { "quit", "character to cause a Break", &termQuitChar }, ! 3342: { "eof", "character to cause an EOF ", &termEofChar }, ! 3343: #endif /* defined(MSDOS) */ ! 3344: { 0 } ! 3345: }; ! 3346: ! 3347: static char ** ! 3348: getnextset(name) ! 3349: char *name; ! 3350: { ! 3351: struct setlist *c = (struct setlist *)name; ! 3352: ! 3353: return (char **) (c+1); ! 3354: } ! 3355: ! 3356: static struct setlist * ! 3357: getset(name) ! 3358: char *name; ! 3359: { ! 3360: return (struct setlist *) genget(name, (char **) Setlist, getnextset); ! 3361: } ! 3362: ! 3363: static ! 3364: setcmd(argc, argv) ! 3365: int argc; ! 3366: char *argv[]; ! 3367: { ! 3368: int value; ! 3369: struct setlist *ct; ! 3370: ! 3371: /* XXX back we go... sigh */ ! 3372: if (argc != 3) { ! 3373: if ((argc == 2) && ! 3374: ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { ! 3375: for (ct = Setlist; ct->name; ct++) { ! 3376: printf("%s\t%s\n", ct->name, ct->help); ! 3377: } ! 3378: printf("?\tdisplay help information\n"); ! 3379: } else { ! 3380: printf("Format is 'set Name Value'\n'set ?' for help.\n"); ! 3381: } ! 3382: return 0; ! 3383: } ! 3384: ! 3385: ct = getset(argv[1]); ! 3386: if (ct == 0) { ! 3387: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", ! 3388: argv[1]); ! 3389: return 0; ! 3390: } else if (ct == Ambiguous(struct setlist *)) { ! 3391: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", ! 3392: argv[1]); ! 3393: return 0; ! 3394: } else { ! 3395: if (strcmp("off", argv[2])) { ! 3396: value = special(argv[2]); ! 3397: } else { ! 3398: value = -1; ! 3399: } ! 3400: *(ct->charp) = value; ! 3401: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); ! 3402: } ! 3403: return 1; ! 3404: } ! 3405: ! 3406: /* ! 3407: * The following are the data structures and routines for the ! 3408: * 'mode' command. ! 3409: */ ! 3410: ! 3411: static ! 3412: dolinemode() ! 3413: { ! 3414: if (hisopts[TELOPT_SGA]) { ! 3415: wontoption(TELOPT_SGA, 0); ! 3416: } ! 3417: if (hisopts[TELOPT_ECHO]) { ! 3418: wontoption(TELOPT_ECHO, 0); ! 3419: } ! 3420: return 1; ! 3421: } ! 3422: ! 3423: static ! 3424: docharmode() ! 3425: { ! 3426: if (!hisopts[TELOPT_SGA]) { ! 3427: willoption(TELOPT_SGA, 0); ! 3428: } ! 3429: if (!hisopts[TELOPT_ECHO]) { ! 3430: willoption(TELOPT_ECHO, 0); ! 3431: } ! 3432: return 1; ! 3433: } ! 3434: ! 3435: static struct cmd Modelist[] = { ! 3436: { "character", "character-at-a-time mode", docharmode, 1, 1 }, ! 3437: { "line", "line-by-line mode", dolinemode, 1, 1 }, ! 3438: { 0 }, ! 3439: }; ! 3440: ! 3441: static char ** ! 3442: getnextmode(name) ! 3443: char *name; ! 3444: { ! 3445: struct cmd *c = (struct cmd *) name; ! 3446: ! 3447: return (char **) (c+1); ! 3448: } ! 3449: ! 3450: static struct cmd * ! 3451: getmodecmd(name) ! 3452: char *name; ! 3453: { ! 3454: return (struct cmd *) genget(name, (char **) Modelist, getnextmode); ! 3455: } ! 3456: ! 3457: static ! 3458: modecmd(argc, argv) ! 3459: int argc; ! 3460: char *argv[]; ! 3461: { ! 3462: struct cmd *mt; ! 3463: ! 3464: if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { ! 3465: printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); ! 3466: for (mt = Modelist; mt->name; mt++) { ! 3467: printf("%s\t%s\n", mt->name, mt->help); ! 3468: } ! 3469: return 0; ! 3470: } ! 3471: mt = getmodecmd(argv[1]); ! 3472: if (mt == 0) { ! 3473: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); ! 3474: return 0; ! 3475: } else if (mt == Ambiguous(struct cmd *)) { ! 3476: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); ! 3477: return 0; ! 3478: } else { ! 3479: (*mt->handler)(); ! 3480: } ! 3481: return 1; ! 3482: } ! 3483: ! 3484: /* ! 3485: * The following data structures and routines implement the ! 3486: * "display" command. ! 3487: */ ! 3488: ! 3489: static ! 3490: display(argc, argv) ! 3491: int argc; ! 3492: char *argv[]; ! 3493: { ! 3494: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ ! 3495: if (*tl->variable) { \ ! 3496: printf("will"); \ ! 3497: } else { \ ! 3498: printf("won't"); \ ! 3499: } \ ! 3500: printf(" %s.\n", tl->actionexplanation); \ ! 3501: } ! 3502: ! 3503: #define doset(sl) if (sl->name && *sl->name != ' ') { \ ! 3504: printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ ! 3505: } ! 3506: ! 3507: struct togglelist *tl; ! 3508: struct setlist *sl; ! 3509: ! 3510: if (argc == 1) { ! 3511: for (tl = Togglelist; tl->name; tl++) { ! 3512: dotog(tl); ! 3513: } ! 3514: printf("\n"); ! 3515: for (sl = Setlist; sl->name; sl++) { ! 3516: doset(sl); ! 3517: } ! 3518: } else { ! 3519: int i; ! 3520: ! 3521: for (i = 1; i < argc; i++) { ! 3522: sl = getset(argv[i]); ! 3523: tl = gettoggle(argv[i]); ! 3524: if ((sl == Ambiguous(struct setlist *)) || ! 3525: (tl == Ambiguous(struct togglelist *))) { ! 3526: printf("?Ambiguous argument '%s'.\n", argv[i]); ! 3527: return 0; ! 3528: } else if (!sl && !tl) { ! 3529: printf("?Unknown argument '%s'.\n", argv[i]); ! 3530: return 0; ! 3531: } else { ! 3532: if (tl) { ! 3533: dotog(tl); ! 3534: } ! 3535: if (sl) { ! 3536: doset(sl); ! 3537: } ! 3538: } ! 3539: } ! 3540: } ! 3541: return 1; ! 3542: #undef doset ! 3543: #undef dotog ! 3544: } ! 3545: ! 3546: /* ! 3547: * The following are the data structures, and many of the routines, ! 3548: * relating to command processing. ! 3549: */ ! 3550: ! 3551: /* ! 3552: * Set the escape character. ! 3553: */ ! 3554: static ! 3555: setescape(argc, argv) ! 3556: int argc; ! 3557: char *argv[]; ! 3558: { ! 3559: register char *arg; ! 3560: char buf[50]; ! 3561: ! 3562: printf( ! 3563: "Deprecated usage - please use 'set escape%s%s' in the future.\n", ! 3564: (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); ! 3565: if (argc > 2) ! 3566: arg = argv[1]; ! 3567: else { ! 3568: printf("new escape character: "); ! 3569: gets(buf); ! 3570: arg = buf; ! 3571: } ! 3572: if (arg[0] != '\0') ! 3573: escape = arg[0]; ! 3574: if (!In3270) { ! 3575: printf("Escape character is '%s'.\n", control(escape)); ! 3576: } ! 3577: fflush(stdout); ! 3578: return 1; ! 3579: } ! 3580: ! 3581: /*VARARGS*/ ! 3582: static ! 3583: togcrmod() ! 3584: { ! 3585: crmod = !crmod; ! 3586: printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); ! 3587: printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); ! 3588: fflush(stdout); ! 3589: return 1; ! 3590: } ! 3591: ! 3592: /*VARARGS*/ ! 3593: suspend() ! 3594: { ! 3595: setcommandmode(); ! 3596: #if defined(unix) ! 3597: kill(0, SIGTSTP); ! 3598: #endif /* defined(unix) */ ! 3599: /* reget parameters in case they were changed */ ! 3600: TerminalSaveState(); ! 3601: setconnmode(); ! 3602: return 1; ! 3603: } ! 3604: ! 3605: /*VARARGS*/ ! 3606: static ! 3607: bye(argc, argv) ! 3608: int argc; /* Number of arguments */ ! 3609: char *argv[]; /* arguments */ ! 3610: { ! 3611: if (connected) { ! 3612: shutdown(net, 2); ! 3613: printf("Connection closed.\n"); ! 3614: NetClose(net); ! 3615: connected = 0; ! 3616: /* reset options */ ! 3617: tninit(); ! 3618: #if defined(TN3270) ! 3619: SetIn3270(); /* Get out of 3270 mode */ ! 3620: #endif /* defined(TN3270) */ ! 3621: } ! 3622: if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { ! 3623: longjmp(toplevel, 1); ! 3624: /* NOTREACHED */ ! 3625: } ! 3626: return 1; /* Keep lint, etc., happy */ ! 3627: } ! 3628: ! 3629: /*VARARGS*/ ! 3630: quit() ! 3631: { ! 3632: (void) call(bye, "bye", "fromquit", 0); ! 3633: Exit(0); ! 3634: /*NOTREACHED*/ ! 3635: return 1; /* just to keep lint happy */ ! 3636: } ! 3637: ! 3638: /* ! 3639: * Print status about the connection. ! 3640: */ ! 3641: static ! 3642: status(argc, argv) ! 3643: int argc; ! 3644: char *argv[]; ! 3645: { ! 3646: if (connected) { ! 3647: printf("Connected to %s.\n", hostname); ! 3648: if (argc < 2) { ! 3649: printf("Operating in %s.\n", ! 3650: modelist[getconnmode()].modedescriptions); ! 3651: if (localchars) { ! 3652: printf("Catching signals locally.\n"); ! 3653: } ! 3654: } ! 3655: } else { ! 3656: printf("No connection.\n"); ! 3657: } ! 3658: # if !defined(TN3270) ! 3659: printf("Escape character is '%s'.\n", control(escape)); ! 3660: fflush(stdout); ! 3661: # else /* !defined(TN3270) */ ! 3662: if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { ! 3663: printf("Escape character is '%s'.\n", control(escape)); ! 3664: } ! 3665: # if defined(unix) ! 3666: if (In3270 && transcom) { ! 3667: printf("Transparent mode command is '%s'.\n", transcom); ! 3668: } ! 3669: # endif /* defined(unix) */ ! 3670: fflush(stdout); ! 3671: if (In3270) { ! 3672: return 0; ! 3673: } ! 3674: # endif /* defined(TN3270) */ ! 3675: return 1; ! 3676: } ! 3677: ! 3678: #if defined(TN3270) && defined(unix) ! 3679: static ! 3680: settranscom(argc, argv) ! 3681: int argc; ! 3682: char *argv[]; ! 3683: { ! 3684: int i, len = 0; ! 3685: char *strcpy(), *strcat(); ! 3686: ! 3687: if (argc == 1 && transcom) { ! 3688: transcom = 0; ! 3689: } ! 3690: if (argc == 1) { ! 3691: return; ! 3692: } ! 3693: for (i = 1; i < argc; ++i) { ! 3694: len += 1 + strlen(argv[1]); ! 3695: } ! 3696: transcom = tline; ! 3697: (void) strcpy(transcom, argv[1]); ! 3698: for (i = 2; i < argc; ++i) { ! 3699: (void) strcat(transcom, " "); ! 3700: (void) strcat(transcom, argv[i]); ! 3701: } ! 3702: } ! 3703: #endif /* defined(TN3270) && defined(unix) */ ! 3704: ! 3705: ! 3706: ! 3707: static ! 3708: tn(argc, argv) ! 3709: int argc; ! 3710: char *argv[]; ! 3711: { ! 3712: register struct hostent *host = 0; ! 3713: #if defined(MSDOS) ! 3714: char *cp; ! 3715: #endif /* defined(MSDOS) */ ! 3716: ! 3717: if (connected) { ! 3718: printf("?Already connected to %s\n", hostname); ! 3719: return 0; ! 3720: } ! 3721: if (argc < 2) { ! 3722: (void) strcpy(line, "Connect "); ! 3723: printf("(to) "); ! 3724: gets(&line[strlen(line)]); ! 3725: makeargv(); ! 3726: argc = margc; ! 3727: argv = margv; ! 3728: } ! 3729: if ((argc < 2) || (argc > 3)) { ! 3730: printf("usage: %s host-name [port]\n", argv[0]); ! 3731: return 0; ! 3732: } ! 3733: #if defined(MSDOS) ! 3734: for (cp = argv[1]; *cp; cp++) { ! 3735: if (isupper(*cp)) { ! 3736: *cp = tolower(*cp); ! 3737: } ! 3738: } ! 3739: #endif /* defined(MSDOS) */ ! 3740: sin.sin_addr.s_addr = inet_addr(argv[1]); ! 3741: if (sin.sin_addr.s_addr != -1) { ! 3742: sin.sin_family = AF_INET; ! 3743: (void) strcpy(hnamebuf, argv[1]); ! 3744: hostname = hnamebuf; ! 3745: } else { ! 3746: host = gethostbyname(argv[1]); ! 3747: if (host) { ! 3748: sin.sin_family = host->h_addrtype; ! 3749: #if defined(h_addr) /* In 4.3, this is a #define */ ! 3750: memcpy((caddr_t)&sin.sin_addr, ! 3751: host->h_addr_list[0], host->h_length); ! 3752: #else /* defined(h_addr) */ ! 3753: memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); ! 3754: #endif /* defined(h_addr) */ ! 3755: hostname = host->h_name; ! 3756: } else { ! 3757: printf("%s: unknown host\n", argv[1]); ! 3758: return 0; ! 3759: } ! 3760: } ! 3761: sin.sin_port = sp->s_port; ! 3762: if (argc == 3) { ! 3763: sin.sin_port = atoi(argv[2]); ! 3764: if (sin.sin_port == 0) { ! 3765: sp = getservbyname(argv[2], "tcp"); ! 3766: if (sp) ! 3767: sin.sin_port = sp->s_port; ! 3768: else { ! 3769: printf("%s: bad port number\n", argv[2]); ! 3770: return 0; ! 3771: } ! 3772: } else { ! 3773: sin.sin_port = atoi(argv[2]); ! 3774: sin.sin_port = htons(sin.sin_port); ! 3775: } ! 3776: telnetport = 0; ! 3777: } else { ! 3778: telnetport = 1; ! 3779: } ! 3780: #if defined(unix) ! 3781: signal(SIGINT, intr); ! 3782: signal(SIGQUIT, intr2); ! 3783: signal(SIGPIPE, deadpeer); ! 3784: #endif /* defined(unix) */ ! 3785: printf("Trying...\n"); ! 3786: do { ! 3787: net = socket(AF_INET, SOCK_STREAM, 0); ! 3788: if (net < 0) { ! 3789: perror("telnet: socket"); ! 3790: return 0; ! 3791: } ! 3792: if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { ! 3793: perror("setsockopt (SO_DEBUG)"); ! 3794: } ! 3795: ! 3796: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { ! 3797: #if defined(h_addr) /* In 4.3, this is a #define */ ! 3798: if (host && host->h_addr_list[1]) { ! 3799: int oerrno = errno; ! 3800: ! 3801: fprintf(stderr, "telnet: connect to address %s: ", ! 3802: inet_ntoa(sin.sin_addr)); ! 3803: errno = oerrno; ! 3804: perror((char *)0); ! 3805: host->h_addr_list++; ! 3806: memcpy((caddr_t)&sin.sin_addr, ! 3807: host->h_addr_list[0], host->h_length); ! 3808: fprintf(stderr, "Trying %s...\n", ! 3809: inet_ntoa(sin.sin_addr)); ! 3810: (void) NetClose(net); ! 3811: continue; ! 3812: } ! 3813: #endif /* defined(h_addr) */ ! 3814: perror("telnet: Unable to connect to remote host"); ! 3815: #if defined(unix) ! 3816: signal(SIGINT, SIG_DFL); ! 3817: signal(SIGQUIT, SIG_DFL); ! 3818: #endif /* defined(unix) */ ! 3819: return 0; ! 3820: } ! 3821: connected++; ! 3822: } while (connected == 0); ! 3823: call(status, "status", "notmuch", 0); ! 3824: if (setjmp(peerdied) == 0) ! 3825: telnet(); ! 3826: NetClose(net); ! 3827: ExitString(stderr, "Connection closed by foreign host.\n",1); ! 3828: /*NOTREACHED*/ ! 3829: } ! 3830: ! 3831: ! 3832: #define HELPINDENT (sizeof ("connect")) ! 3833: ! 3834: static char ! 3835: openhelp[] = "connect to a site", ! 3836: closehelp[] = "close current connection", ! 3837: quithelp[] = "exit telnet", ! 3838: statushelp[] = "print status information", ! 3839: helphelp[] = "print help information", ! 3840: sendhelp[] = "transmit special characters ('send ?' for more)", ! 3841: sethelp[] = "set operating parameters ('set ?' for more)", ! 3842: togglestring[] ="toggle operating parameters ('toggle ?' for more)", ! 3843: displayhelp[] = "display operating parameters", ! 3844: #if defined(TN3270) && defined(unix) ! 3845: transcomhelp[] = "specify Unix command for transparent mode pipe", ! 3846: #endif /* defined(TN3270) && defined(unix) */ ! 3847: #if defined(unix) ! 3848: zhelp[] = "suspend telnet", ! 3849: #endif /* defined(unix */ ! 3850: #if defined(TN3270) ! 3851: shellhelp[] = "invoke a subshell", ! 3852: #endif /* defined(TN3270) */ ! 3853: modehelp[] = "try to enter line-by-line or character-at-a-time mode"; ! 3854: ! 3855: extern int help(), shell(); ! 3856: ! 3857: static struct cmd cmdtab[] = { ! 3858: { "close", closehelp, bye, 1, 1 }, ! 3859: { "display", displayhelp, display, 1, 0 }, ! 3860: { "mode", modehelp, modecmd, 1, 1 }, ! 3861: { "open", openhelp, tn, 1, 0 }, ! 3862: { "quit", quithelp, quit, 1, 0 }, ! 3863: { "send", sendhelp, sendcmd, 1, 1 }, ! 3864: { "set", sethelp, setcmd, 1, 0 }, ! 3865: { "status", statushelp, status, 1, 0 }, ! 3866: { "toggle", togglestring, toggle, 1, 0 }, ! 3867: #if defined(TN3270) && defined(unix) ! 3868: { "transcom", transcomhelp, settranscom, 1, 0 }, ! 3869: #endif /* defined(TN3270) && defined(unix) */ ! 3870: #if defined(unix) ! 3871: { "z", zhelp, suspend, 1, 0 }, ! 3872: #endif /* defined(unix) */ ! 3873: #if defined(TN3270) ! 3874: { "!", shellhelp, shell, 1, 1 }, ! 3875: #endif /* defined(TN3270) */ ! 3876: { "?", helphelp, help, 1, 0 }, ! 3877: 0 ! 3878: }; ! 3879: ! 3880: static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; ! 3881: static char escapehelp[] = "deprecated command -- use 'set escape' instead"; ! 3882: ! 3883: static struct cmd cmdtab2[] = { ! 3884: { "help", helphelp, help, 0, 0 }, ! 3885: { "escape", escapehelp, setescape, 1, 0 }, ! 3886: { "crmod", crmodhelp, togcrmod, 1, 0 }, ! 3887: 0 ! 3888: }; ! 3889: ! 3890: /* ! 3891: * Call routine with argc, argv set from args (terminated by 0). ! 3892: * VARARGS2 ! 3893: */ ! 3894: static ! 3895: call(routine, args) ! 3896: int (*routine)(); ! 3897: char *args; ! 3898: { ! 3899: register char **argp; ! 3900: register int argc; ! 3901: ! 3902: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 3903: ; ! 3904: return (*routine)(argc, &args); ! 3905: } ! 3906: ! 3907: static char ** ! 3908: getnextcmd(name) ! 3909: char *name; ! 3910: { ! 3911: struct cmd *c = (struct cmd *) name; ! 3912: ! 3913: return (char **) (c+1); ! 3914: } ! 3915: ! 3916: static struct cmd * ! 3917: getcmd(name) ! 3918: char *name; ! 3919: { ! 3920: struct cmd *cm; ! 3921: ! 3922: if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { ! 3923: return cm; ! 3924: } else { ! 3925: return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); ! 3926: } ! 3927: } ! 3928: ! 3929: void ! 3930: command(top) ! 3931: int top; ! 3932: { ! 3933: register struct cmd *c; ! 3934: ! 3935: setcommandmode(); ! 3936: if (!top) { ! 3937: putchar('\n'); ! 3938: } else { ! 3939: #if defined(unix) ! 3940: signal(SIGINT, SIG_DFL); ! 3941: signal(SIGQUIT, SIG_DFL); ! 3942: #endif /* defined(unix) */ ! 3943: } ! 3944: for (;;) { ! 3945: printf("%s> ", prompt); ! 3946: if (gets(line) == NULL) { ! 3947: if (feof(stdin) || ferror(stdin)) ! 3948: quit(); ! 3949: break; ! 3950: } ! 3951: if (line[0] == 0) ! 3952: break; ! 3953: makeargv(); ! 3954: c = getcmd(margv[0]); ! 3955: if (c == Ambiguous(struct cmd *)) { ! 3956: printf("?Ambiguous command\n"); ! 3957: continue; ! 3958: } ! 3959: if (c == 0) { ! 3960: printf("?Invalid command\n"); ! 3961: continue; ! 3962: } ! 3963: if (c->needconnect && !connected) { ! 3964: printf("?Need to be connected first.\n"); ! 3965: continue; ! 3966: } ! 3967: if ((*c->handler)(margc, margv)) { ! 3968: break; ! 3969: } ! 3970: } ! 3971: if (!top) { ! 3972: if (!connected) { ! 3973: longjmp(toplevel, 1); ! 3974: /*NOTREACHED*/ ! 3975: } ! 3976: #if defined(TN3270) ! 3977: if (shell_active == 0) { ! 3978: setconnmode(); ! 3979: } ! 3980: #else /* defined(TN3270) */ ! 3981: setconnmode(); ! 3982: #endif /* defined(TN3270) */ ! 3983: } ! 3984: } ! 3985: ! 3986: /* ! 3987: * Help command. ! 3988: */ ! 3989: static ! 3990: help(argc, argv) ! 3991: int argc; ! 3992: char *argv[]; ! 3993: { ! 3994: register struct cmd *c; ! 3995: ! 3996: if (argc == 1) { ! 3997: printf("Commands may be abbreviated. Commands are:\n\n"); ! 3998: for (c = cmdtab; c->name; c++) ! 3999: if (c->dohelp) { ! 4000: printf("%-*s\t%s\n", HELPINDENT, c->name, ! 4001: c->help); ! 4002: } ! 4003: return 0; ! 4004: } ! 4005: while (--argc > 0) { ! 4006: register char *arg; ! 4007: arg = *++argv; ! 4008: c = getcmd(arg); ! 4009: if (c == Ambiguous(struct cmd *)) ! 4010: printf("?Ambiguous help command %s\n", arg); ! 4011: else if (c == (struct cmd *)0) ! 4012: printf("?Invalid help command %s\n", arg); ! 4013: else ! 4014: printf("%s\n", c->help); ! 4015: } ! 4016: return 0; ! 4017: } ! 4018: ! 4019: /* ! 4020: * main. Parse arguments, invoke the protocol or command parser. ! 4021: */ ! 4022: ! 4023: ! 4024: void ! 4025: main(argc, argv) ! 4026: int argc; ! 4027: char *argv[]; ! 4028: { ! 4029: tninit(); /* Clear out things */ ! 4030: ! 4031: NetTrace = stdout; ! 4032: TerminalSaveState(); ! 4033: autoflush = TerminalAutoFlush(); ! 4034: ! 4035: prompt = argv[0]; ! 4036: while ((argc > 1) && (argv[1][0] == '-')) { ! 4037: if (!strcmp(argv[1], "-d")) { ! 4038: debug = 1; ! 4039: } else if (!strcmp(argv[1], "-n")) { ! 4040: if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ ! 4041: NetTrace = fopen(argv[2], "w"); ! 4042: argv++; ! 4043: argc--; ! 4044: if (NetTrace == NULL) { ! 4045: NetTrace = stdout; ! 4046: } ! 4047: } ! 4048: } else { ! 4049: #if defined(TN3270) && defined(unix) ! 4050: if (!strcmp(argv[1], "-t")) { ! 4051: if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ ! 4052: transcom = tline; ! 4053: (void) strcpy(transcom, argv[1]); ! 4054: argv++; ! 4055: argc--; ! 4056: } ! 4057: } else if (!strcmp(argv[1], "-noasynch")) { ! 4058: noasynch = 1; ! 4059: } else ! 4060: #endif /* defined(TN3270) && defined(unix) */ ! 4061: if (argv[1][1] != '\0') { ! 4062: fprintf(stderr, "Unknown option *%s*.\n", argv[1]); ! 4063: } ! 4064: } ! 4065: argc--; ! 4066: argv++; ! 4067: } ! 4068: if (argc != 1) { ! 4069: if (setjmp(toplevel) != 0) ! 4070: Exit(0); ! 4071: tn(argc, argv); ! 4072: } ! 4073: setjmp(toplevel); ! 4074: for (;;) { ! 4075: #if !defined(TN3270) ! 4076: command(1); ! 4077: #else /* !defined(TN3270) */ ! 4078: if (!shell_active) { ! 4079: command(1); ! 4080: } else { ! 4081: #if defined(TN3270) ! 4082: shell_continue(); ! 4083: #endif /* defined(TN3270) */ ! 4084: } ! 4085: #endif /* !defined(TN3270) */ ! 4086: } ! 4087: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.