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 9932385Sminshall static Ring netiring, ttyiring; 10032385Sminshall static char netibuf[BUFSIZ]; 10132385Sminshall 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); 19932385Sminshall ring_init(&netiring, netibuf, sizeof netibuf); 20032385Sminshall ring_init(&ttyiring, ttyibuf, sizeof ttyibuf); 2016000Sroot 20232385Sminshall 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); 406*32528Sminshall ring_supply_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 45932385Sminshall static int 46032377Sminshall telrcv() 46127110Sminshall { 46232377Sminshall register int c; 46332385Sminshall register int scc; 46432385Sminshall register char *sbp; 46532385Sminshall int count; 46632385Sminshall int returnValue = 0; 46727088Sminshall 46832385Sminshall scc = 0; 46932385Sminshall count = 0; 47032385Sminshall while (TTYROOM() > 2) { 47132385Sminshall if (scc == 0) { 47232385Sminshall if (count) { 473*32528Sminshall ring_consumed(&netiring, count); 47432385Sminshall returnValue = 1; 47532385Sminshall count = 0; 47632385Sminshall } 477*32528Sminshall sbp = netiring.consume; 478*32528Sminshall scc = ring_full_consecutive(&netiring); 47932385Sminshall if (scc == 0) { 48032385Sminshall /* No more data coming in */ 48132385Sminshall break; 48232385Sminshall } 48332385Sminshall } 48432385Sminshall 48532385Sminshall c = *sbp++ & 0xff, scc--; count++; 48632385Sminshall 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; 50932385Sminshall while (scc > 0) { 51032385Sminshall 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) { 53032385Sminshall sbp++, scc--; count++; 53132377Sminshall /* a "true" CR */ 53232377Sminshall TTYADD('\r'); 53332377Sminshall } else if (!hisopts[TELOPT_ECHO] && 53432377Sminshall (c == '\n')) { 53532385Sminshall 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*32528Sminshall ring_consumed(&netiring, count); 69832385Sminshall return returnValue||count; 69927088Sminshall } 70032385Sminshall 70132385Sminshall static int 70232385Sminshall telsnd(ring) 70332385Sminshall Ring *ring; /* Input ring */ 70432385Sminshall { 70532385Sminshall int tcc; 70632385Sminshall int count; 70732385Sminshall int returnValue = 0; 70832385Sminshall char *tbp; 70932385Sminshall 71032385Sminshall tcc = 0; 71132385Sminshall count = 0; 71232385Sminshall while (NETROOM() > 2) { 71332385Sminshall register int sc; 71432385Sminshall register int c; 71532385Sminshall 71632385Sminshall if (tcc == 0) { 71732385Sminshall if (count) { 718*32528Sminshall ring_consumed(&ttyiring, count); 71932385Sminshall returnValue = 1; 72032385Sminshall count = 0; 72132385Sminshall } 722*32528Sminshall tbp = ttyiring.consume; 723*32528Sminshall tcc = ring_full_consecutive(&ttyiring); 72432385Sminshall if (tcc == 0) { 72532385Sminshall break; 72632385Sminshall } 72732385Sminshall } 72832385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 72932385Sminshall if (sc == escape) { 73032385Sminshall command(0); 73132385Sminshall tcc = 0; 73232385Sminshall flushline = 1; 73332385Sminshall break; 73432385Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 73532385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 73632385Sminshall tcc--; tbp++; count++; 73732385Sminshall } else { 73832385Sminshall dontlecho = !dontlecho; 73932385Sminshall settimer(echotoggle); 74032385Sminshall setconnmode(); 74132385Sminshall flushline = 1; 74232385Sminshall break; 74332385Sminshall } 74432385Sminshall } 74532385Sminshall if (localchars) { 74632385Sminshall if (TerminalSpecialChars(sc) == 0) { 74732385Sminshall break; 74832385Sminshall } 74932385Sminshall } 75032385Sminshall if (!myopts[TELOPT_BINARY]) { 75132385Sminshall switch (c) { 75232385Sminshall case '\n': 75332385Sminshall /* 75432385Sminshall * If we are in CRMOD mode (\r ==> \n) 75532385Sminshall * on our local machine, then probably 75632385Sminshall * a newline (unix) is CRLF (TELNET). 75732385Sminshall */ 75832385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 75932385Sminshall NETADD('\r'); 76032385Sminshall } 76132385Sminshall NETADD('\n'); 76232385Sminshall flushline = 1; 76332385Sminshall break; 76432385Sminshall case '\r': 76532385Sminshall if (!crlf) { 76632385Sminshall NET2ADD('\r', '\0'); 76732385Sminshall } else { 76832385Sminshall NET2ADD('\r', '\n'); 76932385Sminshall } 77032385Sminshall flushline = 1; 77132385Sminshall break; 77232385Sminshall case IAC: 77332385Sminshall NET2ADD(IAC, IAC); 77432385Sminshall break; 77532385Sminshall default: 77632385Sminshall NETADD(c); 77732385Sminshall break; 77832385Sminshall } 77932385Sminshall } else if (c == IAC) { 78032385Sminshall NET2ADD(IAC, IAC); 78132385Sminshall } else { 78232385Sminshall NETADD(c); 78332385Sminshall } 78432385Sminshall } 785*32528Sminshall ring_consumed(&ttyiring, count); 78632385Sminshall return returnValue||count; /* Non-zero if we did anything */ 78732385Sminshall } 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) */ 87232385Sminshall 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); 94832385Sminshall 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*32528Sminshall c = recv(net, netiring.supply, 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*32528Sminshall Dump('<', netiring.supply, c); 101332377Sminshall } 1014*32528Sminshall ring_supplied(&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*32528Sminshall c = TerminalRead(tin, ttyiring.supply, 1029*32528Sminshall ring_empty_consecutive(&ttyiring)); 103032377Sminshall if (c < 0 && errno == EWOULDBLOCK) { 103132377Sminshall c = 0; 103232377Sminshall } else { 103332377Sminshall #if defined(unix) 103432377Sminshall /* EOF detection for line mode!!!! */ 103532377Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 103632377Sminshall /* must be an EOF... */ 1037*32528Sminshall *ttyiring.supply = termEofChar; 103832377Sminshall c = 1; 103932377Sminshall } 104032377Sminshall #endif /* defined(unix) */ 104132377Sminshall if (c <= 0) { 104232377Sminshall return -1; 104332377Sminshall } 104427178Sminshall } 1045*32528Sminshall ring_supplied(&ttyiring, c); 104632377Sminshall returnValue = 1; /* did something useful */ 104732377Sminshall } 104827178Sminshall 104932377Sminshall # if defined(TN3270) 1050*32528Sminshall if (ring_full_count(&ttyiring)) { 105132377Sminshall if (In3270) { 105232385Sminshall c = DataFromTerminal(ttyiring.send, 1053*32528Sminshall ring_full_consecutive(&ttyiring)); 105432377Sminshall if (c) { 105532377Sminshall returnValue = 1; 105632377Sminshall } 1057*32528Sminshall ring_consumed(&ttyiring, c); 105832377Sminshall } else { 105932377Sminshall # endif /* defined(TN3270) */ 106032385Sminshall returnValue |= telsnd(&ttyiring); 106132377Sminshall # if defined(TN3270) 106227178Sminshall } 106327178Sminshall } 106432377Sminshall # endif /* defined(TN3270) */ 106532377Sminshall 106632377Sminshall if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) && 106732377Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 106832377Sminshall FD_CLR(net, &obits); 106932377Sminshall returnValue = netflush(); 107032377Sminshall } 1071*32528Sminshall if (ring_full_count(&netiring)) { 107232377Sminshall # if !defined(TN3270) 107332385Sminshall returnValue |= telrcv(); 107432377Sminshall # else /* !defined(TN3270) */ 107532377Sminshall returnValue = Push3270(); 107632377Sminshall # endif /* !defined(TN3270) */ 107732377Sminshall } 107832377Sminshall #if defined(MSDOS) 107932377Sminshall if (TTYBYTES()) 108032377Sminshall #else /* defined(MSDOS) */ 108132377Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 108232377Sminshall #endif /* defined(MSDOS) */ 108332377Sminshall { 108432377Sminshall FD_CLR(tout, &obits); 108532377Sminshall returnValue = ttyflush(SYNCHing|flushout); 108632377Sminshall } 108732377Sminshall return returnValue; 108827178Sminshall } 108927178Sminshall 109027178Sminshall /* 109132377Sminshall * Select from tty and network... 109227088Sminshall */ 109332377Sminshall void 109432377Sminshall telnet() 109527088Sminshall { 109632377Sminshall #if defined(MSDOS) 109732377Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 109832377Sminshall #else /* defined(MSDOS) */ 109932377Sminshall #define SCHED_BLOCK 1 110032377Sminshall #endif /* defined(MSDOS) */ 110127088Sminshall 110232377Sminshall #if defined(TN3270) && defined(unix) 110332377Sminshall int myPid; 110432377Sminshall #endif /* defined(TN3270) */ 110527088Sminshall 110632377Sminshall tout = fileno(stdout); 110732377Sminshall tin = fileno(stdin); 110832377Sminshall setconnmode(); 110932377Sminshall FD_ZERO(&ibits); 111032377Sminshall FD_ZERO(&obits); 111132377Sminshall FD_ZERO(&xbits); 111227261Sminshall 111332377Sminshall NetNonblockingIO(net, 1); 111427088Sminshall 111532377Sminshall #if defined(TN3270) 111632377Sminshall if (noasynch == 0) { /* DBX can't handle! */ 111732377Sminshall NetSigIO(net, 1); 111832377Sminshall } 111932377Sminshall NetSetPgrp(net); 112032377Sminshall #endif /* defined(TN3270) */ 112127088Sminshall 112227088Sminshall 112332377Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 112432377Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 112532377Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 112627088Sminshall 112732377Sminshall # if !defined(TN3270) 112832377Sminshall if (telnetport) { 112932377Sminshall if (!hisopts[TELOPT_SGA]) { 113032377Sminshall willoption(TELOPT_SGA, 0); 113127110Sminshall } 113232377Sminshall if (!myopts[TELOPT_TTYPE]) { 113332377Sminshall dooption(TELOPT_TTYPE, 0); 113432377Sminshall } 113527178Sminshall } 113632377Sminshall # endif /* !defined(TN3270) */ 113727088Sminshall 113832377Sminshall # if !defined(TN3270) 113932377Sminshall for (;;) { 114032385Sminshall int schedValue; 114132385Sminshall 114232385Sminshall while ((schedValue = Scheduler(0)) != 0) { 114332385Sminshall if (schedValue == -1) { 114432385Sminshall setcommandmode(); 114532385Sminshall return; 114632385Sminshall } 114732385Sminshall } 114832385Sminshall 114932377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 115032377Sminshall setcommandmode(); 115132377Sminshall return; 115232377Sminshall } 115332377Sminshall } 115432377Sminshall # else /* !defined(TN3270) */ 115532377Sminshall for (;;) { 115632377Sminshall int schedValue; 115727088Sminshall 115832377Sminshall while (!In3270 && !shell_active) { 115932377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 116032377Sminshall setcommandmode(); 116132377Sminshall return; 116232377Sminshall } 116327088Sminshall } 116432377Sminshall 116532377Sminshall while ((schedValue = Scheduler(0)) != 0) { 116632377Sminshall if (schedValue == -1) { 116732377Sminshall setcommandmode(); 116832377Sminshall return; 116932377Sminshall } 117027088Sminshall } 117132377Sminshall /* If there is data waiting to go out to terminal, don't 117232377Sminshall * schedule any more data for the terminal. 117332377Sminshall */ 117432377Sminshall if (tfrontp-tbackp) { 117532377Sminshall schedValue = 1; 117627088Sminshall } else { 117732377Sminshall if (shell_active) { 117832377Sminshall if (shell_continue() == 0) { 117932377Sminshall ConnectScreen(); 118027088Sminshall } 118132377Sminshall } else if (In3270) { 118232377Sminshall schedValue = DoTerminalOutput(); 118332377Sminshall } 118427088Sminshall } 118532377Sminshall if (schedValue && (shell_active == 0)) { 118632377Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 118732377Sminshall setcommandmode(); 118832377Sminshall return; 118932377Sminshall } 119027088Sminshall } 119132377Sminshall } 119232377Sminshall # endif /* !defined(TN3270) */ 119327088Sminshall } 119432377Sminshall 119527088Sminshall /* 119632377Sminshall * These routines add various telnet commands to the data stream. 119727088Sminshall */ 119832377Sminshall 119932377Sminshall void 120032377Sminshall xmitAO() 120127088Sminshall { 120232377Sminshall NET2ADD(IAC, AO); 120332377Sminshall if (autoflush) { 120432377Sminshall doflush(); 120532377Sminshall } 120632377Sminshall } 120727088Sminshall 120832377Sminshall 120932377Sminshall void 121032377Sminshall xmitEL() 121127088Sminshall { 121232377Sminshall NET2ADD(IAC, EL); 121327088Sminshall } 121427088Sminshall 121532377Sminshall void 121632377Sminshall xmitEC() 121727088Sminshall { 121832377Sminshall NET2ADD(IAC, EC); 121927088Sminshall } 122027088Sminshall 122132377Sminshall 122232377Sminshall #if defined(NOT43) 122332377Sminshall int 122432377Sminshall #else /* defined(NOT43) */ 122532377Sminshall void 122632377Sminshall #endif /* defined(NOT43) */ 122732377Sminshall dosynch() 122827088Sminshall { 122932377Sminshall netclear(); /* clear the path to the network */ 123032377Sminshall NET2ADD(IAC, DM); 123127088Sminshall 123232377Sminshall #if defined(NOT43) 123332377Sminshall return 0; 123432377Sminshall #endif /* defined(NOT43) */ 123527088Sminshall } 123627088Sminshall 123732377Sminshall void 123832377Sminshall doflush() 123927088Sminshall { 124032377Sminshall NET2ADD(IAC, DO); 124132377Sminshall NETADD(TELOPT_TM); 124232377Sminshall flushline = 1; 124332377Sminshall flushout = 1; 124432377Sminshall ttyflush(1); /* Flush/drop output */ 124532377Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 124632377Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 124727088Sminshall } 124827088Sminshall 124932377Sminshall void 125032377Sminshall intp() 125127088Sminshall { 125232377Sminshall NET2ADD(IAC, IP); 125332377Sminshall flushline = 1; 125432377Sminshall if (autoflush) { 125532377Sminshall doflush(); 125632377Sminshall } 125732377Sminshall if (autosynch) { 125832377Sminshall dosynch(); 125932377Sminshall } 126027088Sminshall } 126127186Sminshall 126232377Sminshall void 126332377Sminshall sendbrk() 126427186Sminshall { 126532377Sminshall NET2ADD(IAC, BREAK); 126632377Sminshall flushline = 1; 126732377Sminshall if (autoflush) { 126832377Sminshall doflush(); 126932377Sminshall } 127032377Sminshall if (autosynch) { 127132377Sminshall dosynch(); 127232377Sminshall } 127327186Sminshall } 1274