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*45234Sborman static char sccsid[] = "@(#)state.c 5.8 (Berkeley) 09/14/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) 3344364Sborman #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 */ 8844364Sborman 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: 11244364Sborman #ifdef DIAGNOSTICS 11344364Sborman if (diagnostic & TD_OPTIONS) 11444364Sborman printoption("td: recv IAC", c); 11544364Sborman #endif /* DIAGNOSTICS */ 11638905Sborman interrupt(); 11738905Sborman break; 11838905Sborman 11938905Sborman case BREAK: 12044364Sborman #ifdef DIAGNOSTICS 12144364Sborman if (diagnostic & TD_OPTIONS) 12244364Sborman printoption("td: recv IAC", c); 12344364Sborman #endif /* DIAGNOSTICS */ 12438905Sborman sendbrk(); 12538905Sborman break; 12638905Sborman 12738905Sborman /* 12838905Sborman * Are You There? 12938905Sborman */ 13038905Sborman case AYT: 13144364Sborman #ifdef DIAGNOSTICS 13244364Sborman if (diagnostic & TD_OPTIONS) 13344364Sborman printoption("td: recv IAC", c); 13444364Sborman #endif /* DIAGNOSTICS */ 135*45234Sborman recv_ayt(); 13638905Sborman break; 13738905Sborman 13838905Sborman /* 13938905Sborman * Abort Output 14038905Sborman */ 14138905Sborman case AO: 14238905Sborman { 14344364Sborman #ifdef DIAGNOSTICS 14444364Sborman if (diagnostic & TD_OPTIONS) 14544364Sborman printoption("td: recv IAC", c); 14644364Sborman #endif /* DIAGNOSTICS */ 14738905Sborman ptyflush(); /* half-hearted */ 14838905Sborman init_termbuf(); 14938905Sborman 15038905Sborman if (slctab[SLC_AO].sptr && 151*45234Sborman *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { 15240242Sborman *pfrontp++ = 15340242Sborman (unsigned char)*slctab[SLC_AO].sptr; 15438905Sborman } 15538905Sborman 15638905Sborman netclear(); /* clear buffer back */ 15738905Sborman *nfrontp++ = IAC; 15838905Sborman *nfrontp++ = DM; 15938905Sborman neturg = nfrontp-1; /* off by one XXX */ 16044364Sborman #ifdef DIAGNOSTICS 16144364Sborman if (diagnostic & TD_OPTIONS) 16244364Sborman printoption("td: send IAC", DM); 16344364Sborman #endif /* DIAGNOSTICS */ 16438905Sborman break; 16538905Sborman } 16638905Sborman 16738905Sborman /* 16838905Sborman * Erase Character and 16938905Sborman * Erase Line 17038905Sborman */ 17138905Sborman case EC: 17238905Sborman case EL: 17338905Sborman { 17440242Sborman cc_t ch; 17538905Sborman 17644364Sborman #ifdef DIAGNOSTICS 17744364Sborman if (diagnostic & TD_OPTIONS) 17844364Sborman printoption("td: recv IAC", c); 17944364Sborman #endif /* DIAGNOSTICS */ 18038905Sborman ptyflush(); /* half-hearted */ 18138905Sborman init_termbuf(); 18244364Sborman if (c == EC) 18344364Sborman ch = *slctab[SLC_EC].sptr; 18444364Sborman else 18544364Sborman ch = *slctab[SLC_EL].sptr; 186*45234Sborman if (ch != (cc_t)(_POSIX_VDISABLE)) 18740242Sborman *pfrontp++ = (unsigned char)ch; 18838905Sborman break; 18938905Sborman } 19038905Sborman 19138905Sborman /* 19238905Sborman * Check for urgent data... 19338905Sborman */ 19438905Sborman case DM: 19544364Sborman #ifdef DIAGNOSTICS 19644364Sborman if (diagnostic & TD_OPTIONS) 19744364Sborman printoption("td: recv IAC", c); 19844364Sborman #endif /* DIAGNOSTICS */ 19938905Sborman SYNCHing = stilloob(net); 20038905Sborman settimer(gotDM); 20138905Sborman break; 20238905Sborman 20338905Sborman 20438905Sborman /* 20538905Sborman * Begin option subnegotiation... 20638905Sborman */ 20738905Sborman case SB: 20838905Sborman state = TS_SB; 20938905Sborman SB_CLEAR(); 21038905Sborman continue; 21138905Sborman 21238905Sborman case WILL: 21338905Sborman state = TS_WILL; 21438905Sborman continue; 21538905Sborman 21638905Sborman case WONT: 21738905Sborman state = TS_WONT; 21838905Sborman continue; 21938905Sborman 22038905Sborman case DO: 22138905Sborman state = TS_DO; 22238905Sborman continue; 22338905Sborman 22438905Sborman case DONT: 22538905Sborman state = TS_DONT; 22638905Sborman continue; 22738905Sborman case EOR: 22844364Sborman if (his_state_is_will(TELOPT_EOR)) 22938905Sborman doeof(); 23038905Sborman break; 23138905Sborman 23238905Sborman /* 23338905Sborman * Handle RFC 10xx Telnet linemode option additions 23438905Sborman * to command stream (EOF, SUSP, ABORT). 23538905Sborman */ 23638905Sborman case xEOF: 23738905Sborman doeof(); 23838905Sborman break; 23938905Sborman 24038905Sborman case SUSP: 24138905Sborman sendsusp(); 24238905Sborman break; 24338905Sborman 24438905Sborman case ABORT: 24538905Sborman sendbrk(); 24638905Sborman break; 24738905Sborman 24838905Sborman case IAC: 24938905Sborman *pfrontp++ = c; 25038905Sborman break; 25138905Sborman } 25238905Sborman state = TS_DATA; 25338905Sborman break; 25438905Sborman 25538905Sborman case TS_SB: 25638905Sborman if (c == IAC) { 25738905Sborman state = TS_SE; 25838905Sborman } else { 25938905Sborman SB_ACCUM(c); 26038905Sborman } 26138905Sborman break; 26238905Sborman 26338905Sborman case TS_SE: 26438905Sborman if (c != SE) { 26538905Sborman if (c != IAC) { 26638905Sborman /* 26738905Sborman * bad form of suboption negotiation. 26838905Sborman * handle it in such a way as to avoid 26938905Sborman * damage to local state. Parse 27038905Sborman * suboption buffer found so far, 27138905Sborman * then treat remaining stream as 27238905Sborman * another command sequence. 27338905Sborman */ 27444364Sborman #ifdef DIAGNOSTICS 27544364Sborman SB_ACCUM(IAC); 27644364Sborman SB_ACCUM(c); 27744364Sborman subpointer -= 2; 27844364Sborman #endif 27938905Sborman SB_TERM(); 28038905Sborman suboption(); 28138905Sborman state = TS_IAC; 28238905Sborman goto gotiac; 28338905Sborman } 28438905Sborman SB_ACCUM(c); 28538905Sborman state = TS_SB; 28638905Sborman } else { 28744364Sborman #ifdef DIAGNOSTICS 28844364Sborman SB_ACCUM(IAC); 28944364Sborman SB_ACCUM(SE); 29044364Sborman subpointer -= 2; 29144364Sborman #endif 29238905Sborman SB_TERM(); 29338905Sborman suboption(); /* handle sub-option */ 29438905Sborman state = TS_DATA; 29538905Sborman } 29638905Sborman break; 29738905Sborman 29838905Sborman case TS_WILL: 29939503Sborman willoption(c); 30038905Sborman state = TS_DATA; 30138905Sborman continue; 30238905Sborman 30338905Sborman case TS_WONT: 30439503Sborman wontoption(c); 30538905Sborman state = TS_DATA; 30638905Sborman continue; 30738905Sborman 30838905Sborman case TS_DO: 30939503Sborman dooption(c); 31038905Sborman state = TS_DATA; 31138905Sborman continue; 31238905Sborman 31338905Sborman case TS_DONT: 31439503Sborman dontoption(c); 31538905Sborman state = TS_DATA; 31638905Sborman continue; 31738905Sborman 31838905Sborman default: 31938905Sborman syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 32038905Sborman printf("telnetd: panic state=%d\n", state); 32138905Sborman exit(1); 32238905Sborman } 32338905Sborman } 32440242Sborman #if defined(CRAY2) && defined(UNICOS5) 32538905Sborman if (!linemode) { 32638905Sborman char xptyobuf[BUFSIZ+NETSLOP]; 32738905Sborman char xbuf2[BUFSIZ]; 32838905Sborman register char *cp; 32938905Sborman int n = pfrontp - opfrontp, oc; 33038905Sborman bcopy(opfrontp, xptyobuf, n); 33138905Sborman pfrontp = opfrontp; 33238905Sborman pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, 33338905Sborman xbuf2, &oc, BUFSIZ); 33438905Sborman for (cp = xbuf2; oc > 0; --oc) 33538905Sborman if ((*nfrontp++ = *cp++) == IAC) 33638905Sborman *nfrontp++ = IAC; 33738905Sborman } 33840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 33938905Sborman } /* end of telrcv */ 34038905Sborman 34138905Sborman /* 34238905Sborman * The will/wont/do/dont state machines are based on Dave Borman's 34344364Sborman * Telnet option processing state machine. 34438905Sborman * 34538905Sborman * These correspond to the following states: 34638905Sborman * my_state = the last negotiated state 34738905Sborman * want_state = what I want the state to go to 34838905Sborman * want_resp = how many requests I have sent 34938905Sborman * All state defaults are negative, and resp defaults to 0. 35038905Sborman * 35138905Sborman * When initiating a request to change state to new_state: 35238905Sborman * 35338905Sborman * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 35438905Sborman * do nothing; 35538905Sborman * } else { 35638905Sborman * want_state = new_state; 35738905Sborman * send new_state; 35838905Sborman * want_resp++; 35938905Sborman * } 36038905Sborman * 36138905Sborman * When receiving new_state: 36238905Sborman * 36338905Sborman * if (want_resp) { 36438905Sborman * want_resp--; 36538905Sborman * if (want_resp && (new_state == my_state)) 36638905Sborman * want_resp--; 36738905Sborman * } 36838905Sborman * if ((want_resp == 0) && (new_state != want_state)) { 36938905Sborman * if (ok_to_switch_to new_state) 37038905Sborman * want_state = new_state; 37138905Sborman * else 37238905Sborman * want_resp++; 37338905Sborman * send want_state; 37438905Sborman * } 37538905Sborman * my_state = new_state; 37638905Sborman * 37738905Sborman * Note that new_state is implied in these functions by the function itself. 37838905Sborman * will and do imply positive new_state, wont and dont imply negative. 37938905Sborman * 38038905Sborman * Finally, there is one catch. If we send a negative response to a 38138905Sborman * positive request, my_state will be the positive while want_state will 38238905Sborman * remain negative. my_state will revert to negative when the negative 38338905Sborman * acknowlegment arrives from the peer. Thus, my_state generally tells 38438905Sborman * us not only the last negotiated state, but also tells us what the peer 38538905Sborman * wants to be doing as well. It is important to understand this difference 38638905Sborman * as we may wish to be processing data streams based on our desired state 38738905Sborman * (want_state) or based on what the peer thinks the state is (my_state). 38838905Sborman * 38938905Sborman * This all works fine because if the peer sends a positive request, the data 39038905Sborman * that we receive prior to negative acknowlegment will probably be affected 39138905Sborman * by the positive state, and we can process it as such (if we can; if we 39238905Sborman * can't then it really doesn't matter). If it is that important, then the 39338905Sborman * peer probably should be buffering until this option state negotiation 39438905Sborman * is complete. 39538905Sborman * 39638905Sborman */ 39739503Sborman send_do(option, init) 39839503Sborman int option, init; 39938905Sborman { 40039503Sborman if (init) { 40144364Sborman if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 40244364Sborman his_want_state_is_will(option)) 40339503Sborman return; 40439531Sborman /* 40539531Sborman * Special case for TELOPT_TM: We send a DO, but pretend 40639531Sborman * that we sent a DONT, so that we can send more DOs if 40739531Sborman * we want to. 40839531Sborman */ 40939531Sborman if (option == TELOPT_TM) 41044364Sborman set_his_want_state_wont(option); 41139531Sborman else 41244364Sborman set_his_want_state_will(option); 41339503Sborman do_dont_resp[option]++; 41439503Sborman } 41539503Sborman (void) sprintf(nfrontp, doopt, option); 41639503Sborman nfrontp += sizeof (dont) - 2; 41744364Sborman #ifdef DIAGNOSTICS 41844364Sborman /* 41944364Sborman * Report sending option to other side. 42044364Sborman */ 42144364Sborman if (diagnostic & TD_OPTIONS) { 42244364Sborman printoption("td: send do", option); 42344364Sborman } 42444364Sborman #endif /* DIAGNOSTICS */ 42539503Sborman } 42639503Sborman 42739503Sborman willoption(option) 42839503Sborman int option; 42939503Sborman { 43038905Sborman int changeok = 0; 43138905Sborman 43239503Sborman /* 43339503Sborman * process input from peer. 43439503Sborman */ 43539503Sborman 43644364Sborman #ifdef DIAGNOSTICS 43744364Sborman /* 43844364Sborman * Report receiving option from other side. 43944364Sborman */ 44044364Sborman if (diagnostic & TD_OPTIONS) { 44144364Sborman printoption("td: recv will", option); 44244364Sborman } 44344364Sborman #endif /* DIAGNOSTICS */ 44444364Sborman 44539503Sborman if (do_dont_resp[option]) { 44639503Sborman do_dont_resp[option]--; 44744364Sborman if (do_dont_resp[option] && his_state_is_will(option)) 44839503Sborman do_dont_resp[option]--; 44939503Sborman } 45039531Sborman if (do_dont_resp[option] == 0) { 45144364Sborman if (his_want_state_is_wont(option)) { 45238905Sborman switch (option) { 45338905Sborman 45438905Sborman case TELOPT_BINARY: 45538905Sborman init_termbuf(); 45638905Sborman tty_binaryin(1); 45738905Sborman set_termbuf(); 45838905Sborman changeok++; 45938905Sborman break; 46038905Sborman 46138905Sborman case TELOPT_ECHO: 46238905Sborman /* 46344364Sborman * See comments below for more info. 46438905Sborman */ 46544364Sborman not42 = 0; /* looks like a 4.2 system */ 46638905Sborman break; 46738905Sborman 46838905Sborman case TELOPT_TM: 46938905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 47038905Sborman /* 47139503Sborman * This telnetd implementation does not really 47239503Sborman * support timing marks, it just uses them to 47339503Sborman * support the kludge linemode stuff. If we 47439503Sborman * receive a will or wont TM in response to our 47539503Sborman * do TM request that may have been sent to 47639503Sborman * determine kludge linemode support, process 47739503Sborman * it, otherwise TM should get a negative 47839503Sborman * response back. 47938905Sborman */ 48038905Sborman /* 48138905Sborman * Handle the linemode kludge stuff. 48238905Sborman * If we are not currently supporting any 48338905Sborman * linemode at all, then we assume that this 48438905Sborman * is the client telling us to use kludge 48538905Sborman * linemode in response to our query. Set the 48638905Sborman * linemode type that is to be supported, note 48738905Sborman * that the client wishes to use linemode, and 48838905Sborman * eat the will TM as though it never arrived. 48938905Sborman */ 49038905Sborman if (lmodetype < KLUDGE_LINEMODE) { 49138905Sborman lmodetype = KLUDGE_LINEMODE; 49238905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 49339503Sborman send_wont(TELOPT_SGA, 1); 49438905Sborman } 49538905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 49638905Sborman /* 49739531Sborman * We never respond to a WILL TM, and 49844364Sborman * we leave the state WONT. 49938905Sborman */ 50038905Sborman return; 50138905Sborman 50238905Sborman case TELOPT_LFLOW: 50338905Sborman /* 50439503Sborman * If we are going to support flow control 50539503Sborman * option, then don't worry peer that we can't 50639503Sborman * change the flow control characters. 50738905Sborman */ 50838905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 50938905Sborman slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 51038905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 51138905Sborman slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 51238905Sborman case TELOPT_TTYPE: 51338905Sborman case TELOPT_SGA: 51438905Sborman case TELOPT_NAWS: 51538905Sborman case TELOPT_TSPEED: 51644364Sborman case TELOPT_XDISPLOC: 51744364Sborman case TELOPT_ENVIRON: 51839531Sborman changeok++; 51939531Sborman break; 52039531Sborman 52138905Sborman #ifdef LINEMODE 52238905Sborman case TELOPT_LINEMODE: 52344364Sborman /* 52444364Sborman * Local processing of 'will linemode' should 52544364Sborman * occur after placing 'do linemode' in the data 52644364Sborman * stream, because we may wish to send other 52744364Sborman * linemode related messages. So, we duplicate 52844364Sborman * the other three lines of code here, and then 52944364Sborman * return. 53044364Sborman */ 53144364Sborman set_his_want_state_will(option); 53244364Sborman send_do(option, 0); 53344364Sborman set_his_state_will(option); 53439531Sborman # ifdef KLUDGELINEMODE 53539531Sborman /* 53639531Sborman * Note client's desire to use linemode. 53739531Sborman */ 53839531Sborman lmodetype = REAL_LINEMODE; 53939531Sborman # endif /* KLUDGELINEMODE */ 54039531Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 54144364Sborman return; 54239531Sborman #endif /* LINEMODE */ 54338905Sborman 54438905Sborman default: 54538905Sborman break; 54638905Sborman } 54739503Sborman if (changeok) { 54844364Sborman set_his_want_state_will(option); 54939503Sborman send_do(option, 0); 55039503Sborman } else { 55139503Sborman do_dont_resp[option]++; 55239503Sborman send_dont(option, 0); 55338905Sborman } 55444364Sborman } else { 55544364Sborman /* 55644364Sborman * Option processing that should happen when 55744364Sborman * we receive conformation of a change in 55844364Sborman * state that we had requested. 55944364Sborman */ 56044364Sborman switch (option) { 56144364Sborman case TELOPT_ECHO: 56244364Sborman not42 = 0; /* looks like a 4.2 system */ 56344364Sborman /* 56444364Sborman * Egads, he responded "WILL ECHO". Turn 56544364Sborman * it off right now! 56644364Sborman */ 56744364Sborman send_dont(option, 1); 56844364Sborman /* 56944364Sborman * "WILL ECHO". Kludge upon kludge! 57044364Sborman * A 4.2 client is now echoing user input at 57144364Sborman * the tty. This is probably undesireable and 57244364Sborman * it should be stopped. The client will 57344364Sborman * respond WONT TM to the DO TM that we send to 57444364Sborman * check for kludge linemode. When the WONT TM 57544364Sborman * arrives, linemode will be turned off and a 57644364Sborman * change propogated to the pty. This change 57744364Sborman * will cause us to process the new pty state 57844364Sborman * in localstat(), which will notice that 57944364Sborman * linemode is off and send a WILL ECHO 58044364Sborman * so that we are properly in character mode and 58144364Sborman * all is well. 58244364Sborman */ 58344364Sborman break; 58444364Sborman #ifdef LINEMODE 58544364Sborman case TELOPT_LINEMODE: 58644364Sborman # ifdef KLUDGELINEMODE 58744364Sborman /* 58844364Sborman * Note client's desire to use linemode. 58944364Sborman */ 59044364Sborman lmodetype = REAL_LINEMODE; 59144364Sborman # endif /* KLUDGELINEMODE */ 59244364Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 59344364Sborman #endif /* LINEMODE */ 59444364Sborman } 59539531Sborman } 59638905Sborman } 59744364Sborman set_his_state_will(option); 59838905Sborman } /* end of willoption */ 59938905Sborman 60039503Sborman send_dont(option, init) 60139503Sborman int option, init; 60238905Sborman { 60339503Sborman if (init) { 60444364Sborman if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 60544364Sborman his_want_state_is_wont(option)) 60639503Sborman return; 60744364Sborman set_his_want_state_wont(option); 60839503Sborman do_dont_resp[option]++; 60939503Sborman } 61039503Sborman (void) sprintf(nfrontp, dont, option); 61139503Sborman nfrontp += sizeof (doopt) - 2; 61244364Sborman #ifdef DIAGNOSTICS 61344364Sborman /* 61444364Sborman * Report sending option to other side. 61544364Sborman */ 61644364Sborman if (diagnostic & TD_OPTIONS) { 61744364Sborman printoption("td: send dont", option); 61844364Sborman } 61944364Sborman #endif /* DIAGNOSTICS */ 62039503Sborman } 62139503Sborman 62239503Sborman wontoption(option) 62339503Sborman int option; 62439503Sborman { 62538905Sborman /* 62638905Sborman * Process client input. 62738905Sborman */ 62839503Sborman 62944364Sborman #ifdef DIAGNOSTICS 63044364Sborman /* 63144364Sborman * Report receiving option from other side. 63244364Sborman */ 63344364Sborman if (diagnostic & TD_OPTIONS) { 63444364Sborman printoption("td: recv wont", option); 63544364Sborman } 63644364Sborman #endif /* DIAGNOSTICS */ 63744364Sborman 63839503Sborman if (do_dont_resp[option]) { 63939503Sborman do_dont_resp[option]--; 64044364Sborman if (do_dont_resp[option] && his_state_is_wont(option)) 64139503Sborman do_dont_resp[option]--; 64239503Sborman } 64339531Sborman if (do_dont_resp[option] == 0) { 64444364Sborman if (his_want_state_is_will(option)) { 64539503Sborman /* it is always ok to change to negative state */ 64638905Sborman switch (option) { 64738905Sborman case TELOPT_ECHO: 64839503Sborman not42 = 1; /* doesn't seem to be a 4.2 system */ 64938905Sborman break; 65038905Sborman 65138905Sborman case TELOPT_BINARY: 65238905Sborman init_termbuf(); 65338905Sborman tty_binaryin(0); 65438905Sborman set_termbuf(); 65538905Sborman break; 65638905Sborman 65738905Sborman #ifdef LINEMODE 65838905Sborman case TELOPT_LINEMODE: 65938905Sborman # ifdef KLUDGELINEMODE 66038905Sborman /* 66138905Sborman * If real linemode is supported, then client is 66238905Sborman * asking to turn linemode off. 66338905Sborman */ 66444364Sborman if (lmodetype != REAL_LINEMODE) 66544364Sborman break; 66644364Sborman lmodetype = KLUDGE_LINEMODE; 66738905Sborman # endif /* KLUDGELINEMODE */ 66844364Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 66938905Sborman break; 67038905Sborman #endif LINEMODE 67138905Sborman 67238905Sborman case TELOPT_TM: 67338905Sborman /* 67439503Sborman * If we get a WONT TM, and had sent a DO TM, 67539503Sborman * don't respond with a DONT TM, just leave it 67639503Sborman * as is. Short circut the state machine to 67739531Sborman * achive this. 67838905Sborman */ 67944364Sborman set_his_want_state_wont(TELOPT_TM); 68038905Sborman return; 68138905Sborman 68238905Sborman case TELOPT_LFLOW: 68338905Sborman /* 68439503Sborman * If we are not going to support flow control 68539503Sborman * option, then let peer know that we can't 68639503Sborman * change the flow control characters. 68738905Sborman */ 68838905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 68938905Sborman slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 69038905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 69138905Sborman slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 69238905Sborman break; 69338905Sborman 69444364Sborman /* 69544364Sborman * For options that we might spin waiting for 69644364Sborman * sub-negotiation, if the client turns off the 69744364Sborman * option rather than responding to the request, 69844364Sborman * we have to treat it here as if we got a response 69944364Sborman * to the sub-negotiation, (by updating the timers) 70044364Sborman * so that we'll break out of the loop. 70144364Sborman */ 70244364Sborman case TELOPT_TTYPE: 70344364Sborman settimer(ttypesubopt); 70444364Sborman break; 70544364Sborman 70644364Sborman case TELOPT_TSPEED: 70744364Sborman settimer(tspeedsubopt); 70844364Sborman break; 70944364Sborman 71044364Sborman case TELOPT_XDISPLOC: 71144364Sborman settimer(xdisplocsubopt); 71244364Sborman break; 71344364Sborman 71444364Sborman case TELOPT_ENVIRON: 71544364Sborman settimer(environsubopt); 71644364Sborman break; 71744364Sborman 71838905Sborman default: 71938905Sborman break; 72038905Sborman } 72144364Sborman set_his_want_state_wont(option); 72244364Sborman if (his_state_is_will(option)) 72344364Sborman send_dont(option, 0); 72439531Sborman } else { 72539531Sborman switch (option) { 72639531Sborman case TELOPT_TM: 72739531Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 72839531Sborman if (lmodetype < REAL_LINEMODE) { 72939531Sborman lmodetype = NO_LINEMODE; 73039531Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 73139531Sborman send_will(TELOPT_SGA, 1); 732*45234Sborman send_will(TELOPT_ECHO, 1); 73339531Sborman } 73439531Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 73539531Sborman default: 73639531Sborman break; 73739531Sborman } 73839531Sborman } 73938905Sborman } 74044364Sborman set_his_state_wont(option); 74138905Sborman 74239503Sborman } /* end of wontoption */ 74338905Sborman 74439503Sborman send_will(option, init) 74539503Sborman int option, init; 74639503Sborman { 74739503Sborman if (init) { 74844364Sborman if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 74944364Sborman my_want_state_is_will(option)) 75039503Sborman return; 75144364Sborman set_my_want_state_will(option); 75239503Sborman will_wont_resp[option]++; 75338905Sborman } 75439503Sborman (void) sprintf(nfrontp, will, option); 75539503Sborman nfrontp += sizeof (doopt) - 2; 75644364Sborman #ifdef DIAGNOSTICS 75744364Sborman /* 75844364Sborman * Report sending option to other side. 75944364Sborman */ 76044364Sborman if (diagnostic & TD_OPTIONS) { 76144364Sborman printoption("td: send will", option); 76244364Sborman } 76344364Sborman #endif /* DIAGNOSTICS */ 76439503Sborman } 76538905Sborman 766*45234Sborman #if !defined(LINEMODE) || !defined(KLUDGELINEMODE) 767*45234Sborman /* 768*45234Sborman * When we get a DONT SGA, we will try once to turn it 769*45234Sborman * back on. If the other side responds DONT SGA, we 770*45234Sborman * leave it at that. This is so that when we talk to 771*45234Sborman * clients that understand KLUDGELINEMODE but not LINEMODE, 772*45234Sborman * we'll keep them in char-at-a-time mode. 773*45234Sborman */ 774*45234Sborman int turn_on_sga = 0; 775*45234Sborman #endif 776*45234Sborman 77739503Sborman dooption(option) 77839503Sborman int option; 77938905Sborman { 78038905Sborman int changeok = 0; 78138905Sborman 78238905Sborman /* 78338905Sborman * Process client input. 78438905Sborman */ 78539503Sborman 78644364Sborman #ifdef DIAGNOSTICS 78744364Sborman /* 78844364Sborman * Report receiving option from other side. 78944364Sborman */ 79044364Sborman if (diagnostic & TD_OPTIONS) { 79144364Sborman printoption("td: recv do", option); 79244364Sborman } 79344364Sborman #endif /* DIAGNOSTICS */ 79444364Sborman 79539503Sborman if (will_wont_resp[option]) { 79639503Sborman will_wont_resp[option]--; 79744364Sborman if (will_wont_resp[option] && my_state_is_will(option)) 79839503Sborman will_wont_resp[option]--; 79939503Sborman } 80044364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 80138905Sborman switch (option) { 80238905Sborman case TELOPT_ECHO: 80338905Sborman #ifdef LINEMODE 804*45234Sborman # ifdef KLUDGELINEMODE 805*45234Sborman if (lmodetype == NO_LINEMODE) 806*45234Sborman # else 807*45234Sborman if (his_state_is_wont(TELOPT_LINEMODE)) 808*45234Sborman # endif 80938905Sborman #endif 810*45234Sborman { 81138905Sborman init_termbuf(); 81238905Sborman tty_setecho(1); 81338905Sborman set_termbuf(); 81438905Sborman } 81538905Sborman changeok++; 81638905Sborman break; 81738905Sborman 81838905Sborman case TELOPT_BINARY: 81938905Sborman init_termbuf(); 82038905Sborman tty_binaryout(1); 82138905Sborman set_termbuf(); 82238905Sborman changeok++; 82338905Sborman break; 82438905Sborman 82538905Sborman case TELOPT_SGA: 82638905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 82738905Sborman /* 82839503Sborman * If kludge linemode is in use, then we must 82939503Sborman * process an incoming do SGA for linemode 83039503Sborman * purposes. 83138905Sborman */ 83238905Sborman if (lmodetype == KLUDGE_LINEMODE) { 83338905Sborman /* 83439503Sborman * Receipt of "do SGA" in kludge 83539503Sborman * linemode is the peer asking us to 83639503Sborman * turn off linemode. Make note of 83739503Sborman * the request. 83838905Sborman */ 83938905Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 84038905Sborman /* 84139503Sborman * If linemode did not get turned off 84239503Sborman * then don't tell peer that we did. 84339503Sborman * Breaking here forces a wont SGA to 84439503Sborman * be returned. 84538905Sborman */ 84638905Sborman if (linemode) 84738905Sborman break; 84838905Sborman } 849*45234Sborman #else 850*45234Sborman turn_on_sga = 0; 85138905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 85238905Sborman changeok++; 85338905Sborman break; 85438905Sborman 85538905Sborman case TELOPT_STATUS: 85638905Sborman changeok++; 85738905Sborman break; 85838905Sborman 85938905Sborman case TELOPT_TM: 86039503Sborman /* 86139503Sborman * Special case for TM. We send a WILL, but 86239503Sborman * pretend we sent a WONT. 86339503Sborman */ 86439503Sborman send_will(option, 0); 86544364Sborman set_my_want_state_wont(option); 86644364Sborman set_my_state_wont(option); 86739503Sborman return; 86839503Sborman 86938905Sborman case TELOPT_LINEMODE: 87038905Sborman case TELOPT_TTYPE: 87138905Sborman case TELOPT_NAWS: 87238905Sborman case TELOPT_TSPEED: 87338905Sborman case TELOPT_LFLOW: 87444364Sborman case TELOPT_XDISPLOC: 87544364Sborman case TELOPT_ENVIRON: 87638905Sborman default: 87738905Sborman break; 87838905Sborman } 87939503Sborman if (changeok) { 88044364Sborman set_my_want_state_will(option); 88139503Sborman send_will(option, 0); 88239503Sborman } else { 88339503Sborman will_wont_resp[option]++; 88439503Sborman send_wont(option, 0); 88538905Sborman } 88638905Sborman } 88744364Sborman set_my_state_will(option); 88838905Sborman 88938905Sborman } /* end of dooption */ 89038905Sborman 89139503Sborman send_wont(option, init) 89239503Sborman int option, init; 89339503Sborman { 89439503Sborman if (init) { 89544364Sborman if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 89644364Sborman my_want_state_is_wont(option)) 89739503Sborman return; 89844364Sborman set_my_want_state_wont(option); 89939503Sborman will_wont_resp[option]++; 90039503Sborman } 90139503Sborman (void) sprintf(nfrontp, wont, option); 90239503Sborman nfrontp += sizeof (wont) - 2; 90344364Sborman #ifdef DIAGNOSTICS 90444364Sborman /* 90544364Sborman * Report sending option to other side. 90644364Sborman */ 90744364Sborman if (diagnostic & TD_OPTIONS) { 90844364Sborman printoption("td: send wont", option); 90944364Sborman } 91044364Sborman #endif /* DIAGNOSTICS */ 91139503Sborman } 91238905Sborman 91339503Sborman dontoption(option) 91439503Sborman int option; 91538905Sborman { 91638905Sborman /* 91738905Sborman * Process client input. 91838905Sborman */ 91944364Sborman #ifdef DIAGNOSTICS 92044364Sborman /* 92144364Sborman * Report receiving option from other side. 92244364Sborman */ 92344364Sborman if (diagnostic & TD_OPTIONS) { 92444364Sborman printoption("td: recv dont", option); 92544364Sborman } 92644364Sborman #endif /* DIAGNOSTICS */ 92740242Sborman 92839503Sborman if (will_wont_resp[option]) { 92939503Sborman will_wont_resp[option]--; 93044364Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 93139503Sborman will_wont_resp[option]--; 93239503Sborman } 93344364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 93438905Sborman switch (option) { 93538905Sborman case TELOPT_BINARY: 93638905Sborman init_termbuf(); 93738905Sborman tty_binaryout(0); 93838905Sborman set_termbuf(); 93938905Sborman break; 94038905Sborman 94139503Sborman case TELOPT_ECHO: /* we should stop echoing */ 94238905Sborman #ifdef LINEMODE 943*45234Sborman # ifdef KLUDGELINEMODE 944*45234Sborman if (lmodetype == NO_LINEMODE) 945*45234Sborman # else 946*45234Sborman if (his_state_is_wont(TELOPT_LINEMODE)) 947*45234Sborman # endif 94838905Sborman #endif 949*45234Sborman { 95038905Sborman init_termbuf(); 95138905Sborman tty_setecho(0); 95238905Sborman set_termbuf(); 95338905Sborman } 95438905Sborman break; 95538905Sborman 95638905Sborman case TELOPT_SGA: 95738905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 95838905Sborman /* 95939503Sborman * If kludge linemode is in use, then we 96039503Sborman * must process an incoming do SGA for 96139503Sborman * linemode purposes. 96238905Sborman */ 96338905Sborman if (lmodetype == KLUDGE_LINEMODE) { 96438905Sborman /* 96539503Sborman * The client is asking us to turn 96639503Sborman * linemode on. 96738905Sborman */ 96838905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 96938905Sborman /* 97039503Sborman * If we did not turn line mode on, 97139503Sborman * then what do we say? Will SGA? 97239503Sborman * This violates design of telnet. 97339503Sborman * Gross. Very Gross. 97438905Sborman */ 97538905Sborman } 976*45234Sborman break; 977*45234Sborman #else 978*45234Sborman set_my_want_state_wont(option); 979*45234Sborman if (my_state_is_will(option)) 980*45234Sborman send_wont(option, 0); 981*45234Sborman set_my_state_wont(option); 982*45234Sborman if (turn_on_sga ^= 1) 983*45234Sborman send_will(option); 984*45234Sborman return; 98538905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 98638905Sborman 98738905Sborman default: 98838905Sborman break; 98938905Sborman } 99038905Sborman 99144364Sborman set_my_want_state_wont(option); 99244364Sborman if (my_state_is_will(option)) 99344364Sborman send_wont(option, 0); 99438905Sborman } 99544364Sborman set_my_state_wont(option); 99638905Sborman 99738905Sborman } /* end of dontoption */ 99838905Sborman 99938905Sborman /* 100038905Sborman * suboption() 100138905Sborman * 100238905Sborman * Look at the sub-option buffer, and try to be helpful to the other 100338905Sborman * side. 100438905Sborman * 100538905Sborman * Currently we recognize: 100638905Sborman * 100738905Sborman * Terminal type is 100838905Sborman * Linemode 100938905Sborman * Window size 101038905Sborman * Terminal speed 101138905Sborman */ 101238905Sborman suboption() 101338905Sborman { 101438905Sborman register int subchar; 101544364Sborman extern void unsetenv(); 101638905Sborman 101744364Sborman #ifdef DIAGNOSTICS 101844364Sborman /* 101944364Sborman * Report receiving option from other side. 102044364Sborman */ 102144364Sborman if (diagnostic & TD_OPTIONS) { 102244364Sborman netflush(); /* get rid of anything waiting to go out */ 102344364Sborman printsub("td: recv", subpointer, SB_LEN()+2); 102444364Sborman } 102544364Sborman #endif DIAGNOSTIC 102638905Sborman subchar = SB_GET(); 102738905Sborman switch (subchar) { 102838905Sborman case TELOPT_TSPEED: { 102938905Sborman register int xspeed, rspeed; 103038905Sborman 103144364Sborman if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 103238905Sborman break; 103338905Sborman 103438905Sborman settimer(tspeedsubopt); 103538905Sborman 103638905Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 103738905Sborman return; 103838905Sborman 103938905Sborman xspeed = atoi(subpointer); 104038905Sborman 104138905Sborman while (SB_GET() != ',' && !SB_EOF()); 104238905Sborman if (SB_EOF()) 104338905Sborman return; 104438905Sborman 104538905Sborman rspeed = atoi(subpointer); 104638905Sborman clientstat(TELOPT_TSPEED, xspeed, rspeed); 104738905Sborman 104838905Sborman break; 104938905Sborman 105038905Sborman } /* end of case TELOPT_TSPEED */ 105138905Sborman 105238905Sborman case TELOPT_TTYPE: { /* Yaaaay! */ 105344364Sborman static char terminalname[41]; 105438905Sborman 105544364Sborman if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 105638905Sborman break; 105738905Sborman settimer(ttypesubopt); 105838905Sborman 105938905Sborman if (SB_GET() != TELQUAL_IS) { 106038905Sborman return; /* ??? XXX but, this is the most robust */ 106138905Sborman } 106238905Sborman 106344364Sborman terminaltype = terminalname; 106438905Sborman 106538905Sborman while ((terminaltype < (terminalname + sizeof terminalname-1)) && 106638905Sborman !SB_EOF()) { 106738905Sborman register int c; 106838905Sborman 106938905Sborman c = SB_GET(); 107038905Sborman if (isupper(c)) { 107138905Sborman c = tolower(c); 107238905Sborman } 107338905Sborman *terminaltype++ = c; /* accumulate name */ 107438905Sborman } 107538905Sborman *terminaltype = 0; 107638905Sborman terminaltype = terminalname; 107738905Sborman break; 107838905Sborman } /* end of case TELOPT_TTYPE */ 107938905Sborman 108038905Sborman case TELOPT_NAWS: { 108138905Sborman register int xwinsize, ywinsize; 108238905Sborman 108344364Sborman if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 108438905Sborman break; 108538905Sborman 108638905Sborman if (SB_EOF()) 108738905Sborman return; 108838905Sborman xwinsize = SB_GET() << 8; 108938905Sborman if (SB_EOF()) 109038905Sborman return; 109138905Sborman xwinsize |= SB_GET(); 109238905Sborman if (SB_EOF()) 109338905Sborman return; 109438905Sborman ywinsize = SB_GET() << 8; 109538905Sborman if (SB_EOF()) 109638905Sborman return; 109738905Sborman ywinsize |= SB_GET(); 109838905Sborman clientstat(TELOPT_NAWS, xwinsize, ywinsize); 109938905Sborman 110038905Sborman break; 110138905Sborman 110238905Sborman } /* end of case TELOPT_NAWS */ 110338905Sborman 110438905Sborman #ifdef LINEMODE 110538905Sborman case TELOPT_LINEMODE: { 110638905Sborman register int request; 110738905Sborman 110844364Sborman if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 110938905Sborman break; 111038905Sborman /* 111138905Sborman * Process linemode suboptions. 111238905Sborman */ 111338905Sborman if (SB_EOF()) break; /* garbage was sent */ 111438905Sborman request = SB_GET(); /* get will/wont */ 111538905Sborman if (SB_EOF()) break; /* another garbage check */ 111638905Sborman 111738905Sborman if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ 111838905Sborman /* 111938905Sborman * Process suboption buffer of slc's 112038905Sborman */ 112138905Sborman start_slc(1); 112238905Sborman do_opt_slc(subpointer, subend - subpointer); 112338905Sborman end_slc(0); 112438905Sborman 112538905Sborman } else if (request == LM_MODE) { 112638905Sborman useeditmode = SB_GET(); /* get mode flag */ 112738905Sborman clientstat(LM_MODE, 0, 0); 112838905Sborman } 112938905Sborman 113038905Sborman switch (SB_GET()) { /* what suboption? */ 113138905Sborman case LM_FORWARDMASK: 113238905Sborman /* 113338905Sborman * According to spec, only server can send request for 113438905Sborman * forwardmask, and client can only return a positive response. 113538905Sborman * So don't worry about it. 113638905Sborman */ 113738905Sborman 113838905Sborman default: 113938905Sborman break; 114038905Sborman } 114140242Sborman break; 114238905Sborman } /* end of case TELOPT_LINEMODE */ 114338905Sborman #endif 114438905Sborman case TELOPT_STATUS: { 114538905Sborman int mode; 114638905Sborman 114738905Sborman mode = SB_GET(); 114838905Sborman switch (mode) { 114938905Sborman case TELQUAL_SEND: 115044364Sborman if (my_state_is_will(TELOPT_STATUS)) 115138905Sborman send_status(); 115238905Sborman break; 115338905Sborman 115438905Sborman case TELQUAL_IS: 115538905Sborman break; 115638905Sborman 115738905Sborman default: 115838905Sborman break; 115938905Sborman } 116040242Sborman break; 116140242Sborman } /* end of case TELOPT_STATUS */ 116238905Sborman 116344364Sborman case TELOPT_XDISPLOC: { 116444364Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 116544364Sborman return; 116644364Sborman settimer(xdisplocsubopt); 116744364Sborman subpointer[SB_LEN()] = '\0'; 116844364Sborman setenv("DISPLAY", subpointer, 1); 116944364Sborman break; 117044364Sborman } /* end of case TELOPT_XDISPLOC */ 117144364Sborman 117244364Sborman case TELOPT_ENVIRON: { 117344364Sborman register int c; 117444364Sborman register char *cp, *varp, *valp; 117544364Sborman 117644364Sborman if (SB_EOF()) 117744364Sborman return; 117844364Sborman c = SB_GET(); 117944364Sborman if (c == TELQUAL_IS) 118044364Sborman settimer(environsubopt); 118144364Sborman else if (c != TELQUAL_INFO) 118244364Sborman return; 118344364Sborman 118444364Sborman while (!SB_EOF() && SB_GET() != ENV_VAR) 118544364Sborman ; 118644364Sborman 118744364Sborman if (SB_EOF()) 118844364Sborman return; 118944364Sborman 119044364Sborman cp = varp = subpointer; 119144364Sborman valp = 0; 119244364Sborman 119344364Sborman while (!SB_EOF()) { 119444364Sborman switch (c = SB_GET()) { 119544364Sborman case ENV_VALUE: 119644364Sborman *cp = '\0'; 119744364Sborman cp = valp = subpointer; 119844364Sborman break; 119944364Sborman 120044364Sborman case ENV_VAR: 120144364Sborman *cp = '\0'; 120244364Sborman if (valp) 120344364Sborman setenv(varp, valp, 1); 120444364Sborman else 120544364Sborman unsetenv(varp); 120644364Sborman cp = varp = subpointer; 120744364Sborman valp = 0; 120844364Sborman break; 120944364Sborman 121044364Sborman case ENV_ESC: 121144364Sborman if (SB_EOF()) 121244364Sborman break; 121344364Sborman c = SB_GET(); 121444364Sborman /* FALL THROUGH */ 121544364Sborman default: 121644364Sborman *cp++ = c; 121744364Sborman break; 121844364Sborman } 121944364Sborman } 122044364Sborman *cp = '\0'; 122144364Sborman if (valp) 122244364Sborman setenv(varp, valp, 1); 122344364Sborman else 122444364Sborman unsetenv(varp); 122544364Sborman break; 122644364Sborman } /* end of case TELOPT_ENVIRON */ 122744364Sborman 122838905Sborman default: 122938905Sborman break; 123038905Sborman } /* end of switch */ 123138905Sborman 123238905Sborman } /* end of suboption */ 123338905Sborman 123438905Sborman #define ADD(c) *ncp++ = c; 123538905Sborman #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; } 123638905Sborman send_status() 123738905Sborman { 123844364Sborman unsigned char statusbuf[256]; 123944364Sborman register unsigned char *ncp; 124044364Sborman register unsigned char i; 124138905Sborman 124238905Sborman ncp = statusbuf; 124338905Sborman 124438905Sborman netflush(); /* get rid of anything waiting to go out */ 124538905Sborman 124638905Sborman ADD(IAC); 124738905Sborman ADD(SB); 124838905Sborman ADD(TELOPT_STATUS); 124938905Sborman ADD(TELQUAL_IS); 125038905Sborman 125138905Sborman for (i = 0; i < NTELOPTS; i++) { 125244364Sborman if (my_state_is_will(i)) { 125338905Sborman ADD(WILL); 125438905Sborman ADD_DATA(i); 125538905Sborman if (i == IAC) 125638905Sborman ADD(IAC); 125738905Sborman } 125844364Sborman if (his_state_is_will(i)) { 125938905Sborman ADD(DO); 126038905Sborman ADD_DATA(i); 126138905Sborman if (i == IAC) 126238905Sborman ADD(IAC); 126338905Sborman } 126438905Sborman } 126538905Sborman 126638905Sborman #ifdef LINEMODE 126744364Sborman if (his_state_is_will(TELOPT_LINEMODE)) { 126844364Sborman unsigned char *cp, *cpe; 126938905Sborman int len; 127038905Sborman 127138905Sborman ADD(SB); 127238905Sborman ADD(TELOPT_LINEMODE); 127338905Sborman ADD(LM_MODE); 127438905Sborman ADD_DATA(editmode); 127538905Sborman if (editmode == IAC) 127638905Sborman ADD(IAC); 127738905Sborman ADD(SE); 127838905Sborman 127938905Sborman ADD(SB); 128038905Sborman ADD(TELOPT_LINEMODE); 128138905Sborman ADD(LM_SLC); 128238905Sborman start_slc(0); 128338905Sborman send_slc(); 128438905Sborman len = end_slc(&cp); 128538905Sborman for (cpe = cp + len; cp < cpe; cp++) 128638905Sborman ADD_DATA(*cp); 128738905Sborman ADD(SE); 128838905Sborman } 128938905Sborman #endif /* LINEMODE */ 129038905Sborman 129138905Sborman ADD(IAC); 129238905Sborman ADD(SE); 129338905Sborman 129438905Sborman writenet(statusbuf, ncp - statusbuf); 129538905Sborman netflush(); /* Send it on its way */ 129644364Sborman #ifdef DIAGNOSTICS 129744364Sborman /* 129844364Sborman * Report sending status suboption. 129944364Sborman */ 130044364Sborman if (diagnostic & TD_OPTIONS) { 130144364Sborman printsub("td: send", statusbuf, ncp - statusbuf); 130244364Sborman netflush(); /* Send it on its way */ 130344364Sborman } 130444364Sborman #endif DIAGNOSTIC 130538905Sborman } 130644364Sborman 130744364Sborman #ifdef NO_SETENV 130844364Sborman #include "setenv.c" 130944364Sborman #endif 1310