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> 129217Ssam 1332377Sminshall #if defined(unix) 1432377Sminshall /* By the way, we need to include curses.h before telnet.h since, 1532377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 1632377Sminshall * declared in curses.h. 1732377Sminshall */ 1832377Sminshall #include <curses.h> 1932377Sminshall #endif /* defined(unix) */ 2032377Sminshall 2112212Ssam #include <arpa/telnet.h> 2232377Sminshall 2332377Sminshall #if defined(unix) 2427186Sminshall #include <strings.h> 2532377Sminshall #else /* defined(unix) */ 2632377Sminshall #include <string.h> 2732377Sminshall #endif /* defined(unix) */ 289217Ssam 2932381Sminshall #include "ring.h" 3032381Sminshall 3132377Sminshall #include "defines.h" 3232377Sminshall #include "externs.h" 3332377Sminshall #include "types.h" 3432377Sminshall #include "general.h" 3527178Sminshall 3627178Sminshall 3727228Sminshall #define strip(x) ((x)&0x7f) 386000Sroot 3927088Sminshall 4032377Sminshall static char subbuffer[SUBBUFSIZE], 4132377Sminshall *subpointer, *subend; /* buffer for sub-options */ 4227676Sminshall #define SB_CLEAR() subpointer = subbuffer; 4327676Sminshall #define SB_TERM() subend = subpointer; 4427676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4527676Sminshall *subpointer++ = (c); \ 4627676Sminshall } 4727676Sminshall 486000Sroot char hisopts[256]; 496000Sroot char myopts[256]; 506000Sroot 516000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 526000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 536000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 546000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 556000Sroot 5632377Sminshall int 5732377Sminshall connected, 5832377Sminshall showoptions, 5932377Sminshall In3270, /* Are we in 3270 mode? */ 6032377Sminshall ISend, /* trying to send network data in */ 6132377Sminshall debug = 0, 6232377Sminshall crmod, 6332377Sminshall netdata, /* Print out network data flow */ 6432377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 6532377Sminshall noasynch = 0, /* User specified "-noasynch" on command line */ 6632377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 67*32531Sminshall telnetport = 1, 68*32531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 69*32531Sminshall flushout, /* flush output */ 70*32531Sminshall autoflush = 0, /* flush output when interrupting? */ 71*32531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 72*32531Sminshall localchars, /* we recognize interrupt/quit */ 73*32531Sminshall donelclchars, /* the user has set "localchars" */ 74*32531Sminshall donebinarytoggle, /* the user has put us in binary */ 75*32531Sminshall dontlecho, /* do we suppress local echoing right now? */ 76*32531Sminshall globalmode; 7727088Sminshall 7832377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 796000Sroot 8032377Sminshall char 8132377Sminshall *prompt = 0, 8232377Sminshall escape, 8332377Sminshall echoc; 8427186Sminshall 8527186Sminshall /* 866000Sroot * Telnet receiver states for fsm 876000Sroot */ 886000Sroot #define TS_DATA 0 896000Sroot #define TS_IAC 1 906000Sroot #define TS_WILL 2 916000Sroot #define TS_WONT 3 926000Sroot #define TS_DO 4 936000Sroot #define TS_DONT 5 9427021Sminshall #define TS_CR 6 9527676Sminshall #define TS_SB 7 /* sub-option collection */ 9627676Sminshall #define TS_SE 8 /* looking for sub-option end */ 976000Sroot 9832377Sminshall static int telrcv_state; 996000Sroot 10032377Sminshall jmp_buf toplevel = { 0 }; 10132377Sminshall jmp_buf peerdied; 1026000Sroot 10332377Sminshall int flushline; 10427021Sminshall 10532377Sminshall /* 10632377Sminshall * The following are some clocks used to decide how to interpret 10732377Sminshall * the relationship between various variables. 10832377Sminshall */ 1096000Sroot 11032377Sminshall Clocks clocks; 11132377Sminshall 11232377Sminshall Modelist modelist[] = { 11332377Sminshall { "telnet command mode", COMMAND_LINE }, 11432377Sminshall { "character-at-a-time mode", 0 }, 11532377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 11632377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 11732377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 11832377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 11932377Sminshall { "3270 mode", 0 }, 12032377Sminshall }; 1216000Sroot 12232377Sminshall 12332377Sminshall /* 12432377Sminshall * Initialize telnet environment. 12532377Sminshall */ 1266000Sroot 12732377Sminshall init_telnet() 12832377Sminshall { 12932377Sminshall /* Don't change telnetport */ 13032377Sminshall SB_CLEAR(); 13132377Sminshall ClearArray(hisopts); 13232377Sminshall ClearArray(myopts); 1336000Sroot 13432385Sminshall connected = net = In3270 = ISend = donebinarytoggle = 0; 13532377Sminshall telnetport = 0; 1366000Sroot 13732377Sminshall #if defined(unix) && defined(TN3270) 13832377Sminshall HaveInput = 0; 13932377Sminshall #endif /* defined(unix) && defined(TN3270) */ 1406000Sroot 14132377Sminshall SYNCHing = 0; 1426000Sroot 14332377Sminshall /* Don't change NetTrace */ 1446000Sroot 14532377Sminshall escape = CONTROL(']'); 14632377Sminshall echoc = CONTROL('E'); 1476000Sroot 14832377Sminshall flushline = 1; 14932377Sminshall telrcv_state = TS_DATA; 15032377Sminshall } 1516000Sroot 1526000Sroot 15332377Sminshall void 15427676Sminshall willoption(option, reply) 15527676Sminshall int option, reply; 1566000Sroot { 1576000Sroot char *fmt; 1586000Sroot 1596000Sroot switch (option) { 1606000Sroot 1616000Sroot case TELOPT_ECHO: 16232377Sminshall # if defined(TN3270) 16332377Sminshall /* 16432377Sminshall * The following is a pain in the rear-end. 16532377Sminshall * Various IBM servers (some versions of Wiscnet, 16632377Sminshall * possibly Fibronics/Spartacus, and who knows who 16732377Sminshall * else) will NOT allow us to send "DO SGA" too early 16832377Sminshall * in the setup proceedings. On the other hand, 16932377Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 17032377Sminshall * So, we are stuck. Empirically (but, based on 17132377Sminshall * a VERY small sample), the IBM servers don't send 17232377Sminshall * out anything about ECHO, so we postpone our sending 17332377Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 17432377Sminshall * DO send). 17532377Sminshall */ 17632377Sminshall { 17732377Sminshall if (askedSGA == 0) { 17832377Sminshall askedSGA = 1; 17932377Sminshall if (!hisopts[TELOPT_SGA]) { 18032377Sminshall willoption(TELOPT_SGA, 0); 18132377Sminshall } 18232377Sminshall } 18332377Sminshall } 18432377Sminshall /* Fall through */ 18532377Sminshall case TELOPT_EOR: 18632377Sminshall case TELOPT_BINARY: 18732377Sminshall #endif /* defined(TN3270) */ 1886000Sroot case TELOPT_SGA: 18927110Sminshall settimer(modenegotiated); 1906000Sroot hisopts[option] = 1; 1916000Sroot fmt = doopt; 19227110Sminshall setconnmode(); /* possibly set new tty mode */ 1936000Sroot break; 1946000Sroot 1956000Sroot case TELOPT_TM: 19627110Sminshall return; /* Never reply to TM will's/wont's */ 1976000Sroot 1986000Sroot default: 1996000Sroot fmt = dont; 2006000Sroot break; 2016000Sroot } 20232381Sminshall netoprint(fmt, option); 20327676Sminshall if (reply) 20432377Sminshall printoption(">SENT", fmt, option, reply); 20527676Sminshall else 20632377Sminshall printoption("<SENT", fmt, option, reply); 2076000Sroot } 2086000Sroot 20932377Sminshall void 21027676Sminshall wontoption(option, reply) 21127676Sminshall int option, reply; 2126000Sroot { 2136000Sroot char *fmt; 2146000Sroot 2156000Sroot switch (option) { 2166000Sroot 2176000Sroot case TELOPT_ECHO: 2186000Sroot case TELOPT_SGA: 21927110Sminshall settimer(modenegotiated); 2206000Sroot hisopts[option] = 0; 2216000Sroot fmt = dont; 22227110Sminshall setconnmode(); /* Set new tty mode */ 2236000Sroot break; 2246000Sroot 22527110Sminshall case TELOPT_TM: 22627110Sminshall return; /* Never reply to TM will's/wont's */ 22727110Sminshall 2286000Sroot default: 2296000Sroot fmt = dont; 2306000Sroot } 23132381Sminshall netoprint(fmt, option); 23227676Sminshall if (reply) 23332377Sminshall printoption(">SENT", fmt, option, reply); 23427676Sminshall else 23532377Sminshall printoption("<SENT", fmt, option, reply); 2366000Sroot } 2376000Sroot 23832377Sminshall static void 2396000Sroot dooption(option) 2406000Sroot int option; 2416000Sroot { 2426000Sroot char *fmt; 2436000Sroot 2446000Sroot switch (option) { 2456000Sroot 2466000Sroot case TELOPT_TM: 24713231Ssam fmt = will; 24813231Ssam break; 24913231Ssam 25032377Sminshall # if defined(TN3270) 25132377Sminshall case TELOPT_EOR: 25232377Sminshall case TELOPT_BINARY: 25332377Sminshall # endif /* defined(TN3270) */ 25427676Sminshall case TELOPT_TTYPE: /* terminal type option */ 25527110Sminshall case TELOPT_SGA: /* no big deal */ 2566000Sroot fmt = will; 25727110Sminshall myopts[option] = 1; 2586000Sroot break; 2596000Sroot 26027110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 2616000Sroot default: 2626000Sroot fmt = wont; 2636000Sroot break; 2646000Sroot } 26532381Sminshall netoprint(fmt, option); 26632377Sminshall printoption(">SENT", fmt, option, 0); 2676000Sroot } 26827676Sminshall 26927676Sminshall /* 27027676Sminshall * suboption() 27127676Sminshall * 27227676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 27327676Sminshall * side. 27427676Sminshall * 27527676Sminshall * Currently we recognize: 27627676Sminshall * 27727676Sminshall * Terminal type, send request. 27827676Sminshall */ 27927676Sminshall 28032377Sminshall static void 28127676Sminshall suboption() 28227676Sminshall { 28332377Sminshall printsub("<", subbuffer, subend-subbuffer+1); 28427676Sminshall switch (subbuffer[0]&0xff) { 28527676Sminshall case TELOPT_TTYPE: 28627676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 28727676Sminshall ; 28827676Sminshall } else { 28927676Sminshall char *name; 29027676Sminshall char namebuf[41]; 29132377Sminshall extern char *getenv(); 29227676Sminshall int len; 29327676Sminshall 29432377Sminshall #if defined(TN3270) 295*32531Sminshall if (tn3270_ttype()) { 29632377Sminshall return; 29732377Sminshall } 29832377Sminshall #endif /* defined(TN3270) */ 29927676Sminshall name = getenv("TERM"); 30027676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 30127676Sminshall name = "UNKNOWN"; 30227676Sminshall } 30327676Sminshall if ((len + 4+2) < NETROOM()) { 30427676Sminshall strcpy(namebuf, name); 30527676Sminshall upcase(namebuf); 30632381Sminshall netoprint("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 30727676Sminshall TELQUAL_IS, namebuf, IAC, SE); 30832381Sminshall /* XXX */ 30932381Sminshall /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */ 31032377Sminshall } else { 31132381Sminshall ExitString("No room in buffer for terminal type.\n", 31232377Sminshall 1); 31332377Sminshall /*NOTREACHED*/ 31427676Sminshall } 31527676Sminshall } 31627676Sminshall 31727676Sminshall default: 31827676Sminshall break; 31927676Sminshall } 32027676Sminshall } 32132377Sminshall 32227088Sminshall 32332385Sminshall static int 32432377Sminshall telrcv() 32527110Sminshall { 32632377Sminshall register int c; 32732385Sminshall register int scc; 32832385Sminshall register char *sbp; 32932385Sminshall int count; 33032385Sminshall int returnValue = 0; 33127088Sminshall 33232385Sminshall scc = 0; 33332385Sminshall count = 0; 33432385Sminshall while (TTYROOM() > 2) { 33532385Sminshall if (scc == 0) { 33632385Sminshall if (count) { 33732528Sminshall ring_consumed(&netiring, count); 33832385Sminshall returnValue = 1; 33932385Sminshall count = 0; 34032385Sminshall } 34132528Sminshall sbp = netiring.consume; 34232528Sminshall scc = ring_full_consecutive(&netiring); 34332385Sminshall if (scc == 0) { 34432385Sminshall /* No more data coming in */ 34532385Sminshall break; 34632385Sminshall } 34732385Sminshall } 34832385Sminshall 34932385Sminshall c = *sbp++ & 0xff, scc--; count++; 35032385Sminshall 35132377Sminshall switch (telrcv_state) { 35227110Sminshall 35332377Sminshall case TS_CR: 35432377Sminshall telrcv_state = TS_DATA; 35532377Sminshall if (c == '\0') { 35632377Sminshall break; /* Ignore \0 after CR */ 35732377Sminshall } else if (c == '\n') { 35832377Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 35932377Sminshall TTYADD(c); 36032377Sminshall } 36132377Sminshall break; 36232377Sminshall } 36332377Sminshall /* Else, fall through */ 36427088Sminshall 36532377Sminshall case TS_DATA: 36632377Sminshall if (c == IAC) { 36732377Sminshall telrcv_state = TS_IAC; 36832377Sminshall continue; 36932377Sminshall } 37032377Sminshall # if defined(TN3270) 37132377Sminshall if (In3270) { 37232377Sminshall *Ifrontp++ = c; 37332385Sminshall while (scc > 0) { 37432385Sminshall c = *sbp++ & 0377, scc--; count++; 37532377Sminshall if (c == IAC) { 37632377Sminshall telrcv_state = TS_IAC; 37732377Sminshall break; 37832377Sminshall } 37932377Sminshall *Ifrontp++ = c; 38032377Sminshall } 38132377Sminshall } else 38232377Sminshall # endif /* defined(TN3270) */ 38332377Sminshall /* 38432377Sminshall * The 'crmod' hack (see following) is needed 38532377Sminshall * since we can't * set CRMOD on output only. 38632377Sminshall * Machines like MULTICS like to send \r without 38732377Sminshall * \n; since we must turn off CRMOD to get proper 38832377Sminshall * input, the mapping is done here (sigh). 38932377Sminshall */ 39032377Sminshall if ((c == '\r') && !hisopts[TELOPT_BINARY]) { 39132377Sminshall if (scc > 0) { 39232377Sminshall c = *sbp&0xff; 39332377Sminshall if (c == 0) { 39432385Sminshall sbp++, scc--; count++; 39532377Sminshall /* a "true" CR */ 39632377Sminshall TTYADD('\r'); 39732377Sminshall } else if (!hisopts[TELOPT_ECHO] && 39832377Sminshall (c == '\n')) { 39932385Sminshall sbp++, scc--; count++; 40032377Sminshall TTYADD('\n'); 40132377Sminshall } else { 40232377Sminshall TTYADD('\r'); 40332377Sminshall if (crmod) { 40432377Sminshall TTYADD('\n'); 40532377Sminshall } 40632377Sminshall } 40732377Sminshall } else { 40832377Sminshall telrcv_state = TS_CR; 40932377Sminshall TTYADD('\r'); 41032377Sminshall if (crmod) { 41132377Sminshall TTYADD('\n'); 41232377Sminshall } 41332377Sminshall } 41432377Sminshall } else { 41532377Sminshall TTYADD(c); 41632377Sminshall } 41732377Sminshall continue; 41827088Sminshall 41932377Sminshall case TS_IAC: 42032377Sminshall switch (c) { 42132377Sminshall 42232377Sminshall case WILL: 42332377Sminshall telrcv_state = TS_WILL; 42432377Sminshall continue; 42527261Sminshall 42632377Sminshall case WONT: 42732377Sminshall telrcv_state = TS_WONT; 42832377Sminshall continue; 42927261Sminshall 43032377Sminshall case DO: 43132377Sminshall telrcv_state = TS_DO; 43232377Sminshall continue; 43327261Sminshall 43432377Sminshall case DONT: 43532377Sminshall telrcv_state = TS_DONT; 43632377Sminshall continue; 43727261Sminshall 43832377Sminshall case DM: 43932377Sminshall /* 44032377Sminshall * We may have missed an urgent notification, 44132377Sminshall * so make sure we flush whatever is in the 44232377Sminshall * buffer currently. 44332377Sminshall */ 44432377Sminshall SYNCHing = 1; 44532377Sminshall ttyflush(1); 44632377Sminshall SYNCHing = stilloob(net); 44732377Sminshall settimer(gotDM); 44832377Sminshall break; 44927088Sminshall 45032377Sminshall case NOP: 45132377Sminshall case GA: 45232377Sminshall break; 45327088Sminshall 45432377Sminshall case SB: 45532377Sminshall SB_CLEAR(); 45632377Sminshall telrcv_state = TS_SB; 45732377Sminshall continue; 45827261Sminshall 45932377Sminshall # if defined(TN3270) 46032377Sminshall case EOR: 46132377Sminshall if (In3270) { 46232377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 46332377Sminshall if (Ibackp == Ifrontp) { 46432377Sminshall Ibackp = Ifrontp = Ibuf; 46532377Sminshall ISend = 0; /* should have been! */ 46632377Sminshall } else { 46732377Sminshall ISend = 1; 46827088Sminshall } 46927088Sminshall } 47027088Sminshall break; 47132377Sminshall # endif /* defined(TN3270) */ 47232377Sminshall 47332377Sminshall case IAC: 47432377Sminshall # if !defined(TN3270) 47532377Sminshall TTYADD(IAC); 47632377Sminshall # else /* !defined(TN3270) */ 47732377Sminshall if (In3270) { 47832377Sminshall *Ifrontp++ = IAC; 47932377Sminshall } else { 48032377Sminshall TTYADD(IAC); 48132377Sminshall } 48232377Sminshall # endif /* !defined(TN3270) */ 48327088Sminshall break; 48432377Sminshall 48527088Sminshall default: 48627088Sminshall break; 48727088Sminshall } 48832377Sminshall telrcv_state = TS_DATA; 48932377Sminshall continue; 49027088Sminshall 49132377Sminshall case TS_WILL: 49232377Sminshall printoption(">RCVD", will, c, !hisopts[c]); 49332377Sminshall if (c == TELOPT_TM) { 49432377Sminshall if (flushout) { 49532377Sminshall flushout = 0; 49632377Sminshall } 49732377Sminshall } else if (!hisopts[c]) { 49832377Sminshall willoption(c, 1); 49932377Sminshall } 50032377Sminshall SetIn3270(); 50132377Sminshall telrcv_state = TS_DATA; 50232377Sminshall continue; 50327110Sminshall 50432377Sminshall case TS_WONT: 50532377Sminshall printoption(">RCVD", wont, c, hisopts[c]); 50632377Sminshall if (c == TELOPT_TM) { 50732377Sminshall if (flushout) { 50832377Sminshall flushout = 0; 50932377Sminshall } 51032377Sminshall } else if (hisopts[c]) { 51132377Sminshall wontoption(c, 1); 51232377Sminshall } 51332377Sminshall SetIn3270(); 51432377Sminshall telrcv_state = TS_DATA; 51532377Sminshall continue; 51627088Sminshall 51732377Sminshall case TS_DO: 51832377Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 51932377Sminshall if (!myopts[c]) 52032377Sminshall dooption(c); 52132377Sminshall SetIn3270(); 52232377Sminshall telrcv_state = TS_DATA; 52332377Sminshall continue; 52427088Sminshall 52532377Sminshall case TS_DONT: 52632377Sminshall printoption(">RCVD", dont, c, myopts[c]); 52732377Sminshall if (myopts[c]) { 52832377Sminshall myopts[c] = 0; 52932381Sminshall netoprint(wont, c); 53032377Sminshall flushline = 1; 53132377Sminshall setconnmode(); /* set new tty mode (maybe) */ 53232377Sminshall printoption(">SENT", wont, c, 0); 53332377Sminshall } 53432377Sminshall SetIn3270(); 53532377Sminshall telrcv_state = TS_DATA; 53632377Sminshall continue; 53727088Sminshall 53832377Sminshall case TS_SB: 53932377Sminshall if (c == IAC) { 54032377Sminshall telrcv_state = TS_SE; 54132377Sminshall } else { 54232377Sminshall SB_ACCUM(c); 54332377Sminshall } 54432377Sminshall continue; 54527088Sminshall 54632377Sminshall case TS_SE: 54732377Sminshall if (c != SE) { 54832377Sminshall if (c != IAC) { 54932377Sminshall SB_ACCUM(IAC); 55032377Sminshall } 55132377Sminshall SB_ACCUM(c); 55232377Sminshall telrcv_state = TS_SB; 55332377Sminshall } else { 55432377Sminshall SB_TERM(); 55532377Sminshall suboption(); /* handle sub-option */ 55632377Sminshall SetIn3270(); 55732377Sminshall telrcv_state = TS_DATA; 55832377Sminshall } 55927088Sminshall } 56027088Sminshall } 56132528Sminshall ring_consumed(&netiring, count); 56232385Sminshall return returnValue||count; 56327088Sminshall } 56432385Sminshall 56532385Sminshall static int 56632385Sminshall telsnd(ring) 56732385Sminshall Ring *ring; /* Input ring */ 56832385Sminshall { 56932385Sminshall int tcc; 57032385Sminshall int count; 57132385Sminshall int returnValue = 0; 57232385Sminshall char *tbp; 57332385Sminshall 57432385Sminshall tcc = 0; 57532385Sminshall count = 0; 57632385Sminshall while (NETROOM() > 2) { 57732385Sminshall register int sc; 57832385Sminshall register int c; 57932385Sminshall 58032385Sminshall if (tcc == 0) { 58132385Sminshall if (count) { 58232528Sminshall ring_consumed(&ttyiring, count); 58332385Sminshall returnValue = 1; 58432385Sminshall count = 0; 58532385Sminshall } 58632528Sminshall tbp = ttyiring.consume; 58732528Sminshall tcc = ring_full_consecutive(&ttyiring); 58832385Sminshall if (tcc == 0) { 58932385Sminshall break; 59032385Sminshall } 59132385Sminshall } 59232385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 59332385Sminshall if (sc == escape) { 59432385Sminshall command(0); 59532385Sminshall tcc = 0; 59632385Sminshall flushline = 1; 59732385Sminshall break; 59832385Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 59932385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 60032385Sminshall tcc--; tbp++; count++; 60132385Sminshall } else { 60232385Sminshall dontlecho = !dontlecho; 60332385Sminshall settimer(echotoggle); 60432385Sminshall setconnmode(); 60532385Sminshall flushline = 1; 60632385Sminshall break; 60732385Sminshall } 60832385Sminshall } 60932385Sminshall if (localchars) { 61032385Sminshall if (TerminalSpecialChars(sc) == 0) { 61132385Sminshall break; 61232385Sminshall } 61332385Sminshall } 61432385Sminshall if (!myopts[TELOPT_BINARY]) { 61532385Sminshall switch (c) { 61632385Sminshall case '\n': 61732385Sminshall /* 61832385Sminshall * If we are in CRMOD mode (\r ==> \n) 61932385Sminshall * on our local machine, then probably 62032385Sminshall * a newline (unix) is CRLF (TELNET). 62132385Sminshall */ 62232385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 62332385Sminshall NETADD('\r'); 62432385Sminshall } 62532385Sminshall NETADD('\n'); 62632385Sminshall flushline = 1; 62732385Sminshall break; 62832385Sminshall case '\r': 62932385Sminshall if (!crlf) { 63032385Sminshall NET2ADD('\r', '\0'); 63132385Sminshall } else { 63232385Sminshall NET2ADD('\r', '\n'); 63332385Sminshall } 63432385Sminshall flushline = 1; 63532385Sminshall break; 63632385Sminshall case IAC: 63732385Sminshall NET2ADD(IAC, IAC); 63832385Sminshall break; 63932385Sminshall default: 64032385Sminshall NETADD(c); 64132385Sminshall break; 64232385Sminshall } 64332385Sminshall } else if (c == IAC) { 64432385Sminshall NET2ADD(IAC, IAC); 64532385Sminshall } else { 64632385Sminshall NETADD(c); 64732385Sminshall } 64832385Sminshall } 64932528Sminshall ring_consumed(&ttyiring, count); 65032385Sminshall return returnValue||count; /* Non-zero if we did anything */ 65132385Sminshall } 65232377Sminshall 65327088Sminshall /* 65432377Sminshall * Scheduler() 65532377Sminshall * 65632377Sminshall * Try to do something. 65732377Sminshall * 65832377Sminshall * If we do something useful, return 1; else return 0. 65932377Sminshall * 66027110Sminshall */ 66127110Sminshall 66227110Sminshall 66332377Sminshall int 66432377Sminshall Scheduler(block) 66532377Sminshall int block; /* should we block in the select ? */ 66627110Sminshall { 66732377Sminshall register int c; 66832377Sminshall /* One wants to be a bit careful about setting returnValue 66932377Sminshall * to one, since a one implies we did some useful work, 67032377Sminshall * and therefore probably won't be called to block next 67132377Sminshall * time (TN3270 mode only). 67232377Sminshall */ 673*32531Sminshall int returnValue; 674*32531Sminshall int netin, netout, netex, ttyin, ttyout; 67527110Sminshall 676*32531Sminshall /* Decide which rings should be processed */ 677*32531Sminshall 678*32531Sminshall netout = ring_full_count(&netoring) && 679*32531Sminshall (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]); 680*32531Sminshall ttyout = ring_full_count(&ttyoring); 681*32531Sminshall 68232377Sminshall #if defined(TN3270) 683*32531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 68432377Sminshall #else /* defined(TN3270) */ 685*32531Sminshall ttyin = ring_empty_count(&ttyiring); 68632377Sminshall #endif /* defined(TN3270) */ 687*32531Sminshall 688*32531Sminshall #if defined(TN3270) 689*32531Sminshall netin = ring_empty_count(&netiring); 69032377Sminshall # else /* !defined(TN3270) */ 691*32531Sminshall netin = !ISend && ring_empty_count(&netiring); 69232377Sminshall # endif /* !defined(TN3270) */ 693*32531Sminshall 694*32531Sminshall netex = !SYNCHing; 695*32531Sminshall 696*32531Sminshall /* If we have seen a signal recently, reset things */ 69732377Sminshall # if defined(TN3270) && defined(unix) 69832377Sminshall if (HaveInput) { 69932377Sminshall HaveInput = 0; 70032377Sminshall signal(SIGIO, inputAvailable); 70132377Sminshall } 70232377Sminshall #endif /* defined(TN3270) && defined(unix) */ 70332377Sminshall 704*32531Sminshall /* Call to system code to process rings */ 70527178Sminshall 706*32531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 70727178Sminshall 708*32531Sminshall /* Now, look at the input rings, looking for work to do. */ 70932377Sminshall 710*32531Sminshall if (ring_full_count(&ttyiring)) { 71132377Sminshall # if defined(TN3270) 71232377Sminshall if (In3270) { 71332385Sminshall c = DataFromTerminal(ttyiring.send, 71432528Sminshall ring_full_consecutive(&ttyiring)); 71532377Sminshall if (c) { 71632377Sminshall returnValue = 1; 71732377Sminshall } 71832528Sminshall ring_consumed(&ttyiring, c); 71932377Sminshall } else { 72032377Sminshall # endif /* defined(TN3270) */ 72132385Sminshall returnValue |= telsnd(&ttyiring); 72232377Sminshall # if defined(TN3270) 72327178Sminshall } 724*32531Sminshall # endif /* defined(TN3270) */ 72527178Sminshall } 72632377Sminshall 72732528Sminshall if (ring_full_count(&netiring)) { 72832377Sminshall # if !defined(TN3270) 72932385Sminshall returnValue |= telrcv(); 73032377Sminshall # else /* !defined(TN3270) */ 73132377Sminshall returnValue = Push3270(); 73232377Sminshall # endif /* !defined(TN3270) */ 73332377Sminshall } 73432377Sminshall return returnValue; 73527178Sminshall } 73627178Sminshall 73727178Sminshall /* 73832377Sminshall * Select from tty and network... 73927088Sminshall */ 74032377Sminshall void 74132377Sminshall telnet() 74227088Sminshall { 743*32531Sminshall sys_telnet_init(); 74427088Sminshall 74532377Sminshall # if !defined(TN3270) 74632377Sminshall if (telnetport) { 74732377Sminshall if (!hisopts[TELOPT_SGA]) { 74832377Sminshall willoption(TELOPT_SGA, 0); 74927110Sminshall } 75032377Sminshall if (!myopts[TELOPT_TTYPE]) { 75132377Sminshall dooption(TELOPT_TTYPE, 0); 75232377Sminshall } 75327178Sminshall } 75432377Sminshall # endif /* !defined(TN3270) */ 75527088Sminshall 75632377Sminshall # if !defined(TN3270) 75732377Sminshall for (;;) { 75832385Sminshall int schedValue; 75932385Sminshall 76032385Sminshall while ((schedValue = Scheduler(0)) != 0) { 76132385Sminshall if (schedValue == -1) { 76232385Sminshall setcommandmode(); 76332385Sminshall return; 76432385Sminshall } 76532385Sminshall } 76632385Sminshall 767*32531Sminshall if (Scheduler(1) == -1) { 76832377Sminshall setcommandmode(); 76932377Sminshall return; 77032377Sminshall } 77132377Sminshall } 77232377Sminshall # else /* !defined(TN3270) */ 77332377Sminshall for (;;) { 77432377Sminshall int schedValue; 77527088Sminshall 77632377Sminshall while (!In3270 && !shell_active) { 777*32531Sminshall if (Scheduler(1) == -1) { 77832377Sminshall setcommandmode(); 77932377Sminshall return; 78032377Sminshall } 78127088Sminshall } 78232377Sminshall 78332377Sminshall while ((schedValue = Scheduler(0)) != 0) { 78432377Sminshall if (schedValue == -1) { 78532377Sminshall setcommandmode(); 78632377Sminshall return; 78732377Sminshall } 78827088Sminshall } 78932377Sminshall /* If there is data waiting to go out to terminal, don't 79032377Sminshall * schedule any more data for the terminal. 79132377Sminshall */ 79232377Sminshall if (tfrontp-tbackp) { 79332377Sminshall schedValue = 1; 79427088Sminshall } else { 79532377Sminshall if (shell_active) { 79632377Sminshall if (shell_continue() == 0) { 79732377Sminshall ConnectScreen(); 79827088Sminshall } 79932377Sminshall } else if (In3270) { 80032377Sminshall schedValue = DoTerminalOutput(); 80132377Sminshall } 80227088Sminshall } 80332377Sminshall if (schedValue && (shell_active == 0)) { 804*32531Sminshall if (Scheduler(1) == -1) { 80532377Sminshall setcommandmode(); 80632377Sminshall return; 80732377Sminshall } 80827088Sminshall } 80932377Sminshall } 81032377Sminshall # endif /* !defined(TN3270) */ 81127088Sminshall } 81232377Sminshall 81327088Sminshall /* 81432377Sminshall * These routines add various telnet commands to the data stream. 81527088Sminshall */ 81632377Sminshall 81732377Sminshall void 81832377Sminshall xmitAO() 81927088Sminshall { 82032377Sminshall NET2ADD(IAC, AO); 82132377Sminshall if (autoflush) { 82232377Sminshall doflush(); 82332377Sminshall } 82432377Sminshall } 82527088Sminshall 82632377Sminshall 82732377Sminshall void 82832377Sminshall xmitEL() 82927088Sminshall { 83032377Sminshall NET2ADD(IAC, EL); 83127088Sminshall } 83227088Sminshall 83332377Sminshall void 83432377Sminshall xmitEC() 83527088Sminshall { 83632377Sminshall NET2ADD(IAC, EC); 83727088Sminshall } 83827088Sminshall 83932377Sminshall 84032377Sminshall #if defined(NOT43) 84132377Sminshall int 84232377Sminshall #else /* defined(NOT43) */ 84332377Sminshall void 84432377Sminshall #endif /* defined(NOT43) */ 84532377Sminshall dosynch() 84627088Sminshall { 84732377Sminshall netclear(); /* clear the path to the network */ 84832377Sminshall NET2ADD(IAC, DM); 84927088Sminshall 85032377Sminshall #if defined(NOT43) 85132377Sminshall return 0; 85232377Sminshall #endif /* defined(NOT43) */ 85327088Sminshall } 85427088Sminshall 85532377Sminshall void 85632377Sminshall doflush() 85727088Sminshall { 85832377Sminshall NET2ADD(IAC, DO); 85932377Sminshall NETADD(TELOPT_TM); 86032377Sminshall flushline = 1; 86132377Sminshall flushout = 1; 86232377Sminshall ttyflush(1); /* Flush/drop output */ 86332377Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 86432377Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 86527088Sminshall } 86627088Sminshall 86732377Sminshall void 86832377Sminshall intp() 86927088Sminshall { 87032377Sminshall NET2ADD(IAC, IP); 87132377Sminshall flushline = 1; 87232377Sminshall if (autoflush) { 87332377Sminshall doflush(); 87432377Sminshall } 87532377Sminshall if (autosynch) { 87632377Sminshall dosynch(); 87732377Sminshall } 87827088Sminshall } 87927186Sminshall 88032377Sminshall void 88132377Sminshall sendbrk() 88227186Sminshall { 88332377Sminshall NET2ADD(IAC, BREAK); 88432377Sminshall flushline = 1; 88532377Sminshall if (autoflush) { 88632377Sminshall doflush(); 88732377Sminshall } 88832377Sminshall if (autosynch) { 88932377Sminshall dosynch(); 89032377Sminshall } 89127186Sminshall } 892