113e3f4d6SMark Murray /* 213e3f4d6SMark Murray * Copyright (c) 1989, 1993 313e3f4d6SMark Murray * The Regents of the University of California. All rights reserved. 413e3f4d6SMark Murray * 513e3f4d6SMark Murray * Redistribution and use in source and binary forms, with or without 613e3f4d6SMark Murray * modification, are permitted provided that the following conditions 713e3f4d6SMark Murray * are met: 813e3f4d6SMark Murray * 1. Redistributions of source code must retain the above copyright 913e3f4d6SMark Murray * notice, this list of conditions and the following disclaimer. 1013e3f4d6SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 1113e3f4d6SMark Murray * notice, this list of conditions and the following disclaimer in the 1213e3f4d6SMark Murray * documentation and/or other materials provided with the distribution. 1313e3f4d6SMark Murray * 3. All advertising materials mentioning features or use of this software 1413e3f4d6SMark Murray * must display the following acknowledgement: 1513e3f4d6SMark Murray * This product includes software developed by the University of 1613e3f4d6SMark Murray * California, Berkeley and its contributors. 1713e3f4d6SMark Murray * 4. Neither the name of the University nor the names of its contributors 1813e3f4d6SMark Murray * may be used to endorse or promote products derived from this software 1913e3f4d6SMark Murray * without specific prior written permission. 2013e3f4d6SMark Murray * 2113e3f4d6SMark Murray * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2213e3f4d6SMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2313e3f4d6SMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2413e3f4d6SMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2513e3f4d6SMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2613e3f4d6SMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2713e3f4d6SMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2813e3f4d6SMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2913e3f4d6SMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3013e3f4d6SMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3113e3f4d6SMark Murray * SUCH DAMAGE. 3213e3f4d6SMark Murray */ 3313e3f4d6SMark Murray 3413e3f4d6SMark Murray #include "telnetd.h" 3513e3f4d6SMark Murray 3613e3f4d6SMark Murray RCSID("$Id: state.c,v 1.13 1999/05/13 23:12:50 assar Exp $"); 3713e3f4d6SMark Murray 3813e3f4d6SMark Murray unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; 3913e3f4d6SMark Murray unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; 4013e3f4d6SMark Murray unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; 4113e3f4d6SMark Murray unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; 4213e3f4d6SMark Murray int not42 = 1; 4313e3f4d6SMark Murray 4413e3f4d6SMark Murray /* 4513e3f4d6SMark Murray * Buffer for sub-options, and macros 4613e3f4d6SMark Murray * for suboptions buffer manipulations 4713e3f4d6SMark Murray */ 4813e3f4d6SMark Murray unsigned char subbuffer[2048], *subpointer= subbuffer, *subend= subbuffer; 4913e3f4d6SMark Murray 5013e3f4d6SMark Murray #define SB_CLEAR() subpointer = subbuffer 5113e3f4d6SMark Murray #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 5213e3f4d6SMark Murray #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 5313e3f4d6SMark Murray *subpointer++ = (c); \ 5413e3f4d6SMark Murray } 5513e3f4d6SMark Murray #define SB_GET() ((*subpointer++)&0xff) 5613e3f4d6SMark Murray #define SB_EOF() (subpointer >= subend) 5713e3f4d6SMark Murray #define SB_LEN() (subend - subpointer) 5813e3f4d6SMark Murray 5913e3f4d6SMark Murray #ifdef ENV_HACK 6013e3f4d6SMark Murray unsigned char *subsave; 6113e3f4d6SMark Murray #define SB_SAVE() subsave = subpointer; 6213e3f4d6SMark Murray #define SB_RESTORE() subpointer = subsave; 6313e3f4d6SMark Murray #endif 6413e3f4d6SMark Murray 6513e3f4d6SMark Murray 6613e3f4d6SMark Murray /* 6713e3f4d6SMark Murray * State for recv fsm 6813e3f4d6SMark Murray */ 6913e3f4d6SMark Murray #define TS_DATA 0 /* base state */ 7013e3f4d6SMark Murray #define TS_IAC 1 /* look for double IAC's */ 7113e3f4d6SMark Murray #define TS_CR 2 /* CR-LF ->'s CR */ 7213e3f4d6SMark Murray #define TS_SB 3 /* throw away begin's... */ 7313e3f4d6SMark Murray #define TS_SE 4 /* ...end's (suboption negotiation) */ 7413e3f4d6SMark Murray #define TS_WILL 5 /* will option negotiation */ 7513e3f4d6SMark Murray #define TS_WONT 6 /* wont -''- */ 7613e3f4d6SMark Murray #define TS_DO 7 /* do -''- */ 7713e3f4d6SMark Murray #define TS_DONT 8 /* dont -''- */ 7813e3f4d6SMark Murray 7913e3f4d6SMark Murray void 8013e3f4d6SMark Murray telrcv(void) 8113e3f4d6SMark Murray { 8213e3f4d6SMark Murray int c; 8313e3f4d6SMark Murray static int state = TS_DATA; 8413e3f4d6SMark Murray 8513e3f4d6SMark Murray while (ncc > 0) { 8613e3f4d6SMark Murray if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 8713e3f4d6SMark Murray break; 8813e3f4d6SMark Murray c = *netip++ & 0377, ncc--; 8913e3f4d6SMark Murray #ifdef ENCRYPTION 9013e3f4d6SMark Murray if (decrypt_input) 9113e3f4d6SMark Murray c = (*decrypt_input)(c); 9213e3f4d6SMark Murray #endif 9313e3f4d6SMark Murray switch (state) { 9413e3f4d6SMark Murray 9513e3f4d6SMark Murray case TS_CR: 9613e3f4d6SMark Murray state = TS_DATA; 9713e3f4d6SMark Murray /* Strip off \n or \0 after a \r */ 9813e3f4d6SMark Murray if ((c == 0) || (c == '\n')) { 9913e3f4d6SMark Murray break; 10013e3f4d6SMark Murray } 10113e3f4d6SMark Murray /* FALL THROUGH */ 10213e3f4d6SMark Murray 10313e3f4d6SMark Murray case TS_DATA: 10413e3f4d6SMark Murray if (c == IAC) { 10513e3f4d6SMark Murray state = TS_IAC; 10613e3f4d6SMark Murray break; 10713e3f4d6SMark Murray } 10813e3f4d6SMark Murray /* 10913e3f4d6SMark Murray * We now map \r\n ==> \r for pragmatic reasons. 11013e3f4d6SMark Murray * Many client implementations send \r\n when 11113e3f4d6SMark Murray * the user hits the CarriageReturn key. 11213e3f4d6SMark Murray * 11313e3f4d6SMark Murray * We USED to map \r\n ==> \n, since \r\n says 11413e3f4d6SMark Murray * that we want to be in column 1 of the next 11513e3f4d6SMark Murray * printable line, and \n is the standard 11613e3f4d6SMark Murray * unix way of saying that (\r is only good 11713e3f4d6SMark Murray * if CRMOD is set, which it normally is). 11813e3f4d6SMark Murray */ 11913e3f4d6SMark Murray if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { 12013e3f4d6SMark Murray int nc = *netip; 12113e3f4d6SMark Murray #ifdef ENCRYPTION 12213e3f4d6SMark Murray if (decrypt_input) 12313e3f4d6SMark Murray nc = (*decrypt_input)(nc & 0xff); 12413e3f4d6SMark Murray #endif 12513e3f4d6SMark Murray { 12613e3f4d6SMark Murray #ifdef ENCRYPTION 12713e3f4d6SMark Murray if (decrypt_input) 12813e3f4d6SMark Murray (void)(*decrypt_input)(-1); 12913e3f4d6SMark Murray #endif 13013e3f4d6SMark Murray state = TS_CR; 13113e3f4d6SMark Murray } 13213e3f4d6SMark Murray } 13313e3f4d6SMark Murray *pfrontp++ = c; 13413e3f4d6SMark Murray break; 13513e3f4d6SMark Murray 13613e3f4d6SMark Murray case TS_IAC: 13713e3f4d6SMark Murray gotiac: switch (c) { 13813e3f4d6SMark Murray 13913e3f4d6SMark Murray /* 14013e3f4d6SMark Murray * Send the process on the pty side an 14113e3f4d6SMark Murray * interrupt. Do this with a NULL or 14213e3f4d6SMark Murray * interrupt char; depending on the tty mode. 14313e3f4d6SMark Murray */ 14413e3f4d6SMark Murray case IP: 14513e3f4d6SMark Murray DIAG(TD_OPTIONS, 14613e3f4d6SMark Murray printoption("td: recv IAC", c)); 14713e3f4d6SMark Murray interrupt(); 14813e3f4d6SMark Murray break; 14913e3f4d6SMark Murray 15013e3f4d6SMark Murray case BREAK: 15113e3f4d6SMark Murray DIAG(TD_OPTIONS, 15213e3f4d6SMark Murray printoption("td: recv IAC", c)); 15313e3f4d6SMark Murray sendbrk(); 15413e3f4d6SMark Murray break; 15513e3f4d6SMark Murray 15613e3f4d6SMark Murray /* 15713e3f4d6SMark Murray * Are You There? 15813e3f4d6SMark Murray */ 15913e3f4d6SMark Murray case AYT: 16013e3f4d6SMark Murray DIAG(TD_OPTIONS, 16113e3f4d6SMark Murray printoption("td: recv IAC", c)); 16213e3f4d6SMark Murray recv_ayt(); 16313e3f4d6SMark Murray break; 16413e3f4d6SMark Murray 16513e3f4d6SMark Murray /* 16613e3f4d6SMark Murray * Abort Output 16713e3f4d6SMark Murray */ 16813e3f4d6SMark Murray case AO: 16913e3f4d6SMark Murray { 17013e3f4d6SMark Murray DIAG(TD_OPTIONS, 17113e3f4d6SMark Murray printoption("td: recv IAC", c)); 17213e3f4d6SMark Murray ptyflush(); /* half-hearted */ 17313e3f4d6SMark Murray init_termbuf(); 17413e3f4d6SMark Murray 17513e3f4d6SMark Murray if (slctab[SLC_AO].sptr && 17613e3f4d6SMark Murray *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { 17713e3f4d6SMark Murray *pfrontp++ = 17813e3f4d6SMark Murray (unsigned char)*slctab[SLC_AO].sptr; 17913e3f4d6SMark Murray } 18013e3f4d6SMark Murray 18113e3f4d6SMark Murray netclear(); /* clear buffer back */ 18213e3f4d6SMark Murray output_data ("%c%c", IAC, DM); 18313e3f4d6SMark Murray neturg = nfrontp-1; /* off by one XXX */ 18413e3f4d6SMark Murray DIAG(TD_OPTIONS, 18513e3f4d6SMark Murray printoption("td: send IAC", DM)); 18613e3f4d6SMark Murray break; 18713e3f4d6SMark Murray } 18813e3f4d6SMark Murray 18913e3f4d6SMark Murray /* 19013e3f4d6SMark Murray * Erase Character and 19113e3f4d6SMark Murray * Erase Line 19213e3f4d6SMark Murray */ 19313e3f4d6SMark Murray case EC: 19413e3f4d6SMark Murray case EL: 19513e3f4d6SMark Murray { 19613e3f4d6SMark Murray cc_t ch; 19713e3f4d6SMark Murray 19813e3f4d6SMark Murray DIAG(TD_OPTIONS, 19913e3f4d6SMark Murray printoption("td: recv IAC", c)); 20013e3f4d6SMark Murray ptyflush(); /* half-hearted */ 20113e3f4d6SMark Murray init_termbuf(); 20213e3f4d6SMark Murray if (c == EC) 20313e3f4d6SMark Murray ch = *slctab[SLC_EC].sptr; 20413e3f4d6SMark Murray else 20513e3f4d6SMark Murray ch = *slctab[SLC_EL].sptr; 20613e3f4d6SMark Murray if (ch != (cc_t)(_POSIX_VDISABLE)) 20713e3f4d6SMark Murray *pfrontp++ = (unsigned char)ch; 20813e3f4d6SMark Murray break; 20913e3f4d6SMark Murray } 21013e3f4d6SMark Murray 21113e3f4d6SMark Murray /* 21213e3f4d6SMark Murray * Check for urgent data... 21313e3f4d6SMark Murray */ 21413e3f4d6SMark Murray case DM: 21513e3f4d6SMark Murray DIAG(TD_OPTIONS, 21613e3f4d6SMark Murray printoption("td: recv IAC", c)); 21713e3f4d6SMark Murray SYNCHing = stilloob(net); 21813e3f4d6SMark Murray settimer(gotDM); 21913e3f4d6SMark Murray break; 22013e3f4d6SMark Murray 22113e3f4d6SMark Murray 22213e3f4d6SMark Murray /* 22313e3f4d6SMark Murray * Begin option subnegotiation... 22413e3f4d6SMark Murray */ 22513e3f4d6SMark Murray case SB: 22613e3f4d6SMark Murray state = TS_SB; 22713e3f4d6SMark Murray SB_CLEAR(); 22813e3f4d6SMark Murray continue; 22913e3f4d6SMark Murray 23013e3f4d6SMark Murray case WILL: 23113e3f4d6SMark Murray state = TS_WILL; 23213e3f4d6SMark Murray continue; 23313e3f4d6SMark Murray 23413e3f4d6SMark Murray case WONT: 23513e3f4d6SMark Murray state = TS_WONT; 23613e3f4d6SMark Murray continue; 23713e3f4d6SMark Murray 23813e3f4d6SMark Murray case DO: 23913e3f4d6SMark Murray state = TS_DO; 24013e3f4d6SMark Murray continue; 24113e3f4d6SMark Murray 24213e3f4d6SMark Murray case DONT: 24313e3f4d6SMark Murray state = TS_DONT; 24413e3f4d6SMark Murray continue; 24513e3f4d6SMark Murray case EOR: 24613e3f4d6SMark Murray if (his_state_is_will(TELOPT_EOR)) 24713e3f4d6SMark Murray doeof(); 24813e3f4d6SMark Murray break; 24913e3f4d6SMark Murray 25013e3f4d6SMark Murray /* 25113e3f4d6SMark Murray * Handle RFC 10xx Telnet linemode option additions 25213e3f4d6SMark Murray * to command stream (EOF, SUSP, ABORT). 25313e3f4d6SMark Murray */ 25413e3f4d6SMark Murray case xEOF: 25513e3f4d6SMark Murray doeof(); 25613e3f4d6SMark Murray break; 25713e3f4d6SMark Murray 25813e3f4d6SMark Murray case SUSP: 25913e3f4d6SMark Murray sendsusp(); 26013e3f4d6SMark Murray break; 26113e3f4d6SMark Murray 26213e3f4d6SMark Murray case ABORT: 26313e3f4d6SMark Murray sendbrk(); 26413e3f4d6SMark Murray break; 26513e3f4d6SMark Murray 26613e3f4d6SMark Murray case IAC: 26713e3f4d6SMark Murray *pfrontp++ = c; 26813e3f4d6SMark Murray break; 26913e3f4d6SMark Murray } 27013e3f4d6SMark Murray state = TS_DATA; 27113e3f4d6SMark Murray break; 27213e3f4d6SMark Murray 27313e3f4d6SMark Murray case TS_SB: 27413e3f4d6SMark Murray if (c == IAC) { 27513e3f4d6SMark Murray state = TS_SE; 27613e3f4d6SMark Murray } else { 27713e3f4d6SMark Murray SB_ACCUM(c); 27813e3f4d6SMark Murray } 27913e3f4d6SMark Murray break; 28013e3f4d6SMark Murray 28113e3f4d6SMark Murray case TS_SE: 28213e3f4d6SMark Murray if (c != SE) { 28313e3f4d6SMark Murray if (c != IAC) { 28413e3f4d6SMark Murray /* 28513e3f4d6SMark Murray * bad form of suboption negotiation. 28613e3f4d6SMark Murray * handle it in such a way as to avoid 28713e3f4d6SMark Murray * damage to local state. Parse 28813e3f4d6SMark Murray * suboption buffer found so far, 28913e3f4d6SMark Murray * then treat remaining stream as 29013e3f4d6SMark Murray * another command sequence. 29113e3f4d6SMark Murray */ 29213e3f4d6SMark Murray 29313e3f4d6SMark Murray /* for DIAGNOSTICS */ 29413e3f4d6SMark Murray SB_ACCUM(IAC); 29513e3f4d6SMark Murray SB_ACCUM(c); 29613e3f4d6SMark Murray subpointer -= 2; 29713e3f4d6SMark Murray 29813e3f4d6SMark Murray SB_TERM(); 29913e3f4d6SMark Murray suboption(); 30013e3f4d6SMark Murray state = TS_IAC; 30113e3f4d6SMark Murray goto gotiac; 30213e3f4d6SMark Murray } 30313e3f4d6SMark Murray SB_ACCUM(c); 30413e3f4d6SMark Murray state = TS_SB; 30513e3f4d6SMark Murray } else { 30613e3f4d6SMark Murray /* for DIAGNOSTICS */ 30713e3f4d6SMark Murray SB_ACCUM(IAC); 30813e3f4d6SMark Murray SB_ACCUM(SE); 30913e3f4d6SMark Murray subpointer -= 2; 31013e3f4d6SMark Murray 31113e3f4d6SMark Murray SB_TERM(); 31213e3f4d6SMark Murray suboption(); /* handle sub-option */ 31313e3f4d6SMark Murray state = TS_DATA; 31413e3f4d6SMark Murray } 31513e3f4d6SMark Murray break; 31613e3f4d6SMark Murray 31713e3f4d6SMark Murray case TS_WILL: 31813e3f4d6SMark Murray willoption(c); 31913e3f4d6SMark Murray state = TS_DATA; 32013e3f4d6SMark Murray continue; 32113e3f4d6SMark Murray 32213e3f4d6SMark Murray case TS_WONT: 32313e3f4d6SMark Murray wontoption(c); 32413e3f4d6SMark Murray if (c==TELOPT_ENCRYPT && his_do_dont_is_changing(TELOPT_ENCRYPT) ) 32513e3f4d6SMark Murray dontoption(c); 32613e3f4d6SMark Murray state = TS_DATA; 32713e3f4d6SMark Murray continue; 32813e3f4d6SMark Murray 32913e3f4d6SMark Murray case TS_DO: 33013e3f4d6SMark Murray dooption(c); 33113e3f4d6SMark Murray state = TS_DATA; 33213e3f4d6SMark Murray continue; 33313e3f4d6SMark Murray 33413e3f4d6SMark Murray case TS_DONT: 33513e3f4d6SMark Murray dontoption(c); 33613e3f4d6SMark Murray state = TS_DATA; 33713e3f4d6SMark Murray continue; 33813e3f4d6SMark Murray 33913e3f4d6SMark Murray default: 34013e3f4d6SMark Murray syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 34113e3f4d6SMark Murray printf("telnetd: panic state=%d\n", state); 34213e3f4d6SMark Murray exit(1); 34313e3f4d6SMark Murray } 34413e3f4d6SMark Murray } 34513e3f4d6SMark Murray } /* end of telrcv */ 34613e3f4d6SMark Murray 34713e3f4d6SMark Murray /* 34813e3f4d6SMark Murray * The will/wont/do/dont state machines are based on Dave Borman's 34913e3f4d6SMark Murray * Telnet option processing state machine. 35013e3f4d6SMark Murray * 35113e3f4d6SMark Murray * These correspond to the following states: 35213e3f4d6SMark Murray * my_state = the last negotiated state 35313e3f4d6SMark Murray * want_state = what I want the state to go to 35413e3f4d6SMark Murray * want_resp = how many requests I have sent 35513e3f4d6SMark Murray * All state defaults are negative, and resp defaults to 0. 35613e3f4d6SMark Murray * 35713e3f4d6SMark Murray * When initiating a request to change state to new_state: 35813e3f4d6SMark Murray * 35913e3f4d6SMark Murray * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 36013e3f4d6SMark Murray * do nothing; 36113e3f4d6SMark Murray * } else { 36213e3f4d6SMark Murray * want_state = new_state; 36313e3f4d6SMark Murray * send new_state; 36413e3f4d6SMark Murray * want_resp++; 36513e3f4d6SMark Murray * } 36613e3f4d6SMark Murray * 36713e3f4d6SMark Murray * When receiving new_state: 36813e3f4d6SMark Murray * 36913e3f4d6SMark Murray * if (want_resp) { 37013e3f4d6SMark Murray * want_resp--; 37113e3f4d6SMark Murray * if (want_resp && (new_state == my_state)) 37213e3f4d6SMark Murray * want_resp--; 37313e3f4d6SMark Murray * } 37413e3f4d6SMark Murray * if ((want_resp == 0) && (new_state != want_state)) { 37513e3f4d6SMark Murray * if (ok_to_switch_to new_state) 37613e3f4d6SMark Murray * want_state = new_state; 37713e3f4d6SMark Murray * else 37813e3f4d6SMark Murray * want_resp++; 37913e3f4d6SMark Murray * send want_state; 38013e3f4d6SMark Murray * } 38113e3f4d6SMark Murray * my_state = new_state; 38213e3f4d6SMark Murray * 38313e3f4d6SMark Murray * Note that new_state is implied in these functions by the function itself. 38413e3f4d6SMark Murray * will and do imply positive new_state, wont and dont imply negative. 38513e3f4d6SMark Murray * 38613e3f4d6SMark Murray * Finally, there is one catch. If we send a negative response to a 38713e3f4d6SMark Murray * positive request, my_state will be the positive while want_state will 38813e3f4d6SMark Murray * remain negative. my_state will revert to negative when the negative 38913e3f4d6SMark Murray * acknowlegment arrives from the peer. Thus, my_state generally tells 39013e3f4d6SMark Murray * us not only the last negotiated state, but also tells us what the peer 39113e3f4d6SMark Murray * wants to be doing as well. It is important to understand this difference 39213e3f4d6SMark Murray * as we may wish to be processing data streams based on our desired state 39313e3f4d6SMark Murray * (want_state) or based on what the peer thinks the state is (my_state). 39413e3f4d6SMark Murray * 39513e3f4d6SMark Murray * This all works fine because if the peer sends a positive request, the data 39613e3f4d6SMark Murray * that we receive prior to negative acknowlegment will probably be affected 39713e3f4d6SMark Murray * by the positive state, and we can process it as such (if we can; if we 39813e3f4d6SMark Murray * can't then it really doesn't matter). If it is that important, then the 39913e3f4d6SMark Murray * peer probably should be buffering until this option state negotiation 40013e3f4d6SMark Murray * is complete. 40113e3f4d6SMark Murray * 40213e3f4d6SMark Murray */ 40313e3f4d6SMark Murray void 40413e3f4d6SMark Murray send_do(int option, int init) 40513e3f4d6SMark Murray { 40613e3f4d6SMark Murray if (init) { 40713e3f4d6SMark Murray if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 40813e3f4d6SMark Murray his_want_state_is_will(option)) 40913e3f4d6SMark Murray return; 41013e3f4d6SMark Murray /* 41113e3f4d6SMark Murray * Special case for TELOPT_TM: We send a DO, but pretend 41213e3f4d6SMark Murray * that we sent a DONT, so that we can send more DOs if 41313e3f4d6SMark Murray * we want to. 41413e3f4d6SMark Murray */ 41513e3f4d6SMark Murray if (option == TELOPT_TM) 41613e3f4d6SMark Murray set_his_want_state_wont(option); 41713e3f4d6SMark Murray else 41813e3f4d6SMark Murray set_his_want_state_will(option); 41913e3f4d6SMark Murray do_dont_resp[option]++; 42013e3f4d6SMark Murray } 42113e3f4d6SMark Murray output_data((const char *)doopt, option); 42213e3f4d6SMark Murray 42313e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: send do", option)); 42413e3f4d6SMark Murray } 42513e3f4d6SMark Murray 42613e3f4d6SMark Murray #ifdef AUTHENTICATION 42713e3f4d6SMark Murray extern void auth_request(void); 42813e3f4d6SMark Murray #endif 42913e3f4d6SMark Murray #ifdef ENCRYPTION 43013e3f4d6SMark Murray extern void encrypt_send_support(); 43113e3f4d6SMark Murray #endif 43213e3f4d6SMark Murray 43313e3f4d6SMark Murray void 43413e3f4d6SMark Murray willoption(int option) 43513e3f4d6SMark Murray { 43613e3f4d6SMark Murray int changeok = 0; 43713e3f4d6SMark Murray void (*func)() = 0; 43813e3f4d6SMark Murray 43913e3f4d6SMark Murray /* 44013e3f4d6SMark Murray * process input from peer. 44113e3f4d6SMark Murray */ 44213e3f4d6SMark Murray 44313e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: recv will", option)); 44413e3f4d6SMark Murray 44513e3f4d6SMark Murray if (do_dont_resp[option]) { 44613e3f4d6SMark Murray do_dont_resp[option]--; 44713e3f4d6SMark Murray if (do_dont_resp[option] && his_state_is_will(option)) 44813e3f4d6SMark Murray do_dont_resp[option]--; 44913e3f4d6SMark Murray } 45013e3f4d6SMark Murray if (do_dont_resp[option] == 0) { 45113e3f4d6SMark Murray if (his_want_state_is_wont(option)) { 45213e3f4d6SMark Murray switch (option) { 45313e3f4d6SMark Murray 45413e3f4d6SMark Murray case TELOPT_BINARY: 45513e3f4d6SMark Murray init_termbuf(); 45613e3f4d6SMark Murray tty_binaryin(1); 45713e3f4d6SMark Murray set_termbuf(); 45813e3f4d6SMark Murray changeok++; 45913e3f4d6SMark Murray break; 46013e3f4d6SMark Murray 46113e3f4d6SMark Murray case TELOPT_ECHO: 46213e3f4d6SMark Murray /* 46313e3f4d6SMark Murray * See comments below for more info. 46413e3f4d6SMark Murray */ 46513e3f4d6SMark Murray not42 = 0; /* looks like a 4.2 system */ 46613e3f4d6SMark Murray break; 46713e3f4d6SMark Murray 46813e3f4d6SMark Murray case TELOPT_TM: 46913e3f4d6SMark Murray /* 47013e3f4d6SMark Murray * We never respond to a WILL TM, and 47113e3f4d6SMark Murray * we leave the state WONT. 47213e3f4d6SMark Murray */ 47313e3f4d6SMark Murray return; 47413e3f4d6SMark Murray 47513e3f4d6SMark Murray case TELOPT_LFLOW: 47613e3f4d6SMark Murray /* 47713e3f4d6SMark Murray * If we are going to support flow control 47813e3f4d6SMark Murray * option, then don't worry peer that we can't 47913e3f4d6SMark Murray * change the flow control characters. 48013e3f4d6SMark Murray */ 48113e3f4d6SMark Murray slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 48213e3f4d6SMark Murray slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 48313e3f4d6SMark Murray slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 48413e3f4d6SMark Murray slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 48513e3f4d6SMark Murray case TELOPT_TTYPE: 48613e3f4d6SMark Murray case TELOPT_SGA: 48713e3f4d6SMark Murray case TELOPT_NAWS: 48813e3f4d6SMark Murray case TELOPT_TSPEED: 48913e3f4d6SMark Murray case TELOPT_XDISPLOC: 49013e3f4d6SMark Murray case TELOPT_NEW_ENVIRON: 49113e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: 49213e3f4d6SMark Murray changeok++; 49313e3f4d6SMark Murray break; 49413e3f4d6SMark Murray 49513e3f4d6SMark Murray 49613e3f4d6SMark Murray #ifdef AUTHENTICATION 49713e3f4d6SMark Murray case TELOPT_AUTHENTICATION: 49813e3f4d6SMark Murray func = auth_request; 49913e3f4d6SMark Murray changeok++; 50013e3f4d6SMark Murray break; 50113e3f4d6SMark Murray #endif 50213e3f4d6SMark Murray 50313e3f4d6SMark Murray #ifdef ENCRYPTION 50413e3f4d6SMark Murray case TELOPT_ENCRYPT: 50513e3f4d6SMark Murray func = encrypt_send_support; 50613e3f4d6SMark Murray changeok++; 50713e3f4d6SMark Murray break; 50813e3f4d6SMark Murray #endif 50913e3f4d6SMark Murray 51013e3f4d6SMark Murray default: 51113e3f4d6SMark Murray break; 51213e3f4d6SMark Murray } 51313e3f4d6SMark Murray if (changeok) { 51413e3f4d6SMark Murray set_his_want_state_will(option); 51513e3f4d6SMark Murray send_do(option, 0); 51613e3f4d6SMark Murray } else { 51713e3f4d6SMark Murray do_dont_resp[option]++; 51813e3f4d6SMark Murray send_dont(option, 0); 51913e3f4d6SMark Murray } 52013e3f4d6SMark Murray } else { 52113e3f4d6SMark Murray /* 52213e3f4d6SMark Murray * Option processing that should happen when 52313e3f4d6SMark Murray * we receive conformation of a change in 52413e3f4d6SMark Murray * state that we had requested. 52513e3f4d6SMark Murray */ 52613e3f4d6SMark Murray switch (option) { 52713e3f4d6SMark Murray case TELOPT_ECHO: 52813e3f4d6SMark Murray not42 = 0; /* looks like a 4.2 system */ 52913e3f4d6SMark Murray /* 53013e3f4d6SMark Murray * Egads, he responded "WILL ECHO". Turn 53113e3f4d6SMark Murray * it off right now! 53213e3f4d6SMark Murray */ 53313e3f4d6SMark Murray send_dont(option, 1); 53413e3f4d6SMark Murray /* 53513e3f4d6SMark Murray * "WILL ECHO". Kludge upon kludge! 53613e3f4d6SMark Murray * A 4.2 client is now echoing user input at 53713e3f4d6SMark Murray * the tty. This is probably undesireable and 53813e3f4d6SMark Murray * it should be stopped. The client will 53913e3f4d6SMark Murray * respond WONT TM to the DO TM that we send to 54013e3f4d6SMark Murray * check for kludge linemode. When the WONT TM 54113e3f4d6SMark Murray * arrives, linemode will be turned off and a 54213e3f4d6SMark Murray * change propogated to the pty. This change 54313e3f4d6SMark Murray * will cause us to process the new pty state 54413e3f4d6SMark Murray * in localstat(), which will notice that 54513e3f4d6SMark Murray * linemode is off and send a WILL ECHO 54613e3f4d6SMark Murray * so that we are properly in character mode and 54713e3f4d6SMark Murray * all is well. 54813e3f4d6SMark Murray */ 54913e3f4d6SMark Murray break; 55013e3f4d6SMark Murray 55113e3f4d6SMark Murray #ifdef AUTHENTICATION 55213e3f4d6SMark Murray case TELOPT_AUTHENTICATION: 55313e3f4d6SMark Murray func = auth_request; 55413e3f4d6SMark Murray break; 55513e3f4d6SMark Murray #endif 55613e3f4d6SMark Murray 55713e3f4d6SMark Murray #ifdef ENCRYPTION 55813e3f4d6SMark Murray case TELOPT_ENCRYPT: 55913e3f4d6SMark Murray func = encrypt_send_support; 56013e3f4d6SMark Murray break; 56113e3f4d6SMark Murray #endif 56213e3f4d6SMark Murray 56313e3f4d6SMark Murray case TELOPT_LFLOW: 56413e3f4d6SMark Murray func = flowstat; 56513e3f4d6SMark Murray break; 56613e3f4d6SMark Murray } 56713e3f4d6SMark Murray } 56813e3f4d6SMark Murray } 56913e3f4d6SMark Murray set_his_state_will(option); 57013e3f4d6SMark Murray if (func) 57113e3f4d6SMark Murray (*func)(); 57213e3f4d6SMark Murray } /* end of willoption */ 57313e3f4d6SMark Murray 57413e3f4d6SMark Murray void 57513e3f4d6SMark Murray send_dont(int option, int init) 57613e3f4d6SMark Murray { 57713e3f4d6SMark Murray if (init) { 57813e3f4d6SMark Murray if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 57913e3f4d6SMark Murray his_want_state_is_wont(option)) 58013e3f4d6SMark Murray return; 58113e3f4d6SMark Murray set_his_want_state_wont(option); 58213e3f4d6SMark Murray do_dont_resp[option]++; 58313e3f4d6SMark Murray } 58413e3f4d6SMark Murray output_data((const char *)dont, option); 58513e3f4d6SMark Murray 58613e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: send dont", option)); 58713e3f4d6SMark Murray } 58813e3f4d6SMark Murray 58913e3f4d6SMark Murray void 59013e3f4d6SMark Murray wontoption(int option) 59113e3f4d6SMark Murray { 59213e3f4d6SMark Murray /* 59313e3f4d6SMark Murray * Process client input. 59413e3f4d6SMark Murray */ 59513e3f4d6SMark Murray 59613e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 59713e3f4d6SMark Murray 59813e3f4d6SMark Murray if (do_dont_resp[option]) { 59913e3f4d6SMark Murray do_dont_resp[option]--; 60013e3f4d6SMark Murray if (do_dont_resp[option] && his_state_is_wont(option)) 60113e3f4d6SMark Murray do_dont_resp[option]--; 60213e3f4d6SMark Murray } 60313e3f4d6SMark Murray if (do_dont_resp[option] == 0) { 60413e3f4d6SMark Murray if (his_want_state_is_will(option)) { 60513e3f4d6SMark Murray /* it is always ok to change to negative state */ 60613e3f4d6SMark Murray switch (option) { 60713e3f4d6SMark Murray case TELOPT_ECHO: 60813e3f4d6SMark Murray not42 = 1; /* doesn't seem to be a 4.2 system */ 60913e3f4d6SMark Murray break; 61013e3f4d6SMark Murray 61113e3f4d6SMark Murray case TELOPT_BINARY: 61213e3f4d6SMark Murray init_termbuf(); 61313e3f4d6SMark Murray tty_binaryin(0); 61413e3f4d6SMark Murray set_termbuf(); 61513e3f4d6SMark Murray break; 61613e3f4d6SMark Murray 61713e3f4d6SMark Murray case TELOPT_TM: 61813e3f4d6SMark Murray /* 61913e3f4d6SMark Murray * If we get a WONT TM, and had sent a DO TM, 62013e3f4d6SMark Murray * don't respond with a DONT TM, just leave it 62113e3f4d6SMark Murray * as is. Short circut the state machine to 62213e3f4d6SMark Murray * achive this. 62313e3f4d6SMark Murray */ 62413e3f4d6SMark Murray set_his_want_state_wont(TELOPT_TM); 62513e3f4d6SMark Murray return; 62613e3f4d6SMark Murray 62713e3f4d6SMark Murray case TELOPT_LFLOW: 62813e3f4d6SMark Murray /* 62913e3f4d6SMark Murray * If we are not going to support flow control 63013e3f4d6SMark Murray * option, then let peer know that we can't 63113e3f4d6SMark Murray * change the flow control characters. 63213e3f4d6SMark Murray */ 63313e3f4d6SMark Murray slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 63413e3f4d6SMark Murray slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 63513e3f4d6SMark Murray slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 63613e3f4d6SMark Murray slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 63713e3f4d6SMark Murray break; 63813e3f4d6SMark Murray 63913e3f4d6SMark Murray #ifdef AUTHENTICATION 64013e3f4d6SMark Murray case TELOPT_AUTHENTICATION: 64113e3f4d6SMark Murray auth_finished(0, AUTH_REJECT); 64213e3f4d6SMark Murray break; 64313e3f4d6SMark Murray #endif 64413e3f4d6SMark Murray 64513e3f4d6SMark Murray /* 64613e3f4d6SMark Murray * For options that we might spin waiting for 64713e3f4d6SMark Murray * sub-negotiation, if the client turns off the 64813e3f4d6SMark Murray * option rather than responding to the request, 64913e3f4d6SMark Murray * we have to treat it here as if we got a response 65013e3f4d6SMark Murray * to the sub-negotiation, (by updating the timers) 65113e3f4d6SMark Murray * so that we'll break out of the loop. 65213e3f4d6SMark Murray */ 65313e3f4d6SMark Murray case TELOPT_TTYPE: 65413e3f4d6SMark Murray settimer(ttypesubopt); 65513e3f4d6SMark Murray break; 65613e3f4d6SMark Murray 65713e3f4d6SMark Murray case TELOPT_TSPEED: 65813e3f4d6SMark Murray settimer(tspeedsubopt); 65913e3f4d6SMark Murray break; 66013e3f4d6SMark Murray 66113e3f4d6SMark Murray case TELOPT_XDISPLOC: 66213e3f4d6SMark Murray settimer(xdisplocsubopt); 66313e3f4d6SMark Murray break; 66413e3f4d6SMark Murray 66513e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: 66613e3f4d6SMark Murray settimer(oenvironsubopt); 66713e3f4d6SMark Murray break; 66813e3f4d6SMark Murray 66913e3f4d6SMark Murray case TELOPT_NEW_ENVIRON: 67013e3f4d6SMark Murray settimer(environsubopt); 67113e3f4d6SMark Murray break; 67213e3f4d6SMark Murray 67313e3f4d6SMark Murray default: 67413e3f4d6SMark Murray break; 67513e3f4d6SMark Murray } 67613e3f4d6SMark Murray set_his_want_state_wont(option); 67713e3f4d6SMark Murray if (his_state_is_will(option)) 67813e3f4d6SMark Murray send_dont(option, 0); 67913e3f4d6SMark Murray } else { 68013e3f4d6SMark Murray switch (option) { 68113e3f4d6SMark Murray case TELOPT_TM: 68213e3f4d6SMark Murray break; 68313e3f4d6SMark Murray 68413e3f4d6SMark Murray #ifdef AUTHENTICATION 68513e3f4d6SMark Murray case TELOPT_AUTHENTICATION: 68613e3f4d6SMark Murray auth_finished(0, AUTH_REJECT); 68713e3f4d6SMark Murray break; 68813e3f4d6SMark Murray #endif 68913e3f4d6SMark Murray default: 69013e3f4d6SMark Murray break; 69113e3f4d6SMark Murray } 69213e3f4d6SMark Murray } 69313e3f4d6SMark Murray } 69413e3f4d6SMark Murray set_his_state_wont(option); 69513e3f4d6SMark Murray 69613e3f4d6SMark Murray } /* end of wontoption */ 69713e3f4d6SMark Murray 69813e3f4d6SMark Murray void 69913e3f4d6SMark Murray send_will(int option, int init) 70013e3f4d6SMark Murray { 70113e3f4d6SMark Murray if (init) { 70213e3f4d6SMark Murray if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 70313e3f4d6SMark Murray my_want_state_is_will(option)) 70413e3f4d6SMark Murray return; 70513e3f4d6SMark Murray set_my_want_state_will(option); 70613e3f4d6SMark Murray will_wont_resp[option]++; 70713e3f4d6SMark Murray } 70813e3f4d6SMark Murray output_data ((const char *)will, option); 70913e3f4d6SMark Murray 71013e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: send will", option)); 71113e3f4d6SMark Murray } 71213e3f4d6SMark Murray 71313e3f4d6SMark Murray /* 71413e3f4d6SMark Murray * When we get a DONT SGA, we will try once to turn it 71513e3f4d6SMark Murray * back on. If the other side responds DONT SGA, we 71613e3f4d6SMark Murray * leave it at that. This is so that when we talk to 71713e3f4d6SMark Murray * clients that understand KLUDGELINEMODE but not LINEMODE, 71813e3f4d6SMark Murray * we'll keep them in char-at-a-time mode. 71913e3f4d6SMark Murray */ 72013e3f4d6SMark Murray int turn_on_sga = 0; 72113e3f4d6SMark Murray 72213e3f4d6SMark Murray void 72313e3f4d6SMark Murray dooption(int option) 72413e3f4d6SMark Murray { 72513e3f4d6SMark Murray int changeok = 0; 72613e3f4d6SMark Murray 72713e3f4d6SMark Murray /* 72813e3f4d6SMark Murray * Process client input. 72913e3f4d6SMark Murray */ 73013e3f4d6SMark Murray 73113e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: recv do", option)); 73213e3f4d6SMark Murray 73313e3f4d6SMark Murray if (will_wont_resp[option]) { 73413e3f4d6SMark Murray will_wont_resp[option]--; 73513e3f4d6SMark Murray if (will_wont_resp[option] && my_state_is_will(option)) 73613e3f4d6SMark Murray will_wont_resp[option]--; 73713e3f4d6SMark Murray } 73813e3f4d6SMark Murray if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 73913e3f4d6SMark Murray switch (option) { 74013e3f4d6SMark Murray case TELOPT_ECHO: 74113e3f4d6SMark Murray { 74213e3f4d6SMark Murray init_termbuf(); 74313e3f4d6SMark Murray tty_setecho(1); 74413e3f4d6SMark Murray set_termbuf(); 74513e3f4d6SMark Murray } 74613e3f4d6SMark Murray changeok++; 74713e3f4d6SMark Murray break; 74813e3f4d6SMark Murray 74913e3f4d6SMark Murray case TELOPT_BINARY: 75013e3f4d6SMark Murray init_termbuf(); 75113e3f4d6SMark Murray tty_binaryout(1); 75213e3f4d6SMark Murray set_termbuf(); 75313e3f4d6SMark Murray changeok++; 75413e3f4d6SMark Murray break; 75513e3f4d6SMark Murray 75613e3f4d6SMark Murray case TELOPT_SGA: 75713e3f4d6SMark Murray turn_on_sga = 0; 75813e3f4d6SMark Murray changeok++; 75913e3f4d6SMark Murray break; 76013e3f4d6SMark Murray 76113e3f4d6SMark Murray case TELOPT_STATUS: 76213e3f4d6SMark Murray changeok++; 76313e3f4d6SMark Murray break; 76413e3f4d6SMark Murray 76513e3f4d6SMark Murray case TELOPT_TM: 76613e3f4d6SMark Murray /* 76713e3f4d6SMark Murray * Special case for TM. We send a WILL, but 76813e3f4d6SMark Murray * pretend we sent a WONT. 76913e3f4d6SMark Murray */ 77013e3f4d6SMark Murray send_will(option, 0); 77113e3f4d6SMark Murray set_my_want_state_wont(option); 77213e3f4d6SMark Murray set_my_state_wont(option); 77313e3f4d6SMark Murray return; 77413e3f4d6SMark Murray 77513e3f4d6SMark Murray case TELOPT_LOGOUT: 77613e3f4d6SMark Murray /* 77713e3f4d6SMark Murray * When we get a LOGOUT option, respond 77813e3f4d6SMark Murray * with a WILL LOGOUT, make sure that 77913e3f4d6SMark Murray * it gets written out to the network, 78013e3f4d6SMark Murray * and then just go away... 78113e3f4d6SMark Murray */ 78213e3f4d6SMark Murray set_my_want_state_will(TELOPT_LOGOUT); 78313e3f4d6SMark Murray send_will(TELOPT_LOGOUT, 0); 78413e3f4d6SMark Murray set_my_state_will(TELOPT_LOGOUT); 78513e3f4d6SMark Murray netflush(); 78613e3f4d6SMark Murray cleanup(0); 78713e3f4d6SMark Murray /* NOT REACHED */ 78813e3f4d6SMark Murray break; 78913e3f4d6SMark Murray 79013e3f4d6SMark Murray #ifdef ENCRYPTION 79113e3f4d6SMark Murray case TELOPT_ENCRYPT: 79213e3f4d6SMark Murray changeok++; 79313e3f4d6SMark Murray break; 79413e3f4d6SMark Murray #endif 79513e3f4d6SMark Murray case TELOPT_LINEMODE: 79613e3f4d6SMark Murray case TELOPT_TTYPE: 79713e3f4d6SMark Murray case TELOPT_NAWS: 79813e3f4d6SMark Murray case TELOPT_TSPEED: 79913e3f4d6SMark Murray case TELOPT_LFLOW: 80013e3f4d6SMark Murray case TELOPT_XDISPLOC: 80113e3f4d6SMark Murray #ifdef TELOPT_ENVIRON 80213e3f4d6SMark Murray case TELOPT_NEW_ENVIRON: 80313e3f4d6SMark Murray #endif 80413e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: 80513e3f4d6SMark Murray default: 80613e3f4d6SMark Murray break; 80713e3f4d6SMark Murray } 80813e3f4d6SMark Murray if (changeok) { 80913e3f4d6SMark Murray set_my_want_state_will(option); 81013e3f4d6SMark Murray send_will(option, 0); 81113e3f4d6SMark Murray } else { 81213e3f4d6SMark Murray will_wont_resp[option]++; 81313e3f4d6SMark Murray send_wont(option, 0); 81413e3f4d6SMark Murray } 81513e3f4d6SMark Murray } 81613e3f4d6SMark Murray set_my_state_will(option); 81713e3f4d6SMark Murray 81813e3f4d6SMark Murray } /* end of dooption */ 81913e3f4d6SMark Murray 82013e3f4d6SMark Murray void 82113e3f4d6SMark Murray send_wont(int option, int init) 82213e3f4d6SMark Murray { 82313e3f4d6SMark Murray if (init) { 82413e3f4d6SMark Murray if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 82513e3f4d6SMark Murray my_want_state_is_wont(option)) 82613e3f4d6SMark Murray return; 82713e3f4d6SMark Murray set_my_want_state_wont(option); 82813e3f4d6SMark Murray will_wont_resp[option]++; 82913e3f4d6SMark Murray } 83013e3f4d6SMark Murray output_data ((const char *)wont, option); 83113e3f4d6SMark Murray 83213e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: send wont", option)); 83313e3f4d6SMark Murray } 83413e3f4d6SMark Murray 83513e3f4d6SMark Murray void 83613e3f4d6SMark Murray dontoption(int option) 83713e3f4d6SMark Murray { 83813e3f4d6SMark Murray /* 83913e3f4d6SMark Murray * Process client input. 84013e3f4d6SMark Murray */ 84113e3f4d6SMark Murray 84213e3f4d6SMark Murray 84313e3f4d6SMark Murray DIAG(TD_OPTIONS, printoption("td: recv dont", option)); 84413e3f4d6SMark Murray 84513e3f4d6SMark Murray if (will_wont_resp[option]) { 84613e3f4d6SMark Murray will_wont_resp[option]--; 84713e3f4d6SMark Murray if (will_wont_resp[option] && my_state_is_wont(option)) 84813e3f4d6SMark Murray will_wont_resp[option]--; 84913e3f4d6SMark Murray } 85013e3f4d6SMark Murray if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 85113e3f4d6SMark Murray switch (option) { 85213e3f4d6SMark Murray case TELOPT_BINARY: 85313e3f4d6SMark Murray init_termbuf(); 85413e3f4d6SMark Murray tty_binaryout(0); 85513e3f4d6SMark Murray set_termbuf(); 85613e3f4d6SMark Murray break; 85713e3f4d6SMark Murray 85813e3f4d6SMark Murray case TELOPT_ECHO: /* we should stop echoing */ 85913e3f4d6SMark Murray { 86013e3f4d6SMark Murray init_termbuf(); 86113e3f4d6SMark Murray tty_setecho(0); 86213e3f4d6SMark Murray set_termbuf(); 86313e3f4d6SMark Murray } 86413e3f4d6SMark Murray break; 86513e3f4d6SMark Murray 86613e3f4d6SMark Murray case TELOPT_SGA: 86713e3f4d6SMark Murray set_my_want_state_wont(option); 86813e3f4d6SMark Murray if (my_state_is_will(option)) 86913e3f4d6SMark Murray send_wont(option, 0); 87013e3f4d6SMark Murray set_my_state_wont(option); 87113e3f4d6SMark Murray if (turn_on_sga ^= 1) 87213e3f4d6SMark Murray send_will(option, 1); 87313e3f4d6SMark Murray return; 87413e3f4d6SMark Murray 87513e3f4d6SMark Murray default: 87613e3f4d6SMark Murray break; 87713e3f4d6SMark Murray } 87813e3f4d6SMark Murray 87913e3f4d6SMark Murray set_my_want_state_wont(option); 88013e3f4d6SMark Murray if (my_state_is_will(option)) 88113e3f4d6SMark Murray send_wont(option, 0); 88213e3f4d6SMark Murray } 88313e3f4d6SMark Murray set_my_state_wont(option); 88413e3f4d6SMark Murray 88513e3f4d6SMark Murray } /* end of dontoption */ 88613e3f4d6SMark Murray 88713e3f4d6SMark Murray #ifdef ENV_HACK 88813e3f4d6SMark Murray int env_ovar = -1; 88913e3f4d6SMark Murray int env_ovalue = -1; 89013e3f4d6SMark Murray #else /* ENV_HACK */ 89113e3f4d6SMark Murray # define env_ovar OLD_ENV_VAR 89213e3f4d6SMark Murray # define env_ovalue OLD_ENV_VALUE 89313e3f4d6SMark Murray #endif /* ENV_HACK */ 89413e3f4d6SMark Murray 89513e3f4d6SMark Murray /* 89613e3f4d6SMark Murray * suboption() 89713e3f4d6SMark Murray * 89813e3f4d6SMark Murray * Look at the sub-option buffer, and try to be helpful to the other 89913e3f4d6SMark Murray * side. 90013e3f4d6SMark Murray * 90113e3f4d6SMark Murray * Currently we recognize: 90213e3f4d6SMark Murray * 90313e3f4d6SMark Murray * Terminal type is 90413e3f4d6SMark Murray * Linemode 90513e3f4d6SMark Murray * Window size 90613e3f4d6SMark Murray * Terminal speed 90713e3f4d6SMark Murray */ 90813e3f4d6SMark Murray void 90913e3f4d6SMark Murray suboption(void) 91013e3f4d6SMark Murray { 91113e3f4d6SMark Murray int subchar; 91213e3f4d6SMark Murray 91313e3f4d6SMark Murray DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 91413e3f4d6SMark Murray 91513e3f4d6SMark Murray subchar = SB_GET(); 91613e3f4d6SMark Murray switch (subchar) { 91713e3f4d6SMark Murray case TELOPT_TSPEED: { 91813e3f4d6SMark Murray int xspeed, rspeed; 91913e3f4d6SMark Murray 92013e3f4d6SMark Murray if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 92113e3f4d6SMark Murray break; 92213e3f4d6SMark Murray 92313e3f4d6SMark Murray settimer(tspeedsubopt); 92413e3f4d6SMark Murray 92513e3f4d6SMark Murray if (SB_EOF() || SB_GET() != TELQUAL_IS) 92613e3f4d6SMark Murray return; 92713e3f4d6SMark Murray 92813e3f4d6SMark Murray xspeed = atoi((char *)subpointer); 92913e3f4d6SMark Murray 93013e3f4d6SMark Murray while (SB_GET() != ',' && !SB_EOF()); 93113e3f4d6SMark Murray if (SB_EOF()) 93213e3f4d6SMark Murray return; 93313e3f4d6SMark Murray 93413e3f4d6SMark Murray rspeed = atoi((char *)subpointer); 93513e3f4d6SMark Murray clientstat(TELOPT_TSPEED, xspeed, rspeed); 93613e3f4d6SMark Murray 93713e3f4d6SMark Murray break; 93813e3f4d6SMark Murray 93913e3f4d6SMark Murray } /* end of case TELOPT_TSPEED */ 94013e3f4d6SMark Murray 94113e3f4d6SMark Murray case TELOPT_TTYPE: { /* Yaaaay! */ 94213e3f4d6SMark Murray static char terminalname[41]; 94313e3f4d6SMark Murray 94413e3f4d6SMark Murray if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 94513e3f4d6SMark Murray break; 94613e3f4d6SMark Murray settimer(ttypesubopt); 94713e3f4d6SMark Murray 94813e3f4d6SMark Murray if (SB_EOF() || SB_GET() != TELQUAL_IS) { 94913e3f4d6SMark Murray return; /* ??? XXX but, this is the most robust */ 95013e3f4d6SMark Murray } 95113e3f4d6SMark Murray 95213e3f4d6SMark Murray terminaltype = terminalname; 95313e3f4d6SMark Murray 95413e3f4d6SMark Murray while ((terminaltype < (terminalname + sizeof terminalname-1)) && 95513e3f4d6SMark Murray !SB_EOF()) { 95613e3f4d6SMark Murray int c; 95713e3f4d6SMark Murray 95813e3f4d6SMark Murray c = SB_GET(); 95913e3f4d6SMark Murray if (isupper(c)) { 96013e3f4d6SMark Murray c = tolower(c); 96113e3f4d6SMark Murray } 96213e3f4d6SMark Murray *terminaltype++ = c; /* accumulate name */ 96313e3f4d6SMark Murray } 96413e3f4d6SMark Murray *terminaltype = 0; 96513e3f4d6SMark Murray terminaltype = terminalname; 96613e3f4d6SMark Murray break; 96713e3f4d6SMark Murray } /* end of case TELOPT_TTYPE */ 96813e3f4d6SMark Murray 96913e3f4d6SMark Murray case TELOPT_NAWS: { 97013e3f4d6SMark Murray int xwinsize, ywinsize; 97113e3f4d6SMark Murray 97213e3f4d6SMark Murray if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 97313e3f4d6SMark Murray break; 97413e3f4d6SMark Murray 97513e3f4d6SMark Murray if (SB_EOF()) 97613e3f4d6SMark Murray return; 97713e3f4d6SMark Murray xwinsize = SB_GET() << 8; 97813e3f4d6SMark Murray if (SB_EOF()) 97913e3f4d6SMark Murray return; 98013e3f4d6SMark Murray xwinsize |= SB_GET(); 98113e3f4d6SMark Murray if (SB_EOF()) 98213e3f4d6SMark Murray return; 98313e3f4d6SMark Murray ywinsize = SB_GET() << 8; 98413e3f4d6SMark Murray if (SB_EOF()) 98513e3f4d6SMark Murray return; 98613e3f4d6SMark Murray ywinsize |= SB_GET(); 98713e3f4d6SMark Murray clientstat(TELOPT_NAWS, xwinsize, ywinsize); 98813e3f4d6SMark Murray 98913e3f4d6SMark Murray break; 99013e3f4d6SMark Murray 99113e3f4d6SMark Murray } /* end of case TELOPT_NAWS */ 99213e3f4d6SMark Murray 99313e3f4d6SMark Murray case TELOPT_STATUS: { 99413e3f4d6SMark Murray int mode; 99513e3f4d6SMark Murray 99613e3f4d6SMark Murray if (SB_EOF()) 99713e3f4d6SMark Murray break; 99813e3f4d6SMark Murray mode = SB_GET(); 99913e3f4d6SMark Murray switch (mode) { 100013e3f4d6SMark Murray case TELQUAL_SEND: 100113e3f4d6SMark Murray if (my_state_is_will(TELOPT_STATUS)) 100213e3f4d6SMark Murray send_status(); 100313e3f4d6SMark Murray break; 100413e3f4d6SMark Murray 100513e3f4d6SMark Murray case TELQUAL_IS: 100613e3f4d6SMark Murray break; 100713e3f4d6SMark Murray 100813e3f4d6SMark Murray default: 100913e3f4d6SMark Murray break; 101013e3f4d6SMark Murray } 101113e3f4d6SMark Murray break; 101213e3f4d6SMark Murray } /* end of case TELOPT_STATUS */ 101313e3f4d6SMark Murray 101413e3f4d6SMark Murray case TELOPT_XDISPLOC: { 101513e3f4d6SMark Murray if (SB_EOF() || SB_GET() != TELQUAL_IS) 101613e3f4d6SMark Murray return; 101713e3f4d6SMark Murray settimer(xdisplocsubopt); 101813e3f4d6SMark Murray subpointer[SB_LEN()] = '\0'; 101913e3f4d6SMark Murray setenv("DISPLAY", (char *)subpointer, 1); 102013e3f4d6SMark Murray break; 102113e3f4d6SMark Murray } /* end of case TELOPT_XDISPLOC */ 102213e3f4d6SMark Murray 102313e3f4d6SMark Murray #ifdef TELOPT_NEW_ENVIRON 102413e3f4d6SMark Murray case TELOPT_NEW_ENVIRON: 102513e3f4d6SMark Murray #endif 102613e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: { 102713e3f4d6SMark Murray int c; 102813e3f4d6SMark Murray char *cp, *varp, *valp; 102913e3f4d6SMark Murray 103013e3f4d6SMark Murray if (SB_EOF()) 103113e3f4d6SMark Murray return; 103213e3f4d6SMark Murray c = SB_GET(); 103313e3f4d6SMark Murray if (c == TELQUAL_IS) { 103413e3f4d6SMark Murray if (subchar == TELOPT_OLD_ENVIRON) 103513e3f4d6SMark Murray settimer(oenvironsubopt); 103613e3f4d6SMark Murray else 103713e3f4d6SMark Murray settimer(environsubopt); 103813e3f4d6SMark Murray } else if (c != TELQUAL_INFO) { 103913e3f4d6SMark Murray return; 104013e3f4d6SMark Murray } 104113e3f4d6SMark Murray 104213e3f4d6SMark Murray #ifdef TELOPT_NEW_ENVIRON 104313e3f4d6SMark Murray if (subchar == TELOPT_NEW_ENVIRON) { 104413e3f4d6SMark Murray while (!SB_EOF()) { 104513e3f4d6SMark Murray c = SB_GET(); 104613e3f4d6SMark Murray if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 104713e3f4d6SMark Murray break; 104813e3f4d6SMark Murray } 104913e3f4d6SMark Murray } else 105013e3f4d6SMark Murray #endif 105113e3f4d6SMark Murray { 105213e3f4d6SMark Murray #ifdef ENV_HACK 105313e3f4d6SMark Murray /* 105413e3f4d6SMark Murray * We only want to do this if we haven't already decided 105513e3f4d6SMark Murray * whether or not the other side has its VALUE and VAR 105613e3f4d6SMark Murray * reversed. 105713e3f4d6SMark Murray */ 105813e3f4d6SMark Murray if (env_ovar < 0) { 105913e3f4d6SMark Murray int last = -1; /* invalid value */ 106013e3f4d6SMark Murray int empty = 0; 106113e3f4d6SMark Murray int got_var = 0, got_value = 0, got_uservar = 0; 106213e3f4d6SMark Murray 106313e3f4d6SMark Murray /* 106413e3f4d6SMark Murray * The other side might have its VALUE and VAR values 106513e3f4d6SMark Murray * reversed. To be interoperable, we need to determine 106613e3f4d6SMark Murray * which way it is. If the first recognized character 106713e3f4d6SMark Murray * is a VAR or VALUE, then that will tell us what 106813e3f4d6SMark Murray * type of client it is. If the fist recognized 106913e3f4d6SMark Murray * character is a USERVAR, then we continue scanning 107013e3f4d6SMark Murray * the suboption looking for two consecutive 107113e3f4d6SMark Murray * VAR or VALUE fields. We should not get two 107213e3f4d6SMark Murray * consecutive VALUE fields, so finding two 107313e3f4d6SMark Murray * consecutive VALUE or VAR fields will tell us 107413e3f4d6SMark Murray * what the client is. 107513e3f4d6SMark Murray */ 107613e3f4d6SMark Murray SB_SAVE(); 107713e3f4d6SMark Murray while (!SB_EOF()) { 107813e3f4d6SMark Murray c = SB_GET(); 107913e3f4d6SMark Murray switch(c) { 108013e3f4d6SMark Murray case OLD_ENV_VAR: 108113e3f4d6SMark Murray if (last < 0 || last == OLD_ENV_VAR 108213e3f4d6SMark Murray || (empty && (last == OLD_ENV_VALUE))) 108313e3f4d6SMark Murray goto env_ovar_ok; 108413e3f4d6SMark Murray got_var++; 108513e3f4d6SMark Murray last = OLD_ENV_VAR; 108613e3f4d6SMark Murray break; 108713e3f4d6SMark Murray case OLD_ENV_VALUE: 108813e3f4d6SMark Murray if (last < 0 || last == OLD_ENV_VALUE 108913e3f4d6SMark Murray || (empty && (last == OLD_ENV_VAR))) 109013e3f4d6SMark Murray goto env_ovar_wrong; 109113e3f4d6SMark Murray got_value++; 109213e3f4d6SMark Murray last = OLD_ENV_VALUE; 109313e3f4d6SMark Murray break; 109413e3f4d6SMark Murray case ENV_USERVAR: 109513e3f4d6SMark Murray /* count strings of USERVAR as one */ 109613e3f4d6SMark Murray if (last != ENV_USERVAR) 109713e3f4d6SMark Murray got_uservar++; 109813e3f4d6SMark Murray if (empty) { 109913e3f4d6SMark Murray if (last == OLD_ENV_VALUE) 110013e3f4d6SMark Murray goto env_ovar_ok; 110113e3f4d6SMark Murray if (last == OLD_ENV_VAR) 110213e3f4d6SMark Murray goto env_ovar_wrong; 110313e3f4d6SMark Murray } 110413e3f4d6SMark Murray last = ENV_USERVAR; 110513e3f4d6SMark Murray break; 110613e3f4d6SMark Murray case ENV_ESC: 110713e3f4d6SMark Murray if (!SB_EOF()) 110813e3f4d6SMark Murray c = SB_GET(); 110913e3f4d6SMark Murray /* FALL THROUGH */ 111013e3f4d6SMark Murray default: 111113e3f4d6SMark Murray empty = 0; 111213e3f4d6SMark Murray continue; 111313e3f4d6SMark Murray } 111413e3f4d6SMark Murray empty = 1; 111513e3f4d6SMark Murray } 111613e3f4d6SMark Murray if (empty) { 111713e3f4d6SMark Murray if (last == OLD_ENV_VALUE) 111813e3f4d6SMark Murray goto env_ovar_ok; 111913e3f4d6SMark Murray if (last == OLD_ENV_VAR) 112013e3f4d6SMark Murray goto env_ovar_wrong; 112113e3f4d6SMark Murray } 112213e3f4d6SMark Murray /* 112313e3f4d6SMark Murray * Ok, the first thing was a USERVAR, and there 112413e3f4d6SMark Murray * are not two consecutive VAR or VALUE commands, 112513e3f4d6SMark Murray * and none of the VAR or VALUE commands are empty. 112613e3f4d6SMark Murray * If the client has sent us a well-formed option, 112713e3f4d6SMark Murray * then the number of VALUEs received should always 112813e3f4d6SMark Murray * be less than or equal to the number of VARs and 112913e3f4d6SMark Murray * USERVARs received. 113013e3f4d6SMark Murray * 113113e3f4d6SMark Murray * If we got exactly as many VALUEs as VARs and 113213e3f4d6SMark Murray * USERVARs, the client has the same definitions. 113313e3f4d6SMark Murray * 113413e3f4d6SMark Murray * If we got exactly as many VARs as VALUEs and 113513e3f4d6SMark Murray * USERVARS, the client has reversed definitions. 113613e3f4d6SMark Murray */ 113713e3f4d6SMark Murray if (got_uservar + got_var == got_value) { 113813e3f4d6SMark Murray env_ovar_ok: 113913e3f4d6SMark Murray env_ovar = OLD_ENV_VAR; 114013e3f4d6SMark Murray env_ovalue = OLD_ENV_VALUE; 114113e3f4d6SMark Murray } else if (got_uservar + got_value == got_var) { 114213e3f4d6SMark Murray env_ovar_wrong: 114313e3f4d6SMark Murray env_ovar = OLD_ENV_VALUE; 114413e3f4d6SMark Murray env_ovalue = OLD_ENV_VAR; 114513e3f4d6SMark Murray DIAG(TD_OPTIONS, { 114613e3f4d6SMark Murray output_data("ENVIRON VALUE and VAR are reversed!\r\n"); 114713e3f4d6SMark Murray }); 114813e3f4d6SMark Murray 114913e3f4d6SMark Murray } 115013e3f4d6SMark Murray } 115113e3f4d6SMark Murray SB_RESTORE(); 115213e3f4d6SMark Murray #endif 115313e3f4d6SMark Murray 115413e3f4d6SMark Murray while (!SB_EOF()) { 115513e3f4d6SMark Murray c = SB_GET(); 115613e3f4d6SMark Murray if ((c == env_ovar) || (c == ENV_USERVAR)) 115713e3f4d6SMark Murray break; 115813e3f4d6SMark Murray } 115913e3f4d6SMark Murray } 116013e3f4d6SMark Murray 116113e3f4d6SMark Murray if (SB_EOF()) 116213e3f4d6SMark Murray return; 116313e3f4d6SMark Murray 116413e3f4d6SMark Murray cp = varp = (char *)subpointer; 116513e3f4d6SMark Murray valp = 0; 116613e3f4d6SMark Murray 116713e3f4d6SMark Murray while (!SB_EOF()) { 116813e3f4d6SMark Murray c = SB_GET(); 116913e3f4d6SMark Murray if (subchar == TELOPT_OLD_ENVIRON) { 117013e3f4d6SMark Murray if (c == env_ovar) 117113e3f4d6SMark Murray c = NEW_ENV_VAR; 117213e3f4d6SMark Murray else if (c == env_ovalue) 117313e3f4d6SMark Murray c = NEW_ENV_VALUE; 117413e3f4d6SMark Murray } 117513e3f4d6SMark Murray switch (c) { 117613e3f4d6SMark Murray 117713e3f4d6SMark Murray case NEW_ENV_VALUE: 117813e3f4d6SMark Murray *cp = '\0'; 117913e3f4d6SMark Murray cp = valp = (char *)subpointer; 118013e3f4d6SMark Murray break; 118113e3f4d6SMark Murray 118213e3f4d6SMark Murray case NEW_ENV_VAR: 118313e3f4d6SMark Murray case ENV_USERVAR: 118413e3f4d6SMark Murray *cp = '\0'; 118513e3f4d6SMark Murray if (valp) 118613e3f4d6SMark Murray setenv(varp, valp, 1); 118713e3f4d6SMark Murray else 118813e3f4d6SMark Murray unsetenv(varp); 118913e3f4d6SMark Murray cp = varp = (char *)subpointer; 119013e3f4d6SMark Murray valp = 0; 119113e3f4d6SMark Murray break; 119213e3f4d6SMark Murray 119313e3f4d6SMark Murray case ENV_ESC: 119413e3f4d6SMark Murray if (SB_EOF()) 119513e3f4d6SMark Murray break; 119613e3f4d6SMark Murray c = SB_GET(); 119713e3f4d6SMark Murray /* FALL THROUGH */ 119813e3f4d6SMark Murray default: 119913e3f4d6SMark Murray *cp++ = c; 120013e3f4d6SMark Murray break; 120113e3f4d6SMark Murray } 120213e3f4d6SMark Murray } 120313e3f4d6SMark Murray *cp = '\0'; 120413e3f4d6SMark Murray if (valp) 120513e3f4d6SMark Murray setenv(varp, valp, 1); 120613e3f4d6SMark Murray else 120713e3f4d6SMark Murray unsetenv(varp); 120813e3f4d6SMark Murray break; 120913e3f4d6SMark Murray } /* end of case TELOPT_NEW_ENVIRON */ 121013e3f4d6SMark Murray #ifdef AUTHENTICATION 121113e3f4d6SMark Murray case TELOPT_AUTHENTICATION: 121213e3f4d6SMark Murray if (SB_EOF()) 121313e3f4d6SMark Murray break; 121413e3f4d6SMark Murray switch(SB_GET()) { 121513e3f4d6SMark Murray case TELQUAL_SEND: 121613e3f4d6SMark Murray case TELQUAL_REPLY: 121713e3f4d6SMark Murray /* 121813e3f4d6SMark Murray * These are sent by us and cannot be sent by 121913e3f4d6SMark Murray * the client. 122013e3f4d6SMark Murray */ 122113e3f4d6SMark Murray break; 122213e3f4d6SMark Murray case TELQUAL_IS: 122313e3f4d6SMark Murray auth_is(subpointer, SB_LEN()); 122413e3f4d6SMark Murray break; 122513e3f4d6SMark Murray case TELQUAL_NAME: 122613e3f4d6SMark Murray auth_name(subpointer, SB_LEN()); 122713e3f4d6SMark Murray break; 122813e3f4d6SMark Murray } 122913e3f4d6SMark Murray break; 123013e3f4d6SMark Murray #endif 123113e3f4d6SMark Murray #ifdef ENCRYPTION 123213e3f4d6SMark Murray case TELOPT_ENCRYPT: 123313e3f4d6SMark Murray if (SB_EOF()) 123413e3f4d6SMark Murray break; 123513e3f4d6SMark Murray switch(SB_GET()) { 123613e3f4d6SMark Murray case ENCRYPT_SUPPORT: 123713e3f4d6SMark Murray encrypt_support(subpointer, SB_LEN()); 123813e3f4d6SMark Murray break; 123913e3f4d6SMark Murray case ENCRYPT_IS: 124013e3f4d6SMark Murray encrypt_is(subpointer, SB_LEN()); 124113e3f4d6SMark Murray break; 124213e3f4d6SMark Murray case ENCRYPT_REPLY: 124313e3f4d6SMark Murray encrypt_reply(subpointer, SB_LEN()); 124413e3f4d6SMark Murray break; 124513e3f4d6SMark Murray case ENCRYPT_START: 124613e3f4d6SMark Murray encrypt_start(subpointer, SB_LEN()); 124713e3f4d6SMark Murray break; 124813e3f4d6SMark Murray case ENCRYPT_END: 124913e3f4d6SMark Murray encrypt_end(); 125013e3f4d6SMark Murray break; 125113e3f4d6SMark Murray case ENCRYPT_REQSTART: 125213e3f4d6SMark Murray encrypt_request_start(subpointer, SB_LEN()); 125313e3f4d6SMark Murray break; 125413e3f4d6SMark Murray case ENCRYPT_REQEND: 125513e3f4d6SMark Murray /* 125613e3f4d6SMark Murray * We can always send an REQEND so that we cannot 125713e3f4d6SMark Murray * get stuck encrypting. We should only get this 125813e3f4d6SMark Murray * if we have been able to get in the correct mode 125913e3f4d6SMark Murray * anyhow. 126013e3f4d6SMark Murray */ 126113e3f4d6SMark Murray encrypt_request_end(); 126213e3f4d6SMark Murray break; 126313e3f4d6SMark Murray case ENCRYPT_ENC_KEYID: 126413e3f4d6SMark Murray encrypt_enc_keyid(subpointer, SB_LEN()); 126513e3f4d6SMark Murray break; 126613e3f4d6SMark Murray case ENCRYPT_DEC_KEYID: 126713e3f4d6SMark Murray encrypt_dec_keyid(subpointer, SB_LEN()); 126813e3f4d6SMark Murray break; 126913e3f4d6SMark Murray default: 127013e3f4d6SMark Murray break; 127113e3f4d6SMark Murray } 127213e3f4d6SMark Murray break; 127313e3f4d6SMark Murray #endif 127413e3f4d6SMark Murray 127513e3f4d6SMark Murray default: 127613e3f4d6SMark Murray break; 127713e3f4d6SMark Murray } /* end of switch */ 127813e3f4d6SMark Murray 127913e3f4d6SMark Murray } /* end of suboption */ 128013e3f4d6SMark Murray 128113e3f4d6SMark Murray void 128213e3f4d6SMark Murray doclientstat(void) 128313e3f4d6SMark Murray { 128413e3f4d6SMark Murray clientstat(TELOPT_LINEMODE, WILL, 0); 128513e3f4d6SMark Murray } 128613e3f4d6SMark Murray 128713e3f4d6SMark Murray #define ADD(c) *ncp++ = c 128813e3f4d6SMark Murray #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } 128913e3f4d6SMark Murray 129013e3f4d6SMark Murray void 129113e3f4d6SMark Murray send_status(void) 129213e3f4d6SMark Murray { 129313e3f4d6SMark Murray unsigned char statusbuf[256]; 129413e3f4d6SMark Murray unsigned char *ncp; 129513e3f4d6SMark Murray unsigned char i; 129613e3f4d6SMark Murray 129713e3f4d6SMark Murray ncp = statusbuf; 129813e3f4d6SMark Murray 129913e3f4d6SMark Murray netflush(); /* get rid of anything waiting to go out */ 130013e3f4d6SMark Murray 130113e3f4d6SMark Murray ADD(IAC); 130213e3f4d6SMark Murray ADD(SB); 130313e3f4d6SMark Murray ADD(TELOPT_STATUS); 130413e3f4d6SMark Murray ADD(TELQUAL_IS); 130513e3f4d6SMark Murray 130613e3f4d6SMark Murray /* 130713e3f4d6SMark Murray * We check the want_state rather than the current state, 130813e3f4d6SMark Murray * because if we received a DO/WILL for an option that we 130913e3f4d6SMark Murray * don't support, and the other side didn't send a DONT/WONT 131013e3f4d6SMark Murray * in response to our WONT/DONT, then the "state" will be 131113e3f4d6SMark Murray * WILL/DO, and the "want_state" will be WONT/DONT. We 131213e3f4d6SMark Murray * need to go by the latter. 131313e3f4d6SMark Murray */ 131413e3f4d6SMark Murray for (i = 0; i < (unsigned char)NTELOPTS; i++) { 131513e3f4d6SMark Murray if (my_want_state_is_will(i)) { 131613e3f4d6SMark Murray ADD(WILL); 131713e3f4d6SMark Murray ADD_DATA(i); 131813e3f4d6SMark Murray } 131913e3f4d6SMark Murray if (his_want_state_is_will(i)) { 132013e3f4d6SMark Murray ADD(DO); 132113e3f4d6SMark Murray ADD_DATA(i); 132213e3f4d6SMark Murray } 132313e3f4d6SMark Murray } 132413e3f4d6SMark Murray 132513e3f4d6SMark Murray if (his_want_state_is_will(TELOPT_LFLOW)) { 132613e3f4d6SMark Murray ADD(SB); 132713e3f4d6SMark Murray ADD(TELOPT_LFLOW); 132813e3f4d6SMark Murray if (flowmode) { 132913e3f4d6SMark Murray ADD(LFLOW_ON); 133013e3f4d6SMark Murray } else { 133113e3f4d6SMark Murray ADD(LFLOW_OFF); 133213e3f4d6SMark Murray } 133313e3f4d6SMark Murray ADD(SE); 133413e3f4d6SMark Murray 133513e3f4d6SMark Murray if (restartany >= 0) { 133613e3f4d6SMark Murray ADD(SB); 133713e3f4d6SMark Murray ADD(TELOPT_LFLOW); 133813e3f4d6SMark Murray if (restartany) { 133913e3f4d6SMark Murray ADD(LFLOW_RESTART_ANY); 134013e3f4d6SMark Murray } else { 134113e3f4d6SMark Murray ADD(LFLOW_RESTART_XON); 134213e3f4d6SMark Murray } 134313e3f4d6SMark Murray ADD(SE); 134413e3f4d6SMark Murray } 134513e3f4d6SMark Murray } 134613e3f4d6SMark Murray 134713e3f4d6SMark Murray 134813e3f4d6SMark Murray ADD(IAC); 134913e3f4d6SMark Murray ADD(SE); 135013e3f4d6SMark Murray 135113e3f4d6SMark Murray writenet(statusbuf, ncp - statusbuf); 135213e3f4d6SMark Murray netflush(); /* Send it on its way */ 135313e3f4d6SMark Murray 135413e3f4d6SMark Murray DIAG(TD_OPTIONS, 135513e3f4d6SMark Murray {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 135613e3f4d6SMark Murray } 1357