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
36*ae771770SStanislav Sedov RCSID("$Id$");
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 */
488d4ba808SJacques Vidrine unsigned char subbuffer[1024*64], *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
telrcv(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
send_do(int option,int init)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
430c19800e8SDoug Rabson extern void encrypt_send_support(void);
43113e3f4d6SMark Murray #endif
43213e3f4d6SMark Murray
43313e3f4d6SMark Murray void
willoption(int option)43413e3f4d6SMark Murray willoption(int option)
43513e3f4d6SMark Murray {
43613e3f4d6SMark Murray int changeok = 0;
437c19800e8SDoug Rabson void (*func)(void) = NULL;
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
send_dont(int option,int init)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
wontoption(int option)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
send_will(int option,int init)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
dooption(int option)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
send_wont(int option,int init)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
dontoption(int option)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
suboption(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! */
942c19800e8SDoug Rabson char *p;
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
952c19800e8SDoug Rabson p = terminaltype;
95313e3f4d6SMark Murray
954c19800e8SDoug Rabson while ((p < (terminaltype + sizeof terminaltype-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 }
962c19800e8SDoug Rabson *p++ = c; /* accumulate name */
96313e3f4d6SMark Murray }
964c19800e8SDoug Rabson *p = 0;
96513e3f4d6SMark Murray break;
96613e3f4d6SMark Murray } /* end of case TELOPT_TTYPE */
96713e3f4d6SMark Murray
96813e3f4d6SMark Murray case TELOPT_NAWS: {
96913e3f4d6SMark Murray int xwinsize, ywinsize;
97013e3f4d6SMark Murray
97113e3f4d6SMark Murray if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
97213e3f4d6SMark Murray break;
97313e3f4d6SMark Murray
97413e3f4d6SMark Murray if (SB_EOF())
97513e3f4d6SMark Murray return;
97613e3f4d6SMark Murray xwinsize = SB_GET() << 8;
97713e3f4d6SMark Murray if (SB_EOF())
97813e3f4d6SMark Murray return;
97913e3f4d6SMark Murray xwinsize |= SB_GET();
98013e3f4d6SMark Murray if (SB_EOF())
98113e3f4d6SMark Murray return;
98213e3f4d6SMark Murray ywinsize = SB_GET() << 8;
98313e3f4d6SMark Murray if (SB_EOF())
98413e3f4d6SMark Murray return;
98513e3f4d6SMark Murray ywinsize |= SB_GET();
98613e3f4d6SMark Murray clientstat(TELOPT_NAWS, xwinsize, ywinsize);
98713e3f4d6SMark Murray
98813e3f4d6SMark Murray break;
98913e3f4d6SMark Murray
99013e3f4d6SMark Murray } /* end of case TELOPT_NAWS */
99113e3f4d6SMark Murray
99213e3f4d6SMark Murray case TELOPT_STATUS: {
99313e3f4d6SMark Murray int mode;
99413e3f4d6SMark Murray
99513e3f4d6SMark Murray if (SB_EOF())
99613e3f4d6SMark Murray break;
99713e3f4d6SMark Murray mode = SB_GET();
99813e3f4d6SMark Murray switch (mode) {
99913e3f4d6SMark Murray case TELQUAL_SEND:
100013e3f4d6SMark Murray if (my_state_is_will(TELOPT_STATUS))
100113e3f4d6SMark Murray send_status();
100213e3f4d6SMark Murray break;
100313e3f4d6SMark Murray
100413e3f4d6SMark Murray case TELQUAL_IS:
100513e3f4d6SMark Murray break;
100613e3f4d6SMark Murray
100713e3f4d6SMark Murray default:
100813e3f4d6SMark Murray break;
100913e3f4d6SMark Murray }
101013e3f4d6SMark Murray break;
101113e3f4d6SMark Murray } /* end of case TELOPT_STATUS */
101213e3f4d6SMark Murray
101313e3f4d6SMark Murray case TELOPT_XDISPLOC: {
101413e3f4d6SMark Murray if (SB_EOF() || SB_GET() != TELQUAL_IS)
101513e3f4d6SMark Murray return;
101613e3f4d6SMark Murray settimer(xdisplocsubopt);
101713e3f4d6SMark Murray subpointer[SB_LEN()] = '\0';
10185e9cd1aeSAssar Westerlund esetenv("DISPLAY", (char *)subpointer, 1);
101913e3f4d6SMark Murray break;
102013e3f4d6SMark Murray } /* end of case TELOPT_XDISPLOC */
102113e3f4d6SMark Murray
102213e3f4d6SMark Murray #ifdef TELOPT_NEW_ENVIRON
102313e3f4d6SMark Murray case TELOPT_NEW_ENVIRON:
102413e3f4d6SMark Murray #endif
102513e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: {
102613e3f4d6SMark Murray int c;
102713e3f4d6SMark Murray char *cp, *varp, *valp;
102813e3f4d6SMark Murray
102913e3f4d6SMark Murray if (SB_EOF())
103013e3f4d6SMark Murray return;
103113e3f4d6SMark Murray c = SB_GET();
103213e3f4d6SMark Murray if (c == TELQUAL_IS) {
103313e3f4d6SMark Murray if (subchar == TELOPT_OLD_ENVIRON)
103413e3f4d6SMark Murray settimer(oenvironsubopt);
103513e3f4d6SMark Murray else
103613e3f4d6SMark Murray settimer(environsubopt);
103713e3f4d6SMark Murray } else if (c != TELQUAL_INFO) {
103813e3f4d6SMark Murray return;
103913e3f4d6SMark Murray }
104013e3f4d6SMark Murray
104113e3f4d6SMark Murray #ifdef TELOPT_NEW_ENVIRON
104213e3f4d6SMark Murray if (subchar == TELOPT_NEW_ENVIRON) {
104313e3f4d6SMark Murray while (!SB_EOF()) {
104413e3f4d6SMark Murray c = SB_GET();
104513e3f4d6SMark Murray if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
104613e3f4d6SMark Murray break;
104713e3f4d6SMark Murray }
104813e3f4d6SMark Murray } else
104913e3f4d6SMark Murray #endif
105013e3f4d6SMark Murray {
105113e3f4d6SMark Murray #ifdef ENV_HACK
105213e3f4d6SMark Murray /*
105313e3f4d6SMark Murray * We only want to do this if we haven't already decided
105413e3f4d6SMark Murray * whether or not the other side has its VALUE and VAR
105513e3f4d6SMark Murray * reversed.
105613e3f4d6SMark Murray */
105713e3f4d6SMark Murray if (env_ovar < 0) {
105813e3f4d6SMark Murray int last = -1; /* invalid value */
105913e3f4d6SMark Murray int empty = 0;
106013e3f4d6SMark Murray int got_var = 0, got_value = 0, got_uservar = 0;
106113e3f4d6SMark Murray
106213e3f4d6SMark Murray /*
106313e3f4d6SMark Murray * The other side might have its VALUE and VAR values
106413e3f4d6SMark Murray * reversed. To be interoperable, we need to determine
106513e3f4d6SMark Murray * which way it is. If the first recognized character
106613e3f4d6SMark Murray * is a VAR or VALUE, then that will tell us what
106713e3f4d6SMark Murray * type of client it is. If the fist recognized
106813e3f4d6SMark Murray * character is a USERVAR, then we continue scanning
106913e3f4d6SMark Murray * the suboption looking for two consecutive
107013e3f4d6SMark Murray * VAR or VALUE fields. We should not get two
107113e3f4d6SMark Murray * consecutive VALUE fields, so finding two
107213e3f4d6SMark Murray * consecutive VALUE or VAR fields will tell us
107313e3f4d6SMark Murray * what the client is.
107413e3f4d6SMark Murray */
107513e3f4d6SMark Murray SB_SAVE();
107613e3f4d6SMark Murray while (!SB_EOF()) {
107713e3f4d6SMark Murray c = SB_GET();
107813e3f4d6SMark Murray switch(c) {
107913e3f4d6SMark Murray case OLD_ENV_VAR:
108013e3f4d6SMark Murray if (last < 0 || last == OLD_ENV_VAR
108113e3f4d6SMark Murray || (empty && (last == OLD_ENV_VALUE)))
108213e3f4d6SMark Murray goto env_ovar_ok;
108313e3f4d6SMark Murray got_var++;
108413e3f4d6SMark Murray last = OLD_ENV_VAR;
108513e3f4d6SMark Murray break;
108613e3f4d6SMark Murray case OLD_ENV_VALUE:
108713e3f4d6SMark Murray if (last < 0 || last == OLD_ENV_VALUE
108813e3f4d6SMark Murray || (empty && (last == OLD_ENV_VAR)))
108913e3f4d6SMark Murray goto env_ovar_wrong;
109013e3f4d6SMark Murray got_value++;
109113e3f4d6SMark Murray last = OLD_ENV_VALUE;
109213e3f4d6SMark Murray break;
109313e3f4d6SMark Murray case ENV_USERVAR:
109413e3f4d6SMark Murray /* count strings of USERVAR as one */
109513e3f4d6SMark Murray if (last != ENV_USERVAR)
109613e3f4d6SMark Murray got_uservar++;
109713e3f4d6SMark Murray if (empty) {
109813e3f4d6SMark Murray if (last == OLD_ENV_VALUE)
109913e3f4d6SMark Murray goto env_ovar_ok;
110013e3f4d6SMark Murray if (last == OLD_ENV_VAR)
110113e3f4d6SMark Murray goto env_ovar_wrong;
110213e3f4d6SMark Murray }
110313e3f4d6SMark Murray last = ENV_USERVAR;
110413e3f4d6SMark Murray break;
110513e3f4d6SMark Murray case ENV_ESC:
110613e3f4d6SMark Murray if (!SB_EOF())
110713e3f4d6SMark Murray c = SB_GET();
110813e3f4d6SMark Murray /* FALL THROUGH */
110913e3f4d6SMark Murray default:
111013e3f4d6SMark Murray empty = 0;
111113e3f4d6SMark Murray continue;
111213e3f4d6SMark Murray }
111313e3f4d6SMark Murray empty = 1;
111413e3f4d6SMark Murray }
111513e3f4d6SMark Murray if (empty) {
111613e3f4d6SMark Murray if (last == OLD_ENV_VALUE)
111713e3f4d6SMark Murray goto env_ovar_ok;
111813e3f4d6SMark Murray if (last == OLD_ENV_VAR)
111913e3f4d6SMark Murray goto env_ovar_wrong;
112013e3f4d6SMark Murray }
112113e3f4d6SMark Murray /*
112213e3f4d6SMark Murray * Ok, the first thing was a USERVAR, and there
112313e3f4d6SMark Murray * are not two consecutive VAR or VALUE commands,
112413e3f4d6SMark Murray * and none of the VAR or VALUE commands are empty.
112513e3f4d6SMark Murray * If the client has sent us a well-formed option,
112613e3f4d6SMark Murray * then the number of VALUEs received should always
112713e3f4d6SMark Murray * be less than or equal to the number of VARs and
112813e3f4d6SMark Murray * USERVARs received.
112913e3f4d6SMark Murray *
113013e3f4d6SMark Murray * If we got exactly as many VALUEs as VARs and
113113e3f4d6SMark Murray * USERVARs, the client has the same definitions.
113213e3f4d6SMark Murray *
113313e3f4d6SMark Murray * If we got exactly as many VARs as VALUEs and
113413e3f4d6SMark Murray * USERVARS, the client has reversed definitions.
113513e3f4d6SMark Murray */
113613e3f4d6SMark Murray if (got_uservar + got_var == got_value) {
113713e3f4d6SMark Murray env_ovar_ok:
113813e3f4d6SMark Murray env_ovar = OLD_ENV_VAR;
113913e3f4d6SMark Murray env_ovalue = OLD_ENV_VALUE;
114013e3f4d6SMark Murray } else if (got_uservar + got_value == got_var) {
114113e3f4d6SMark Murray env_ovar_wrong:
114213e3f4d6SMark Murray env_ovar = OLD_ENV_VALUE;
114313e3f4d6SMark Murray env_ovalue = OLD_ENV_VAR;
114413e3f4d6SMark Murray DIAG(TD_OPTIONS, {
114513e3f4d6SMark Murray output_data("ENVIRON VALUE and VAR are reversed!\r\n");
114613e3f4d6SMark Murray });
114713e3f4d6SMark Murray
114813e3f4d6SMark Murray }
114913e3f4d6SMark Murray }
115013e3f4d6SMark Murray SB_RESTORE();
115113e3f4d6SMark Murray #endif
115213e3f4d6SMark Murray
115313e3f4d6SMark Murray while (!SB_EOF()) {
115413e3f4d6SMark Murray c = SB_GET();
115513e3f4d6SMark Murray if ((c == env_ovar) || (c == ENV_USERVAR))
115613e3f4d6SMark Murray break;
115713e3f4d6SMark Murray }
115813e3f4d6SMark Murray }
115913e3f4d6SMark Murray
116013e3f4d6SMark Murray if (SB_EOF())
116113e3f4d6SMark Murray return;
116213e3f4d6SMark Murray
116313e3f4d6SMark Murray cp = varp = (char *)subpointer;
116413e3f4d6SMark Murray valp = 0;
116513e3f4d6SMark Murray
116613e3f4d6SMark Murray while (!SB_EOF()) {
116713e3f4d6SMark Murray c = SB_GET();
116813e3f4d6SMark Murray if (subchar == TELOPT_OLD_ENVIRON) {
116913e3f4d6SMark Murray if (c == env_ovar)
117013e3f4d6SMark Murray c = NEW_ENV_VAR;
117113e3f4d6SMark Murray else if (c == env_ovalue)
117213e3f4d6SMark Murray c = NEW_ENV_VALUE;
117313e3f4d6SMark Murray }
117413e3f4d6SMark Murray switch (c) {
117513e3f4d6SMark Murray
117613e3f4d6SMark Murray case NEW_ENV_VALUE:
117713e3f4d6SMark Murray *cp = '\0';
117813e3f4d6SMark Murray cp = valp = (char *)subpointer;
117913e3f4d6SMark Murray break;
118013e3f4d6SMark Murray
118113e3f4d6SMark Murray case NEW_ENV_VAR:
118213e3f4d6SMark Murray case ENV_USERVAR:
118313e3f4d6SMark Murray *cp = '\0';
118413e3f4d6SMark Murray if (valp)
11855e9cd1aeSAssar Westerlund esetenv(varp, valp, 1);
118613e3f4d6SMark Murray else
118713e3f4d6SMark Murray unsetenv(varp);
118813e3f4d6SMark Murray cp = varp = (char *)subpointer;
118913e3f4d6SMark Murray valp = 0;
119013e3f4d6SMark Murray break;
119113e3f4d6SMark Murray
119213e3f4d6SMark Murray case ENV_ESC:
119313e3f4d6SMark Murray if (SB_EOF())
119413e3f4d6SMark Murray break;
119513e3f4d6SMark Murray c = SB_GET();
119613e3f4d6SMark Murray /* FALL THROUGH */
119713e3f4d6SMark Murray default:
119813e3f4d6SMark Murray *cp++ = c;
119913e3f4d6SMark Murray break;
120013e3f4d6SMark Murray }
120113e3f4d6SMark Murray }
120213e3f4d6SMark Murray *cp = '\0';
120313e3f4d6SMark Murray if (valp)
12045e9cd1aeSAssar Westerlund esetenv(varp, valp, 1);
120513e3f4d6SMark Murray else
120613e3f4d6SMark Murray unsetenv(varp);
120713e3f4d6SMark Murray break;
120813e3f4d6SMark Murray } /* end of case TELOPT_NEW_ENVIRON */
120913e3f4d6SMark Murray #ifdef AUTHENTICATION
121013e3f4d6SMark Murray case TELOPT_AUTHENTICATION:
121113e3f4d6SMark Murray if (SB_EOF())
121213e3f4d6SMark Murray break;
121313e3f4d6SMark Murray switch(SB_GET()) {
121413e3f4d6SMark Murray case TELQUAL_SEND:
121513e3f4d6SMark Murray case TELQUAL_REPLY:
121613e3f4d6SMark Murray /*
121713e3f4d6SMark Murray * These are sent by us and cannot be sent by
121813e3f4d6SMark Murray * the client.
121913e3f4d6SMark Murray */
122013e3f4d6SMark Murray break;
122113e3f4d6SMark Murray case TELQUAL_IS:
122213e3f4d6SMark Murray auth_is(subpointer, SB_LEN());
122313e3f4d6SMark Murray break;
122413e3f4d6SMark Murray case TELQUAL_NAME:
122513e3f4d6SMark Murray auth_name(subpointer, SB_LEN());
122613e3f4d6SMark Murray break;
122713e3f4d6SMark Murray }
122813e3f4d6SMark Murray break;
122913e3f4d6SMark Murray #endif
123013e3f4d6SMark Murray #ifdef ENCRYPTION
123113e3f4d6SMark Murray case TELOPT_ENCRYPT:
123213e3f4d6SMark Murray if (SB_EOF())
123313e3f4d6SMark Murray break;
123413e3f4d6SMark Murray switch(SB_GET()) {
123513e3f4d6SMark Murray case ENCRYPT_SUPPORT:
123613e3f4d6SMark Murray encrypt_support(subpointer, SB_LEN());
123713e3f4d6SMark Murray break;
123813e3f4d6SMark Murray case ENCRYPT_IS:
123913e3f4d6SMark Murray encrypt_is(subpointer, SB_LEN());
124013e3f4d6SMark Murray break;
124113e3f4d6SMark Murray case ENCRYPT_REPLY:
124213e3f4d6SMark Murray encrypt_reply(subpointer, SB_LEN());
124313e3f4d6SMark Murray break;
124413e3f4d6SMark Murray case ENCRYPT_START:
124513e3f4d6SMark Murray encrypt_start(subpointer, SB_LEN());
124613e3f4d6SMark Murray break;
124713e3f4d6SMark Murray case ENCRYPT_END:
1248c19800e8SDoug Rabson if (require_encryption)
1249c19800e8SDoug Rabson fatal(net, "Output encryption is not possible to turn off");
125013e3f4d6SMark Murray encrypt_end();
125113e3f4d6SMark Murray break;
125213e3f4d6SMark Murray case ENCRYPT_REQSTART:
125313e3f4d6SMark Murray encrypt_request_start(subpointer, SB_LEN());
125413e3f4d6SMark Murray break;
125513e3f4d6SMark Murray case ENCRYPT_REQEND:
125613e3f4d6SMark Murray /*
125713e3f4d6SMark Murray * We can always send an REQEND so that we cannot
125813e3f4d6SMark Murray * get stuck encrypting. We should only get this
125913e3f4d6SMark Murray * if we have been able to get in the correct mode
126013e3f4d6SMark Murray * anyhow.
126113e3f4d6SMark Murray */
1262c19800e8SDoug Rabson if (require_encryption)
1263c19800e8SDoug Rabson fatal(net, "Input encryption is not possible to turn off");
126413e3f4d6SMark Murray encrypt_request_end();
126513e3f4d6SMark Murray break;
126613e3f4d6SMark Murray case ENCRYPT_ENC_KEYID:
126713e3f4d6SMark Murray encrypt_enc_keyid(subpointer, SB_LEN());
126813e3f4d6SMark Murray break;
126913e3f4d6SMark Murray case ENCRYPT_DEC_KEYID:
127013e3f4d6SMark Murray encrypt_dec_keyid(subpointer, SB_LEN());
127113e3f4d6SMark Murray break;
127213e3f4d6SMark Murray default:
127313e3f4d6SMark Murray break;
127413e3f4d6SMark Murray }
127513e3f4d6SMark Murray break;
127613e3f4d6SMark Murray #endif
127713e3f4d6SMark Murray
127813e3f4d6SMark Murray default:
127913e3f4d6SMark Murray break;
128013e3f4d6SMark Murray } /* end of switch */
128113e3f4d6SMark Murray
128213e3f4d6SMark Murray } /* end of suboption */
128313e3f4d6SMark Murray
128413e3f4d6SMark Murray void
doclientstat(void)128513e3f4d6SMark Murray doclientstat(void)
128613e3f4d6SMark Murray {
128713e3f4d6SMark Murray clientstat(TELOPT_LINEMODE, WILL, 0);
128813e3f4d6SMark Murray }
128913e3f4d6SMark Murray
12908d4ba808SJacques Vidrine #undef ADD
129113e3f4d6SMark Murray #define ADD(c) *ncp++ = c
129213e3f4d6SMark Murray #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
129313e3f4d6SMark Murray
129413e3f4d6SMark Murray void
send_status(void)129513e3f4d6SMark Murray send_status(void)
129613e3f4d6SMark Murray {
129713e3f4d6SMark Murray unsigned char statusbuf[256];
129813e3f4d6SMark Murray unsigned char *ncp;
129913e3f4d6SMark Murray unsigned char i;
130013e3f4d6SMark Murray
130113e3f4d6SMark Murray ncp = statusbuf;
130213e3f4d6SMark Murray
130313e3f4d6SMark Murray netflush(); /* get rid of anything waiting to go out */
130413e3f4d6SMark Murray
130513e3f4d6SMark Murray ADD(IAC);
130613e3f4d6SMark Murray ADD(SB);
130713e3f4d6SMark Murray ADD(TELOPT_STATUS);
130813e3f4d6SMark Murray ADD(TELQUAL_IS);
130913e3f4d6SMark Murray
131013e3f4d6SMark Murray /*
131113e3f4d6SMark Murray * We check the want_state rather than the current state,
131213e3f4d6SMark Murray * because if we received a DO/WILL for an option that we
131313e3f4d6SMark Murray * don't support, and the other side didn't send a DONT/WONT
131413e3f4d6SMark Murray * in response to our WONT/DONT, then the "state" will be
131513e3f4d6SMark Murray * WILL/DO, and the "want_state" will be WONT/DONT. We
131613e3f4d6SMark Murray * need to go by the latter.
131713e3f4d6SMark Murray */
131813e3f4d6SMark Murray for (i = 0; i < (unsigned char)NTELOPTS; i++) {
131913e3f4d6SMark Murray if (my_want_state_is_will(i)) {
132013e3f4d6SMark Murray ADD(WILL);
132113e3f4d6SMark Murray ADD_DATA(i);
132213e3f4d6SMark Murray }
132313e3f4d6SMark Murray if (his_want_state_is_will(i)) {
132413e3f4d6SMark Murray ADD(DO);
132513e3f4d6SMark Murray ADD_DATA(i);
132613e3f4d6SMark Murray }
132713e3f4d6SMark Murray }
132813e3f4d6SMark Murray
132913e3f4d6SMark Murray if (his_want_state_is_will(TELOPT_LFLOW)) {
133013e3f4d6SMark Murray ADD(SB);
133113e3f4d6SMark Murray ADD(TELOPT_LFLOW);
133213e3f4d6SMark Murray if (flowmode) {
133313e3f4d6SMark Murray ADD(LFLOW_ON);
133413e3f4d6SMark Murray } else {
133513e3f4d6SMark Murray ADD(LFLOW_OFF);
133613e3f4d6SMark Murray }
133713e3f4d6SMark Murray ADD(SE);
133813e3f4d6SMark Murray
133913e3f4d6SMark Murray if (restartany >= 0) {
134013e3f4d6SMark Murray ADD(SB);
134113e3f4d6SMark Murray ADD(TELOPT_LFLOW);
134213e3f4d6SMark Murray if (restartany) {
134313e3f4d6SMark Murray ADD(LFLOW_RESTART_ANY);
134413e3f4d6SMark Murray } else {
134513e3f4d6SMark Murray ADD(LFLOW_RESTART_XON);
134613e3f4d6SMark Murray }
134713e3f4d6SMark Murray ADD(SE);
134813e3f4d6SMark Murray }
134913e3f4d6SMark Murray }
135013e3f4d6SMark Murray
135113e3f4d6SMark Murray
135213e3f4d6SMark Murray ADD(IAC);
135313e3f4d6SMark Murray ADD(SE);
135413e3f4d6SMark Murray
135513e3f4d6SMark Murray writenet(statusbuf, ncp - statusbuf);
135613e3f4d6SMark Murray netflush(); /* Send it on its way */
135713e3f4d6SMark Murray
135813e3f4d6SMark Murray DIAG(TD_OPTIONS,
135913e3f4d6SMark Murray {printsub('>', statusbuf, ncp - statusbuf); netflush();});
136013e3f4d6SMark Murray }
1361