111758Ssam #ifndef lint 2*32377Sminshall static char copyright[] = 3*32377Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\ 421580Sdist All rights reserved.\n"; 5*32377Sminshall #endif /* not lint */ 611758Ssam 721580Sdist #ifndef lint 8*32377Sminshall static char sccsid[] = "@(#)telnet.c 1.2 (Berkeley) 9/25/87"; 9*32377Sminshall #endif /* not lint */ 1021580Sdist 116000Sroot /* 12*32377Sminshall * User telnet program, modified for use by tn3270.c. 1328066Sminshall * 14*32377Sminshall * Many of the FUNCTIONAL changes in this newest version of TELNET 1528066Sminshall * were suggested by Dave Borman of Cray Research, Inc. 16*32377Sminshall * 17*32377Sminshall * Other changes in the tn3270 side come from Alan Crosswell (Columbia), 18*32377Sminshall * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley). 19*32377Sminshall * 20*32377Sminshall * This code is common between telnet(1c) and tn3270(1c). There are the 21*32377Sminshall * following defines used to generate the various versions: 22*32377Sminshall * 23*32377Sminshall * TN3270 - This is to be linked with tn3270. 24*32377Sminshall * 25*32377Sminshall * NOT43 - Allows the program to compile and run on 26*32377Sminshall * a 4.2BSD system. 27*32377Sminshall * 28*32377Sminshall * PUTCHAR - Within tn3270, on a NOT43 system, 29*32377Sminshall * allows the use of the 4.3 curses 30*32377Sminshall * (greater speed updating the screen). 31*32377Sminshall * You need the 4.3 curses for this to work. 32*32377Sminshall * 33*32377Sminshall * FD_SETSIZE - On whichever system, if this isn't defined, 34*32377Sminshall * we patch over the FD_SET, etc., macros with 35*32377Sminshall * some homebrewed ones. 36*32377Sminshall * 37*32377Sminshall * SO_OOBINLINE - This is a socket option which we would like 38*32377Sminshall * to set to allow TCP urgent data to come 39*32377Sminshall * to us "inline". This is NECESSARY for 40*32377Sminshall * CORRECT operation, and desireable for 41*32377Sminshall * simpler operation. 42*32377Sminshall * 43*32377Sminshall * LNOFLSH - Detects the presence of the LNOFLSH bit 44*32377Sminshall * in the tty structure. 45*32377Sminshall * 46*32377Sminshall * unix - Compiles in unix specific stuff. 47*32377Sminshall * 48*32377Sminshall * MSDOS - Compiles in MSDOS specific stuff. 49*32377Sminshall * 506000Sroot */ 5128066Sminshall 529217Ssam #include <sys/types.h> 53*32377Sminshall #include <sys/time.h> 549217Ssam #include <sys/socket.h> 559217Ssam 569217Ssam #include <netinet/in.h> 579217Ssam 58*32377Sminshall #if defined(unix) 59*32377Sminshall /* By the way, we need to include curses.h before telnet.h since, 60*32377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 61*32377Sminshall * declared in curses.h. 62*32377Sminshall */ 63*32377Sminshall #include <curses.h> 64*32377Sminshall #endif /* defined(unix) */ 65*32377Sminshall 6612212Ssam #include <arpa/telnet.h> 67*32377Sminshall 68*32377Sminshall #if !defined(NOT43) 6927186Sminshall #include <arpa/inet.h> 70*32377Sminshall #else /* !defined(NOT43) */ 71*32377Sminshall extern unsigned long inet_addr(); 72*32377Sminshall extern char *inet_ntoa(); 73*32377Sminshall #endif /* !defined(NOT43) */ 7412212Ssam 756000Sroot #include <ctype.h> 766000Sroot #include <errno.h> 778345Ssam #include <netdb.h> 78*32377Sminshall 79*32377Sminshall #if defined(unix) 8027186Sminshall #include <strings.h> 81*32377Sminshall #else /* defined(unix) */ 82*32377Sminshall #include <string.h> 83*32377Sminshall #endif /* defined(unix) */ 849217Ssam 85*32377Sminshall #include "defines.h" 86*32377Sminshall #include "externs.h" 87*32377Sminshall #include "types.h" 88*32377Sminshall #include "general.h" 8927178Sminshall 9027178Sminshall 91*32377Sminshall #if !defined(TN3270) 92*32377Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); } 93*32377Sminshall #define Exit(x) exit(x) 94*32377Sminshall #define SetIn3270() 95*32377Sminshall 96*32377Sminshall void setcommandmode(), command(); /* forward declarations */ 97*32377Sminshall #endif /* !defined(TN3270) */ 98*32377Sminshall 9927676Sminshall #ifndef FD_SETSIZE 10027178Sminshall /* 10127178Sminshall * The following is defined just in case someone should want to run 10227178Sminshall * this telnet on a 4.2 system. 10327178Sminshall * 10427178Sminshall */ 10527178Sminshall 10627676Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 10727676Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 10827676Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 10927676Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 11027178Sminshall 11127178Sminshall #endif 11227178Sminshall 11327228Sminshall #define strip(x) ((x)&0x7f) 114*32377Sminshall #define min(x,y) ((x<y)? x:y) 1156000Sroot 116*32377Sminshall #if defined(TN3270) 117*32377Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 118*32377Sminshall #endif /* defined(TN3270) */ 11927088Sminshall 1206000Sroot 121*32377Sminshall static char subbuffer[SUBBUFSIZE], 122*32377Sminshall *subpointer, *subend; /* buffer for sub-options */ 12327676Sminshall #define SB_CLEAR() subpointer = subbuffer; 12427676Sminshall #define SB_TERM() subend = subpointer; 12527676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 12627676Sminshall *subpointer++ = (c); \ 12727676Sminshall } 12827676Sminshall 129*32377Sminshall static char sb_terminal[] = { IAC, SB, 130*32377Sminshall TELOPT_TTYPE, TELQUAL_IS, 131*32377Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 132*32377Sminshall IAC, SE }; 133*32377Sminshall #define SBTERMMODEL 13 134*32377Sminshall 135*32377Sminshall 1366000Sroot char hisopts[256]; 1376000Sroot char myopts[256]; 1386000Sroot 1396000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 1406000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 1416000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 1426000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 1436000Sroot 144*32377Sminshall static char sibuf[BUFSIZ], *sbp; 145*32377Sminshall static char tibuf[BUFSIZ], *tbp; 146*32377Sminshall static fd_set ibits, obits, xbits; 14727088Sminshall 14827088Sminshall 149*32377Sminshall int 150*32377Sminshall connected, 151*32377Sminshall net, 152*32377Sminshall scc, 153*32377Sminshall tcc, 154*32377Sminshall showoptions, 155*32377Sminshall In3270, /* Are we in 3270 mode? */ 156*32377Sminshall ISend, /* trying to send network data in */ 157*32377Sminshall debug = 0, 158*32377Sminshall crmod, 159*32377Sminshall netdata, /* Print out network data flow */ 160*32377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 161*32377Sminshall noasynch = 0, /* User specified "-noasynch" on command line */ 162*32377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 163*32377Sminshall telnetport = 1; 16427088Sminshall 165*32377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 1666000Sroot 167*32377Sminshall char 168*32377Sminshall *prompt = 0, 169*32377Sminshall escape, 170*32377Sminshall echoc; 17127186Sminshall 172*32377Sminshall int 173*32377Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 174*32377Sminshall flushout, /* flush output */ 175*32377Sminshall autoflush = 0, /* flush output when interrupting? */ 176*32377Sminshall autosynch, /* send interrupt characters with SYNCH? */ 177*32377Sminshall localchars, /* we recognize interrupt/quit */ 178*32377Sminshall donelclchars, /* the user has set "localchars" */ 179*32377Sminshall donebinarytoggle, /* the user has put us in binary */ 180*32377Sminshall dontlecho, /* do we suppress local echoing right now? */ 181*32377Sminshall globalmode; 1826000Sroot 183*32377Sminshall /* The following are some tn3270 specific flags */ 184*32377Sminshall #if defined(TN3270) 1856000Sroot 186*32377Sminshall static int 187*32377Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 1886000Sroot 189*32377Sminshall #endif /* defined(TN3270) */ 19027186Sminshall int 19127186Sminshall 192*32377Sminshall tout, /* Output file descriptor */ 193*32377Sminshall tin; /* Input file descriptor */ 19427186Sminshall 19527186Sminshall 19627186Sminshall 19727186Sminshall /* 1986000Sroot * Telnet receiver states for fsm 1996000Sroot */ 2006000Sroot #define TS_DATA 0 2016000Sroot #define TS_IAC 1 2026000Sroot #define TS_WILL 2 2036000Sroot #define TS_WONT 3 2046000Sroot #define TS_DO 4 2056000Sroot #define TS_DONT 5 20627021Sminshall #define TS_CR 6 20727676Sminshall #define TS_SB 7 /* sub-option collection */ 20827676Sminshall #define TS_SE 8 /* looking for sub-option end */ 2096000Sroot 210*32377Sminshall static int telrcv_state; 2116000Sroot 212*32377Sminshall jmp_buf toplevel = { 0 }; 213*32377Sminshall jmp_buf peerdied; 2146000Sroot 215*32377Sminshall int flushline; 21627021Sminshall 217*32377Sminshall /* 218*32377Sminshall * The following are some clocks used to decide how to interpret 219*32377Sminshall * the relationship between various variables. 220*32377Sminshall */ 2216000Sroot 222*32377Sminshall Clocks clocks; 223*32377Sminshall 224*32377Sminshall Modelist modelist[] = { 225*32377Sminshall { "telnet command mode", COMMAND_LINE }, 226*32377Sminshall { "character-at-a-time mode", 0 }, 227*32377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 228*32377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 229*32377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 230*32377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 231*32377Sminshall { "3270 mode", 0 }, 232*32377Sminshall }; 2336000Sroot 234*32377Sminshall 235*32377Sminshall /* 236*32377Sminshall * Initialize telnet environment. 237*32377Sminshall */ 2386000Sroot 239*32377Sminshall init_telnet() 240*32377Sminshall { 241*32377Sminshall /* Don't change telnetport */ 242*32377Sminshall SB_CLEAR(); 243*32377Sminshall ClearArray(hisopts); 244*32377Sminshall ClearArray(myopts); 245*32377Sminshall sbp = sibuf; 246*32377Sminshall tbp = tibuf; 2476000Sroot 248*32377Sminshall connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0; 249*32377Sminshall telnetport = 0; 2506000Sroot 251*32377Sminshall #if defined(unix) && defined(TN3270) 252*32377Sminshall HaveInput = 0; 253*32377Sminshall #endif /* defined(unix) && defined(TN3270) */ 2546000Sroot 255*32377Sminshall SYNCHing = 0; 2566000Sroot 257*32377Sminshall errno = 0; 25827676Sminshall 259*32377Sminshall /* Don't change NetTrace */ 2606000Sroot 261*32377Sminshall escape = CONTROL(']'); 262*32377Sminshall echoc = CONTROL('E'); 2636000Sroot 264*32377Sminshall flushline = 1; 265*32377Sminshall telrcv_state = TS_DATA; 266*32377Sminshall } 2676000Sroot 2686000Sroot 269*32377Sminshall void 27027676Sminshall willoption(option, reply) 27127676Sminshall int option, reply; 2726000Sroot { 2736000Sroot char *fmt; 2746000Sroot 2756000Sroot switch (option) { 2766000Sroot 2776000Sroot case TELOPT_ECHO: 278*32377Sminshall # if defined(TN3270) 279*32377Sminshall /* 280*32377Sminshall * The following is a pain in the rear-end. 281*32377Sminshall * Various IBM servers (some versions of Wiscnet, 282*32377Sminshall * possibly Fibronics/Spartacus, and who knows who 283*32377Sminshall * else) will NOT allow us to send "DO SGA" too early 284*32377Sminshall * in the setup proceedings. On the other hand, 285*32377Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 286*32377Sminshall * So, we are stuck. Empirically (but, based on 287*32377Sminshall * a VERY small sample), the IBM servers don't send 288*32377Sminshall * out anything about ECHO, so we postpone our sending 289*32377Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 290*32377Sminshall * DO send). 291*32377Sminshall */ 292*32377Sminshall { 293*32377Sminshall if (askedSGA == 0) { 294*32377Sminshall askedSGA = 1; 295*32377Sminshall if (!hisopts[TELOPT_SGA]) { 296*32377Sminshall willoption(TELOPT_SGA, 0); 297*32377Sminshall } 298*32377Sminshall } 299*32377Sminshall } 300*32377Sminshall /* Fall through */ 301*32377Sminshall case TELOPT_EOR: 302*32377Sminshall case TELOPT_BINARY: 303*32377Sminshall #endif /* defined(TN3270) */ 3046000Sroot case TELOPT_SGA: 30527110Sminshall settimer(modenegotiated); 3066000Sroot hisopts[option] = 1; 3076000Sroot fmt = doopt; 30827110Sminshall setconnmode(); /* possibly set new tty mode */ 3096000Sroot break; 3106000Sroot 3116000Sroot case TELOPT_TM: 31227110Sminshall return; /* Never reply to TM will's/wont's */ 3136000Sroot 3146000Sroot default: 3156000Sroot fmt = dont; 3166000Sroot break; 3176000Sroot } 3186024Ssam sprintf(nfrontp, fmt, option); 3198378Ssam nfrontp += sizeof (dont) - 2; 32027676Sminshall if (reply) 321*32377Sminshall printoption(">SENT", fmt, option, reply); 32227676Sminshall else 323*32377Sminshall printoption("<SENT", fmt, option, reply); 3246000Sroot } 3256000Sroot 326*32377Sminshall void 32727676Sminshall wontoption(option, reply) 32827676Sminshall int option, reply; 3296000Sroot { 3306000Sroot char *fmt; 3316000Sroot 3326000Sroot switch (option) { 3336000Sroot 3346000Sroot case TELOPT_ECHO: 3356000Sroot case TELOPT_SGA: 33627110Sminshall settimer(modenegotiated); 3376000Sroot hisopts[option] = 0; 3386000Sroot fmt = dont; 33927110Sminshall setconnmode(); /* Set new tty mode */ 3406000Sroot break; 3416000Sroot 34227110Sminshall case TELOPT_TM: 34327110Sminshall return; /* Never reply to TM will's/wont's */ 34427110Sminshall 3456000Sroot default: 3466000Sroot fmt = dont; 3476000Sroot } 3486000Sroot sprintf(nfrontp, fmt, option); 3498378Ssam nfrontp += sizeof (doopt) - 2; 35027676Sminshall if (reply) 351*32377Sminshall printoption(">SENT", fmt, option, reply); 35227676Sminshall else 353*32377Sminshall printoption("<SENT", fmt, option, reply); 3546000Sroot } 3556000Sroot 356*32377Sminshall static void 3576000Sroot dooption(option) 3586000Sroot int option; 3596000Sroot { 3606000Sroot char *fmt; 3616000Sroot 3626000Sroot switch (option) { 3636000Sroot 3646000Sroot case TELOPT_TM: 36513231Ssam fmt = will; 36613231Ssam break; 36713231Ssam 368*32377Sminshall # if defined(TN3270) 369*32377Sminshall case TELOPT_EOR: 370*32377Sminshall case TELOPT_BINARY: 371*32377Sminshall # endif /* defined(TN3270) */ 37227676Sminshall case TELOPT_TTYPE: /* terminal type option */ 37327110Sminshall case TELOPT_SGA: /* no big deal */ 3746000Sroot fmt = will; 37527110Sminshall myopts[option] = 1; 3766000Sroot break; 3776000Sroot 37827110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 3796000Sroot default: 3806000Sroot fmt = wont; 3816000Sroot break; 3826000Sroot } 3836000Sroot sprintf(nfrontp, fmt, option); 3848378Ssam nfrontp += sizeof (doopt) - 2; 385*32377Sminshall printoption(">SENT", fmt, option, 0); 3866000Sroot } 38727676Sminshall 38827676Sminshall /* 38927676Sminshall * suboption() 39027676Sminshall * 39127676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 39227676Sminshall * side. 39327676Sminshall * 39427676Sminshall * Currently we recognize: 39527676Sminshall * 39627676Sminshall * Terminal type, send request. 39727676Sminshall */ 39827676Sminshall 399*32377Sminshall static void 40027676Sminshall suboption() 40127676Sminshall { 402*32377Sminshall printsub("<", subbuffer, subend-subbuffer+1); 40327676Sminshall switch (subbuffer[0]&0xff) { 40427676Sminshall case TELOPT_TTYPE: 40527676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 40627676Sminshall ; 40727676Sminshall } else { 40827676Sminshall char *name; 40927676Sminshall char namebuf[41]; 410*32377Sminshall extern char *getenv(); 41127676Sminshall int len; 41227676Sminshall 413*32377Sminshall #if defined(TN3270) 414*32377Sminshall /* 415*32377Sminshall * Try to send a 3270 type terminal name. Decide which one based 416*32377Sminshall * on the format of our screen, and (in the future) color 417*32377Sminshall * capaiblities. 418*32377Sminshall */ 419*32377Sminshall #if defined(unix) 420*32377Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 421*32377Sminshall MaxNumberLines = LINES; 422*32377Sminshall MaxNumberColumns = COLS; 423*32377Sminshall } 424*32377Sminshall #else /* defined(unix) */ 425*32377Sminshall InitTerminal(); 426*32377Sminshall #endif /* defined(unix) */ 427*32377Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 428*32377Sminshall Sent3270TerminalType = 1; 429*32377Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 430*32377Sminshall MaxNumberLines = 27; 431*32377Sminshall MaxNumberColumns = 132; 432*32377Sminshall sb_terminal[SBTERMMODEL] = '5'; 433*32377Sminshall } else if (MaxNumberLines >= 43) { 434*32377Sminshall MaxNumberLines = 43; 435*32377Sminshall MaxNumberColumns = 80; 436*32377Sminshall sb_terminal[SBTERMMODEL] = '4'; 437*32377Sminshall } else if (MaxNumberLines >= 32) { 438*32377Sminshall MaxNumberLines = 32; 439*32377Sminshall MaxNumberColumns = 80; 440*32377Sminshall sb_terminal[SBTERMMODEL] = '3'; 441*32377Sminshall } else { 442*32377Sminshall MaxNumberLines = 24; 443*32377Sminshall MaxNumberColumns = 80; 444*32377Sminshall sb_terminal[SBTERMMODEL] = '2'; 445*32377Sminshall } 446*32377Sminshall NumberLines = 24; /* before we start out... */ 447*32377Sminshall NumberColumns = 80; 448*32377Sminshall ScreenSize = NumberLines*NumberColumns; 449*32377Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 450*32377Sminshall ExitString(stderr, 451*32377Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 452*32377Sminshall /*NOTREACHED*/ 453*32377Sminshall } 454*32377Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 455*32377Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 456*32377Sminshall nfrontp += sizeof sb_terminal; 457*32377Sminshall return; 458*32377Sminshall } 459*32377Sminshall #endif /* defined(TN3270) */ 460*32377Sminshall 46127676Sminshall name = getenv("TERM"); 46227676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 46327676Sminshall name = "UNKNOWN"; 46427676Sminshall } 46527676Sminshall if ((len + 4+2) < NETROOM()) { 46627676Sminshall strcpy(namebuf, name); 46727676Sminshall upcase(namebuf); 46827676Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 46927676Sminshall TELQUAL_IS, namebuf, IAC, SE); 470*32377Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 47127676Sminshall nfrontp += 4+strlen(namebuf)+2; 472*32377Sminshall } else { 473*32377Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 474*32377Sminshall 1); 475*32377Sminshall /*NOTREACHED*/ 47627676Sminshall } 47727676Sminshall } 47827676Sminshall 47927676Sminshall default: 48027676Sminshall break; 48127676Sminshall } 48227676Sminshall } 48327088Sminshall 484*32377Sminshall #if defined(TN3270) 485*32377Sminshall static void 486*32377Sminshall SetIn3270() 48727088Sminshall { 488*32377Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 489*32377Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 490*32377Sminshall if (!In3270) { 491*32377Sminshall In3270 = 1; 492*32377Sminshall Init3270(); /* Initialize 3270 functions */ 493*32377Sminshall /* initialize terminal key mapping */ 494*32377Sminshall InitTerminal(); /* Start terminal going */ 495*32377Sminshall setconnmode(); 496*32377Sminshall } 497*32377Sminshall } else { 498*32377Sminshall if (In3270) { 499*32377Sminshall StopScreen(1); 500*32377Sminshall In3270 = 0; 501*32377Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 502*32377Sminshall setconnmode(); 503*32377Sminshall } 50427228Sminshall } 50527088Sminshall } 506*32377Sminshall #endif /* defined(TN3270) */ 507*32377Sminshall 50827088Sminshall 509*32377Sminshall static void 510*32377Sminshall telrcv() 51127110Sminshall { 512*32377Sminshall register int c; 513*32377Sminshall static int telrcv_state = TS_DATA; 514*32377Sminshall # if defined(TN3270) 515*32377Sminshall register int Scc; 516*32377Sminshall register char *Sbp; 517*32377Sminshall # endif /* defined(TN3270) */ 51827088Sminshall 519*32377Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 520*32377Sminshall c = *sbp++ & 0xff, scc--; 521*32377Sminshall switch (telrcv_state) { 52227110Sminshall 523*32377Sminshall case TS_CR: 524*32377Sminshall telrcv_state = TS_DATA; 525*32377Sminshall if (c == '\0') { 526*32377Sminshall break; /* Ignore \0 after CR */ 527*32377Sminshall } else if (c == '\n') { 528*32377Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 529*32377Sminshall TTYADD(c); 530*32377Sminshall } 531*32377Sminshall break; 532*32377Sminshall } 533*32377Sminshall /* Else, fall through */ 53427088Sminshall 535*32377Sminshall case TS_DATA: 536*32377Sminshall if (c == IAC) { 537*32377Sminshall telrcv_state = TS_IAC; 538*32377Sminshall continue; 539*32377Sminshall } 540*32377Sminshall # if defined(TN3270) 541*32377Sminshall if (In3270) { 542*32377Sminshall *Ifrontp++ = c; 543*32377Sminshall Sbp = sbp; 544*32377Sminshall Scc = scc; 545*32377Sminshall while (Scc > 0) { 546*32377Sminshall c = *Sbp++ & 0377, Scc--; 547*32377Sminshall if (c == IAC) { 548*32377Sminshall telrcv_state = TS_IAC; 549*32377Sminshall break; 550*32377Sminshall } 551*32377Sminshall *Ifrontp++ = c; 552*32377Sminshall } 553*32377Sminshall sbp = Sbp; 554*32377Sminshall scc = Scc; 555*32377Sminshall } else 556*32377Sminshall # endif /* defined(TN3270) */ 557*32377Sminshall /* 558*32377Sminshall * The 'crmod' hack (see following) is needed 559*32377Sminshall * since we can't * set CRMOD on output only. 560*32377Sminshall * Machines like MULTICS like to send \r without 561*32377Sminshall * \n; since we must turn off CRMOD to get proper 562*32377Sminshall * input, the mapping is done here (sigh). 563*32377Sminshall */ 564*32377Sminshall if ((c == '\r') && !hisopts[TELOPT_BINARY]) { 565*32377Sminshall if (scc > 0) { 566*32377Sminshall c = *sbp&0xff; 567*32377Sminshall if (c == 0) { 568*32377Sminshall sbp++, scc--; 569*32377Sminshall /* a "true" CR */ 570*32377Sminshall TTYADD('\r'); 571*32377Sminshall } else if (!hisopts[TELOPT_ECHO] && 572*32377Sminshall (c == '\n')) { 573*32377Sminshall sbp++, scc--; 574*32377Sminshall TTYADD('\n'); 575*32377Sminshall } else { 576*32377Sminshall TTYADD('\r'); 577*32377Sminshall if (crmod) { 578*32377Sminshall TTYADD('\n'); 579*32377Sminshall } 580*32377Sminshall } 581*32377Sminshall } else { 582*32377Sminshall telrcv_state = TS_CR; 583*32377Sminshall TTYADD('\r'); 584*32377Sminshall if (crmod) { 585*32377Sminshall TTYADD('\n'); 586*32377Sminshall } 587*32377Sminshall } 588*32377Sminshall } else { 589*32377Sminshall TTYADD(c); 590*32377Sminshall } 591*32377Sminshall continue; 59227088Sminshall 593*32377Sminshall case TS_IAC: 594*32377Sminshall switch (c) { 595*32377Sminshall 596*32377Sminshall case WILL: 597*32377Sminshall telrcv_state = TS_WILL; 598*32377Sminshall continue; 59927261Sminshall 600*32377Sminshall case WONT: 601*32377Sminshall telrcv_state = TS_WONT; 602*32377Sminshall continue; 60327261Sminshall 604*32377Sminshall case DO: 605*32377Sminshall telrcv_state = TS_DO; 606*32377Sminshall continue; 60727261Sminshall 608*32377Sminshall case DONT: 609*32377Sminshall telrcv_state = TS_DONT; 610*32377Sminshall continue; 61127261Sminshall 612*32377Sminshall case DM: 613*32377Sminshall /* 614*32377Sminshall * We may have missed an urgent notification, 615*32377Sminshall * so make sure we flush whatever is in the 616*32377Sminshall * buffer currently. 617*32377Sminshall */ 618*32377Sminshall SYNCHing = 1; 619*32377Sminshall ttyflush(1); 620*32377Sminshall SYNCHing = stilloob(net); 621*32377Sminshall settimer(gotDM); 622*32377Sminshall break; 62327088Sminshall 624*32377Sminshall case NOP: 625*32377Sminshall case GA: 626*32377Sminshall break; 62727088Sminshall 628*32377Sminshall case SB: 629*32377Sminshall SB_CLEAR(); 630*32377Sminshall telrcv_state = TS_SB; 631*32377Sminshall continue; 63227261Sminshall 633*32377Sminshall # if defined(TN3270) 634*32377Sminshall case EOR: 635*32377Sminshall if (In3270) { 636*32377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 637*32377Sminshall if (Ibackp == Ifrontp) { 638*32377Sminshall Ibackp = Ifrontp = Ibuf; 639*32377Sminshall ISend = 0; /* should have been! */ 640*32377Sminshall } else { 641*32377Sminshall ISend = 1; 64227088Sminshall } 64327088Sminshall } 64427088Sminshall break; 645*32377Sminshall # endif /* defined(TN3270) */ 646*32377Sminshall 647*32377Sminshall case IAC: 648*32377Sminshall # if !defined(TN3270) 649*32377Sminshall TTYADD(IAC); 650*32377Sminshall # else /* !defined(TN3270) */ 651*32377Sminshall if (In3270) { 652*32377Sminshall *Ifrontp++ = IAC; 653*32377Sminshall } else { 654*32377Sminshall TTYADD(IAC); 655*32377Sminshall } 656*32377Sminshall # endif /* !defined(TN3270) */ 65727088Sminshall break; 658*32377Sminshall 65927088Sminshall default: 66027088Sminshall break; 66127088Sminshall } 662*32377Sminshall telrcv_state = TS_DATA; 663*32377Sminshall continue; 66427088Sminshall 665*32377Sminshall case TS_WILL: 666*32377Sminshall printoption(">RCVD", will, c, !hisopts[c]); 667*32377Sminshall if (c == TELOPT_TM) { 668*32377Sminshall if (flushout) { 669*32377Sminshall flushout = 0; 670*32377Sminshall } 671*32377Sminshall } else if (!hisopts[c]) { 672*32377Sminshall willoption(c, 1); 673*32377Sminshall } 674*32377Sminshall SetIn3270(); 675*32377Sminshall telrcv_state = TS_DATA; 676*32377Sminshall continue; 67727110Sminshall 678*32377Sminshall case TS_WONT: 679*32377Sminshall printoption(">RCVD", wont, c, hisopts[c]); 680*32377Sminshall if (c == TELOPT_TM) { 681*32377Sminshall if (flushout) { 682*32377Sminshall flushout = 0; 683*32377Sminshall } 684*32377Sminshall } else if (hisopts[c]) { 685*32377Sminshall wontoption(c, 1); 686*32377Sminshall } 687*32377Sminshall SetIn3270(); 688*32377Sminshall telrcv_state = TS_DATA; 689*32377Sminshall continue; 69027088Sminshall 691*32377Sminshall case TS_DO: 692*32377Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 693*32377Sminshall if (!myopts[c]) 694*32377Sminshall dooption(c); 695*32377Sminshall SetIn3270(); 696*32377Sminshall telrcv_state = TS_DATA; 697*32377Sminshall continue; 69827088Sminshall 699*32377Sminshall case TS_DONT: 700*32377Sminshall printoption(">RCVD", dont, c, myopts[c]); 701*32377Sminshall if (myopts[c]) { 702*32377Sminshall myopts[c] = 0; 703*32377Sminshall sprintf(nfrontp, wont, c); 704*32377Sminshall nfrontp += sizeof (wont) - 2; 705*32377Sminshall flushline = 1; 706*32377Sminshall setconnmode(); /* set new tty mode (maybe) */ 707*32377Sminshall printoption(">SENT", wont, c, 0); 708*32377Sminshall } 709*32377Sminshall SetIn3270(); 710*32377Sminshall telrcv_state = TS_DATA; 711*32377Sminshall continue; 71227088Sminshall 713*32377Sminshall case TS_SB: 714*32377Sminshall if (c == IAC) { 715*32377Sminshall telrcv_state = TS_SE; 716*32377Sminshall } else { 717*32377Sminshall SB_ACCUM(c); 718*32377Sminshall } 719*32377Sminshall continue; 72027088Sminshall 721*32377Sminshall case TS_SE: 722*32377Sminshall if (c != SE) { 723*32377Sminshall if (c != IAC) { 724*32377Sminshall SB_ACCUM(IAC); 725*32377Sminshall } 726*32377Sminshall SB_ACCUM(c); 727*32377Sminshall telrcv_state = TS_SB; 728*32377Sminshall } else { 729*32377Sminshall SB_TERM(); 730*32377Sminshall suboption(); /* handle sub-option */ 731*32377Sminshall SetIn3270(); 732*32377Sminshall telrcv_state = TS_DATA; 733*32377Sminshall } 73427088Sminshall } 73527088Sminshall } 73627088Sminshall } 737*32377Sminshall 738*32377Sminshall #if defined(TN3270) 739*32377Sminshall static void 740*32377Sminshall SetForExit() 741*32377Sminshall { 742*32377Sminshall setconnmode(); 743*32377Sminshall if (In3270) { 744*32377Sminshall Finish3270(); 745*32377Sminshall } 746*32377Sminshall setcommandmode(); 747*32377Sminshall fflush(stdout); 748*32377Sminshall fflush(stderr); 749*32377Sminshall if (In3270) { 750*32377Sminshall StopScreen(1); 751*32377Sminshall } 752*32377Sminshall setconnmode(); 753*32377Sminshall setcommandmode(); 754*32377Sminshall } 75527088Sminshall 756*32377Sminshall static void 757*32377Sminshall Exit(returnCode) 758*32377Sminshall int returnCode; 75927088Sminshall { 760*32377Sminshall SetForExit(); 761*32377Sminshall exit(returnCode); 76227088Sminshall } 76327088Sminshall 764*32377Sminshall void 765*32377Sminshall ExitString(file, string, returnCode) 766*32377Sminshall FILE *file; 767*32377Sminshall char *string; 768*32377Sminshall int returnCode; 76927088Sminshall { 770*32377Sminshall SetForExit(); 771*32377Sminshall fwrite(string, 1, strlen(string), file); 772*32377Sminshall exit(returnCode); 77327088Sminshall } 77427088Sminshall 775*32377Sminshall void 776*32377Sminshall ExitPerror(string, returnCode) 777*32377Sminshall char *string; 778*32377Sminshall int returnCode; 77927088Sminshall { 780*32377Sminshall SetForExit(); 781*32377Sminshall perror(string); 782*32377Sminshall exit(returnCode); 783*32377Sminshall } 784*32377Sminshall #endif /* defined(TN3270) */ 78527088Sminshall 78627088Sminshall 78727088Sminshall /* 788*32377Sminshall * Scheduler() 789*32377Sminshall * 790*32377Sminshall * Try to do something. 791*32377Sminshall * 792*32377Sminshall * If we do something useful, return 1; else return 0. 793*32377Sminshall * 79427110Sminshall */ 79527110Sminshall 79627110Sminshall 797*32377Sminshall int 798*32377Sminshall Scheduler(block) 799*32377Sminshall int block; /* should we block in the select ? */ 80027110Sminshall { 801*32377Sminshall register int c; 802*32377Sminshall /* One wants to be a bit careful about setting returnValue 803*32377Sminshall * to one, since a one implies we did some useful work, 804*32377Sminshall * and therefore probably won't be called to block next 805*32377Sminshall * time (TN3270 mode only). 806*32377Sminshall */ 807*32377Sminshall int returnValue = 0; 808*32377Sminshall static struct timeval TimeValue = { 0 }; 80927110Sminshall 810*32377Sminshall if (scc < 0 && tcc < 0) { 811*32377Sminshall return -1; 81227110Sminshall } 81327110Sminshall 814*32377Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 815*32377Sminshall FD_SET(net, &obits); 816*32377Sminshall } 817*32377Sminshall #if !defined(MSDOS) 818*32377Sminshall if (TTYBYTES()) { 819*32377Sminshall FD_SET(tout, &obits); 82027110Sminshall } 821*32377Sminshall #if defined(TN3270) 822*32377Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 823*32377Sminshall FD_SET(tin, &ibits); 82427110Sminshall } 825*32377Sminshall #else /* defined(TN3270) */ 826*32377Sminshall if ((tcc == 0) && NETROOM()) { 827*32377Sminshall FD_SET(tin, &ibits); 82827110Sminshall } 829*32377Sminshall #endif /* defined(TN3270) */ 830*32377Sminshall #endif /* !defined(MSDOS) */ 831*32377Sminshall # if !defined(TN3270) 832*32377Sminshall if (TTYROOM()) { 833*32377Sminshall FD_SET(net, &ibits); 83427110Sminshall } 835*32377Sminshall # else /* !defined(TN3270) */ 836*32377Sminshall if (!ISend && TTYROOM()) { 837*32377Sminshall FD_SET(net, &ibits); 83827110Sminshall } 839*32377Sminshall # endif /* !defined(TN3270) */ 840*32377Sminshall if (!SYNCHing) { 841*32377Sminshall FD_SET(net, &xbits); 842*32377Sminshall } 843*32377Sminshall # if defined(TN3270) && defined(unix) 844*32377Sminshall if (HaveInput) { 845*32377Sminshall HaveInput = 0; 846*32377Sminshall signal(SIGIO, inputAvailable); 847*32377Sminshall } 848*32377Sminshall #endif /* defined(TN3270) && defined(unix) */ 849*32377Sminshall if ((c = select(16, &ibits, &obits, &xbits, 850*32377Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 851*32377Sminshall if (c == -1) { 852*32377Sminshall /* 853*32377Sminshall * we can get EINTR if we are in line mode, 854*32377Sminshall * and the user does an escape (TSTP), or 855*32377Sminshall * some other signal generator. 856*32377Sminshall */ 857*32377Sminshall if (errno == EINTR) { 858*32377Sminshall return 0; 859*32377Sminshall } 860*32377Sminshall # if defined(TN3270) 861*32377Sminshall /* 862*32377Sminshall * we can get EBADF if we were in transparent 863*32377Sminshall * mode, and the transcom process died. 864*32377Sminshall */ 865*32377Sminshall if (errno == EBADF) { 866*32377Sminshall /* 867*32377Sminshall * zero the bits (even though kernel does it) 868*32377Sminshall * to make sure we are selecting on the right 869*32377Sminshall * ones. 870*32377Sminshall */ 871*32377Sminshall FD_ZERO(&ibits); 872*32377Sminshall FD_ZERO(&obits); 873*32377Sminshall FD_ZERO(&xbits); 874*32377Sminshall return 0; 875*32377Sminshall } 876*32377Sminshall # endif /* defined(TN3270) */ 877*32377Sminshall /* I don't like this, does it ever happen? */ 878*32377Sminshall printf("sleep(5) from telnet, after select\r\n"); 879*32377Sminshall #if defined(unix) 880*32377Sminshall sleep(5); 881*32377Sminshall #endif /* defined(unix) */ 88227110Sminshall } 88327261Sminshall return 0; 88427110Sminshall } 885*32377Sminshall 886*32377Sminshall /* 887*32377Sminshall * Any urgent data? 888*32377Sminshall */ 889*32377Sminshall if (FD_ISSET(net, &xbits)) { 890*32377Sminshall FD_CLR(net, &xbits); 891*32377Sminshall SYNCHing = 1; 892*32377Sminshall ttyflush(1); /* flush already enqueued data */ 89327110Sminshall } 89427178Sminshall 895*32377Sminshall /* 896*32377Sminshall * Something to read from the network... 897*32377Sminshall */ 898*32377Sminshall if (FD_ISSET(net, &ibits)) { 899*32377Sminshall int canread; 90027178Sminshall 901*32377Sminshall FD_CLR(net, &ibits); 902*32377Sminshall if (scc == 0) { 903*32377Sminshall sbp = sibuf; 904*32377Sminshall } 905*32377Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 906*32377Sminshall #if !defined(SO_OOBINLINE) 907*32377Sminshall /* 908*32377Sminshall * In 4.2 (and some early 4.3) systems, the 909*32377Sminshall * OOB indication and data handling in the kernel 910*32377Sminshall * is such that if two separate TCP Urgent requests 911*32377Sminshall * come in, one byte of TCP data will be overlaid. 912*32377Sminshall * This is fatal for Telnet, but we try to live 913*32377Sminshall * with it. 914*32377Sminshall * 915*32377Sminshall * In addition, in 4.2 (and...), a special protocol 916*32377Sminshall * is needed to pick up the TCP Urgent data in 917*32377Sminshall * the correct sequence. 918*32377Sminshall * 919*32377Sminshall * What we do is: if we think we are in urgent 920*32377Sminshall * mode, we look to see if we are "at the mark". 921*32377Sminshall * If we are, we do an OOB receive. If we run 922*32377Sminshall * this twice, we will do the OOB receive twice, 923*32377Sminshall * but the second will fail, since the second 924*32377Sminshall * time we were "at the mark", but there wasn't 925*32377Sminshall * any data there (the kernel doesn't reset 926*32377Sminshall * "at the mark" until we do a normal read). 927*32377Sminshall * Once we've read the OOB data, we go ahead 928*32377Sminshall * and do normal reads. 929*32377Sminshall * 930*32377Sminshall * There is also another problem, which is that 931*32377Sminshall * since the OOB byte we read doesn't put us 932*32377Sminshall * out of OOB state, and since that byte is most 933*32377Sminshall * likely the TELNET DM (data mark), we would 934*32377Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 935*32377Sminshall * So, clocks to the rescue. If we've "just" 936*32377Sminshall * received a DM, then we test for the 937*32377Sminshall * presence of OOB data when the receive OOB 938*32377Sminshall * fails (and AFTER we did the normal mode read 939*32377Sminshall * to clear "at the mark"). 940*32377Sminshall */ 941*32377Sminshall if (SYNCHing) { 942*32377Sminshall int atmark; 943*32377Sminshall 944*32377Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 945*32377Sminshall if (atmark) { 946*32377Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 947*32377Sminshall if ((c == -1) && (errno == EINVAL)) { 948*32377Sminshall c = recv(net, sbp+scc, canread, 0); 949*32377Sminshall if (clocks.didnetreceive < clocks.gotDM) { 950*32377Sminshall SYNCHing = stilloob(net); 95127261Sminshall } 952*32377Sminshall } 953*32377Sminshall } else { 954*32377Sminshall c = recv(net, sbp+scc, canread, 0); 955*32377Sminshall } 956*32377Sminshall } else { 957*32377Sminshall c = recv(net, sbp+scc, canread, 0); 958*32377Sminshall } 959*32377Sminshall settimer(didnetreceive); 960*32377Sminshall #else /* !defined(SO_OOBINLINE) */ 961*32377Sminshall c = recv(net, sbp+scc, canread, 0); 962*32377Sminshall #endif /* !defined(SO_OOBINLINE) */ 963*32377Sminshall if (c < 0 && errno == EWOULDBLOCK) { 964*32377Sminshall c = 0; 965*32377Sminshall } else if (c <= 0) { 966*32377Sminshall return -1; 967*32377Sminshall } 968*32377Sminshall if (netdata) { 969*32377Sminshall Dump('<', sbp+scc, c); 970*32377Sminshall } 971*32377Sminshall scc += c; 972*32377Sminshall returnValue = 1; 973*32377Sminshall } 97427178Sminshall 975*32377Sminshall /* 976*32377Sminshall * Something to read from the tty... 977*32377Sminshall */ 978*32377Sminshall #if defined(MSDOS) 979*32377Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 980*32377Sminshall #else /* defined(MSDOS) */ 981*32377Sminshall if (FD_ISSET(tin, &ibits)) 982*32377Sminshall #endif /* defined(MSDOS) */ 983*32377Sminshall { 984*32377Sminshall FD_CLR(tin, &ibits); 985*32377Sminshall if (tcc == 0) { 986*32377Sminshall tbp = tibuf; /* nothing left, reset */ 98727178Sminshall } 988*32377Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 989*32377Sminshall if (c < 0 && errno == EWOULDBLOCK) { 990*32377Sminshall c = 0; 991*32377Sminshall } else { 992*32377Sminshall #if defined(unix) 993*32377Sminshall /* EOF detection for line mode!!!! */ 994*32377Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 995*32377Sminshall /* must be an EOF... */ 996*32377Sminshall *tbp = termEofChar; 997*32377Sminshall c = 1; 998*32377Sminshall } 999*32377Sminshall #endif /* defined(unix) */ 1000*32377Sminshall if (c <= 0) { 1001*32377Sminshall tcc = c; 1002*32377Sminshall return -1; 1003*32377Sminshall } 100427178Sminshall } 1005*32377Sminshall tcc += c; 1006*32377Sminshall returnValue = 1; /* did something useful */ 1007*32377Sminshall } 100827178Sminshall 1009*32377Sminshall # if defined(TN3270) 1010*32377Sminshall if (tcc > 0) { 1011*32377Sminshall if (In3270) { 1012*32377Sminshall c = DataFromTerminal(tbp, tcc); 1013*32377Sminshall if (c) { 1014*32377Sminshall returnValue = 1; 1015*32377Sminshall } 1016*32377Sminshall tcc -= c; 1017*32377Sminshall tbp += c; 1018*32377Sminshall } else { 1019*32377Sminshall # endif /* defined(TN3270) */ 1020*32377Sminshall returnValue = 1; 1021*32377Sminshall while (tcc > 0) { 1022*32377Sminshall register int sc; 1023*32377Sminshall 1024*32377Sminshall if (NETROOM() < 2) { 1025*32377Sminshall flushline = 1; 1026*32377Sminshall break; 102727186Sminshall } 1028*32377Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 1029*32377Sminshall if (sc == escape) { 1030*32377Sminshall command(0); 1031*32377Sminshall tcc = 0; 1032*32377Sminshall flushline = 1; 1033*32377Sminshall break; 1034*32377Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 1035*32377Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 1036*32377Sminshall tbp++; 1037*32377Sminshall tcc--; 1038*32377Sminshall } else { 1039*32377Sminshall dontlecho = !dontlecho; 1040*32377Sminshall settimer(echotoggle); 1041*32377Sminshall setconnmode(); 1042*32377Sminshall tcc = 0; 1043*32377Sminshall flushline = 1; 1044*32377Sminshall break; 1045*32377Sminshall } 104627186Sminshall } 1047*32377Sminshall if (localchars) { 1048*32377Sminshall if (TerminalSpecialChars(sc) == 0) { 1049*32377Sminshall break; 1050*32377Sminshall } 1051*32377Sminshall } 1052*32377Sminshall if (!myopts[TELOPT_BINARY]) { 1053*32377Sminshall switch (c) { 1054*32377Sminshall case '\n': 1055*32377Sminshall /* 1056*32377Sminshall * If we are in CRMOD mode (\r ==> \n) 1057*32377Sminshall * on our local machine, then probably 1058*32377Sminshall * a newline (unix) is CRLF (TELNET). 1059*32377Sminshall */ 1060*32377Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 1061*32377Sminshall NETADD('\r'); 1062*32377Sminshall } 1063*32377Sminshall NETADD('\n'); 1064*32377Sminshall flushline = 1; 1065*32377Sminshall break; 1066*32377Sminshall case '\r': 1067*32377Sminshall if (!crlf) { 1068*32377Sminshall NET2ADD('\r', '\0'); 1069*32377Sminshall } else { 1070*32377Sminshall NET2ADD('\r', '\n'); 1071*32377Sminshall } 1072*32377Sminshall flushline = 1; 1073*32377Sminshall break; 1074*32377Sminshall case IAC: 1075*32377Sminshall NET2ADD(IAC, IAC); 1076*32377Sminshall break; 1077*32377Sminshall default: 1078*32377Sminshall NETADD(c); 1079*32377Sminshall break; 1080*32377Sminshall } 1081*32377Sminshall } else if (c == IAC) { 1082*32377Sminshall NET2ADD(IAC, IAC); 1083*32377Sminshall } else { 1084*32377Sminshall NETADD(c); 1085*32377Sminshall } 108627178Sminshall } 1087*32377Sminshall # if defined(TN3270) 108827178Sminshall } 108927178Sminshall } 1090*32377Sminshall # endif /* defined(TN3270) */ 1091*32377Sminshall 1092*32377Sminshall if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) && 1093*32377Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 1094*32377Sminshall FD_CLR(net, &obits); 1095*32377Sminshall returnValue = netflush(); 1096*32377Sminshall } 1097*32377Sminshall if (scc > 0) { 1098*32377Sminshall # if !defined(TN3270) 1099*32377Sminshall telrcv(); 1100*32377Sminshall returnValue = 1; 1101*32377Sminshall # else /* !defined(TN3270) */ 1102*32377Sminshall returnValue = Push3270(); 1103*32377Sminshall # endif /* !defined(TN3270) */ 1104*32377Sminshall } 1105*32377Sminshall #if defined(MSDOS) 1106*32377Sminshall if (TTYBYTES()) 1107*32377Sminshall #else /* defined(MSDOS) */ 1108*32377Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 1109*32377Sminshall #endif /* defined(MSDOS) */ 1110*32377Sminshall { 1111*32377Sminshall FD_CLR(tout, &obits); 1112*32377Sminshall returnValue = ttyflush(SYNCHing|flushout); 1113*32377Sminshall } 1114*32377Sminshall return returnValue; 111527178Sminshall } 111627178Sminshall 111727178Sminshall /* 1118*32377Sminshall * Select from tty and network... 111927088Sminshall */ 1120*32377Sminshall void 1121*32377Sminshall telnet() 112227088Sminshall { 1123*32377Sminshall #if defined(MSDOS) 1124*32377Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 1125*32377Sminshall #else /* defined(MSDOS) */ 1126*32377Sminshall #define SCHED_BLOCK 1 1127*32377Sminshall #endif /* defined(MSDOS) */ 112827088Sminshall 1129*32377Sminshall #if defined(TN3270) && defined(unix) 1130*32377Sminshall int myPid; 1131*32377Sminshall #endif /* defined(TN3270) */ 113227088Sminshall 1133*32377Sminshall tout = fileno(stdout); 1134*32377Sminshall tin = fileno(stdin); 1135*32377Sminshall setconnmode(); 1136*32377Sminshall scc = 0; 1137*32377Sminshall tcc = 0; 1138*32377Sminshall FD_ZERO(&ibits); 1139*32377Sminshall FD_ZERO(&obits); 1140*32377Sminshall FD_ZERO(&xbits); 114127261Sminshall 1142*32377Sminshall NetNonblockingIO(net, 1); 114327088Sminshall 1144*32377Sminshall #if defined(TN3270) 1145*32377Sminshall if (noasynch == 0) { /* DBX can't handle! */ 1146*32377Sminshall NetSigIO(net, 1); 1147*32377Sminshall } 1148*32377Sminshall NetSetPgrp(net); 1149*32377Sminshall #endif /* defined(TN3270) */ 115027088Sminshall 115127088Sminshall 1152*32377Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 1153*32377Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 1154*32377Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 115527088Sminshall 1156*32377Sminshall # if !defined(TN3270) 1157*32377Sminshall if (telnetport) { 1158*32377Sminshall if (!hisopts[TELOPT_SGA]) { 1159*32377Sminshall willoption(TELOPT_SGA, 0); 116027110Sminshall } 1161*32377Sminshall if (!myopts[TELOPT_TTYPE]) { 1162*32377Sminshall dooption(TELOPT_TTYPE, 0); 1163*32377Sminshall } 116427178Sminshall } 1165*32377Sminshall # endif /* !defined(TN3270) */ 116627088Sminshall 1167*32377Sminshall # if !defined(TN3270) 1168*32377Sminshall for (;;) { 1169*32377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 1170*32377Sminshall setcommandmode(); 1171*32377Sminshall return; 1172*32377Sminshall } 1173*32377Sminshall } 1174*32377Sminshall # else /* !defined(TN3270) */ 1175*32377Sminshall for (;;) { 1176*32377Sminshall int schedValue; 117727088Sminshall 1178*32377Sminshall while (!In3270 && !shell_active) { 1179*32377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 1180*32377Sminshall setcommandmode(); 1181*32377Sminshall return; 1182*32377Sminshall } 118327088Sminshall } 1184*32377Sminshall 1185*32377Sminshall while ((schedValue = Scheduler(0)) != 0) { 1186*32377Sminshall if (schedValue == -1) { 1187*32377Sminshall setcommandmode(); 1188*32377Sminshall return; 1189*32377Sminshall } 119027088Sminshall } 1191*32377Sminshall /* If there is data waiting to go out to terminal, don't 1192*32377Sminshall * schedule any more data for the terminal. 1193*32377Sminshall */ 1194*32377Sminshall if (tfrontp-tbackp) { 1195*32377Sminshall schedValue = 1; 119627088Sminshall } else { 1197*32377Sminshall if (shell_active) { 1198*32377Sminshall if (shell_continue() == 0) { 1199*32377Sminshall ConnectScreen(); 120027088Sminshall } 1201*32377Sminshall } else if (In3270) { 1202*32377Sminshall schedValue = DoTerminalOutput(); 1203*32377Sminshall } 120427088Sminshall } 1205*32377Sminshall if (schedValue && (shell_active == 0)) { 1206*32377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 1207*32377Sminshall setcommandmode(); 1208*32377Sminshall return; 1209*32377Sminshall } 121027088Sminshall } 1211*32377Sminshall } 1212*32377Sminshall # endif /* !defined(TN3270) */ 121327088Sminshall } 1214*32377Sminshall 121527088Sminshall /* 1216*32377Sminshall * These routines add various telnet commands to the data stream. 121727088Sminshall */ 1218*32377Sminshall 1219*32377Sminshall void 1220*32377Sminshall xmitAO() 122127088Sminshall { 1222*32377Sminshall NET2ADD(IAC, AO); 1223*32377Sminshall if (autoflush) { 1224*32377Sminshall doflush(); 1225*32377Sminshall } 1226*32377Sminshall } 122727088Sminshall 1228*32377Sminshall 1229*32377Sminshall void 1230*32377Sminshall xmitEL() 123127088Sminshall { 1232*32377Sminshall NET2ADD(IAC, EL); 123327088Sminshall } 123427088Sminshall 1235*32377Sminshall void 1236*32377Sminshall xmitEC() 123727088Sminshall { 1238*32377Sminshall NET2ADD(IAC, EC); 123927088Sminshall } 124027088Sminshall 1241*32377Sminshall 1242*32377Sminshall #if defined(NOT43) 1243*32377Sminshall int 1244*32377Sminshall #else /* defined(NOT43) */ 1245*32377Sminshall void 1246*32377Sminshall #endif /* defined(NOT43) */ 1247*32377Sminshall dosynch() 124827088Sminshall { 1249*32377Sminshall netclear(); /* clear the path to the network */ 1250*32377Sminshall NET2ADD(IAC, DM); 125127088Sminshall 1252*32377Sminshall #if defined(NOT43) 1253*32377Sminshall return 0; 1254*32377Sminshall #endif /* defined(NOT43) */ 125527088Sminshall } 125627088Sminshall 1257*32377Sminshall void 1258*32377Sminshall doflush() 125927088Sminshall { 1260*32377Sminshall NET2ADD(IAC, DO); 1261*32377Sminshall NETADD(TELOPT_TM); 1262*32377Sminshall flushline = 1; 1263*32377Sminshall flushout = 1; 1264*32377Sminshall ttyflush(1); /* Flush/drop output */ 1265*32377Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 1266*32377Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 126727088Sminshall } 126827088Sminshall 1269*32377Sminshall void 1270*32377Sminshall intp() 127127088Sminshall { 1272*32377Sminshall NET2ADD(IAC, IP); 1273*32377Sminshall flushline = 1; 1274*32377Sminshall if (autoflush) { 1275*32377Sminshall doflush(); 1276*32377Sminshall } 1277*32377Sminshall if (autosynch) { 1278*32377Sminshall dosynch(); 1279*32377Sminshall } 128027088Sminshall } 128127186Sminshall 1282*32377Sminshall void 1283*32377Sminshall sendbrk() 128427186Sminshall { 1285*32377Sminshall NET2ADD(IAC, BREAK); 1286*32377Sminshall flushline = 1; 1287*32377Sminshall if (autoflush) { 1288*32377Sminshall doflush(); 1289*32377Sminshall } 1290*32377Sminshall if (autosynch) { 1291*32377Sminshall dosynch(); 1292*32377Sminshall } 129327186Sminshall } 1294