111758Ssam #ifndef lint 232377Sminshall static char copyright[] = 332377Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\ 421580Sdist All rights reserved.\n"; 532377Sminshall #endif /* not lint */ 611758Ssam 721580Sdist #ifndef lint 832377Sminshall static char sccsid[] = "@(#)telnet.c 1.2 (Berkeley) 9/25/87"; 932377Sminshall #endif /* not lint */ 1021580Sdist 119217Ssam #include <sys/types.h> 1232377Sminshall #include <sys/time.h> 139217Ssam #include <sys/socket.h> 149217Ssam 159217Ssam #include <netinet/in.h> 169217Ssam 1732377Sminshall #if defined(unix) 1832377Sminshall /* By the way, we need to include curses.h before telnet.h since, 1932377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 2032377Sminshall * declared in curses.h. 2132377Sminshall */ 2232377Sminshall #include <curses.h> 2332377Sminshall #endif /* defined(unix) */ 2432377Sminshall 2512212Ssam #include <arpa/telnet.h> 2632377Sminshall 2732377Sminshall #if !defined(NOT43) 2827186Sminshall #include <arpa/inet.h> 2932377Sminshall #else /* !defined(NOT43) */ 3032377Sminshall extern unsigned long inet_addr(); 3132377Sminshall extern char *inet_ntoa(); 3232377Sminshall #endif /* !defined(NOT43) */ 3312212Ssam 346000Sroot #include <ctype.h> 356000Sroot #include <errno.h> 368345Ssam #include <netdb.h> 3732377Sminshall 3832377Sminshall #if defined(unix) 3927186Sminshall #include <strings.h> 4032377Sminshall #else /* defined(unix) */ 4132377Sminshall #include <string.h> 4232377Sminshall #endif /* defined(unix) */ 439217Ssam 4432381Sminshall #include "ring.h" 4532381Sminshall 4632377Sminshall #include "defines.h" 4732377Sminshall #include "externs.h" 4832377Sminshall #include "types.h" 4932377Sminshall #include "general.h" 5027178Sminshall 5127178Sminshall 5232377Sminshall void setcommandmode(), command(); /* forward declarations */ 5332377Sminshall 5427676Sminshall #ifndef FD_SETSIZE 5527178Sminshall /* 5627178Sminshall * The following is defined just in case someone should want to run 5727178Sminshall * this telnet on a 4.2 system. 5827178Sminshall * 5927178Sminshall */ 6027178Sminshall 6127676Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 6227676Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 6327676Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 6427676Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 6527178Sminshall 6627178Sminshall #endif 6727178Sminshall 6827228Sminshall #define strip(x) ((x)&0x7f) 6932377Sminshall #define min(x,y) ((x<y)? x:y) 706000Sroot 7132377Sminshall #if defined(TN3270) 7232377Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 7332377Sminshall #endif /* defined(TN3270) */ 7427088Sminshall 756000Sroot 7632377Sminshall static char subbuffer[SUBBUFSIZE], 7732377Sminshall *subpointer, *subend; /* buffer for sub-options */ 7827676Sminshall #define SB_CLEAR() subpointer = subbuffer; 7927676Sminshall #define SB_TERM() subend = subpointer; 8027676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 8127676Sminshall *subpointer++ = (c); \ 8227676Sminshall } 8327676Sminshall 8432377Sminshall static char sb_terminal[] = { IAC, SB, 8532377Sminshall TELOPT_TTYPE, TELQUAL_IS, 8632377Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 8732377Sminshall IAC, SE }; 8832377Sminshall #define SBTERMMODEL 13 8932377Sminshall 9032377Sminshall 916000Sroot char hisopts[256]; 926000Sroot char myopts[256]; 936000Sroot 946000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 956000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 966000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 976000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 986000Sroot 99*32385Sminshall static Ring netiring, ttyiring; 100*32385Sminshall static char netibuf[BUFSIZ]; 101*32385Sminshall static char ttyibuf[BUFSIZ]; 10232377Sminshall static fd_set ibits, obits, xbits; 10327088Sminshall 10427088Sminshall 10532377Sminshall int 10632377Sminshall connected, 10732377Sminshall net, 10832377Sminshall showoptions, 10932377Sminshall In3270, /* Are we in 3270 mode? */ 11032377Sminshall ISend, /* trying to send network data in */ 11132377Sminshall debug = 0, 11232377Sminshall crmod, 11332377Sminshall netdata, /* Print out network data flow */ 11432377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 11532377Sminshall noasynch = 0, /* User specified "-noasynch" on command line */ 11632377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 11732377Sminshall telnetport = 1; 11827088Sminshall 11932377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 1206000Sroot 12132377Sminshall char 12232377Sminshall *prompt = 0, 12332377Sminshall escape, 12432377Sminshall echoc; 12527186Sminshall 12632377Sminshall int 12732377Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 12832377Sminshall flushout, /* flush output */ 12932377Sminshall autoflush = 0, /* flush output when interrupting? */ 13032377Sminshall autosynch, /* send interrupt characters with SYNCH? */ 13132377Sminshall localchars, /* we recognize interrupt/quit */ 13232377Sminshall donelclchars, /* the user has set "localchars" */ 13332377Sminshall donebinarytoggle, /* the user has put us in binary */ 13432377Sminshall dontlecho, /* do we suppress local echoing right now? */ 13532377Sminshall globalmode; 1366000Sroot 13732377Sminshall /* The following are some tn3270 specific flags */ 13832377Sminshall #if defined(TN3270) 1396000Sroot 14032377Sminshall static int 14132377Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 1426000Sroot 14332377Sminshall #endif /* defined(TN3270) */ 14427186Sminshall int 14527186Sminshall 14632377Sminshall tout, /* Output file descriptor */ 14732377Sminshall tin; /* Input file descriptor */ 14827186Sminshall 14927186Sminshall 15027186Sminshall 15127186Sminshall /* 1526000Sroot * Telnet receiver states for fsm 1536000Sroot */ 1546000Sroot #define TS_DATA 0 1556000Sroot #define TS_IAC 1 1566000Sroot #define TS_WILL 2 1576000Sroot #define TS_WONT 3 1586000Sroot #define TS_DO 4 1596000Sroot #define TS_DONT 5 16027021Sminshall #define TS_CR 6 16127676Sminshall #define TS_SB 7 /* sub-option collection */ 16227676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1636000Sroot 16432377Sminshall static int telrcv_state; 1656000Sroot 16632377Sminshall jmp_buf toplevel = { 0 }; 16732377Sminshall jmp_buf peerdied; 1686000Sroot 16932377Sminshall int flushline; 17027021Sminshall 17132377Sminshall /* 17232377Sminshall * The following are some clocks used to decide how to interpret 17332377Sminshall * the relationship between various variables. 17432377Sminshall */ 1756000Sroot 17632377Sminshall Clocks clocks; 17732377Sminshall 17832377Sminshall Modelist modelist[] = { 17932377Sminshall { "telnet command mode", COMMAND_LINE }, 18032377Sminshall { "character-at-a-time mode", 0 }, 18132377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 18232377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 18332377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 18432377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 18532377Sminshall { "3270 mode", 0 }, 18632377Sminshall }; 1876000Sroot 18832377Sminshall 18932377Sminshall /* 19032377Sminshall * Initialize telnet environment. 19132377Sminshall */ 1926000Sroot 19332377Sminshall init_telnet() 19432377Sminshall { 19532377Sminshall /* Don't change telnetport */ 19632377Sminshall SB_CLEAR(); 19732377Sminshall ClearArray(hisopts); 19832377Sminshall ClearArray(myopts); 199*32385Sminshall ring_init(&netiring, netibuf, sizeof netibuf); 200*32385Sminshall ring_init(&ttyiring, ttyibuf, sizeof ttyibuf); 2016000Sroot 202*32385Sminshall connected = net = In3270 = ISend = donebinarytoggle = 0; 20332377Sminshall telnetport = 0; 2046000Sroot 20532377Sminshall #if defined(unix) && defined(TN3270) 20632377Sminshall HaveInput = 0; 20732377Sminshall #endif /* defined(unix) && defined(TN3270) */ 2086000Sroot 20932377Sminshall SYNCHing = 0; 2106000Sroot 21132377Sminshall errno = 0; 21227676Sminshall 21332377Sminshall /* Don't change NetTrace */ 2146000Sroot 21532377Sminshall escape = CONTROL(']'); 21632377Sminshall echoc = CONTROL('E'); 2176000Sroot 21832377Sminshall flushline = 1; 21932377Sminshall telrcv_state = TS_DATA; 22032377Sminshall } 2216000Sroot 2226000Sroot 22332377Sminshall void 22427676Sminshall willoption(option, reply) 22527676Sminshall int option, reply; 2266000Sroot { 2276000Sroot char *fmt; 2286000Sroot 2296000Sroot switch (option) { 2306000Sroot 2316000Sroot case TELOPT_ECHO: 23232377Sminshall # if defined(TN3270) 23332377Sminshall /* 23432377Sminshall * The following is a pain in the rear-end. 23532377Sminshall * Various IBM servers (some versions of Wiscnet, 23632377Sminshall * possibly Fibronics/Spartacus, and who knows who 23732377Sminshall * else) will NOT allow us to send "DO SGA" too early 23832377Sminshall * in the setup proceedings. On the other hand, 23932377Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 24032377Sminshall * So, we are stuck. Empirically (but, based on 24132377Sminshall * a VERY small sample), the IBM servers don't send 24232377Sminshall * out anything about ECHO, so we postpone our sending 24332377Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 24432377Sminshall * DO send). 24532377Sminshall */ 24632377Sminshall { 24732377Sminshall if (askedSGA == 0) { 24832377Sminshall askedSGA = 1; 24932377Sminshall if (!hisopts[TELOPT_SGA]) { 25032377Sminshall willoption(TELOPT_SGA, 0); 25132377Sminshall } 25232377Sminshall } 25332377Sminshall } 25432377Sminshall /* Fall through */ 25532377Sminshall case TELOPT_EOR: 25632377Sminshall case TELOPT_BINARY: 25732377Sminshall #endif /* defined(TN3270) */ 2586000Sroot case TELOPT_SGA: 25927110Sminshall settimer(modenegotiated); 2606000Sroot hisopts[option] = 1; 2616000Sroot fmt = doopt; 26227110Sminshall setconnmode(); /* possibly set new tty mode */ 2636000Sroot break; 2646000Sroot 2656000Sroot case TELOPT_TM: 26627110Sminshall return; /* Never reply to TM will's/wont's */ 2676000Sroot 2686000Sroot default: 2696000Sroot fmt = dont; 2706000Sroot break; 2716000Sroot } 27232381Sminshall netoprint(fmt, option); 27327676Sminshall if (reply) 27432377Sminshall printoption(">SENT", fmt, option, reply); 27527676Sminshall else 27632377Sminshall printoption("<SENT", fmt, option, reply); 2776000Sroot } 2786000Sroot 27932377Sminshall void 28027676Sminshall wontoption(option, reply) 28127676Sminshall int option, reply; 2826000Sroot { 2836000Sroot char *fmt; 2846000Sroot 2856000Sroot switch (option) { 2866000Sroot 2876000Sroot case TELOPT_ECHO: 2886000Sroot case TELOPT_SGA: 28927110Sminshall settimer(modenegotiated); 2906000Sroot hisopts[option] = 0; 2916000Sroot fmt = dont; 29227110Sminshall setconnmode(); /* Set new tty mode */ 2936000Sroot break; 2946000Sroot 29527110Sminshall case TELOPT_TM: 29627110Sminshall return; /* Never reply to TM will's/wont's */ 29727110Sminshall 2986000Sroot default: 2996000Sroot fmt = dont; 3006000Sroot } 30132381Sminshall netoprint(fmt, option); 30227676Sminshall if (reply) 30332377Sminshall printoption(">SENT", fmt, option, reply); 30427676Sminshall else 30532377Sminshall printoption("<SENT", fmt, option, reply); 3066000Sroot } 3076000Sroot 30832377Sminshall static void 3096000Sroot dooption(option) 3106000Sroot int option; 3116000Sroot { 3126000Sroot char *fmt; 3136000Sroot 3146000Sroot switch (option) { 3156000Sroot 3166000Sroot case TELOPT_TM: 31713231Ssam fmt = will; 31813231Ssam break; 31913231Ssam 32032377Sminshall # if defined(TN3270) 32132377Sminshall case TELOPT_EOR: 32232377Sminshall case TELOPT_BINARY: 32332377Sminshall # endif /* defined(TN3270) */ 32427676Sminshall case TELOPT_TTYPE: /* terminal type option */ 32527110Sminshall case TELOPT_SGA: /* no big deal */ 3266000Sroot fmt = will; 32727110Sminshall myopts[option] = 1; 3286000Sroot break; 3296000Sroot 33027110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 3316000Sroot default: 3326000Sroot fmt = wont; 3336000Sroot break; 3346000Sroot } 33532381Sminshall netoprint(fmt, option); 33632377Sminshall printoption(">SENT", fmt, option, 0); 3376000Sroot } 33827676Sminshall 33927676Sminshall /* 34027676Sminshall * suboption() 34127676Sminshall * 34227676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 34327676Sminshall * side. 34427676Sminshall * 34527676Sminshall * Currently we recognize: 34627676Sminshall * 34727676Sminshall * Terminal type, send request. 34827676Sminshall */ 34927676Sminshall 35032377Sminshall static void 35127676Sminshall suboption() 35227676Sminshall { 35332377Sminshall printsub("<", subbuffer, subend-subbuffer+1); 35427676Sminshall switch (subbuffer[0]&0xff) { 35527676Sminshall case TELOPT_TTYPE: 35627676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 35727676Sminshall ; 35827676Sminshall } else { 35927676Sminshall char *name; 36027676Sminshall char namebuf[41]; 36132377Sminshall extern char *getenv(); 36227676Sminshall int len; 36327676Sminshall 36432377Sminshall #if defined(TN3270) 36532377Sminshall /* 36632377Sminshall * Try to send a 3270 type terminal name. Decide which one based 36732377Sminshall * on the format of our screen, and (in the future) color 36832377Sminshall * capaiblities. 36932377Sminshall */ 37032377Sminshall #if defined(unix) 37132377Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 37232377Sminshall MaxNumberLines = LINES; 37332377Sminshall MaxNumberColumns = COLS; 37432377Sminshall } 37532377Sminshall #else /* defined(unix) */ 37632377Sminshall InitTerminal(); 37732377Sminshall #endif /* defined(unix) */ 37832377Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 37932377Sminshall Sent3270TerminalType = 1; 38032377Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 38132377Sminshall MaxNumberLines = 27; 38232377Sminshall MaxNumberColumns = 132; 38332377Sminshall sb_terminal[SBTERMMODEL] = '5'; 38432377Sminshall } else if (MaxNumberLines >= 43) { 38532377Sminshall MaxNumberLines = 43; 38632377Sminshall MaxNumberColumns = 80; 38732377Sminshall sb_terminal[SBTERMMODEL] = '4'; 38832377Sminshall } else if (MaxNumberLines >= 32) { 38932377Sminshall MaxNumberLines = 32; 39032377Sminshall MaxNumberColumns = 80; 39132377Sminshall sb_terminal[SBTERMMODEL] = '3'; 39232377Sminshall } else { 39332377Sminshall MaxNumberLines = 24; 39432377Sminshall MaxNumberColumns = 80; 39532377Sminshall sb_terminal[SBTERMMODEL] = '2'; 39632377Sminshall } 39732377Sminshall NumberLines = 24; /* before we start out... */ 39832377Sminshall NumberColumns = 80; 39932377Sminshall ScreenSize = NumberLines*NumberColumns; 40032377Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 40132381Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 40232381Sminshall 1); 40332377Sminshall /*NOTREACHED*/ 40432377Sminshall } 40532381Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 40632381Sminshall ring_add_data(&netoring, sb_terminal, sizeof sb_terminal); 40732377Sminshall return; 40832377Sminshall } 40932377Sminshall #endif /* defined(TN3270) */ 41032377Sminshall 41127676Sminshall name = getenv("TERM"); 41227676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 41327676Sminshall name = "UNKNOWN"; 41427676Sminshall } 41527676Sminshall if ((len + 4+2) < NETROOM()) { 41627676Sminshall strcpy(namebuf, name); 41727676Sminshall upcase(namebuf); 41832381Sminshall netoprint("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 41927676Sminshall TELQUAL_IS, namebuf, IAC, SE); 42032381Sminshall /* XXX */ 42132381Sminshall /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */ 42232377Sminshall } else { 42332381Sminshall ExitString("No room in buffer for terminal type.\n", 42432377Sminshall 1); 42532377Sminshall /*NOTREACHED*/ 42627676Sminshall } 42727676Sminshall } 42827676Sminshall 42927676Sminshall default: 43027676Sminshall break; 43127676Sminshall } 43227676Sminshall } 43327088Sminshall 43432377Sminshall #if defined(TN3270) 43532377Sminshall static void 43632377Sminshall SetIn3270() 43727088Sminshall { 43832377Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 43932377Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 44032377Sminshall if (!In3270) { 44132377Sminshall In3270 = 1; 44232377Sminshall Init3270(); /* Initialize 3270 functions */ 44332377Sminshall /* initialize terminal key mapping */ 44432377Sminshall InitTerminal(); /* Start terminal going */ 44532377Sminshall setconnmode(); 44632377Sminshall } 44732377Sminshall } else { 44832377Sminshall if (In3270) { 44932377Sminshall StopScreen(1); 45032377Sminshall In3270 = 0; 45132377Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 45232377Sminshall setconnmode(); 45332377Sminshall } 45427228Sminshall } 45527088Sminshall } 45632377Sminshall #endif /* defined(TN3270) */ 45732377Sminshall 45827088Sminshall 459*32385Sminshall static int 46032377Sminshall telrcv() 46127110Sminshall { 46232377Sminshall register int c; 463*32385Sminshall register int scc; 464*32385Sminshall register char *sbp; 465*32385Sminshall int count; 466*32385Sminshall int returnValue = 0; 46727088Sminshall 468*32385Sminshall scc = 0; 469*32385Sminshall count = 0; 470*32385Sminshall while (TTYROOM() > 2) { 471*32385Sminshall if (scc == 0) { 472*32385Sminshall if (count) { 473*32385Sminshall ring_sent_acked(&netiring, count); 474*32385Sminshall returnValue = 1; 475*32385Sminshall count = 0; 476*32385Sminshall } 477*32385Sminshall sbp = netiring.send; 478*32385Sminshall scc = ring_unsent_consecutive(&netiring); 479*32385Sminshall if (scc == 0) { 480*32385Sminshall /* No more data coming in */ 481*32385Sminshall break; 482*32385Sminshall } 483*32385Sminshall } 484*32385Sminshall 485*32385Sminshall c = *sbp++ & 0xff, scc--; count++; 486*32385Sminshall 48732377Sminshall switch (telrcv_state) { 48827110Sminshall 48932377Sminshall case TS_CR: 49032377Sminshall telrcv_state = TS_DATA; 49132377Sminshall if (c == '\0') { 49232377Sminshall break; /* Ignore \0 after CR */ 49332377Sminshall } else if (c == '\n') { 49432377Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 49532377Sminshall TTYADD(c); 49632377Sminshall } 49732377Sminshall break; 49832377Sminshall } 49932377Sminshall /* Else, fall through */ 50027088Sminshall 50132377Sminshall case TS_DATA: 50232377Sminshall if (c == IAC) { 50332377Sminshall telrcv_state = TS_IAC; 50432377Sminshall continue; 50532377Sminshall } 50632377Sminshall # if defined(TN3270) 50732377Sminshall if (In3270) { 50832377Sminshall *Ifrontp++ = c; 509*32385Sminshall while (scc > 0) { 510*32385Sminshall c = *sbp++ & 0377, scc--; count++; 51132377Sminshall if (c == IAC) { 51232377Sminshall telrcv_state = TS_IAC; 51332377Sminshall break; 51432377Sminshall } 51532377Sminshall *Ifrontp++ = c; 51632377Sminshall } 51732377Sminshall } else 51832377Sminshall # endif /* defined(TN3270) */ 51932377Sminshall /* 52032377Sminshall * The 'crmod' hack (see following) is needed 52132377Sminshall * since we can't * set CRMOD on output only. 52232377Sminshall * Machines like MULTICS like to send \r without 52332377Sminshall * \n; since we must turn off CRMOD to get proper 52432377Sminshall * input, the mapping is done here (sigh). 52532377Sminshall */ 52632377Sminshall if ((c == '\r') && !hisopts[TELOPT_BINARY]) { 52732377Sminshall if (scc > 0) { 52832377Sminshall c = *sbp&0xff; 52932377Sminshall if (c == 0) { 530*32385Sminshall sbp++, scc--; count++; 53132377Sminshall /* a "true" CR */ 53232377Sminshall TTYADD('\r'); 53332377Sminshall } else if (!hisopts[TELOPT_ECHO] && 53432377Sminshall (c == '\n')) { 535*32385Sminshall sbp++, scc--; count++; 53632377Sminshall TTYADD('\n'); 53732377Sminshall } else { 53832377Sminshall TTYADD('\r'); 53932377Sminshall if (crmod) { 54032377Sminshall TTYADD('\n'); 54132377Sminshall } 54232377Sminshall } 54332377Sminshall } else { 54432377Sminshall telrcv_state = TS_CR; 54532377Sminshall TTYADD('\r'); 54632377Sminshall if (crmod) { 54732377Sminshall TTYADD('\n'); 54832377Sminshall } 54932377Sminshall } 55032377Sminshall } else { 55132377Sminshall TTYADD(c); 55232377Sminshall } 55332377Sminshall continue; 55427088Sminshall 55532377Sminshall case TS_IAC: 55632377Sminshall switch (c) { 55732377Sminshall 55832377Sminshall case WILL: 55932377Sminshall telrcv_state = TS_WILL; 56032377Sminshall continue; 56127261Sminshall 56232377Sminshall case WONT: 56332377Sminshall telrcv_state = TS_WONT; 56432377Sminshall continue; 56527261Sminshall 56632377Sminshall case DO: 56732377Sminshall telrcv_state = TS_DO; 56832377Sminshall continue; 56927261Sminshall 57032377Sminshall case DONT: 57132377Sminshall telrcv_state = TS_DONT; 57232377Sminshall continue; 57327261Sminshall 57432377Sminshall case DM: 57532377Sminshall /* 57632377Sminshall * We may have missed an urgent notification, 57732377Sminshall * so make sure we flush whatever is in the 57832377Sminshall * buffer currently. 57932377Sminshall */ 58032377Sminshall SYNCHing = 1; 58132377Sminshall ttyflush(1); 58232377Sminshall SYNCHing = stilloob(net); 58332377Sminshall settimer(gotDM); 58432377Sminshall break; 58527088Sminshall 58632377Sminshall case NOP: 58732377Sminshall case GA: 58832377Sminshall break; 58927088Sminshall 59032377Sminshall case SB: 59132377Sminshall SB_CLEAR(); 59232377Sminshall telrcv_state = TS_SB; 59332377Sminshall continue; 59427261Sminshall 59532377Sminshall # if defined(TN3270) 59632377Sminshall case EOR: 59732377Sminshall if (In3270) { 59832377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 59932377Sminshall if (Ibackp == Ifrontp) { 60032377Sminshall Ibackp = Ifrontp = Ibuf; 60132377Sminshall ISend = 0; /* should have been! */ 60232377Sminshall } else { 60332377Sminshall ISend = 1; 60427088Sminshall } 60527088Sminshall } 60627088Sminshall break; 60732377Sminshall # endif /* defined(TN3270) */ 60832377Sminshall 60932377Sminshall case IAC: 61032377Sminshall # if !defined(TN3270) 61132377Sminshall TTYADD(IAC); 61232377Sminshall # else /* !defined(TN3270) */ 61332377Sminshall if (In3270) { 61432377Sminshall *Ifrontp++ = IAC; 61532377Sminshall } else { 61632377Sminshall TTYADD(IAC); 61732377Sminshall } 61832377Sminshall # endif /* !defined(TN3270) */ 61927088Sminshall break; 62032377Sminshall 62127088Sminshall default: 62227088Sminshall break; 62327088Sminshall } 62432377Sminshall telrcv_state = TS_DATA; 62532377Sminshall continue; 62627088Sminshall 62732377Sminshall case TS_WILL: 62832377Sminshall printoption(">RCVD", will, c, !hisopts[c]); 62932377Sminshall if (c == TELOPT_TM) { 63032377Sminshall if (flushout) { 63132377Sminshall flushout = 0; 63232377Sminshall } 63332377Sminshall } else if (!hisopts[c]) { 63432377Sminshall willoption(c, 1); 63532377Sminshall } 63632377Sminshall SetIn3270(); 63732377Sminshall telrcv_state = TS_DATA; 63832377Sminshall continue; 63927110Sminshall 64032377Sminshall case TS_WONT: 64132377Sminshall printoption(">RCVD", wont, c, hisopts[c]); 64232377Sminshall if (c == TELOPT_TM) { 64332377Sminshall if (flushout) { 64432377Sminshall flushout = 0; 64532377Sminshall } 64632377Sminshall } else if (hisopts[c]) { 64732377Sminshall wontoption(c, 1); 64832377Sminshall } 64932377Sminshall SetIn3270(); 65032377Sminshall telrcv_state = TS_DATA; 65132377Sminshall continue; 65227088Sminshall 65332377Sminshall case TS_DO: 65432377Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 65532377Sminshall if (!myopts[c]) 65632377Sminshall dooption(c); 65732377Sminshall SetIn3270(); 65832377Sminshall telrcv_state = TS_DATA; 65932377Sminshall continue; 66027088Sminshall 66132377Sminshall case TS_DONT: 66232377Sminshall printoption(">RCVD", dont, c, myopts[c]); 66332377Sminshall if (myopts[c]) { 66432377Sminshall myopts[c] = 0; 66532381Sminshall netoprint(wont, c); 66632377Sminshall flushline = 1; 66732377Sminshall setconnmode(); /* set new tty mode (maybe) */ 66832377Sminshall printoption(">SENT", wont, c, 0); 66932377Sminshall } 67032377Sminshall SetIn3270(); 67132377Sminshall telrcv_state = TS_DATA; 67232377Sminshall continue; 67327088Sminshall 67432377Sminshall case TS_SB: 67532377Sminshall if (c == IAC) { 67632377Sminshall telrcv_state = TS_SE; 67732377Sminshall } else { 67832377Sminshall SB_ACCUM(c); 67932377Sminshall } 68032377Sminshall continue; 68127088Sminshall 68232377Sminshall case TS_SE: 68332377Sminshall if (c != SE) { 68432377Sminshall if (c != IAC) { 68532377Sminshall SB_ACCUM(IAC); 68632377Sminshall } 68732377Sminshall SB_ACCUM(c); 68832377Sminshall telrcv_state = TS_SB; 68932377Sminshall } else { 69032377Sminshall SB_TERM(); 69132377Sminshall suboption(); /* handle sub-option */ 69232377Sminshall SetIn3270(); 69332377Sminshall telrcv_state = TS_DATA; 69432377Sminshall } 69527088Sminshall } 69627088Sminshall } 697*32385Sminshall ring_sent_acked(&netiring, count); 698*32385Sminshall return returnValue||count; 69927088Sminshall } 700*32385Sminshall 701*32385Sminshall static int 702*32385Sminshall telsnd(ring) 703*32385Sminshall Ring *ring; /* Input ring */ 704*32385Sminshall { 705*32385Sminshall int tcc; 706*32385Sminshall int count; 707*32385Sminshall int returnValue = 0; 708*32385Sminshall char *tbp; 709*32385Sminshall 710*32385Sminshall tcc = 0; 711*32385Sminshall count = 0; 712*32385Sminshall while (NETROOM() > 2) { 713*32385Sminshall register int sc; 714*32385Sminshall register int c; 715*32385Sminshall 716*32385Sminshall if (tcc == 0) { 717*32385Sminshall if (count) { 718*32385Sminshall ring_sent_acked(&ttyiring, count); 719*32385Sminshall returnValue = 1; 720*32385Sminshall count = 0; 721*32385Sminshall } 722*32385Sminshall tbp = ttyiring.send; 723*32385Sminshall tcc = ring_unsent_consecutive(&ttyiring); 724*32385Sminshall if (tcc == 0) { 725*32385Sminshall break; 726*32385Sminshall } 727*32385Sminshall } 728*32385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 729*32385Sminshall if (sc == escape) { 730*32385Sminshall command(0); 731*32385Sminshall tcc = 0; 732*32385Sminshall flushline = 1; 733*32385Sminshall break; 734*32385Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 735*32385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 736*32385Sminshall tcc--; tbp++; count++; 737*32385Sminshall } else { 738*32385Sminshall dontlecho = !dontlecho; 739*32385Sminshall settimer(echotoggle); 740*32385Sminshall setconnmode(); 741*32385Sminshall flushline = 1; 742*32385Sminshall break; 743*32385Sminshall } 744*32385Sminshall } 745*32385Sminshall if (localchars) { 746*32385Sminshall if (TerminalSpecialChars(sc) == 0) { 747*32385Sminshall break; 748*32385Sminshall } 749*32385Sminshall } 750*32385Sminshall if (!myopts[TELOPT_BINARY]) { 751*32385Sminshall switch (c) { 752*32385Sminshall case '\n': 753*32385Sminshall /* 754*32385Sminshall * If we are in CRMOD mode (\r ==> \n) 755*32385Sminshall * on our local machine, then probably 756*32385Sminshall * a newline (unix) is CRLF (TELNET). 757*32385Sminshall */ 758*32385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 759*32385Sminshall NETADD('\r'); 760*32385Sminshall } 761*32385Sminshall NETADD('\n'); 762*32385Sminshall flushline = 1; 763*32385Sminshall break; 764*32385Sminshall case '\r': 765*32385Sminshall if (!crlf) { 766*32385Sminshall NET2ADD('\r', '\0'); 767*32385Sminshall } else { 768*32385Sminshall NET2ADD('\r', '\n'); 769*32385Sminshall } 770*32385Sminshall flushline = 1; 771*32385Sminshall break; 772*32385Sminshall case IAC: 773*32385Sminshall NET2ADD(IAC, IAC); 774*32385Sminshall break; 775*32385Sminshall default: 776*32385Sminshall NETADD(c); 777*32385Sminshall break; 778*32385Sminshall } 779*32385Sminshall } else if (c == IAC) { 780*32385Sminshall NET2ADD(IAC, IAC); 781*32385Sminshall } else { 782*32385Sminshall NETADD(c); 783*32385Sminshall } 784*32385Sminshall } 785*32385Sminshall ring_sent_acked(&ttyiring, count); 786*32385Sminshall return returnValue||count; /* Non-zero if we did anything */ 787*32385Sminshall } 78832377Sminshall 78932377Sminshall #if defined(TN3270) 79032377Sminshall static void 79132377Sminshall SetForExit() 79232377Sminshall { 79332377Sminshall setconnmode(); 79432377Sminshall if (In3270) { 79532377Sminshall Finish3270(); 79632377Sminshall } 79732377Sminshall setcommandmode(); 79832377Sminshall fflush(stdout); 79932377Sminshall fflush(stderr); 80032377Sminshall if (In3270) { 80132377Sminshall StopScreen(1); 80232377Sminshall } 80332377Sminshall setconnmode(); 80432377Sminshall setcommandmode(); 80532377Sminshall } 80627088Sminshall 80732377Sminshall static void 80832377Sminshall Exit(returnCode) 80932377Sminshall int returnCode; 81027088Sminshall { 81132377Sminshall SetForExit(); 81232377Sminshall exit(returnCode); 81327088Sminshall } 81427088Sminshall 81532377Sminshall void 81632381Sminshall ExitString(string, returnCode) 81732377Sminshall char *string; 81832377Sminshall int returnCode; 81927088Sminshall { 82032377Sminshall SetForExit(); 82132381Sminshall fwrite(string, 1, strlen(string), stderr); 82232377Sminshall exit(returnCode); 82327088Sminshall } 82427088Sminshall 82532377Sminshall void 82632377Sminshall ExitPerror(string, returnCode) 82732377Sminshall char *string; 82832377Sminshall int returnCode; 82927088Sminshall { 83032377Sminshall SetForExit(); 83132377Sminshall perror(string); 83232377Sminshall exit(returnCode); 83332377Sminshall } 83432377Sminshall #endif /* defined(TN3270) */ 83527088Sminshall 83627088Sminshall 83727088Sminshall /* 83832377Sminshall * Scheduler() 83932377Sminshall * 84032377Sminshall * Try to do something. 84132377Sminshall * 84232377Sminshall * If we do something useful, return 1; else return 0. 84332377Sminshall * 84427110Sminshall */ 84527110Sminshall 84627110Sminshall 84732377Sminshall int 84832377Sminshall Scheduler(block) 84932377Sminshall int block; /* should we block in the select ? */ 85027110Sminshall { 85132377Sminshall register int c; 85232377Sminshall /* One wants to be a bit careful about setting returnValue 85332377Sminshall * to one, since a one implies we did some useful work, 85432377Sminshall * and therefore probably won't be called to block next 85532377Sminshall * time (TN3270 mode only). 85632377Sminshall */ 85732377Sminshall int returnValue = 0; 85832377Sminshall static struct timeval TimeValue = { 0 }; 85927110Sminshall 86032377Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 86132377Sminshall FD_SET(net, &obits); 86232377Sminshall } 86332377Sminshall #if !defined(MSDOS) 86432377Sminshall if (TTYBYTES()) { 86532377Sminshall FD_SET(tout, &obits); 86627110Sminshall } 86732377Sminshall #if defined(TN3270) 86832377Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 86932377Sminshall FD_SET(tin, &ibits); 87027110Sminshall } 87132377Sminshall #else /* defined(TN3270) */ 872*32385Sminshall if (ring_empty_count(&netiring) && NETROOM()) { 87332377Sminshall FD_SET(tin, &ibits); 87427110Sminshall } 87532377Sminshall #endif /* defined(TN3270) */ 87632377Sminshall #endif /* !defined(MSDOS) */ 87732377Sminshall # if !defined(TN3270) 87832377Sminshall if (TTYROOM()) { 87932377Sminshall FD_SET(net, &ibits); 88027110Sminshall } 88132377Sminshall # else /* !defined(TN3270) */ 88232377Sminshall if (!ISend && TTYROOM()) { 88332377Sminshall FD_SET(net, &ibits); 88427110Sminshall } 88532377Sminshall # endif /* !defined(TN3270) */ 88632377Sminshall if (!SYNCHing) { 88732377Sminshall FD_SET(net, &xbits); 88832377Sminshall } 88932377Sminshall # if defined(TN3270) && defined(unix) 89032377Sminshall if (HaveInput) { 89132377Sminshall HaveInput = 0; 89232377Sminshall signal(SIGIO, inputAvailable); 89332377Sminshall } 89432377Sminshall #endif /* defined(TN3270) && defined(unix) */ 89532377Sminshall if ((c = select(16, &ibits, &obits, &xbits, 89632377Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 89732377Sminshall if (c == -1) { 89832377Sminshall /* 89932377Sminshall * we can get EINTR if we are in line mode, 90032377Sminshall * and the user does an escape (TSTP), or 90132377Sminshall * some other signal generator. 90232377Sminshall */ 90332377Sminshall if (errno == EINTR) { 90432377Sminshall return 0; 90532377Sminshall } 90632377Sminshall # if defined(TN3270) 90732377Sminshall /* 90832377Sminshall * we can get EBADF if we were in transparent 90932377Sminshall * mode, and the transcom process died. 91032377Sminshall */ 91132377Sminshall if (errno == EBADF) { 91232377Sminshall /* 91332377Sminshall * zero the bits (even though kernel does it) 91432377Sminshall * to make sure we are selecting on the right 91532377Sminshall * ones. 91632377Sminshall */ 91732377Sminshall FD_ZERO(&ibits); 91832377Sminshall FD_ZERO(&obits); 91932377Sminshall FD_ZERO(&xbits); 92032377Sminshall return 0; 92132377Sminshall } 92232377Sminshall # endif /* defined(TN3270) */ 92332377Sminshall /* I don't like this, does it ever happen? */ 92432377Sminshall printf("sleep(5) from telnet, after select\r\n"); 92532377Sminshall #if defined(unix) 92632377Sminshall sleep(5); 92732377Sminshall #endif /* defined(unix) */ 92827110Sminshall } 92927261Sminshall return 0; 93027110Sminshall } 93132377Sminshall 93232377Sminshall /* 93332377Sminshall * Any urgent data? 93432377Sminshall */ 93532377Sminshall if (FD_ISSET(net, &xbits)) { 93632377Sminshall FD_CLR(net, &xbits); 93732377Sminshall SYNCHing = 1; 93832377Sminshall ttyflush(1); /* flush already enqueued data */ 93927110Sminshall } 94027178Sminshall 94132377Sminshall /* 94232377Sminshall * Something to read from the network... 94332377Sminshall */ 94432377Sminshall if (FD_ISSET(net, &ibits)) { 94532377Sminshall int canread; 94627178Sminshall 94732377Sminshall FD_CLR(net, &ibits); 948*32385Sminshall canread = ring_empty_consecutive(&netiring); 94932377Sminshall #if !defined(SO_OOBINLINE) 95032377Sminshall /* 95132377Sminshall * In 4.2 (and some early 4.3) systems, the 95232377Sminshall * OOB indication and data handling in the kernel 95332377Sminshall * is such that if two separate TCP Urgent requests 95432377Sminshall * come in, one byte of TCP data will be overlaid. 95532377Sminshall * This is fatal for Telnet, but we try to live 95632377Sminshall * with it. 95732377Sminshall * 95832377Sminshall * In addition, in 4.2 (and...), a special protocol 95932377Sminshall * is needed to pick up the TCP Urgent data in 96032377Sminshall * the correct sequence. 96132377Sminshall * 96232377Sminshall * What we do is: if we think we are in urgent 96332377Sminshall * mode, we look to see if we are "at the mark". 96432377Sminshall * If we are, we do an OOB receive. If we run 96532377Sminshall * this twice, we will do the OOB receive twice, 96632377Sminshall * but the second will fail, since the second 96732377Sminshall * time we were "at the mark", but there wasn't 96832377Sminshall * any data there (the kernel doesn't reset 96932377Sminshall * "at the mark" until we do a normal read). 97032377Sminshall * Once we've read the OOB data, we go ahead 97132377Sminshall * and do normal reads. 97232377Sminshall * 97332377Sminshall * There is also another problem, which is that 97432377Sminshall * since the OOB byte we read doesn't put us 97532377Sminshall * out of OOB state, and since that byte is most 97632377Sminshall * likely the TELNET DM (data mark), we would 97732377Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 97832377Sminshall * So, clocks to the rescue. If we've "just" 97932377Sminshall * received a DM, then we test for the 98032377Sminshall * presence of OOB data when the receive OOB 98132377Sminshall * fails (and AFTER we did the normal mode read 98232377Sminshall * to clear "at the mark"). 98332377Sminshall */ 98432377Sminshall if (SYNCHing) { 98532377Sminshall int atmark; 98632377Sminshall 98732377Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 98832377Sminshall if (atmark) { 98932377Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 99032377Sminshall if ((c == -1) && (errno == EINVAL)) { 99132377Sminshall c = recv(net, sbp+scc, canread, 0); 99232377Sminshall if (clocks.didnetreceive < clocks.gotDM) { 99332377Sminshall SYNCHing = stilloob(net); 99427261Sminshall } 99532377Sminshall } 99632377Sminshall } else { 99732377Sminshall c = recv(net, sbp+scc, canread, 0); 99832377Sminshall } 99932377Sminshall } else { 100032377Sminshall c = recv(net, sbp+scc, canread, 0); 100132377Sminshall } 100232377Sminshall settimer(didnetreceive); 100332377Sminshall #else /* !defined(SO_OOBINLINE) */ 1004*32385Sminshall c = recv(net, netiring.add, canread, 0); 100532377Sminshall #endif /* !defined(SO_OOBINLINE) */ 100632377Sminshall if (c < 0 && errno == EWOULDBLOCK) { 100732377Sminshall c = 0; 100832377Sminshall } else if (c <= 0) { 100932377Sminshall return -1; 101032377Sminshall } 101132377Sminshall if (netdata) { 1012*32385Sminshall Dump('<', netiring.add, c); 101332377Sminshall } 1014*32385Sminshall ring_added(&netiring, c); 101532377Sminshall returnValue = 1; 101632377Sminshall } 101727178Sminshall 101832377Sminshall /* 101932377Sminshall * Something to read from the tty... 102032377Sminshall */ 102132377Sminshall #if defined(MSDOS) 102232377Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 102332377Sminshall #else /* defined(MSDOS) */ 102432377Sminshall if (FD_ISSET(tin, &ibits)) 102532377Sminshall #endif /* defined(MSDOS) */ 102632377Sminshall { 102732377Sminshall FD_CLR(tin, &ibits); 1028*32385Sminshall c = TerminalRead(tin, ttyiring.add, ring_empty_consecutive(&ttyiring)); 102932377Sminshall if (c < 0 && errno == EWOULDBLOCK) { 103032377Sminshall c = 0; 103132377Sminshall } else { 103232377Sminshall #if defined(unix) 103332377Sminshall /* EOF detection for line mode!!!! */ 103432377Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 103532377Sminshall /* must be an EOF... */ 1036*32385Sminshall *ttyiring.add = termEofChar; 103732377Sminshall c = 1; 103832377Sminshall } 103932377Sminshall #endif /* defined(unix) */ 104032377Sminshall if (c <= 0) { 104132377Sminshall return -1; 104232377Sminshall } 104327178Sminshall } 1044*32385Sminshall ring_added(&ttyiring, c); 104532377Sminshall returnValue = 1; /* did something useful */ 104632377Sminshall } 104727178Sminshall 104832377Sminshall # if defined(TN3270) 1049*32385Sminshall if (ring_unsent_count(&ttyiring)) { 105032377Sminshall if (In3270) { 1051*32385Sminshall c = DataFromTerminal(ttyiring.send, 1052*32385Sminshall ring_unsent_consecutive(&ttyiring)); 105332377Sminshall if (c) { 105432377Sminshall returnValue = 1; 105532377Sminshall } 1056*32385Sminshall ring_sent_acked(&ttyiring, c); 105732377Sminshall } else { 105832377Sminshall # endif /* defined(TN3270) */ 1059*32385Sminshall returnValue |= telsnd(&ttyiring); 106032377Sminshall # if defined(TN3270) 106127178Sminshall } 106227178Sminshall } 106332377Sminshall # endif /* defined(TN3270) */ 106432377Sminshall 106532377Sminshall if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) && 106632377Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 106732377Sminshall FD_CLR(net, &obits); 106832377Sminshall returnValue = netflush(); 106932377Sminshall } 1070*32385Sminshall if (ring_unsent_count(&netiring)) { 107132377Sminshall # if !defined(TN3270) 1072*32385Sminshall returnValue |= telrcv(); 107332377Sminshall # else /* !defined(TN3270) */ 107432377Sminshall returnValue = Push3270(); 107532377Sminshall # endif /* !defined(TN3270) */ 107632377Sminshall } 107732377Sminshall #if defined(MSDOS) 107832377Sminshall if (TTYBYTES()) 107932377Sminshall #else /* defined(MSDOS) */ 108032377Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 108132377Sminshall #endif /* defined(MSDOS) */ 108232377Sminshall { 108332377Sminshall FD_CLR(tout, &obits); 108432377Sminshall returnValue = ttyflush(SYNCHing|flushout); 108532377Sminshall } 108632377Sminshall return returnValue; 108727178Sminshall } 108827178Sminshall 108927178Sminshall /* 109032377Sminshall * Select from tty and network... 109127088Sminshall */ 109232377Sminshall void 109332377Sminshall telnet() 109427088Sminshall { 109532377Sminshall #if defined(MSDOS) 109632377Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 109732377Sminshall #else /* defined(MSDOS) */ 109832377Sminshall #define SCHED_BLOCK 1 109932377Sminshall #endif /* defined(MSDOS) */ 110027088Sminshall 110132377Sminshall #if defined(TN3270) && defined(unix) 110232377Sminshall int myPid; 110332377Sminshall #endif /* defined(TN3270) */ 110427088Sminshall 110532377Sminshall tout = fileno(stdout); 110632377Sminshall tin = fileno(stdin); 110732377Sminshall setconnmode(); 110832377Sminshall FD_ZERO(&ibits); 110932377Sminshall FD_ZERO(&obits); 111032377Sminshall FD_ZERO(&xbits); 111127261Sminshall 111232377Sminshall NetNonblockingIO(net, 1); 111327088Sminshall 111432377Sminshall #if defined(TN3270) 111532377Sminshall if (noasynch == 0) { /* DBX can't handle! */ 111632377Sminshall NetSigIO(net, 1); 111732377Sminshall } 111832377Sminshall NetSetPgrp(net); 111932377Sminshall #endif /* defined(TN3270) */ 112027088Sminshall 112127088Sminshall 112232377Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 112332377Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 112432377Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 112527088Sminshall 112632377Sminshall # if !defined(TN3270) 112732377Sminshall if (telnetport) { 112832377Sminshall if (!hisopts[TELOPT_SGA]) { 112932377Sminshall willoption(TELOPT_SGA, 0); 113027110Sminshall } 113132377Sminshall if (!myopts[TELOPT_TTYPE]) { 113232377Sminshall dooption(TELOPT_TTYPE, 0); 113332377Sminshall } 113427178Sminshall } 113532377Sminshall # endif /* !defined(TN3270) */ 113627088Sminshall 113732377Sminshall # if !defined(TN3270) 113832377Sminshall for (;;) { 1139*32385Sminshall int schedValue; 1140*32385Sminshall 1141*32385Sminshall while ((schedValue = Scheduler(0)) != 0) { 1142*32385Sminshall if (schedValue == -1) { 1143*32385Sminshall setcommandmode(); 1144*32385Sminshall return; 1145*32385Sminshall } 1146*32385Sminshall } 1147*32385Sminshall 114832377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 114932377Sminshall setcommandmode(); 115032377Sminshall return; 115132377Sminshall } 115232377Sminshall } 115332377Sminshall # else /* !defined(TN3270) */ 115432377Sminshall for (;;) { 115532377Sminshall int schedValue; 115627088Sminshall 115732377Sminshall while (!In3270 && !shell_active) { 115832377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 115932377Sminshall setcommandmode(); 116032377Sminshall return; 116132377Sminshall } 116227088Sminshall } 116332377Sminshall 116432377Sminshall while ((schedValue = Scheduler(0)) != 0) { 116532377Sminshall if (schedValue == -1) { 116632377Sminshall setcommandmode(); 116732377Sminshall return; 116832377Sminshall } 116927088Sminshall } 117032377Sminshall /* If there is data waiting to go out to terminal, don't 117132377Sminshall * schedule any more data for the terminal. 117232377Sminshall */ 117332377Sminshall if (tfrontp-tbackp) { 117432377Sminshall schedValue = 1; 117527088Sminshall } else { 117632377Sminshall if (shell_active) { 117732377Sminshall if (shell_continue() == 0) { 117832377Sminshall ConnectScreen(); 117927088Sminshall } 118032377Sminshall } else if (In3270) { 118132377Sminshall schedValue = DoTerminalOutput(); 118232377Sminshall } 118327088Sminshall } 118432377Sminshall if (schedValue && (shell_active == 0)) { 118532377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 118632377Sminshall setcommandmode(); 118732377Sminshall return; 118832377Sminshall } 118927088Sminshall } 119032377Sminshall } 119132377Sminshall # endif /* !defined(TN3270) */ 119227088Sminshall } 119332377Sminshall 119427088Sminshall /* 119532377Sminshall * These routines add various telnet commands to the data stream. 119627088Sminshall */ 119732377Sminshall 119832377Sminshall void 119932377Sminshall xmitAO() 120027088Sminshall { 120132377Sminshall NET2ADD(IAC, AO); 120232377Sminshall if (autoflush) { 120332377Sminshall doflush(); 120432377Sminshall } 120532377Sminshall } 120627088Sminshall 120732377Sminshall 120832377Sminshall void 120932377Sminshall xmitEL() 121027088Sminshall { 121132377Sminshall NET2ADD(IAC, EL); 121227088Sminshall } 121327088Sminshall 121432377Sminshall void 121532377Sminshall xmitEC() 121627088Sminshall { 121732377Sminshall NET2ADD(IAC, EC); 121827088Sminshall } 121927088Sminshall 122032377Sminshall 122132377Sminshall #if defined(NOT43) 122232377Sminshall int 122332377Sminshall #else /* defined(NOT43) */ 122432377Sminshall void 122532377Sminshall #endif /* defined(NOT43) */ 122632377Sminshall dosynch() 122727088Sminshall { 122832377Sminshall netclear(); /* clear the path to the network */ 122932377Sminshall NET2ADD(IAC, DM); 123027088Sminshall 123132377Sminshall #if defined(NOT43) 123232377Sminshall return 0; 123332377Sminshall #endif /* defined(NOT43) */ 123427088Sminshall } 123527088Sminshall 123632377Sminshall void 123732377Sminshall doflush() 123827088Sminshall { 123932377Sminshall NET2ADD(IAC, DO); 124032377Sminshall NETADD(TELOPT_TM); 124132377Sminshall flushline = 1; 124232377Sminshall flushout = 1; 124332377Sminshall ttyflush(1); /* Flush/drop output */ 124432377Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 124532377Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 124627088Sminshall } 124727088Sminshall 124832377Sminshall void 124932377Sminshall intp() 125027088Sminshall { 125132377Sminshall NET2ADD(IAC, IP); 125232377Sminshall flushline = 1; 125332377Sminshall if (autoflush) { 125432377Sminshall doflush(); 125532377Sminshall } 125632377Sminshall if (autosynch) { 125732377Sminshall dosynch(); 125832377Sminshall } 125927088Sminshall } 126027186Sminshall 126132377Sminshall void 126232377Sminshall sendbrk() 126327186Sminshall { 126432377Sminshall NET2ADD(IAC, BREAK); 126532377Sminshall flushline = 1; 126632377Sminshall if (autoflush) { 126732377Sminshall doflush(); 126832377Sminshall } 126932377Sminshall if (autosynch) { 127032377Sminshall dosynch(); 127132377Sminshall } 127227186Sminshall } 1273