138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*44364Sborman static char sccsid[] = "@(#)state.c 5.7 (Berkeley) 06/28/90"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman #include "telnetd.h" 1338905Sborman 1438905Sborman char doopt[] = { IAC, DO, '%', 'c', 0 }; 1538905Sborman char dont[] = { IAC, DONT, '%', 'c', 0 }; 1638905Sborman char will[] = { IAC, WILL, '%', 'c', 0 }; 1738905Sborman char wont[] = { IAC, WONT, '%', 'c', 0 }; 1838905Sborman int not42 = 1; 1938905Sborman 2038905Sborman /* 2138905Sborman * Buffer for sub-options, and macros 2238905Sborman * for suboptions buffer manipulations 2338905Sborman */ 2438905Sborman char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer; 2538905Sborman 2638905Sborman #define SB_CLEAR() subpointer = subbuffer; 2738905Sborman #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 2838905Sborman #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 2938905Sborman *subpointer++ = (c); \ 3038905Sborman } 3138905Sborman #define SB_GET() ((*subpointer++)&0xff) 3238905Sborman #define SB_EOF() (subpointer >= subend) 33*44364Sborman #define SB_LEN() (subend - subpointer) 3438905Sborman 3538905Sborman 3638905Sborman 3738905Sborman /* 3838905Sborman * State for recv fsm 3938905Sborman */ 4038905Sborman #define TS_DATA 0 /* base state */ 4138905Sborman #define TS_IAC 1 /* look for double IAC's */ 4238905Sborman #define TS_CR 2 /* CR-LF ->'s CR */ 4338905Sborman #define TS_SB 3 /* throw away begin's... */ 4438905Sborman #define TS_SE 4 /* ...end's (suboption negotiation) */ 4538905Sborman #define TS_WILL 5 /* will option negotiation */ 4638905Sborman #define TS_WONT 6 /* wont " */ 4738905Sborman #define TS_DO 7 /* do " */ 4838905Sborman #define TS_DONT 8 /* dont " */ 4938905Sborman 5038905Sborman telrcv() 5138905Sborman { 5238905Sborman register int c; 5338905Sborman static int state = TS_DATA; 5440242Sborman #if defined(CRAY2) && defined(UNICOS5) 5538905Sborman char *opfrontp = pfrontp; 5638905Sborman #endif 5738905Sborman 5838905Sborman while (ncc > 0) { 5938905Sborman if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 6038905Sborman break; 6138905Sborman c = *netip++ & 0377, ncc--; 6238905Sborman switch (state) { 6338905Sborman 6438905Sborman case TS_CR: 6538905Sborman state = TS_DATA; 6638905Sborman /* Strip off \n or \0 after a \r */ 6738905Sborman if ((c == 0) || (c == '\n')) { 6838905Sborman break; 6938905Sborman } 7038905Sborman /* FALL THROUGH */ 7138905Sborman 7238905Sborman case TS_DATA: 7338905Sborman if (c == IAC) { 7438905Sborman state = TS_IAC; 7538905Sborman break; 7638905Sborman } 7738905Sborman /* 7838905Sborman * We now map \r\n ==> \r for pragmatic reasons. 7938905Sborman * Many client implementations send \r\n when 8038905Sborman * the user hits the CarriageReturn key. 8138905Sborman * 8238905Sborman * We USED to map \r\n ==> \n, since \r\n says 8338905Sborman * that we want to be in column 1 of the next 8438905Sborman * printable line, and \n is the standard 8538905Sborman * unix way of saying that (\r is only good 8638905Sborman * if CRMOD is set, which it normally is). 8738905Sborman */ 88*44364Sborman if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { 8938905Sborman /* 9038905Sborman * If we are operating in linemode, 9138905Sborman * convert to local end-of-line. 9238905Sborman */ 9338905Sborman if ((linemode) && (ncc > 0)&&('\n' == *netip)) { 9438905Sborman netip++; ncc--; 9538905Sborman c = '\n'; 9638905Sborman } else { 9738905Sborman state = TS_CR; 9838905Sborman } 9938905Sborman } 10038905Sborman *pfrontp++ = c; 10138905Sborman break; 10238905Sborman 10338905Sborman case TS_IAC: 10438905Sborman gotiac: switch (c) { 10538905Sborman 10638905Sborman /* 10738905Sborman * Send the process on the pty side an 10838905Sborman * interrupt. Do this with a NULL or 10938905Sborman * interrupt char; depending on the tty mode. 11038905Sborman */ 11138905Sborman case IP: 112*44364Sborman #ifdef DIAGNOSTICS 113*44364Sborman if (diagnostic & TD_OPTIONS) 114*44364Sborman printoption("td: recv IAC", c); 115*44364Sborman #endif /* DIAGNOSTICS */ 11638905Sborman interrupt(); 11738905Sborman break; 11838905Sborman 11938905Sborman case BREAK: 120*44364Sborman #ifdef DIAGNOSTICS 121*44364Sborman if (diagnostic & TD_OPTIONS) 122*44364Sborman printoption("td: recv IAC", c); 123*44364Sborman #endif /* DIAGNOSTICS */ 12438905Sborman sendbrk(); 12538905Sborman break; 12638905Sborman 12738905Sborman /* 12838905Sborman * Are You There? 12938905Sborman */ 13038905Sborman case AYT: 131*44364Sborman #ifdef DIAGNOSTICS 132*44364Sborman if (diagnostic & TD_OPTIONS) 133*44364Sborman printoption("td: recv IAC", c); 134*44364Sborman #endif /* DIAGNOSTICS */ 13538905Sborman (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); 13638905Sborman nfrontp += 9; 13738905Sborman break; 13838905Sborman 13938905Sborman /* 14038905Sborman * Abort Output 14138905Sborman */ 14238905Sborman case AO: 14338905Sborman { 144*44364Sborman #ifdef DIAGNOSTICS 145*44364Sborman if (diagnostic & TD_OPTIONS) 146*44364Sborman printoption("td: recv IAC", c); 147*44364Sborman #endif /* DIAGNOSTICS */ 14838905Sborman ptyflush(); /* half-hearted */ 14938905Sborman init_termbuf(); 15038905Sborman 15138905Sborman if (slctab[SLC_AO].sptr && 15240242Sborman *slctab[SLC_AO].sptr != (cc_t)-1) { 15340242Sborman *pfrontp++ = 15440242Sborman (unsigned char)*slctab[SLC_AO].sptr; 15538905Sborman } 15638905Sborman 15738905Sborman netclear(); /* clear buffer back */ 15838905Sborman *nfrontp++ = IAC; 15938905Sborman *nfrontp++ = DM; 16038905Sborman neturg = nfrontp-1; /* off by one XXX */ 161*44364Sborman #ifdef DIAGNOSTICS 162*44364Sborman if (diagnostic & TD_OPTIONS) 163*44364Sborman printoption("td: send IAC", DM); 164*44364Sborman #endif /* DIAGNOSTICS */ 16538905Sborman break; 16638905Sborman } 16738905Sborman 16838905Sborman /* 16938905Sborman * Erase Character and 17038905Sborman * Erase Line 17138905Sborman */ 17238905Sborman case EC: 17338905Sborman case EL: 17438905Sborman { 17540242Sborman cc_t ch; 17638905Sborman 177*44364Sborman #ifdef DIAGNOSTICS 178*44364Sborman if (diagnostic & TD_OPTIONS) 179*44364Sborman printoption("td: recv IAC", c); 180*44364Sborman #endif /* DIAGNOSTICS */ 18138905Sborman ptyflush(); /* half-hearted */ 18238905Sborman init_termbuf(); 183*44364Sborman if (c == EC) 184*44364Sborman ch = *slctab[SLC_EC].sptr; 185*44364Sborman else 186*44364Sborman ch = *slctab[SLC_EL].sptr; 18740242Sborman if (ch != (cc_t)-1) 18840242Sborman *pfrontp++ = (unsigned char)ch; 18938905Sborman break; 19038905Sborman } 19138905Sborman 19238905Sborman /* 19338905Sborman * Check for urgent data... 19438905Sborman */ 19538905Sborman case DM: 196*44364Sborman #ifdef DIAGNOSTICS 197*44364Sborman if (diagnostic & TD_OPTIONS) 198*44364Sborman printoption("td: recv IAC", c); 199*44364Sborman #endif /* DIAGNOSTICS */ 20038905Sborman SYNCHing = stilloob(net); 20138905Sborman settimer(gotDM); 20238905Sborman break; 20338905Sborman 20438905Sborman 20538905Sborman /* 20638905Sborman * Begin option subnegotiation... 20738905Sborman */ 20838905Sborman case SB: 20938905Sborman state = TS_SB; 21038905Sborman SB_CLEAR(); 21138905Sborman continue; 21238905Sborman 21338905Sborman case WILL: 21438905Sborman state = TS_WILL; 21538905Sborman continue; 21638905Sborman 21738905Sborman case WONT: 21838905Sborman state = TS_WONT; 21938905Sborman continue; 22038905Sborman 22138905Sborman case DO: 22238905Sborman state = TS_DO; 22338905Sborman continue; 22438905Sborman 22538905Sborman case DONT: 22638905Sborman state = TS_DONT; 22738905Sborman continue; 22838905Sborman case EOR: 229*44364Sborman if (his_state_is_will(TELOPT_EOR)) 23038905Sborman doeof(); 23138905Sborman break; 23238905Sborman 23338905Sborman /* 23438905Sborman * Handle RFC 10xx Telnet linemode option additions 23538905Sborman * to command stream (EOF, SUSP, ABORT). 23638905Sborman */ 23738905Sborman case xEOF: 23838905Sborman doeof(); 23938905Sborman break; 24038905Sborman 24138905Sborman case SUSP: 24238905Sborman sendsusp(); 24338905Sborman break; 24438905Sborman 24538905Sborman case ABORT: 24638905Sborman sendbrk(); 24738905Sborman break; 24838905Sborman 24938905Sborman case IAC: 25038905Sborman *pfrontp++ = c; 25138905Sborman break; 25238905Sborman } 25338905Sborman state = TS_DATA; 25438905Sborman break; 25538905Sborman 25638905Sborman case TS_SB: 25738905Sborman if (c == IAC) { 25838905Sborman state = TS_SE; 25938905Sborman } else { 26038905Sborman SB_ACCUM(c); 26138905Sborman } 26238905Sborman break; 26338905Sborman 26438905Sborman case TS_SE: 26538905Sborman if (c != SE) { 26638905Sborman if (c != IAC) { 26738905Sborman /* 26838905Sborman * bad form of suboption negotiation. 26938905Sborman * handle it in such a way as to avoid 27038905Sborman * damage to local state. Parse 27138905Sborman * suboption buffer found so far, 27238905Sborman * then treat remaining stream as 27338905Sborman * another command sequence. 27438905Sborman */ 275*44364Sborman #ifdef DIAGNOSTICS 276*44364Sborman SB_ACCUM(IAC); 277*44364Sborman SB_ACCUM(c); 278*44364Sborman subpointer -= 2; 279*44364Sborman #endif 28038905Sborman SB_TERM(); 28138905Sborman suboption(); 28238905Sborman state = TS_IAC; 28338905Sborman goto gotiac; 28438905Sborman } 28538905Sborman SB_ACCUM(c); 28638905Sborman state = TS_SB; 28738905Sborman } else { 288*44364Sborman #ifdef DIAGNOSTICS 289*44364Sborman SB_ACCUM(IAC); 290*44364Sborman SB_ACCUM(SE); 291*44364Sborman subpointer -= 2; 292*44364Sborman #endif 29338905Sborman SB_TERM(); 29438905Sborman suboption(); /* handle sub-option */ 29538905Sborman state = TS_DATA; 29638905Sborman } 29738905Sborman break; 29838905Sborman 29938905Sborman case TS_WILL: 30039503Sborman willoption(c); 30138905Sborman state = TS_DATA; 30238905Sborman continue; 30338905Sborman 30438905Sborman case TS_WONT: 30539503Sborman wontoption(c); 30638905Sborman state = TS_DATA; 30738905Sborman continue; 30838905Sborman 30938905Sborman case TS_DO: 31039503Sborman dooption(c); 31138905Sborman state = TS_DATA; 31238905Sborman continue; 31338905Sborman 31438905Sborman case TS_DONT: 31539503Sborman dontoption(c); 31638905Sborman state = TS_DATA; 31738905Sborman continue; 31838905Sborman 31938905Sborman default: 32038905Sborman syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 32138905Sborman printf("telnetd: panic state=%d\n", state); 32238905Sborman exit(1); 32338905Sborman } 32438905Sborman } 32540242Sborman #if defined(CRAY2) && defined(UNICOS5) 32638905Sborman if (!linemode) { 32738905Sborman char xptyobuf[BUFSIZ+NETSLOP]; 32838905Sborman char xbuf2[BUFSIZ]; 32938905Sborman register char *cp; 33038905Sborman int n = pfrontp - opfrontp, oc; 33138905Sborman bcopy(opfrontp, xptyobuf, n); 33238905Sborman pfrontp = opfrontp; 33338905Sborman pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, 33438905Sborman xbuf2, &oc, BUFSIZ); 33538905Sborman for (cp = xbuf2; oc > 0; --oc) 33638905Sborman if ((*nfrontp++ = *cp++) == IAC) 33738905Sborman *nfrontp++ = IAC; 33838905Sborman } 33940242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 34038905Sborman } /* end of telrcv */ 34138905Sborman 34238905Sborman /* 34338905Sborman * The will/wont/do/dont state machines are based on Dave Borman's 344*44364Sborman * Telnet option processing state machine. 34538905Sborman * 34638905Sborman * These correspond to the following states: 34738905Sborman * my_state = the last negotiated state 34838905Sborman * want_state = what I want the state to go to 34938905Sborman * want_resp = how many requests I have sent 35038905Sborman * All state defaults are negative, and resp defaults to 0. 35138905Sborman * 35238905Sborman * When initiating a request to change state to new_state: 35338905Sborman * 35438905Sborman * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 35538905Sborman * do nothing; 35638905Sborman * } else { 35738905Sborman * want_state = new_state; 35838905Sborman * send new_state; 35938905Sborman * want_resp++; 36038905Sborman * } 36138905Sborman * 36238905Sborman * When receiving new_state: 36338905Sborman * 36438905Sborman * if (want_resp) { 36538905Sborman * want_resp--; 36638905Sborman * if (want_resp && (new_state == my_state)) 36738905Sborman * want_resp--; 36838905Sborman * } 36938905Sborman * if ((want_resp == 0) && (new_state != want_state)) { 37038905Sborman * if (ok_to_switch_to new_state) 37138905Sborman * want_state = new_state; 37238905Sborman * else 37338905Sborman * want_resp++; 37438905Sborman * send want_state; 37538905Sborman * } 37638905Sborman * my_state = new_state; 37738905Sborman * 37838905Sborman * Note that new_state is implied in these functions by the function itself. 37938905Sborman * will and do imply positive new_state, wont and dont imply negative. 38038905Sborman * 38138905Sborman * Finally, there is one catch. If we send a negative response to a 38238905Sborman * positive request, my_state will be the positive while want_state will 38338905Sborman * remain negative. my_state will revert to negative when the negative 38438905Sborman * acknowlegment arrives from the peer. Thus, my_state generally tells 38538905Sborman * us not only the last negotiated state, but also tells us what the peer 38638905Sborman * wants to be doing as well. It is important to understand this difference 38738905Sborman * as we may wish to be processing data streams based on our desired state 38838905Sborman * (want_state) or based on what the peer thinks the state is (my_state). 38938905Sborman * 39038905Sborman * This all works fine because if the peer sends a positive request, the data 39138905Sborman * that we receive prior to negative acknowlegment will probably be affected 39238905Sborman * by the positive state, and we can process it as such (if we can; if we 39338905Sborman * can't then it really doesn't matter). If it is that important, then the 39438905Sborman * peer probably should be buffering until this option state negotiation 39538905Sborman * is complete. 39638905Sborman * 39738905Sborman */ 39839503Sborman send_do(option, init) 39939503Sborman int option, init; 40038905Sborman { 40139503Sborman if (init) { 402*44364Sborman if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 403*44364Sborman his_want_state_is_will(option)) 40439503Sborman return; 40539531Sborman /* 40639531Sborman * Special case for TELOPT_TM: We send a DO, but pretend 40739531Sborman * that we sent a DONT, so that we can send more DOs if 40839531Sborman * we want to. 40939531Sborman */ 41039531Sborman if (option == TELOPT_TM) 411*44364Sborman set_his_want_state_wont(option); 41239531Sborman else 413*44364Sborman set_his_want_state_will(option); 41439503Sborman do_dont_resp[option]++; 41539503Sborman } 41639503Sborman (void) sprintf(nfrontp, doopt, option); 41739503Sborman nfrontp += sizeof (dont) - 2; 418*44364Sborman #ifdef DIAGNOSTICS 419*44364Sborman /* 420*44364Sborman * Report sending option to other side. 421*44364Sborman */ 422*44364Sborman if (diagnostic & TD_OPTIONS) { 423*44364Sborman printoption("td: send do", option); 424*44364Sborman } 425*44364Sborman #endif /* DIAGNOSTICS */ 42639503Sborman } 42739503Sborman 42839503Sborman willoption(option) 42939503Sborman int option; 43039503Sborman { 43138905Sborman int changeok = 0; 43238905Sborman 43339503Sborman /* 43439503Sborman * process input from peer. 43539503Sborman */ 43639503Sborman 437*44364Sborman #ifdef DIAGNOSTICS 438*44364Sborman /* 439*44364Sborman * Report receiving option from other side. 440*44364Sborman */ 441*44364Sborman if (diagnostic & TD_OPTIONS) { 442*44364Sborman printoption("td: recv will", option); 443*44364Sborman } 444*44364Sborman #endif /* DIAGNOSTICS */ 445*44364Sborman 44639503Sborman if (do_dont_resp[option]) { 44739503Sborman do_dont_resp[option]--; 448*44364Sborman if (do_dont_resp[option] && his_state_is_will(option)) 44939503Sborman do_dont_resp[option]--; 45039503Sborman } 45139531Sborman if (do_dont_resp[option] == 0) { 452*44364Sborman if (his_want_state_is_wont(option)) { 45338905Sborman switch (option) { 45438905Sborman 45538905Sborman case TELOPT_BINARY: 45638905Sborman init_termbuf(); 45738905Sborman tty_binaryin(1); 45838905Sborman set_termbuf(); 45938905Sborman changeok++; 46038905Sborman break; 46138905Sborman 46238905Sborman case TELOPT_ECHO: 46338905Sborman /* 464*44364Sborman * See comments below for more info. 46538905Sborman */ 466*44364Sborman not42 = 0; /* looks like a 4.2 system */ 46738905Sborman break; 46838905Sborman 46938905Sborman case TELOPT_TM: 47038905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 47138905Sborman /* 47239503Sborman * This telnetd implementation does not really 47339503Sborman * support timing marks, it just uses them to 47439503Sborman * support the kludge linemode stuff. If we 47539503Sborman * receive a will or wont TM in response to our 47639503Sborman * do TM request that may have been sent to 47739503Sborman * determine kludge linemode support, process 47839503Sborman * it, otherwise TM should get a negative 47939503Sborman * response back. 48038905Sborman */ 48138905Sborman /* 48238905Sborman * Handle the linemode kludge stuff. 48338905Sborman * If we are not currently supporting any 48438905Sborman * linemode at all, then we assume that this 48538905Sborman * is the client telling us to use kludge 48638905Sborman * linemode in response to our query. Set the 48738905Sborman * linemode type that is to be supported, note 48838905Sborman * that the client wishes to use linemode, and 48938905Sborman * eat the will TM as though it never arrived. 49038905Sborman */ 49138905Sborman if (lmodetype < KLUDGE_LINEMODE) { 49238905Sborman lmodetype = KLUDGE_LINEMODE; 49338905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 49439503Sborman send_wont(TELOPT_SGA, 1); 49538905Sborman } 49638905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 49738905Sborman /* 49839531Sborman * We never respond to a WILL TM, and 499*44364Sborman * we leave the state WONT. 50038905Sborman */ 50138905Sborman return; 50238905Sborman 50338905Sborman case TELOPT_LFLOW: 50438905Sborman /* 50539503Sborman * If we are going to support flow control 50639503Sborman * option, then don't worry peer that we can't 50739503Sborman * change the flow control characters. 50838905Sborman */ 50938905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 51038905Sborman slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 51138905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 51238905Sborman slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 51338905Sborman case TELOPT_TTYPE: 51438905Sborman case TELOPT_SGA: 51538905Sborman case TELOPT_NAWS: 51638905Sborman case TELOPT_TSPEED: 517*44364Sborman case TELOPT_XDISPLOC: 518*44364Sborman case TELOPT_ENVIRON: 51939531Sborman changeok++; 52039531Sborman break; 52139531Sborman 52238905Sborman #ifdef LINEMODE 52338905Sborman case TELOPT_LINEMODE: 524*44364Sborman /* 525*44364Sborman * Local processing of 'will linemode' should 526*44364Sborman * occur after placing 'do linemode' in the data 527*44364Sborman * stream, because we may wish to send other 528*44364Sborman * linemode related messages. So, we duplicate 529*44364Sborman * the other three lines of code here, and then 530*44364Sborman * return. 531*44364Sborman */ 532*44364Sborman set_his_want_state_will(option); 533*44364Sborman send_do(option, 0); 534*44364Sborman set_his_state_will(option); 53539531Sborman # ifdef KLUDGELINEMODE 53639531Sborman /* 53739531Sborman * Note client's desire to use linemode. 53839531Sborman */ 53939531Sborman lmodetype = REAL_LINEMODE; 54039531Sborman # endif /* KLUDGELINEMODE */ 54139531Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 542*44364Sborman return; 54339531Sborman #endif /* LINEMODE */ 54438905Sborman 54538905Sborman default: 54638905Sborman break; 54738905Sborman } 54839503Sborman if (changeok) { 549*44364Sborman set_his_want_state_will(option); 55039503Sborman send_do(option, 0); 55139503Sborman } else { 55239503Sborman do_dont_resp[option]++; 55339503Sborman send_dont(option, 0); 55438905Sborman } 555*44364Sborman } else { 556*44364Sborman /* 557*44364Sborman * Option processing that should happen when 558*44364Sborman * we receive conformation of a change in 559*44364Sborman * state that we had requested. 560*44364Sborman */ 561*44364Sborman switch (option) { 562*44364Sborman case TELOPT_ECHO: 563*44364Sborman not42 = 0; /* looks like a 4.2 system */ 564*44364Sborman /* 565*44364Sborman * Egads, he responded "WILL ECHO". Turn 566*44364Sborman * it off right now! 567*44364Sborman */ 568*44364Sborman send_dont(option, 1); 569*44364Sborman /* 570*44364Sborman * "WILL ECHO". Kludge upon kludge! 571*44364Sborman * A 4.2 client is now echoing user input at 572*44364Sborman * the tty. This is probably undesireable and 573*44364Sborman * it should be stopped. The client will 574*44364Sborman * respond WONT TM to the DO TM that we send to 575*44364Sborman * check for kludge linemode. When the WONT TM 576*44364Sborman * arrives, linemode will be turned off and a 577*44364Sborman * change propogated to the pty. This change 578*44364Sborman * will cause us to process the new pty state 579*44364Sborman * in localstat(), which will notice that 580*44364Sborman * linemode is off and send a WILL ECHO 581*44364Sborman * so that we are properly in character mode and 582*44364Sborman * all is well. 583*44364Sborman */ 584*44364Sborman break; 585*44364Sborman #ifdef LINEMODE 586*44364Sborman case TELOPT_LINEMODE: 587*44364Sborman # ifdef KLUDGELINEMODE 588*44364Sborman /* 589*44364Sborman * Note client's desire to use linemode. 590*44364Sborman */ 591*44364Sborman lmodetype = REAL_LINEMODE; 592*44364Sborman # endif /* KLUDGELINEMODE */ 593*44364Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 594*44364Sborman #endif /* LINEMODE */ 595*44364Sborman } 59639531Sborman } 59738905Sborman } 598*44364Sborman set_his_state_will(option); 59938905Sborman } /* end of willoption */ 60038905Sborman 60139503Sborman send_dont(option, init) 60239503Sborman int option, init; 60338905Sborman { 60439503Sborman if (init) { 605*44364Sborman if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 606*44364Sborman his_want_state_is_wont(option)) 60739503Sborman return; 608*44364Sborman set_his_want_state_wont(option); 60939503Sborman do_dont_resp[option]++; 61039503Sborman } 61139503Sborman (void) sprintf(nfrontp, dont, option); 61239503Sborman nfrontp += sizeof (doopt) - 2; 613*44364Sborman #ifdef DIAGNOSTICS 614*44364Sborman /* 615*44364Sborman * Report sending option to other side. 616*44364Sborman */ 617*44364Sborman if (diagnostic & TD_OPTIONS) { 618*44364Sborman printoption("td: send dont", option); 619*44364Sborman } 620*44364Sborman #endif /* DIAGNOSTICS */ 62139503Sborman } 62239503Sborman 62339503Sborman wontoption(option) 62439503Sborman int option; 62539503Sborman { 62638905Sborman /* 62738905Sborman * Process client input. 62838905Sborman */ 62939503Sborman 630*44364Sborman #ifdef DIAGNOSTICS 631*44364Sborman /* 632*44364Sborman * Report receiving option from other side. 633*44364Sborman */ 634*44364Sborman if (diagnostic & TD_OPTIONS) { 635*44364Sborman printoption("td: recv wont", option); 636*44364Sborman } 637*44364Sborman #endif /* DIAGNOSTICS */ 638*44364Sborman 63939503Sborman if (do_dont_resp[option]) { 64039503Sborman do_dont_resp[option]--; 641*44364Sborman if (do_dont_resp[option] && his_state_is_wont(option)) 64239503Sborman do_dont_resp[option]--; 64339503Sborman } 64439531Sborman if (do_dont_resp[option] == 0) { 645*44364Sborman if (his_want_state_is_will(option)) { 64639503Sborman /* it is always ok to change to negative state */ 64738905Sborman switch (option) { 64838905Sborman case TELOPT_ECHO: 64939503Sborman not42 = 1; /* doesn't seem to be a 4.2 system */ 65038905Sborman break; 65138905Sborman 65238905Sborman case TELOPT_BINARY: 65338905Sborman init_termbuf(); 65438905Sborman tty_binaryin(0); 65538905Sborman set_termbuf(); 65638905Sborman break; 65738905Sborman 65838905Sborman #ifdef LINEMODE 65938905Sborman case TELOPT_LINEMODE: 66038905Sborman # ifdef KLUDGELINEMODE 66138905Sborman /* 66238905Sborman * If real linemode is supported, then client is 66338905Sborman * asking to turn linemode off. 66438905Sborman */ 665*44364Sborman if (lmodetype != REAL_LINEMODE) 666*44364Sborman break; 667*44364Sborman lmodetype = KLUDGE_LINEMODE; 66838905Sborman # endif /* KLUDGELINEMODE */ 669*44364Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 67038905Sborman break; 67138905Sborman #endif LINEMODE 67238905Sborman 67338905Sborman case TELOPT_TM: 67438905Sborman /* 67539503Sborman * If we get a WONT TM, and had sent a DO TM, 67639503Sborman * don't respond with a DONT TM, just leave it 67739503Sborman * as is. Short circut the state machine to 67839531Sborman * achive this. 67938905Sborman */ 680*44364Sborman set_his_want_state_wont(TELOPT_TM); 68138905Sborman return; 68238905Sborman 68338905Sborman case TELOPT_LFLOW: 68438905Sborman /* 68539503Sborman * If we are not going to support flow control 68639503Sborman * option, then let peer know that we can't 68739503Sborman * change the flow control characters. 68838905Sborman */ 68938905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 69038905Sborman slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 69138905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 69238905Sborman slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 69338905Sborman break; 69438905Sborman 695*44364Sborman /* 696*44364Sborman * For options that we might spin waiting for 697*44364Sborman * sub-negotiation, if the client turns off the 698*44364Sborman * option rather than responding to the request, 699*44364Sborman * we have to treat it here as if we got a response 700*44364Sborman * to the sub-negotiation, (by updating the timers) 701*44364Sborman * so that we'll break out of the loop. 702*44364Sborman */ 703*44364Sborman case TELOPT_TTYPE: 704*44364Sborman settimer(ttypesubopt); 705*44364Sborman break; 706*44364Sborman 707*44364Sborman case TELOPT_TSPEED: 708*44364Sborman settimer(tspeedsubopt); 709*44364Sborman break; 710*44364Sborman 711*44364Sborman case TELOPT_XDISPLOC: 712*44364Sborman settimer(xdisplocsubopt); 713*44364Sborman break; 714*44364Sborman 715*44364Sborman case TELOPT_ENVIRON: 716*44364Sborman settimer(environsubopt); 717*44364Sborman break; 718*44364Sborman 71938905Sborman default: 72038905Sborman break; 72138905Sborman } 722*44364Sborman set_his_want_state_wont(option); 723*44364Sborman if (his_state_is_will(option)) 724*44364Sborman send_dont(option, 0); 72539531Sborman } else { 72639531Sborman switch (option) { 72739531Sborman case TELOPT_TM: 72839531Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 72939531Sborman if (lmodetype < REAL_LINEMODE) { 73039531Sborman lmodetype = NO_LINEMODE; 73139531Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 73239531Sborman send_will(TELOPT_SGA, 1); 73339531Sborman /*@*/ send_will(TELOPT_ECHO, 1); 73439531Sborman } 73539531Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 73639531Sborman default: 73739531Sborman break; 73839531Sborman } 73939531Sborman } 74038905Sborman } 741*44364Sborman set_his_state_wont(option); 74238905Sborman 74339503Sborman } /* end of wontoption */ 74438905Sborman 74539503Sborman send_will(option, init) 74639503Sborman int option, init; 74739503Sborman { 74839503Sborman if (init) { 749*44364Sborman if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 750*44364Sborman my_want_state_is_will(option)) 75139503Sborman return; 752*44364Sborman set_my_want_state_will(option); 75339503Sborman will_wont_resp[option]++; 75438905Sborman } 75539503Sborman (void) sprintf(nfrontp, will, option); 75639503Sborman nfrontp += sizeof (doopt) - 2; 757*44364Sborman #ifdef DIAGNOSTICS 758*44364Sborman /* 759*44364Sborman * Report sending option to other side. 760*44364Sborman */ 761*44364Sborman if (diagnostic & TD_OPTIONS) { 762*44364Sborman printoption("td: send will", option); 763*44364Sborman } 764*44364Sborman #endif /* DIAGNOSTICS */ 76539503Sborman } 76638905Sborman 76739503Sborman dooption(option) 76839503Sborman int option; 76938905Sborman { 77038905Sborman int changeok = 0; 77138905Sborman 77238905Sborman /* 77338905Sborman * Process client input. 77438905Sborman */ 77539503Sborman 776*44364Sborman #ifdef DIAGNOSTICS 777*44364Sborman /* 778*44364Sborman * Report receiving option from other side. 779*44364Sborman */ 780*44364Sborman if (diagnostic & TD_OPTIONS) { 781*44364Sborman printoption("td: recv do", option); 782*44364Sborman } 783*44364Sborman #endif /* DIAGNOSTICS */ 784*44364Sborman 78539503Sborman if (will_wont_resp[option]) { 78639503Sborman will_wont_resp[option]--; 787*44364Sborman if (will_wont_resp[option] && my_state_is_will(option)) 78839503Sborman will_wont_resp[option]--; 78939503Sborman } 790*44364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 79138905Sborman switch (option) { 79238905Sborman case TELOPT_ECHO: 79338905Sborman #ifdef LINEMODE 79439503Sborman if (lmodetype == NO_LINEMODE) { 79538905Sborman #endif 79638905Sborman init_termbuf(); 79738905Sborman tty_setecho(1); 79838905Sborman set_termbuf(); 79938905Sborman #ifdef LINEMODE 80038905Sborman } 80138905Sborman #endif 80238905Sborman changeok++; 80338905Sborman break; 80438905Sborman 80538905Sborman case TELOPT_BINARY: 80638905Sborman init_termbuf(); 80738905Sborman tty_binaryout(1); 80838905Sborman set_termbuf(); 80938905Sborman changeok++; 81038905Sborman break; 81138905Sborman 81238905Sborman case TELOPT_SGA: 81338905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 81438905Sborman /* 81539503Sborman * If kludge linemode is in use, then we must 81639503Sborman * process an incoming do SGA for linemode 81739503Sborman * purposes. 81838905Sborman */ 81938905Sborman if (lmodetype == KLUDGE_LINEMODE) { 82038905Sborman /* 82139503Sborman * Receipt of "do SGA" in kludge 82239503Sborman * linemode is the peer asking us to 82339503Sborman * turn off linemode. Make note of 82439503Sborman * the request. 82538905Sborman */ 82638905Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 82738905Sborman /* 82839503Sborman * If linemode did not get turned off 82939503Sborman * then don't tell peer that we did. 83039503Sborman * Breaking here forces a wont SGA to 83139503Sborman * be returned. 83238905Sborman */ 83338905Sborman if (linemode) 83438905Sborman break; 83538905Sborman } 83638905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 83738905Sborman changeok++; 83838905Sborman break; 83938905Sborman 84038905Sborman case TELOPT_STATUS: 84138905Sborman changeok++; 84238905Sborman break; 84338905Sborman 84438905Sborman case TELOPT_TM: 84539503Sborman /* 84639503Sborman * Special case for TM. We send a WILL, but 84739503Sborman * pretend we sent a WONT. 84839503Sborman */ 84939503Sborman send_will(option, 0); 850*44364Sborman set_my_want_state_wont(option); 851*44364Sborman set_my_state_wont(option); 85239503Sborman return; 85339503Sborman 85438905Sborman case TELOPT_LINEMODE: 85538905Sborman case TELOPT_TTYPE: 85638905Sborman case TELOPT_NAWS: 85738905Sborman case TELOPT_TSPEED: 85838905Sborman case TELOPT_LFLOW: 859*44364Sborman case TELOPT_XDISPLOC: 860*44364Sborman case TELOPT_ENVIRON: 86138905Sborman default: 86238905Sborman break; 86338905Sborman } 86439503Sborman if (changeok) { 865*44364Sborman set_my_want_state_will(option); 86639503Sborman send_will(option, 0); 86739503Sborman } else { 86839503Sborman will_wont_resp[option]++; 86939503Sborman send_wont(option, 0); 87038905Sborman } 87138905Sborman } 872*44364Sborman set_my_state_will(option); 87338905Sborman 87438905Sborman } /* end of dooption */ 87538905Sborman 87639503Sborman send_wont(option, init) 87739503Sborman int option, init; 87839503Sborman { 87939503Sborman if (init) { 880*44364Sborman if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 881*44364Sborman my_want_state_is_wont(option)) 88239503Sborman return; 883*44364Sborman set_my_want_state_wont(option); 88439503Sborman will_wont_resp[option]++; 88539503Sborman } 88639503Sborman (void) sprintf(nfrontp, wont, option); 88739503Sborman nfrontp += sizeof (wont) - 2; 888*44364Sborman #ifdef DIAGNOSTICS 889*44364Sborman /* 890*44364Sborman * Report sending option to other side. 891*44364Sborman */ 892*44364Sborman if (diagnostic & TD_OPTIONS) { 893*44364Sborman printoption("td: send wont", option); 894*44364Sborman } 895*44364Sborman #endif /* DIAGNOSTICS */ 89639503Sborman } 89738905Sborman 89839503Sborman dontoption(option) 89939503Sborman int option; 90038905Sborman { 90138905Sborman /* 90238905Sborman * Process client input. 90338905Sborman */ 904*44364Sborman #ifdef DIAGNOSTICS 905*44364Sborman /* 906*44364Sborman * Report receiving option from other side. 907*44364Sborman */ 908*44364Sborman if (diagnostic & TD_OPTIONS) { 909*44364Sborman printoption("td: recv dont", option); 910*44364Sborman } 911*44364Sborman #endif /* DIAGNOSTICS */ 91240242Sborman 91339503Sborman if (will_wont_resp[option]) { 91439503Sborman will_wont_resp[option]--; 915*44364Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 91639503Sborman will_wont_resp[option]--; 91739503Sborman } 918*44364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 91938905Sborman switch (option) { 92038905Sborman case TELOPT_BINARY: 92138905Sborman init_termbuf(); 92238905Sborman tty_binaryout(0); 92338905Sborman set_termbuf(); 92438905Sborman break; 92538905Sborman 92639503Sborman case TELOPT_ECHO: /* we should stop echoing */ 92738905Sborman #ifdef LINEMODE 92839503Sborman if (lmodetype == NO_LINEMODE) { 92938905Sborman #endif 93038905Sborman init_termbuf(); 93138905Sborman tty_setecho(0); 93238905Sborman set_termbuf(); 93338905Sborman #ifdef LINEMODE 93438905Sborman } 93538905Sborman #endif 93638905Sborman break; 93738905Sborman 93838905Sborman case TELOPT_SGA: 93938905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 94038905Sborman /* 94139503Sborman * If kludge linemode is in use, then we 94239503Sborman * must process an incoming do SGA for 94339503Sborman * linemode purposes. 94438905Sborman */ 94538905Sborman if (lmodetype == KLUDGE_LINEMODE) { 94638905Sborman /* 94739503Sborman * The client is asking us to turn 94839503Sborman * linemode on. 94938905Sborman */ 95038905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 95138905Sborman /* 95239503Sborman * If we did not turn line mode on, 95339503Sborman * then what do we say? Will SGA? 95439503Sborman * This violates design of telnet. 95539503Sborman * Gross. Very Gross. 95638905Sborman */ 95738905Sborman } 95838905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 95938905Sborman 96038905Sborman default: 96138905Sborman break; 96238905Sborman } 96338905Sborman 964*44364Sborman set_my_want_state_wont(option); 965*44364Sborman if (my_state_is_will(option)) 966*44364Sborman send_wont(option, 0); 96738905Sborman } 968*44364Sborman set_my_state_wont(option); 96938905Sborman 97038905Sborman } /* end of dontoption */ 97138905Sborman 97238905Sborman /* 97338905Sborman * suboption() 97438905Sborman * 97538905Sborman * Look at the sub-option buffer, and try to be helpful to the other 97638905Sborman * side. 97738905Sborman * 97838905Sborman * Currently we recognize: 97938905Sborman * 98038905Sborman * Terminal type is 98138905Sborman * Linemode 98238905Sborman * Window size 98338905Sborman * Terminal speed 98438905Sborman */ 98538905Sborman suboption() 98638905Sborman { 98738905Sborman register int subchar; 988*44364Sborman extern void unsetenv(); 98938905Sborman 990*44364Sborman #ifdef DIAGNOSTICS 991*44364Sborman /* 992*44364Sborman * Report receiving option from other side. 993*44364Sborman */ 994*44364Sborman if (diagnostic & TD_OPTIONS) { 995*44364Sborman netflush(); /* get rid of anything waiting to go out */ 996*44364Sborman printsub("td: recv", subpointer, SB_LEN()+2); 997*44364Sborman } 998*44364Sborman #endif DIAGNOSTIC 99938905Sborman subchar = SB_GET(); 100038905Sborman switch (subchar) { 100138905Sborman case TELOPT_TSPEED: { 100238905Sborman register int xspeed, rspeed; 100338905Sborman 1004*44364Sborman if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 100538905Sborman break; 100638905Sborman 100738905Sborman settimer(tspeedsubopt); 100838905Sborman 100938905Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 101038905Sborman return; 101138905Sborman 101238905Sborman xspeed = atoi(subpointer); 101338905Sborman 101438905Sborman while (SB_GET() != ',' && !SB_EOF()); 101538905Sborman if (SB_EOF()) 101638905Sborman return; 101738905Sborman 101838905Sborman rspeed = atoi(subpointer); 101938905Sborman clientstat(TELOPT_TSPEED, xspeed, rspeed); 102038905Sborman 102138905Sborman break; 102238905Sborman 102338905Sborman } /* end of case TELOPT_TSPEED */ 102438905Sborman 102538905Sborman case TELOPT_TTYPE: { /* Yaaaay! */ 1026*44364Sborman static char terminalname[41]; 102738905Sborman 1028*44364Sborman if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 102938905Sborman break; 103038905Sborman settimer(ttypesubopt); 103138905Sborman 103238905Sborman if (SB_GET() != TELQUAL_IS) { 103338905Sborman return; /* ??? XXX but, this is the most robust */ 103438905Sborman } 103538905Sborman 1036*44364Sborman terminaltype = terminalname; 103738905Sborman 103838905Sborman while ((terminaltype < (terminalname + sizeof terminalname-1)) && 103938905Sborman !SB_EOF()) { 104038905Sborman register int c; 104138905Sborman 104238905Sborman c = SB_GET(); 104338905Sborman if (isupper(c)) { 104438905Sborman c = tolower(c); 104538905Sborman } 104638905Sborman *terminaltype++ = c; /* accumulate name */ 104738905Sborman } 104838905Sborman *terminaltype = 0; 104938905Sborman terminaltype = terminalname; 105038905Sborman break; 105138905Sborman } /* end of case TELOPT_TTYPE */ 105238905Sborman 105338905Sborman case TELOPT_NAWS: { 105438905Sborman register int xwinsize, ywinsize; 105538905Sborman 1056*44364Sborman if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 105738905Sborman break; 105838905Sborman 105938905Sborman if (SB_EOF()) 106038905Sborman return; 106138905Sborman xwinsize = SB_GET() << 8; 106238905Sborman if (SB_EOF()) 106338905Sborman return; 106438905Sborman xwinsize |= SB_GET(); 106538905Sborman if (SB_EOF()) 106638905Sborman return; 106738905Sborman ywinsize = SB_GET() << 8; 106838905Sborman if (SB_EOF()) 106938905Sborman return; 107038905Sborman ywinsize |= SB_GET(); 107138905Sborman clientstat(TELOPT_NAWS, xwinsize, ywinsize); 107238905Sborman 107338905Sborman break; 107438905Sborman 107538905Sborman } /* end of case TELOPT_NAWS */ 107638905Sborman 107738905Sborman #ifdef LINEMODE 107838905Sborman case TELOPT_LINEMODE: { 107938905Sborman register int request; 108038905Sborman 1081*44364Sborman if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 108238905Sborman break; 108338905Sborman /* 108438905Sborman * Process linemode suboptions. 108538905Sborman */ 108638905Sborman if (SB_EOF()) break; /* garbage was sent */ 108738905Sborman request = SB_GET(); /* get will/wont */ 108838905Sborman if (SB_EOF()) break; /* another garbage check */ 108938905Sborman 109038905Sborman if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ 109138905Sborman /* 109238905Sborman * Process suboption buffer of slc's 109338905Sborman */ 109438905Sborman start_slc(1); 109538905Sborman do_opt_slc(subpointer, subend - subpointer); 109638905Sborman end_slc(0); 109738905Sborman 109838905Sborman } else if (request == LM_MODE) { 109938905Sborman useeditmode = SB_GET(); /* get mode flag */ 110038905Sborman clientstat(LM_MODE, 0, 0); 110138905Sborman } 110238905Sborman 110338905Sborman switch (SB_GET()) { /* what suboption? */ 110438905Sborman case LM_FORWARDMASK: 110538905Sborman /* 110638905Sborman * According to spec, only server can send request for 110738905Sborman * forwardmask, and client can only return a positive response. 110838905Sborman * So don't worry about it. 110938905Sborman */ 111038905Sborman 111138905Sborman default: 111238905Sborman break; 111338905Sborman } 111440242Sborman break; 111538905Sborman } /* end of case TELOPT_LINEMODE */ 111638905Sborman #endif 111738905Sborman case TELOPT_STATUS: { 111838905Sborman int mode; 111938905Sborman 112038905Sborman mode = SB_GET(); 112138905Sborman switch (mode) { 112238905Sborman case TELQUAL_SEND: 1123*44364Sborman if (my_state_is_will(TELOPT_STATUS)) 112438905Sborman send_status(); 112538905Sborman break; 112638905Sborman 112738905Sborman case TELQUAL_IS: 112838905Sborman break; 112938905Sborman 113038905Sborman default: 113138905Sborman break; 113238905Sborman } 113340242Sborman break; 113440242Sborman } /* end of case TELOPT_STATUS */ 113538905Sborman 1136*44364Sborman case TELOPT_XDISPLOC: { 1137*44364Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 1138*44364Sborman return; 1139*44364Sborman settimer(xdisplocsubopt); 1140*44364Sborman subpointer[SB_LEN()] = '\0'; 1141*44364Sborman setenv("DISPLAY", subpointer, 1); 1142*44364Sborman break; 1143*44364Sborman } /* end of case TELOPT_XDISPLOC */ 1144*44364Sborman 1145*44364Sborman case TELOPT_ENVIRON: { 1146*44364Sborman register int c; 1147*44364Sborman register char *cp, *varp, *valp; 1148*44364Sborman 1149*44364Sborman if (SB_EOF()) 1150*44364Sborman return; 1151*44364Sborman c = SB_GET(); 1152*44364Sborman if (c == TELQUAL_IS) 1153*44364Sborman settimer(environsubopt); 1154*44364Sborman else if (c != TELQUAL_INFO) 1155*44364Sborman return; 1156*44364Sborman 1157*44364Sborman while (!SB_EOF() && SB_GET() != ENV_VAR) 1158*44364Sborman ; 1159*44364Sborman 1160*44364Sborman if (SB_EOF()) 1161*44364Sborman return; 1162*44364Sborman 1163*44364Sborman cp = varp = subpointer; 1164*44364Sborman valp = 0; 1165*44364Sborman 1166*44364Sborman while (!SB_EOF()) { 1167*44364Sborman switch (c = SB_GET()) { 1168*44364Sborman case ENV_VALUE: 1169*44364Sborman *cp = '\0'; 1170*44364Sborman cp = valp = subpointer; 1171*44364Sborman break; 1172*44364Sborman 1173*44364Sborman case ENV_VAR: 1174*44364Sborman *cp = '\0'; 1175*44364Sborman if (valp) 1176*44364Sborman setenv(varp, valp, 1); 1177*44364Sborman else 1178*44364Sborman unsetenv(varp); 1179*44364Sborman cp = varp = subpointer; 1180*44364Sborman valp = 0; 1181*44364Sborman break; 1182*44364Sborman 1183*44364Sborman case ENV_ESC: 1184*44364Sborman if (SB_EOF()) 1185*44364Sborman break; 1186*44364Sborman c = SB_GET(); 1187*44364Sborman /* FALL THROUGH */ 1188*44364Sborman default: 1189*44364Sborman *cp++ = c; 1190*44364Sborman break; 1191*44364Sborman } 1192*44364Sborman } 1193*44364Sborman *cp = '\0'; 1194*44364Sborman if (valp) 1195*44364Sborman setenv(varp, valp, 1); 1196*44364Sborman else 1197*44364Sborman unsetenv(varp); 1198*44364Sborman break; 1199*44364Sborman } /* end of case TELOPT_ENVIRON */ 1200*44364Sborman 120138905Sborman default: 120238905Sborman break; 120338905Sborman } /* end of switch */ 120438905Sborman 120538905Sborman } /* end of suboption */ 120638905Sborman 120738905Sborman #define ADD(c) *ncp++ = c; 120838905Sborman #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; } 120938905Sborman send_status() 121038905Sborman { 1211*44364Sborman unsigned char statusbuf[256]; 1212*44364Sborman register unsigned char *ncp; 1213*44364Sborman register unsigned char i; 121438905Sborman 121538905Sborman ncp = statusbuf; 121638905Sborman 121738905Sborman netflush(); /* get rid of anything waiting to go out */ 121838905Sborman 121938905Sborman ADD(IAC); 122038905Sborman ADD(SB); 122138905Sborman ADD(TELOPT_STATUS); 122238905Sborman ADD(TELQUAL_IS); 122338905Sborman 122438905Sborman for (i = 0; i < NTELOPTS; i++) { 1225*44364Sborman if (my_state_is_will(i)) { 122638905Sborman ADD(WILL); 122738905Sborman ADD_DATA(i); 122838905Sborman if (i == IAC) 122938905Sborman ADD(IAC); 123038905Sborman } 1231*44364Sborman if (his_state_is_will(i)) { 123238905Sborman ADD(DO); 123338905Sborman ADD_DATA(i); 123438905Sborman if (i == IAC) 123538905Sborman ADD(IAC); 123638905Sborman } 123738905Sborman } 123838905Sborman 123938905Sborman #ifdef LINEMODE 1240*44364Sborman if (his_state_is_will(TELOPT_LINEMODE)) { 1241*44364Sborman unsigned char *cp, *cpe; 124238905Sborman int len; 124338905Sborman 124438905Sborman ADD(SB); 124538905Sborman ADD(TELOPT_LINEMODE); 124638905Sborman ADD(LM_MODE); 124738905Sborman ADD_DATA(editmode); 124838905Sborman if (editmode == IAC) 124938905Sborman ADD(IAC); 125038905Sborman ADD(SE); 125138905Sborman 125238905Sborman ADD(SB); 125338905Sborman ADD(TELOPT_LINEMODE); 125438905Sborman ADD(LM_SLC); 125538905Sborman start_slc(0); 125638905Sborman send_slc(); 125738905Sborman len = end_slc(&cp); 125838905Sborman for (cpe = cp + len; cp < cpe; cp++) 125938905Sborman ADD_DATA(*cp); 126038905Sborman ADD(SE); 126138905Sborman } 126238905Sborman #endif /* LINEMODE */ 126338905Sborman 126438905Sborman ADD(IAC); 126538905Sborman ADD(SE); 126638905Sborman 126738905Sborman writenet(statusbuf, ncp - statusbuf); 126838905Sborman netflush(); /* Send it on its way */ 1269*44364Sborman #ifdef DIAGNOSTICS 1270*44364Sborman /* 1271*44364Sborman * Report sending status suboption. 1272*44364Sborman */ 1273*44364Sborman if (diagnostic & TD_OPTIONS) { 1274*44364Sborman printsub("td: send", statusbuf, ncp - statusbuf); 1275*44364Sborman netflush(); /* Send it on its way */ 1276*44364Sborman } 1277*44364Sborman #endif DIAGNOSTIC 127838905Sborman } 1279*44364Sborman 1280*44364Sborman #ifdef NO_SETENV 1281*44364Sborman #include "setenv.c" 1282*44364Sborman #endif 1283