113e3f4d6SMark Murray /*
213e3f4d6SMark Murray * Copyright (c) 1988, 1990, 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 "telnet_locl.h"
3513e3f4d6SMark Murray
36c19800e8SDoug Rabson RCSID("$Id$");
3713e3f4d6SMark Murray
3813e3f4d6SMark Murray #define strip(x) (eight ? (x) : ((x) & 0x7f))
3913e3f4d6SMark Murray
4013e3f4d6SMark Murray static unsigned char subbuffer[SUBBUFSIZE],
4113e3f4d6SMark Murray *subpointer, *subend; /* buffer for sub-options */
4213e3f4d6SMark Murray #define SB_CLEAR() subpointer = subbuffer;
4313e3f4d6SMark Murray #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
4413e3f4d6SMark Murray #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
4513e3f4d6SMark Murray *subpointer++ = (c); \
4613e3f4d6SMark Murray }
4713e3f4d6SMark Murray
4813e3f4d6SMark Murray #define SB_GET() ((*subpointer++)&0xff)
4913e3f4d6SMark Murray #define SB_PEEK() ((*subpointer)&0xff)
5013e3f4d6SMark Murray #define SB_EOF() (subpointer >= subend)
5113e3f4d6SMark Murray #define SB_LEN() (subend - subpointer)
5213e3f4d6SMark Murray
5313e3f4d6SMark Murray char options[256]; /* The combined options */
5413e3f4d6SMark Murray char do_dont_resp[256];
5513e3f4d6SMark Murray char will_wont_resp[256];
5613e3f4d6SMark Murray
5713e3f4d6SMark Murray int
5813e3f4d6SMark Murray eight = 3,
5913e3f4d6SMark Murray binary = 0,
6013e3f4d6SMark Murray autologin = 0, /* Autologin anyone? */
6113e3f4d6SMark Murray skiprc = 0,
6213e3f4d6SMark Murray connected,
6313e3f4d6SMark Murray showoptions,
6413e3f4d6SMark Murray ISend, /* trying to send network data in */
6513e3f4d6SMark Murray debug = 0,
6613e3f4d6SMark Murray crmod,
6713e3f4d6SMark Murray netdata, /* Print out network data flow */
6813e3f4d6SMark Murray crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
6913e3f4d6SMark Murray telnetport,
704137ff4cSJacques Vidrine wantencryption = 0,
7113e3f4d6SMark Murray SYNCHing, /* we are in TELNET SYNCH mode */
7213e3f4d6SMark Murray flushout, /* flush output */
7313e3f4d6SMark Murray autoflush = 0, /* flush output when interrupting? */
7413e3f4d6SMark Murray autosynch, /* send interrupt characters with SYNCH? */
7513e3f4d6SMark Murray localflow, /* we handle flow control locally */
7613e3f4d6SMark Murray restartany, /* if flow control enabled, restart on any character */
7713e3f4d6SMark Murray localchars, /* we recognize interrupt/quit */
7813e3f4d6SMark Murray donelclchars, /* the user has set "localchars" */
7913e3f4d6SMark Murray donebinarytoggle, /* the user has put us in binary */
8013e3f4d6SMark Murray dontlecho, /* do we suppress local echoing right now? */
8113e3f4d6SMark Murray globalmode;
8213e3f4d6SMark Murray
8313e3f4d6SMark Murray char *prompt = 0;
8413e3f4d6SMark Murray
854137ff4cSJacques Vidrine int scheduler_lockout_tty = 0;
864137ff4cSJacques Vidrine
8713e3f4d6SMark Murray cc_t escape;
8813e3f4d6SMark Murray cc_t rlogin;
8913e3f4d6SMark Murray #ifdef KLUDGELINEMODE
9013e3f4d6SMark Murray cc_t echoc;
9113e3f4d6SMark Murray #endif
9213e3f4d6SMark Murray
9313e3f4d6SMark Murray /*
9413e3f4d6SMark Murray * Telnet receiver states for fsm
9513e3f4d6SMark Murray */
9613e3f4d6SMark Murray #define TS_DATA 0
9713e3f4d6SMark Murray #define TS_IAC 1
9813e3f4d6SMark Murray #define TS_WILL 2
9913e3f4d6SMark Murray #define TS_WONT 3
10013e3f4d6SMark Murray #define TS_DO 4
10113e3f4d6SMark Murray #define TS_DONT 5
10213e3f4d6SMark Murray #define TS_CR 6
10313e3f4d6SMark Murray #define TS_SB 7 /* sub-option collection */
10413e3f4d6SMark Murray #define TS_SE 8 /* looking for sub-option end */
10513e3f4d6SMark Murray
10613e3f4d6SMark Murray static int telrcv_state;
10713e3f4d6SMark Murray #ifdef OLD_ENVIRON
10813e3f4d6SMark Murray unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
10913e3f4d6SMark Murray #else
11013e3f4d6SMark Murray # define telopt_environ TELOPT_NEW_ENVIRON
11113e3f4d6SMark Murray #endif
11213e3f4d6SMark Murray
11313e3f4d6SMark Murray jmp_buf toplevel;
11413e3f4d6SMark Murray jmp_buf peerdied;
11513e3f4d6SMark Murray
11613e3f4d6SMark Murray int flushline;
11713e3f4d6SMark Murray int linemode;
11813e3f4d6SMark Murray
11913e3f4d6SMark Murray #ifdef KLUDGELINEMODE
12013e3f4d6SMark Murray int kludgelinemode = 1;
12113e3f4d6SMark Murray #endif
12213e3f4d6SMark Murray
12313e3f4d6SMark Murray /*
12413e3f4d6SMark Murray * The following are some clocks used to decide how to interpret
12513e3f4d6SMark Murray * the relationship between various variables.
12613e3f4d6SMark Murray */
12713e3f4d6SMark Murray
12813e3f4d6SMark Murray Clocks clocks;
12913e3f4d6SMark Murray
13013e3f4d6SMark Murray static int is_unique(char *name, char **as, char **ae);
13113e3f4d6SMark Murray
13213e3f4d6SMark Murray
13313e3f4d6SMark Murray /*
13413e3f4d6SMark Murray * Initialize telnet environment.
13513e3f4d6SMark Murray */
13613e3f4d6SMark Murray
13713e3f4d6SMark Murray void
init_telnet(void)13813e3f4d6SMark Murray init_telnet(void)
13913e3f4d6SMark Murray {
14013e3f4d6SMark Murray env_init();
14113e3f4d6SMark Murray
14213e3f4d6SMark Murray SB_CLEAR();
14313e3f4d6SMark Murray memset(options, 0, sizeof options);
14413e3f4d6SMark Murray
14513e3f4d6SMark Murray connected = ISend = localflow = donebinarytoggle = 0;
14613e3f4d6SMark Murray #if defined(AUTHENTICATION) || defined(ENCRYPTION)
14713e3f4d6SMark Murray auth_encrypt_connect(connected);
14813e3f4d6SMark Murray #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
14913e3f4d6SMark Murray restartany = -1;
15013e3f4d6SMark Murray
15113e3f4d6SMark Murray SYNCHing = 0;
15213e3f4d6SMark Murray
15313e3f4d6SMark Murray /* Don't change NetTrace */
15413e3f4d6SMark Murray
15513e3f4d6SMark Murray escape = CONTROL(']');
15613e3f4d6SMark Murray rlogin = _POSIX_VDISABLE;
15713e3f4d6SMark Murray #ifdef KLUDGELINEMODE
15813e3f4d6SMark Murray echoc = CONTROL('E');
15913e3f4d6SMark Murray #endif
16013e3f4d6SMark Murray
16113e3f4d6SMark Murray flushline = 1;
16213e3f4d6SMark Murray telrcv_state = TS_DATA;
16313e3f4d6SMark Murray }
16413e3f4d6SMark Murray
16513e3f4d6SMark Murray
16613e3f4d6SMark Murray /*
16713e3f4d6SMark Murray * These routines are in charge of sending option negotiations
16813e3f4d6SMark Murray * to the other side.
16913e3f4d6SMark Murray *
17013e3f4d6SMark Murray * The basic idea is that we send the negotiation if either side
17113e3f4d6SMark Murray * is in disagreement as to what the current state should be.
17213e3f4d6SMark Murray */
17313e3f4d6SMark Murray
17413e3f4d6SMark Murray void
send_do(int c,int init)17513e3f4d6SMark Murray send_do(int c, int init)
17613e3f4d6SMark Murray {
17713e3f4d6SMark Murray if (init) {
17813e3f4d6SMark Murray if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
17913e3f4d6SMark Murray my_want_state_is_do(c))
18013e3f4d6SMark Murray return;
18113e3f4d6SMark Murray set_my_want_state_do(c);
18213e3f4d6SMark Murray do_dont_resp[c]++;
18313e3f4d6SMark Murray }
18413e3f4d6SMark Murray NET2ADD(IAC, DO);
18513e3f4d6SMark Murray NETADD(c);
18613e3f4d6SMark Murray printoption("SENT", DO, c);
18713e3f4d6SMark Murray }
18813e3f4d6SMark Murray
18913e3f4d6SMark Murray void
send_dont(int c,int init)19013e3f4d6SMark Murray send_dont(int c, int init)
19113e3f4d6SMark Murray {
19213e3f4d6SMark Murray if (init) {
19313e3f4d6SMark Murray if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
19413e3f4d6SMark Murray my_want_state_is_dont(c))
19513e3f4d6SMark Murray return;
19613e3f4d6SMark Murray set_my_want_state_dont(c);
19713e3f4d6SMark Murray do_dont_resp[c]++;
19813e3f4d6SMark Murray }
19913e3f4d6SMark Murray NET2ADD(IAC, DONT);
20013e3f4d6SMark Murray NETADD(c);
20113e3f4d6SMark Murray printoption("SENT", DONT, c);
20213e3f4d6SMark Murray }
20313e3f4d6SMark Murray
20413e3f4d6SMark Murray void
send_will(int c,int init)20513e3f4d6SMark Murray send_will(int c, int init)
20613e3f4d6SMark Murray {
20713e3f4d6SMark Murray if (init) {
20813e3f4d6SMark Murray if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
20913e3f4d6SMark Murray my_want_state_is_will(c))
21013e3f4d6SMark Murray return;
21113e3f4d6SMark Murray set_my_want_state_will(c);
21213e3f4d6SMark Murray will_wont_resp[c]++;
21313e3f4d6SMark Murray }
21413e3f4d6SMark Murray NET2ADD(IAC, WILL);
21513e3f4d6SMark Murray NETADD(c);
21613e3f4d6SMark Murray printoption("SENT", WILL, c);
21713e3f4d6SMark Murray }
21813e3f4d6SMark Murray
21913e3f4d6SMark Murray void
send_wont(int c,int init)22013e3f4d6SMark Murray send_wont(int c, int init)
22113e3f4d6SMark Murray {
22213e3f4d6SMark Murray if (init) {
22313e3f4d6SMark Murray if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
22413e3f4d6SMark Murray my_want_state_is_wont(c))
22513e3f4d6SMark Murray return;
22613e3f4d6SMark Murray set_my_want_state_wont(c);
22713e3f4d6SMark Murray will_wont_resp[c]++;
22813e3f4d6SMark Murray }
22913e3f4d6SMark Murray NET2ADD(IAC, WONT);
23013e3f4d6SMark Murray NETADD(c);
23113e3f4d6SMark Murray printoption("SENT", WONT, c);
23213e3f4d6SMark Murray }
23313e3f4d6SMark Murray
23413e3f4d6SMark Murray
23513e3f4d6SMark Murray void
willoption(int option)23613e3f4d6SMark Murray willoption(int option)
23713e3f4d6SMark Murray {
23813e3f4d6SMark Murray int new_state_ok = 0;
23913e3f4d6SMark Murray
24013e3f4d6SMark Murray if (do_dont_resp[option]) {
24113e3f4d6SMark Murray --do_dont_resp[option];
24213e3f4d6SMark Murray if (do_dont_resp[option] && my_state_is_do(option))
24313e3f4d6SMark Murray --do_dont_resp[option];
24413e3f4d6SMark Murray }
24513e3f4d6SMark Murray
24613e3f4d6SMark Murray if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
24713e3f4d6SMark Murray
24813e3f4d6SMark Murray switch (option) {
24913e3f4d6SMark Murray
25013e3f4d6SMark Murray case TELOPT_ECHO:
25113e3f4d6SMark Murray case TELOPT_BINARY:
25213e3f4d6SMark Murray case TELOPT_SGA:
25313e3f4d6SMark Murray settimer(modenegotiated);
25413e3f4d6SMark Murray /* FALL THROUGH */
25513e3f4d6SMark Murray case TELOPT_STATUS:
25613e3f4d6SMark Murray #if defined(AUTHENTICATION)
25713e3f4d6SMark Murray case TELOPT_AUTHENTICATION:
25813e3f4d6SMark Murray #endif
25913e3f4d6SMark Murray #if defined(ENCRYPTION)
26013e3f4d6SMark Murray case TELOPT_ENCRYPT:
26113e3f4d6SMark Murray #endif
26213e3f4d6SMark Murray new_state_ok = 1;
26313e3f4d6SMark Murray break;
26413e3f4d6SMark Murray
26513e3f4d6SMark Murray case TELOPT_TM:
26613e3f4d6SMark Murray if (flushout)
26713e3f4d6SMark Murray flushout = 0;
26813e3f4d6SMark Murray /*
26913e3f4d6SMark Murray * Special case for TM. If we get back a WILL,
27013e3f4d6SMark Murray * pretend we got back a WONT.
27113e3f4d6SMark Murray */
27213e3f4d6SMark Murray set_my_want_state_dont(option);
27313e3f4d6SMark Murray set_my_state_dont(option);
27413e3f4d6SMark Murray return; /* Never reply to TM will's/wont's */
27513e3f4d6SMark Murray
27613e3f4d6SMark Murray case TELOPT_LINEMODE:
27713e3f4d6SMark Murray default:
27813e3f4d6SMark Murray break;
27913e3f4d6SMark Murray }
28013e3f4d6SMark Murray
28113e3f4d6SMark Murray if (new_state_ok) {
28213e3f4d6SMark Murray set_my_want_state_do(option);
28313e3f4d6SMark Murray send_do(option, 0);
28413e3f4d6SMark Murray setconnmode(0); /* possibly set new tty mode */
28513e3f4d6SMark Murray } else {
28613e3f4d6SMark Murray do_dont_resp[option]++;
28713e3f4d6SMark Murray send_dont(option, 0);
28813e3f4d6SMark Murray }
28913e3f4d6SMark Murray }
29013e3f4d6SMark Murray set_my_state_do(option);
29113e3f4d6SMark Murray #if defined(ENCRYPTION)
29213e3f4d6SMark Murray if (option == TELOPT_ENCRYPT)
29313e3f4d6SMark Murray encrypt_send_support();
29413e3f4d6SMark Murray #endif
29513e3f4d6SMark Murray }
29613e3f4d6SMark Murray
29713e3f4d6SMark Murray void
wontoption(int option)29813e3f4d6SMark Murray wontoption(int option)
29913e3f4d6SMark Murray {
30013e3f4d6SMark Murray if (do_dont_resp[option]) {
30113e3f4d6SMark Murray --do_dont_resp[option];
30213e3f4d6SMark Murray if (do_dont_resp[option] && my_state_is_dont(option))
30313e3f4d6SMark Murray --do_dont_resp[option];
30413e3f4d6SMark Murray }
30513e3f4d6SMark Murray
30613e3f4d6SMark Murray if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
30713e3f4d6SMark Murray
30813e3f4d6SMark Murray switch (option) {
30913e3f4d6SMark Murray
31013e3f4d6SMark Murray #ifdef KLUDGELINEMODE
31113e3f4d6SMark Murray case TELOPT_SGA:
31213e3f4d6SMark Murray if (!kludgelinemode)
31313e3f4d6SMark Murray break;
31413e3f4d6SMark Murray /* FALL THROUGH */
31513e3f4d6SMark Murray #endif
31613e3f4d6SMark Murray case TELOPT_ECHO:
31713e3f4d6SMark Murray settimer(modenegotiated);
31813e3f4d6SMark Murray break;
31913e3f4d6SMark Murray
32013e3f4d6SMark Murray case TELOPT_TM:
32113e3f4d6SMark Murray if (flushout)
32213e3f4d6SMark Murray flushout = 0;
32313e3f4d6SMark Murray set_my_want_state_dont(option);
32413e3f4d6SMark Murray set_my_state_dont(option);
32513e3f4d6SMark Murray return; /* Never reply to TM will's/wont's */
32613e3f4d6SMark Murray
32713e3f4d6SMark Murray #ifdef ENCRYPTION
32813e3f4d6SMark Murray case TELOPT_ENCRYPT:
32913e3f4d6SMark Murray encrypt_not();
33013e3f4d6SMark Murray break;
33113e3f4d6SMark Murray #endif
33213e3f4d6SMark Murray default:
33313e3f4d6SMark Murray break;
33413e3f4d6SMark Murray }
33513e3f4d6SMark Murray set_my_want_state_dont(option);
33613e3f4d6SMark Murray if (my_state_is_do(option))
33713e3f4d6SMark Murray send_dont(option, 0);
33813e3f4d6SMark Murray setconnmode(0); /* Set new tty mode */
33913e3f4d6SMark Murray } else if (option == TELOPT_TM) {
34013e3f4d6SMark Murray /*
34113e3f4d6SMark Murray * Special case for TM.
34213e3f4d6SMark Murray */
34313e3f4d6SMark Murray if (flushout)
34413e3f4d6SMark Murray flushout = 0;
34513e3f4d6SMark Murray set_my_want_state_dont(option);
34613e3f4d6SMark Murray }
34713e3f4d6SMark Murray set_my_state_dont(option);
34813e3f4d6SMark Murray }
34913e3f4d6SMark Murray
35013e3f4d6SMark Murray static void
dooption(int option)35113e3f4d6SMark Murray dooption(int option)
35213e3f4d6SMark Murray {
35313e3f4d6SMark Murray int new_state_ok = 0;
35413e3f4d6SMark Murray
35513e3f4d6SMark Murray if (will_wont_resp[option]) {
35613e3f4d6SMark Murray --will_wont_resp[option];
35713e3f4d6SMark Murray if (will_wont_resp[option] && my_state_is_will(option))
35813e3f4d6SMark Murray --will_wont_resp[option];
35913e3f4d6SMark Murray }
36013e3f4d6SMark Murray
36113e3f4d6SMark Murray if (will_wont_resp[option] == 0) {
36213e3f4d6SMark Murray if (my_want_state_is_wont(option)) {
36313e3f4d6SMark Murray
36413e3f4d6SMark Murray switch (option) {
36513e3f4d6SMark Murray
36613e3f4d6SMark Murray case TELOPT_TM:
36713e3f4d6SMark Murray /*
36813e3f4d6SMark Murray * Special case for TM. We send a WILL, but pretend
36913e3f4d6SMark Murray * we sent WONT.
37013e3f4d6SMark Murray */
37113e3f4d6SMark Murray send_will(option, 0);
37213e3f4d6SMark Murray set_my_want_state_wont(TELOPT_TM);
37313e3f4d6SMark Murray set_my_state_wont(TELOPT_TM);
37413e3f4d6SMark Murray return;
37513e3f4d6SMark Murray
37613e3f4d6SMark Murray case TELOPT_BINARY: /* binary mode */
37713e3f4d6SMark Murray case TELOPT_NAWS: /* window size */
37813e3f4d6SMark Murray case TELOPT_TSPEED: /* terminal speed */
37913e3f4d6SMark Murray case TELOPT_LFLOW: /* local flow control */
38013e3f4d6SMark Murray case TELOPT_TTYPE: /* terminal type option */
38113e3f4d6SMark Murray case TELOPT_SGA: /* no big deal */
38213e3f4d6SMark Murray #if defined(ENCRYPTION)
38313e3f4d6SMark Murray case TELOPT_ENCRYPT: /* encryption variable option */
38413e3f4d6SMark Murray #endif
38513e3f4d6SMark Murray new_state_ok = 1;
38613e3f4d6SMark Murray break;
38713e3f4d6SMark Murray
38813e3f4d6SMark Murray case TELOPT_NEW_ENVIRON: /* New environment variable option */
38913e3f4d6SMark Murray #ifdef OLD_ENVIRON
39013e3f4d6SMark Murray if (my_state_is_will(TELOPT_OLD_ENVIRON))
39113e3f4d6SMark Murray send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
39213e3f4d6SMark Murray goto env_common;
39313e3f4d6SMark Murray case TELOPT_OLD_ENVIRON: /* Old environment variable option */
39413e3f4d6SMark Murray if (my_state_is_will(TELOPT_NEW_ENVIRON))
39513e3f4d6SMark Murray break; /* Don't enable if new one is in use! */
39613e3f4d6SMark Murray env_common:
39713e3f4d6SMark Murray telopt_environ = option;
39813e3f4d6SMark Murray #endif
39913e3f4d6SMark Murray new_state_ok = 1;
40013e3f4d6SMark Murray break;
40113e3f4d6SMark Murray
40213e3f4d6SMark Murray #if defined(AUTHENTICATION)
40313e3f4d6SMark Murray case TELOPT_AUTHENTICATION:
40413e3f4d6SMark Murray if (autologin)
40513e3f4d6SMark Murray new_state_ok = 1;
40613e3f4d6SMark Murray break;
40713e3f4d6SMark Murray #endif
40813e3f4d6SMark Murray
40913e3f4d6SMark Murray case TELOPT_XDISPLOC: /* X Display location */
41013e3f4d6SMark Murray if (env_getvalue((unsigned char *)"DISPLAY"))
41113e3f4d6SMark Murray new_state_ok = 1;
41213e3f4d6SMark Murray break;
41313e3f4d6SMark Murray
41413e3f4d6SMark Murray case TELOPT_LINEMODE:
41513e3f4d6SMark Murray #ifdef KLUDGELINEMODE
41613e3f4d6SMark Murray kludgelinemode = 0;
41713e3f4d6SMark Murray send_do(TELOPT_SGA, 1);
41813e3f4d6SMark Murray #endif
41913e3f4d6SMark Murray set_my_want_state_will(TELOPT_LINEMODE);
42013e3f4d6SMark Murray send_will(option, 0);
42113e3f4d6SMark Murray set_my_state_will(TELOPT_LINEMODE);
42213e3f4d6SMark Murray slc_init();
42313e3f4d6SMark Murray return;
42413e3f4d6SMark Murray
42513e3f4d6SMark Murray case TELOPT_ECHO: /* We're never going to echo... */
42613e3f4d6SMark Murray default:
42713e3f4d6SMark Murray break;
42813e3f4d6SMark Murray }
42913e3f4d6SMark Murray
43013e3f4d6SMark Murray if (new_state_ok) {
43113e3f4d6SMark Murray set_my_want_state_will(option);
43213e3f4d6SMark Murray send_will(option, 0);
43313e3f4d6SMark Murray setconnmode(0); /* Set new tty mode */
43413e3f4d6SMark Murray } else {
43513e3f4d6SMark Murray will_wont_resp[option]++;
43613e3f4d6SMark Murray send_wont(option, 0);
43713e3f4d6SMark Murray }
43813e3f4d6SMark Murray } else {
43913e3f4d6SMark Murray /*
44013e3f4d6SMark Murray * Handle options that need more things done after the
44113e3f4d6SMark Murray * other side has acknowledged the option.
44213e3f4d6SMark Murray */
44313e3f4d6SMark Murray switch (option) {
44413e3f4d6SMark Murray case TELOPT_LINEMODE:
44513e3f4d6SMark Murray #ifdef KLUDGELINEMODE
44613e3f4d6SMark Murray kludgelinemode = 0;
44713e3f4d6SMark Murray send_do(TELOPT_SGA, 1);
44813e3f4d6SMark Murray #endif
44913e3f4d6SMark Murray set_my_state_will(option);
45013e3f4d6SMark Murray slc_init();
45113e3f4d6SMark Murray send_do(TELOPT_SGA, 0);
45213e3f4d6SMark Murray return;
45313e3f4d6SMark Murray }
45413e3f4d6SMark Murray }
45513e3f4d6SMark Murray }
45613e3f4d6SMark Murray set_my_state_will(option);
45713e3f4d6SMark Murray }
45813e3f4d6SMark Murray
45913e3f4d6SMark Murray static void
dontoption(int option)46013e3f4d6SMark Murray dontoption(int option)
46113e3f4d6SMark Murray {
46213e3f4d6SMark Murray
46313e3f4d6SMark Murray if (will_wont_resp[option]) {
46413e3f4d6SMark Murray --will_wont_resp[option];
46513e3f4d6SMark Murray if (will_wont_resp[option] && my_state_is_wont(option))
46613e3f4d6SMark Murray --will_wont_resp[option];
46713e3f4d6SMark Murray }
46813e3f4d6SMark Murray
46913e3f4d6SMark Murray if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
47013e3f4d6SMark Murray switch (option) {
47113e3f4d6SMark Murray case TELOPT_LINEMODE:
47213e3f4d6SMark Murray linemode = 0; /* put us back to the default state */
47313e3f4d6SMark Murray break;
47413e3f4d6SMark Murray #ifdef OLD_ENVIRON
47513e3f4d6SMark Murray case TELOPT_NEW_ENVIRON:
47613e3f4d6SMark Murray /*
47713e3f4d6SMark Murray * The new environ option wasn't recognized, try
47813e3f4d6SMark Murray * the old one.
47913e3f4d6SMark Murray */
48013e3f4d6SMark Murray send_will(TELOPT_OLD_ENVIRON, 1);
48113e3f4d6SMark Murray telopt_environ = TELOPT_OLD_ENVIRON;
48213e3f4d6SMark Murray break;
48313e3f4d6SMark Murray #endif
48413e3f4d6SMark Murray #if 0
48513e3f4d6SMark Murray #ifdef ENCRYPTION
48613e3f4d6SMark Murray case TELOPT_ENCRYPT:
48713e3f4d6SMark Murray encrypt_not();
48813e3f4d6SMark Murray break;
48913e3f4d6SMark Murray #endif
49013e3f4d6SMark Murray #endif
49113e3f4d6SMark Murray }
49213e3f4d6SMark Murray /* we always accept a DONT */
49313e3f4d6SMark Murray set_my_want_state_wont(option);
49413e3f4d6SMark Murray if (my_state_is_will(option))
49513e3f4d6SMark Murray send_wont(option, 0);
49613e3f4d6SMark Murray setconnmode(0); /* Set new tty mode */
49713e3f4d6SMark Murray }
49813e3f4d6SMark Murray set_my_state_wont(option);
49913e3f4d6SMark Murray }
50013e3f4d6SMark Murray
50113e3f4d6SMark Murray /*
50213e3f4d6SMark Murray * Given a buffer returned by tgetent(), this routine will turn
503c19800e8SDoug Rabson * the pipe separated list of names in the buffer into an array
50413e3f4d6SMark Murray * of pointers to null terminated names. We toss out any bad,
50513e3f4d6SMark Murray * duplicate, or verbose names (names with spaces).
50613e3f4d6SMark Murray */
50713e3f4d6SMark Murray
50813e3f4d6SMark Murray static char *name_unknown = "UNKNOWN";
50913e3f4d6SMark Murray static char *unknown[] = { 0, 0 };
51013e3f4d6SMark Murray
51113e3f4d6SMark Murray static char **
mklist(char * buf,char * name)51213e3f4d6SMark Murray mklist(char *buf, char *name)
51313e3f4d6SMark Murray {
51413e3f4d6SMark Murray int n;
51513e3f4d6SMark Murray char c, *cp, **argvp, *cp2, **argv, **avt;
51613e3f4d6SMark Murray
51713e3f4d6SMark Murray if (name) {
51813e3f4d6SMark Murray if ((int)strlen(name) > 40) {
51913e3f4d6SMark Murray name = 0;
52013e3f4d6SMark Murray unknown[0] = name_unknown;
52113e3f4d6SMark Murray } else {
52213e3f4d6SMark Murray unknown[0] = name;
52313e3f4d6SMark Murray strupr(name);
52413e3f4d6SMark Murray }
52513e3f4d6SMark Murray } else
52613e3f4d6SMark Murray unknown[0] = name_unknown;
52713e3f4d6SMark Murray /*
52813e3f4d6SMark Murray * Count up the number of names.
52913e3f4d6SMark Murray */
53013e3f4d6SMark Murray for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
53113e3f4d6SMark Murray if (*cp == '|')
53213e3f4d6SMark Murray n++;
53313e3f4d6SMark Murray }
53413e3f4d6SMark Murray /*
53513e3f4d6SMark Murray * Allocate an array to put the name pointers into
53613e3f4d6SMark Murray */
53713e3f4d6SMark Murray argv = (char **)malloc((n+3)*sizeof(char *));
53813e3f4d6SMark Murray if (argv == 0)
53913e3f4d6SMark Murray return(unknown);
54013e3f4d6SMark Murray
54113e3f4d6SMark Murray /*
54213e3f4d6SMark Murray * Fill up the array of pointers to names.
54313e3f4d6SMark Murray */
54413e3f4d6SMark Murray *argv = 0;
54513e3f4d6SMark Murray argvp = argv+1;
54613e3f4d6SMark Murray n = 0;
54713e3f4d6SMark Murray for (cp = cp2 = buf; (c = *cp); cp++) {
54813e3f4d6SMark Murray if (c == '|' || c == ':') {
54913e3f4d6SMark Murray *cp++ = '\0';
55013e3f4d6SMark Murray /*
55113e3f4d6SMark Murray * Skip entries that have spaces or are over 40
55213e3f4d6SMark Murray * characters long. If this is our environment
55313e3f4d6SMark Murray * name, then put it up front. Otherwise, as
55413e3f4d6SMark Murray * long as this is not a duplicate name (case
55513e3f4d6SMark Murray * insensitive) add it to the list.
55613e3f4d6SMark Murray */
55713e3f4d6SMark Murray if (n || (cp - cp2 > 41))
55813e3f4d6SMark Murray ;
55913e3f4d6SMark Murray else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
56013e3f4d6SMark Murray *argv = cp2;
56113e3f4d6SMark Murray else if (is_unique(cp2, argv+1, argvp))
56213e3f4d6SMark Murray *argvp++ = cp2;
56313e3f4d6SMark Murray if (c == ':')
56413e3f4d6SMark Murray break;
56513e3f4d6SMark Murray /*
56613e3f4d6SMark Murray * Skip multiple delimiters. Reset cp2 to
56713e3f4d6SMark Murray * the beginning of the next name. Reset n,
56813e3f4d6SMark Murray * the flag for names with spaces.
56913e3f4d6SMark Murray */
57013e3f4d6SMark Murray while ((c = *cp) == '|')
57113e3f4d6SMark Murray cp++;
57213e3f4d6SMark Murray cp2 = cp;
57313e3f4d6SMark Murray n = 0;
57413e3f4d6SMark Murray }
57513e3f4d6SMark Murray /*
57613e3f4d6SMark Murray * Skip entries with spaces or non-ascii values.
57713e3f4d6SMark Murray * Convert lower case letters to upper case.
57813e3f4d6SMark Murray */
579c19800e8SDoug Rabson #undef ISASCII
58013e3f4d6SMark Murray #define ISASCII(c) (!((c)&0x80))
58113e3f4d6SMark Murray if ((c == ' ') || !ISASCII(c))
58213e3f4d6SMark Murray n = 1;
5834137ff4cSJacques Vidrine else if (islower((unsigned char)c))
584c19800e8SDoug Rabson *cp = toupper((unsigned char)c);
58513e3f4d6SMark Murray }
58613e3f4d6SMark Murray
58713e3f4d6SMark Murray /*
58813e3f4d6SMark Murray * Check for an old V6 2 character name. If the second
58913e3f4d6SMark Murray * name points to the beginning of the buffer, and is
59013e3f4d6SMark Murray * only 2 characters long, move it to the end of the array.
59113e3f4d6SMark Murray */
59213e3f4d6SMark Murray if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
59313e3f4d6SMark Murray --argvp;
59413e3f4d6SMark Murray for (avt = &argv[1]; avt < argvp; avt++)
59513e3f4d6SMark Murray *avt = *(avt+1);
59613e3f4d6SMark Murray *argvp++ = buf;
59713e3f4d6SMark Murray }
59813e3f4d6SMark Murray
59913e3f4d6SMark Murray /*
60013e3f4d6SMark Murray * Duplicate last name, for TTYPE option, and null
60113e3f4d6SMark Murray * terminate the array. If we didn't find a match on
60213e3f4d6SMark Murray * our terminal name, put that name at the beginning.
60313e3f4d6SMark Murray */
60413e3f4d6SMark Murray cp = *(argvp-1);
60513e3f4d6SMark Murray *argvp++ = cp;
60613e3f4d6SMark Murray *argvp = 0;
60713e3f4d6SMark Murray
60813e3f4d6SMark Murray if (*argv == 0) {
60913e3f4d6SMark Murray if (name)
61013e3f4d6SMark Murray *argv = name;
61113e3f4d6SMark Murray else {
61213e3f4d6SMark Murray --argvp;
61313e3f4d6SMark Murray for (avt = argv; avt < argvp; avt++)
61413e3f4d6SMark Murray *avt = *(avt+1);
61513e3f4d6SMark Murray }
61613e3f4d6SMark Murray }
61713e3f4d6SMark Murray if (*argv)
61813e3f4d6SMark Murray return(argv);
61913e3f4d6SMark Murray else
62013e3f4d6SMark Murray return(unknown);
62113e3f4d6SMark Murray }
62213e3f4d6SMark Murray
62313e3f4d6SMark Murray static int
is_unique(char * name,char ** as,char ** ae)62413e3f4d6SMark Murray is_unique(char *name, char **as, char **ae)
62513e3f4d6SMark Murray {
62613e3f4d6SMark Murray char **ap;
62713e3f4d6SMark Murray int n;
62813e3f4d6SMark Murray
62913e3f4d6SMark Murray n = strlen(name) + 1;
63013e3f4d6SMark Murray for (ap = as; ap < ae; ap++)
63113e3f4d6SMark Murray if (strncasecmp(*ap, name, n) == 0)
63213e3f4d6SMark Murray return(0);
63313e3f4d6SMark Murray return (1);
63413e3f4d6SMark Murray }
63513e3f4d6SMark Murray
63613e3f4d6SMark Murray static char termbuf[1024];
63713e3f4d6SMark Murray
63813e3f4d6SMark Murray static int
telnet_setupterm(const char * tname,int fd,int * errp)63913e3f4d6SMark Murray telnet_setupterm(const char *tname, int fd, int *errp)
64013e3f4d6SMark Murray {
6415e9cd1aeSAssar Westerlund #ifdef HAVE_TGETENT
64213e3f4d6SMark Murray if (tgetent(termbuf, tname) == 1) {
64313e3f4d6SMark Murray termbuf[1023] = '\0';
64413e3f4d6SMark Murray if (errp)
64513e3f4d6SMark Murray *errp = 1;
64613e3f4d6SMark Murray return(0);
64713e3f4d6SMark Murray }
64813e3f4d6SMark Murray if (errp)
64913e3f4d6SMark Murray *errp = 0;
65013e3f4d6SMark Murray return(-1);
6515e9cd1aeSAssar Westerlund #else
6525e9cd1aeSAssar Westerlund strlcpy(termbuf, tname, sizeof(termbuf));
6535e9cd1aeSAssar Westerlund if(errp) *errp = 1;
6545e9cd1aeSAssar Westerlund return 0;
6555e9cd1aeSAssar Westerlund #endif
65613e3f4d6SMark Murray }
65713e3f4d6SMark Murray
65813e3f4d6SMark Murray int resettermname = 1;
65913e3f4d6SMark Murray
66013e3f4d6SMark Murray static char *
gettermname()66113e3f4d6SMark Murray gettermname()
66213e3f4d6SMark Murray {
66313e3f4d6SMark Murray char *tname;
66413e3f4d6SMark Murray static char **tnamep = 0;
66513e3f4d6SMark Murray static char **next;
66613e3f4d6SMark Murray int err;
66713e3f4d6SMark Murray
66813e3f4d6SMark Murray if (resettermname) {
66913e3f4d6SMark Murray resettermname = 0;
67013e3f4d6SMark Murray if (tnamep && tnamep != unknown)
67113e3f4d6SMark Murray free(tnamep);
67213e3f4d6SMark Murray if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
67313e3f4d6SMark Murray telnet_setupterm(tname, 1, &err) == 0) {
67413e3f4d6SMark Murray tnamep = mklist(termbuf, tname);
67513e3f4d6SMark Murray } else {
67613e3f4d6SMark Murray if (tname && ((int)strlen(tname) <= 40)) {
67713e3f4d6SMark Murray unknown[0] = tname;
67813e3f4d6SMark Murray strupr(tname);
67913e3f4d6SMark Murray } else
68013e3f4d6SMark Murray unknown[0] = name_unknown;
68113e3f4d6SMark Murray tnamep = unknown;
68213e3f4d6SMark Murray }
68313e3f4d6SMark Murray next = tnamep;
68413e3f4d6SMark Murray }
68513e3f4d6SMark Murray if (*next == 0)
68613e3f4d6SMark Murray next = tnamep;
68713e3f4d6SMark Murray return(*next++);
68813e3f4d6SMark Murray }
68913e3f4d6SMark Murray /*
69013e3f4d6SMark Murray * suboption()
69113e3f4d6SMark Murray *
69213e3f4d6SMark Murray * Look at the sub-option buffer, and try to be helpful to the other
69313e3f4d6SMark Murray * side.
69413e3f4d6SMark Murray *
69513e3f4d6SMark Murray * Currently we recognize:
69613e3f4d6SMark Murray *
69713e3f4d6SMark Murray * Terminal type, send request.
69813e3f4d6SMark Murray * Terminal speed (send request).
69913e3f4d6SMark Murray * Local flow control (is request).
70013e3f4d6SMark Murray * Linemode
70113e3f4d6SMark Murray */
70213e3f4d6SMark Murray
70313e3f4d6SMark Murray static void
suboption()70413e3f4d6SMark Murray suboption()
70513e3f4d6SMark Murray {
70613e3f4d6SMark Murray unsigned char subchar;
70713e3f4d6SMark Murray
70813e3f4d6SMark Murray printsub('<', subbuffer, SB_LEN()+2);
70913e3f4d6SMark Murray switch (subchar = SB_GET()) {
71013e3f4d6SMark Murray case TELOPT_TTYPE:
71113e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_TTYPE))
71213e3f4d6SMark Murray return;
71313e3f4d6SMark Murray if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
71413e3f4d6SMark Murray return;
71513e3f4d6SMark Murray } else {
71613e3f4d6SMark Murray char *name;
71713e3f4d6SMark Murray unsigned char temp[50];
71813e3f4d6SMark Murray int len;
71913e3f4d6SMark Murray
72013e3f4d6SMark Murray name = gettermname();
72113e3f4d6SMark Murray len = strlen(name) + 4 + 2;
72213e3f4d6SMark Murray if (len < NETROOM()) {
72313e3f4d6SMark Murray snprintf((char *)temp, sizeof(temp),
72413e3f4d6SMark Murray "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
72513e3f4d6SMark Murray TELQUAL_IS, name, IAC, SE);
72613e3f4d6SMark Murray ring_supply_data(&netoring, temp, len);
72713e3f4d6SMark Murray printsub('>', &temp[2], len-2);
72813e3f4d6SMark Murray } else {
72913e3f4d6SMark Murray ExitString("No room in buffer for terminal type.\n", 1);
73013e3f4d6SMark Murray /*NOTREACHED*/
73113e3f4d6SMark Murray }
73213e3f4d6SMark Murray }
73313e3f4d6SMark Murray break;
73413e3f4d6SMark Murray case TELOPT_TSPEED:
73513e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_TSPEED))
73613e3f4d6SMark Murray return;
73713e3f4d6SMark Murray if (SB_EOF())
73813e3f4d6SMark Murray return;
73913e3f4d6SMark Murray if (SB_GET() == TELQUAL_SEND) {
74013e3f4d6SMark Murray long output_speed, input_speed;
74113e3f4d6SMark Murray unsigned char temp[50];
74213e3f4d6SMark Murray int len;
74313e3f4d6SMark Murray
74413e3f4d6SMark Murray TerminalSpeeds(&input_speed, &output_speed);
74513e3f4d6SMark Murray
74613e3f4d6SMark Murray snprintf((char *)temp, sizeof(temp),
74713e3f4d6SMark Murray "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED,
74813e3f4d6SMark Murray TELQUAL_IS,
74913e3f4d6SMark Murray (unsigned)output_speed,
75013e3f4d6SMark Murray (unsigned)input_speed, IAC, SE);
75113e3f4d6SMark Murray len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
75213e3f4d6SMark Murray
75313e3f4d6SMark Murray if (len < NETROOM()) {
75413e3f4d6SMark Murray ring_supply_data(&netoring, temp, len);
75513e3f4d6SMark Murray printsub('>', temp+2, len - 2);
75613e3f4d6SMark Murray }
75713e3f4d6SMark Murray /*@*/ else printf("lm_will: not enough room in buffer\n");
75813e3f4d6SMark Murray }
75913e3f4d6SMark Murray break;
76013e3f4d6SMark Murray case TELOPT_LFLOW:
76113e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_LFLOW))
76213e3f4d6SMark Murray return;
76313e3f4d6SMark Murray if (SB_EOF())
76413e3f4d6SMark Murray return;
76513e3f4d6SMark Murray switch(SB_GET()) {
76613e3f4d6SMark Murray case LFLOW_RESTART_ANY:
76713e3f4d6SMark Murray restartany = 1;
76813e3f4d6SMark Murray break;
76913e3f4d6SMark Murray case LFLOW_RESTART_XON:
77013e3f4d6SMark Murray restartany = 0;
77113e3f4d6SMark Murray break;
77213e3f4d6SMark Murray case LFLOW_ON:
77313e3f4d6SMark Murray localflow = 1;
77413e3f4d6SMark Murray break;
77513e3f4d6SMark Murray case LFLOW_OFF:
77613e3f4d6SMark Murray localflow = 0;
77713e3f4d6SMark Murray break;
77813e3f4d6SMark Murray default:
77913e3f4d6SMark Murray return;
78013e3f4d6SMark Murray }
78113e3f4d6SMark Murray setcommandmode();
78213e3f4d6SMark Murray setconnmode(0);
78313e3f4d6SMark Murray break;
78413e3f4d6SMark Murray
78513e3f4d6SMark Murray case TELOPT_LINEMODE:
78613e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_LINEMODE))
78713e3f4d6SMark Murray return;
78813e3f4d6SMark Murray if (SB_EOF())
78913e3f4d6SMark Murray return;
79013e3f4d6SMark Murray switch (SB_GET()) {
79113e3f4d6SMark Murray case WILL:
79213e3f4d6SMark Murray lm_will(subpointer, SB_LEN());
79313e3f4d6SMark Murray break;
79413e3f4d6SMark Murray case WONT:
79513e3f4d6SMark Murray lm_wont(subpointer, SB_LEN());
79613e3f4d6SMark Murray break;
79713e3f4d6SMark Murray case DO:
79813e3f4d6SMark Murray lm_do(subpointer, SB_LEN());
79913e3f4d6SMark Murray break;
80013e3f4d6SMark Murray case DONT:
80113e3f4d6SMark Murray lm_dont(subpointer, SB_LEN());
80213e3f4d6SMark Murray break;
80313e3f4d6SMark Murray case LM_SLC:
80413e3f4d6SMark Murray slc(subpointer, SB_LEN());
80513e3f4d6SMark Murray break;
80613e3f4d6SMark Murray case LM_MODE:
80713e3f4d6SMark Murray lm_mode(subpointer, SB_LEN(), 0);
80813e3f4d6SMark Murray break;
80913e3f4d6SMark Murray default:
81013e3f4d6SMark Murray break;
81113e3f4d6SMark Murray }
81213e3f4d6SMark Murray break;
81313e3f4d6SMark Murray
81413e3f4d6SMark Murray #ifdef OLD_ENVIRON
81513e3f4d6SMark Murray case TELOPT_OLD_ENVIRON:
81613e3f4d6SMark Murray #endif
81713e3f4d6SMark Murray case TELOPT_NEW_ENVIRON:
81813e3f4d6SMark Murray if (SB_EOF())
81913e3f4d6SMark Murray return;
82013e3f4d6SMark Murray switch(SB_PEEK()) {
82113e3f4d6SMark Murray case TELQUAL_IS:
82213e3f4d6SMark Murray case TELQUAL_INFO:
82313e3f4d6SMark Murray if (my_want_state_is_dont(subchar))
82413e3f4d6SMark Murray return;
82513e3f4d6SMark Murray break;
82613e3f4d6SMark Murray case TELQUAL_SEND:
82713e3f4d6SMark Murray if (my_want_state_is_wont(subchar)) {
82813e3f4d6SMark Murray return;
82913e3f4d6SMark Murray }
83013e3f4d6SMark Murray break;
83113e3f4d6SMark Murray default:
83213e3f4d6SMark Murray return;
83313e3f4d6SMark Murray }
83413e3f4d6SMark Murray env_opt(subpointer, SB_LEN());
83513e3f4d6SMark Murray break;
83613e3f4d6SMark Murray
83713e3f4d6SMark Murray case TELOPT_XDISPLOC:
83813e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_XDISPLOC))
83913e3f4d6SMark Murray return;
84013e3f4d6SMark Murray if (SB_EOF())
84113e3f4d6SMark Murray return;
84213e3f4d6SMark Murray if (SB_GET() == TELQUAL_SEND) {
84313e3f4d6SMark Murray unsigned char temp[50], *dp;
84413e3f4d6SMark Murray int len;
84513e3f4d6SMark Murray
84613e3f4d6SMark Murray if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
84713e3f4d6SMark Murray /*
84813e3f4d6SMark Murray * Something happened, we no longer have a DISPLAY
84913e3f4d6SMark Murray * variable. So, turn off the option.
85013e3f4d6SMark Murray */
85113e3f4d6SMark Murray send_wont(TELOPT_XDISPLOC, 1);
85213e3f4d6SMark Murray break;
85313e3f4d6SMark Murray }
85413e3f4d6SMark Murray snprintf((char *)temp, sizeof(temp),
85513e3f4d6SMark Murray "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
85613e3f4d6SMark Murray TELQUAL_IS, dp, IAC, SE);
85713e3f4d6SMark Murray len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
85813e3f4d6SMark Murray
85913e3f4d6SMark Murray if (len < NETROOM()) {
86013e3f4d6SMark Murray ring_supply_data(&netoring, temp, len);
86113e3f4d6SMark Murray printsub('>', temp+2, len - 2);
86213e3f4d6SMark Murray }
86313e3f4d6SMark Murray /*@*/ else printf("lm_will: not enough room in buffer\n");
86413e3f4d6SMark Murray }
86513e3f4d6SMark Murray break;
86613e3f4d6SMark Murray
86713e3f4d6SMark Murray #if defined(AUTHENTICATION)
86813e3f4d6SMark Murray case TELOPT_AUTHENTICATION: {
86913e3f4d6SMark Murray if (!autologin)
87013e3f4d6SMark Murray break;
87113e3f4d6SMark Murray if (SB_EOF())
87213e3f4d6SMark Murray return;
87313e3f4d6SMark Murray switch(SB_GET()) {
87413e3f4d6SMark Murray case TELQUAL_IS:
87513e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
87613e3f4d6SMark Murray return;
87713e3f4d6SMark Murray auth_is(subpointer, SB_LEN());
87813e3f4d6SMark Murray break;
87913e3f4d6SMark Murray case TELQUAL_SEND:
88013e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
88113e3f4d6SMark Murray return;
88213e3f4d6SMark Murray auth_send(subpointer, SB_LEN());
88313e3f4d6SMark Murray break;
88413e3f4d6SMark Murray case TELQUAL_REPLY:
88513e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
88613e3f4d6SMark Murray return;
88713e3f4d6SMark Murray auth_reply(subpointer, SB_LEN());
88813e3f4d6SMark Murray break;
88913e3f4d6SMark Murray case TELQUAL_NAME:
89013e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
89113e3f4d6SMark Murray return;
89213e3f4d6SMark Murray auth_name(subpointer, SB_LEN());
89313e3f4d6SMark Murray break;
89413e3f4d6SMark Murray }
89513e3f4d6SMark Murray }
89613e3f4d6SMark Murray break;
89713e3f4d6SMark Murray #endif
89813e3f4d6SMark Murray #if defined(ENCRYPTION)
89913e3f4d6SMark Murray case TELOPT_ENCRYPT:
90013e3f4d6SMark Murray if (SB_EOF())
90113e3f4d6SMark Murray return;
90213e3f4d6SMark Murray switch(SB_GET()) {
90313e3f4d6SMark Murray case ENCRYPT_START:
90413e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_ENCRYPT))
90513e3f4d6SMark Murray return;
90613e3f4d6SMark Murray encrypt_start(subpointer, SB_LEN());
90713e3f4d6SMark Murray break;
90813e3f4d6SMark Murray case ENCRYPT_END:
90913e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_ENCRYPT))
91013e3f4d6SMark Murray return;
91113e3f4d6SMark Murray encrypt_end();
91213e3f4d6SMark Murray break;
91313e3f4d6SMark Murray case ENCRYPT_SUPPORT:
91413e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_ENCRYPT))
91513e3f4d6SMark Murray return;
91613e3f4d6SMark Murray encrypt_support(subpointer, SB_LEN());
91713e3f4d6SMark Murray break;
91813e3f4d6SMark Murray case ENCRYPT_REQSTART:
91913e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_ENCRYPT))
92013e3f4d6SMark Murray return;
92113e3f4d6SMark Murray encrypt_request_start(subpointer, SB_LEN());
92213e3f4d6SMark Murray break;
92313e3f4d6SMark Murray case ENCRYPT_REQEND:
92413e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_ENCRYPT))
92513e3f4d6SMark Murray return;
92613e3f4d6SMark Murray /*
92713e3f4d6SMark Murray * We can always send an REQEND so that we cannot
92813e3f4d6SMark Murray * get stuck encrypting. We should only get this
92913e3f4d6SMark Murray * if we have been able to get in the correct mode
93013e3f4d6SMark Murray * anyhow.
93113e3f4d6SMark Murray */
93213e3f4d6SMark Murray encrypt_request_end();
93313e3f4d6SMark Murray break;
93413e3f4d6SMark Murray case ENCRYPT_IS:
93513e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_ENCRYPT))
93613e3f4d6SMark Murray return;
93713e3f4d6SMark Murray encrypt_is(subpointer, SB_LEN());
93813e3f4d6SMark Murray break;
93913e3f4d6SMark Murray case ENCRYPT_REPLY:
94013e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_ENCRYPT))
94113e3f4d6SMark Murray return;
94213e3f4d6SMark Murray encrypt_reply(subpointer, SB_LEN());
94313e3f4d6SMark Murray break;
94413e3f4d6SMark Murray case ENCRYPT_ENC_KEYID:
94513e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_ENCRYPT))
94613e3f4d6SMark Murray return;
94713e3f4d6SMark Murray encrypt_enc_keyid(subpointer, SB_LEN());
94813e3f4d6SMark Murray break;
94913e3f4d6SMark Murray case ENCRYPT_DEC_KEYID:
95013e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_ENCRYPT))
95113e3f4d6SMark Murray return;
95213e3f4d6SMark Murray encrypt_dec_keyid(subpointer, SB_LEN());
95313e3f4d6SMark Murray break;
95413e3f4d6SMark Murray default:
95513e3f4d6SMark Murray break;
95613e3f4d6SMark Murray }
95713e3f4d6SMark Murray break;
95813e3f4d6SMark Murray #endif
95913e3f4d6SMark Murray default:
96013e3f4d6SMark Murray break;
96113e3f4d6SMark Murray }
96213e3f4d6SMark Murray }
96313e3f4d6SMark Murray
96413e3f4d6SMark Murray static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
96513e3f4d6SMark Murray
96613e3f4d6SMark Murray void
lm_will(unsigned char * cmd,int len)96713e3f4d6SMark Murray lm_will(unsigned char *cmd, int len)
96813e3f4d6SMark Murray {
96913e3f4d6SMark Murray if (len < 1) {
97013e3f4d6SMark Murray /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
97113e3f4d6SMark Murray return;
97213e3f4d6SMark Murray }
97313e3f4d6SMark Murray switch(cmd[0]) {
97413e3f4d6SMark Murray case LM_FORWARDMASK: /* We shouldn't ever get this... */
97513e3f4d6SMark Murray default:
97613e3f4d6SMark Murray str_lm[3] = DONT;
97713e3f4d6SMark Murray str_lm[4] = cmd[0];
97813e3f4d6SMark Murray if (NETROOM() > sizeof(str_lm)) {
97913e3f4d6SMark Murray ring_supply_data(&netoring, str_lm, sizeof(str_lm));
98013e3f4d6SMark Murray printsub('>', &str_lm[2], sizeof(str_lm)-2);
98113e3f4d6SMark Murray }
98213e3f4d6SMark Murray /*@*/ else printf("lm_will: not enough room in buffer\n");
98313e3f4d6SMark Murray break;
98413e3f4d6SMark Murray }
98513e3f4d6SMark Murray }
98613e3f4d6SMark Murray
98713e3f4d6SMark Murray void
lm_wont(unsigned char * cmd,int len)98813e3f4d6SMark Murray lm_wont(unsigned char *cmd, int len)
98913e3f4d6SMark Murray {
99013e3f4d6SMark Murray if (len < 1) {
99113e3f4d6SMark Murray /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
99213e3f4d6SMark Murray return;
99313e3f4d6SMark Murray }
99413e3f4d6SMark Murray switch(cmd[0]) {
99513e3f4d6SMark Murray case LM_FORWARDMASK: /* We shouldn't ever get this... */
99613e3f4d6SMark Murray default:
99713e3f4d6SMark Murray /* We are always DONT, so don't respond */
99813e3f4d6SMark Murray return;
99913e3f4d6SMark Murray }
100013e3f4d6SMark Murray }
100113e3f4d6SMark Murray
100213e3f4d6SMark Murray void
lm_do(unsigned char * cmd,int len)100313e3f4d6SMark Murray lm_do(unsigned char *cmd, int len)
100413e3f4d6SMark Murray {
100513e3f4d6SMark Murray if (len < 1) {
100613e3f4d6SMark Murray /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
100713e3f4d6SMark Murray return;
100813e3f4d6SMark Murray }
100913e3f4d6SMark Murray switch(cmd[0]) {
101013e3f4d6SMark Murray case LM_FORWARDMASK:
101113e3f4d6SMark Murray default:
101213e3f4d6SMark Murray str_lm[3] = WONT;
101313e3f4d6SMark Murray str_lm[4] = cmd[0];
101413e3f4d6SMark Murray if (NETROOM() > sizeof(str_lm)) {
101513e3f4d6SMark Murray ring_supply_data(&netoring, str_lm, sizeof(str_lm));
101613e3f4d6SMark Murray printsub('>', &str_lm[2], sizeof(str_lm)-2);
101713e3f4d6SMark Murray }
101813e3f4d6SMark Murray /*@*/ else printf("lm_do: not enough room in buffer\n");
101913e3f4d6SMark Murray break;
102013e3f4d6SMark Murray }
102113e3f4d6SMark Murray }
102213e3f4d6SMark Murray
102313e3f4d6SMark Murray void
lm_dont(unsigned char * cmd,int len)102413e3f4d6SMark Murray lm_dont(unsigned char *cmd, int len)
102513e3f4d6SMark Murray {
102613e3f4d6SMark Murray if (len < 1) {
102713e3f4d6SMark Murray /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
102813e3f4d6SMark Murray return;
102913e3f4d6SMark Murray }
103013e3f4d6SMark Murray switch(cmd[0]) {
103113e3f4d6SMark Murray case LM_FORWARDMASK:
103213e3f4d6SMark Murray default:
103313e3f4d6SMark Murray /* we are always WONT, so don't respond */
103413e3f4d6SMark Murray break;
103513e3f4d6SMark Murray }
103613e3f4d6SMark Murray }
103713e3f4d6SMark Murray
103813e3f4d6SMark Murray static unsigned char str_lm_mode[] = {
103913e3f4d6SMark Murray IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
104013e3f4d6SMark Murray };
104113e3f4d6SMark Murray
104213e3f4d6SMark Murray void
lm_mode(unsigned char * cmd,int len,int init)104313e3f4d6SMark Murray lm_mode(unsigned char *cmd, int len, int init)
104413e3f4d6SMark Murray {
104513e3f4d6SMark Murray if (len != 1)
104613e3f4d6SMark Murray return;
104713e3f4d6SMark Murray if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
104813e3f4d6SMark Murray return;
104913e3f4d6SMark Murray if (*cmd&MODE_ACK)
105013e3f4d6SMark Murray return;
105113e3f4d6SMark Murray linemode = *cmd&(MODE_MASK&~MODE_ACK);
105213e3f4d6SMark Murray str_lm_mode[4] = linemode;
105313e3f4d6SMark Murray if (!init)
105413e3f4d6SMark Murray str_lm_mode[4] |= MODE_ACK;
105513e3f4d6SMark Murray if (NETROOM() > sizeof(str_lm_mode)) {
105613e3f4d6SMark Murray ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
105713e3f4d6SMark Murray printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
105813e3f4d6SMark Murray }
105913e3f4d6SMark Murray /*@*/ else printf("lm_mode: not enough room in buffer\n");
106013e3f4d6SMark Murray setconnmode(0); /* set changed mode */
106113e3f4d6SMark Murray }
106213e3f4d6SMark Murray
106313e3f4d6SMark Murray
106413e3f4d6SMark Murray
106513e3f4d6SMark Murray /*
106613e3f4d6SMark Murray * slc()
106713e3f4d6SMark Murray * Handle special character suboption of LINEMODE.
106813e3f4d6SMark Murray */
106913e3f4d6SMark Murray
107013e3f4d6SMark Murray struct spc {
107113e3f4d6SMark Murray cc_t val;
107213e3f4d6SMark Murray cc_t *valp;
107313e3f4d6SMark Murray char flags; /* Current flags & level */
107413e3f4d6SMark Murray char mylevel; /* Maximum level & flags */
107513e3f4d6SMark Murray } spc_data[NSLC+1];
107613e3f4d6SMark Murray
107713e3f4d6SMark Murray #define SLC_IMPORT 0
107813e3f4d6SMark Murray #define SLC_EXPORT 1
107913e3f4d6SMark Murray #define SLC_RVALUE 2
108013e3f4d6SMark Murray static int slc_mode = SLC_EXPORT;
108113e3f4d6SMark Murray
108213e3f4d6SMark Murray void
slc_init()108313e3f4d6SMark Murray slc_init()
108413e3f4d6SMark Murray {
108513e3f4d6SMark Murray struct spc *spcp;
108613e3f4d6SMark Murray
108713e3f4d6SMark Murray localchars = 1;
108813e3f4d6SMark Murray for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
108913e3f4d6SMark Murray spcp->val = 0;
109013e3f4d6SMark Murray spcp->valp = 0;
109113e3f4d6SMark Murray spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
109213e3f4d6SMark Murray }
109313e3f4d6SMark Murray
109413e3f4d6SMark Murray #define initfunc(func, flags) { \
109513e3f4d6SMark Murray spcp = &spc_data[func]; \
109613e3f4d6SMark Murray if ((spcp->valp = tcval(func))) { \
109713e3f4d6SMark Murray spcp->val = *spcp->valp; \
109813e3f4d6SMark Murray spcp->mylevel = SLC_VARIABLE|flags; \
109913e3f4d6SMark Murray } else { \
110013e3f4d6SMark Murray spcp->val = 0; \
110113e3f4d6SMark Murray spcp->mylevel = SLC_DEFAULT; \
110213e3f4d6SMark Murray } \
110313e3f4d6SMark Murray }
110413e3f4d6SMark Murray
110513e3f4d6SMark Murray initfunc(SLC_SYNCH, 0);
110613e3f4d6SMark Murray /* No BRK */
110713e3f4d6SMark Murray initfunc(SLC_AO, 0);
110813e3f4d6SMark Murray initfunc(SLC_AYT, 0);
110913e3f4d6SMark Murray /* No EOR */
111013e3f4d6SMark Murray initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
111113e3f4d6SMark Murray initfunc(SLC_EOF, 0);
111213e3f4d6SMark Murray initfunc(SLC_SUSP, SLC_FLUSHIN);
111313e3f4d6SMark Murray initfunc(SLC_EC, 0);
111413e3f4d6SMark Murray initfunc(SLC_EL, 0);
111513e3f4d6SMark Murray initfunc(SLC_EW, 0);
111613e3f4d6SMark Murray initfunc(SLC_RP, 0);
111713e3f4d6SMark Murray initfunc(SLC_LNEXT, 0);
111813e3f4d6SMark Murray initfunc(SLC_XON, 0);
111913e3f4d6SMark Murray initfunc(SLC_XOFF, 0);
112013e3f4d6SMark Murray initfunc(SLC_FORW1, 0);
112113e3f4d6SMark Murray initfunc(SLC_FORW2, 0);
112213e3f4d6SMark Murray /* No FORW2 */
112313e3f4d6SMark Murray
112413e3f4d6SMark Murray initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
112513e3f4d6SMark Murray #undef initfunc
112613e3f4d6SMark Murray
112713e3f4d6SMark Murray if (slc_mode == SLC_EXPORT)
112813e3f4d6SMark Murray slc_export();
112913e3f4d6SMark Murray else
113013e3f4d6SMark Murray slc_import(1);
113113e3f4d6SMark Murray
113213e3f4d6SMark Murray }
113313e3f4d6SMark Murray
113413e3f4d6SMark Murray void
slcstate()113513e3f4d6SMark Murray slcstate()
113613e3f4d6SMark Murray {
113713e3f4d6SMark Murray printf("Special characters are %s values\n",
113813e3f4d6SMark Murray slc_mode == SLC_IMPORT ? "remote default" :
113913e3f4d6SMark Murray slc_mode == SLC_EXPORT ? "local" :
114013e3f4d6SMark Murray "remote");
114113e3f4d6SMark Murray }
114213e3f4d6SMark Murray
114313e3f4d6SMark Murray void
slc_mode_export()114413e3f4d6SMark Murray slc_mode_export()
114513e3f4d6SMark Murray {
114613e3f4d6SMark Murray slc_mode = SLC_EXPORT;
114713e3f4d6SMark Murray if (my_state_is_will(TELOPT_LINEMODE))
114813e3f4d6SMark Murray slc_export();
114913e3f4d6SMark Murray }
115013e3f4d6SMark Murray
115113e3f4d6SMark Murray void
slc_mode_import(int def)115213e3f4d6SMark Murray slc_mode_import(int def)
115313e3f4d6SMark Murray {
115413e3f4d6SMark Murray slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
115513e3f4d6SMark Murray if (my_state_is_will(TELOPT_LINEMODE))
115613e3f4d6SMark Murray slc_import(def);
115713e3f4d6SMark Murray }
115813e3f4d6SMark Murray
115913e3f4d6SMark Murray unsigned char slc_import_val[] = {
116013e3f4d6SMark Murray IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
116113e3f4d6SMark Murray };
116213e3f4d6SMark Murray unsigned char slc_import_def[] = {
116313e3f4d6SMark Murray IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
116413e3f4d6SMark Murray };
116513e3f4d6SMark Murray
116613e3f4d6SMark Murray void
slc_import(int def)116713e3f4d6SMark Murray slc_import(int def)
116813e3f4d6SMark Murray {
116913e3f4d6SMark Murray if (NETROOM() > sizeof(slc_import_val)) {
117013e3f4d6SMark Murray if (def) {
117113e3f4d6SMark Murray ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
117213e3f4d6SMark Murray printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
117313e3f4d6SMark Murray } else {
117413e3f4d6SMark Murray ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
117513e3f4d6SMark Murray printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
117613e3f4d6SMark Murray }
117713e3f4d6SMark Murray }
117813e3f4d6SMark Murray /*@*/ else printf("slc_import: not enough room\n");
117913e3f4d6SMark Murray }
118013e3f4d6SMark Murray
118113e3f4d6SMark Murray void
slc_export()118213e3f4d6SMark Murray slc_export()
118313e3f4d6SMark Murray {
118413e3f4d6SMark Murray struct spc *spcp;
118513e3f4d6SMark Murray
118613e3f4d6SMark Murray TerminalDefaultChars();
118713e3f4d6SMark Murray
118813e3f4d6SMark Murray slc_start_reply();
118913e3f4d6SMark Murray for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
119013e3f4d6SMark Murray if (spcp->mylevel != SLC_NOSUPPORT) {
119113e3f4d6SMark Murray if (spcp->val == (cc_t)(_POSIX_VDISABLE))
119213e3f4d6SMark Murray spcp->flags = SLC_NOSUPPORT;
119313e3f4d6SMark Murray else
119413e3f4d6SMark Murray spcp->flags = spcp->mylevel;
119513e3f4d6SMark Murray if (spcp->valp)
119613e3f4d6SMark Murray spcp->val = *spcp->valp;
119713e3f4d6SMark Murray slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
119813e3f4d6SMark Murray }
119913e3f4d6SMark Murray }
120013e3f4d6SMark Murray slc_end_reply();
120113e3f4d6SMark Murray slc_update();
120213e3f4d6SMark Murray setconnmode(1); /* Make sure the character values are set */
120313e3f4d6SMark Murray }
120413e3f4d6SMark Murray
120513e3f4d6SMark Murray void
slc(unsigned char * cp,int len)120613e3f4d6SMark Murray slc(unsigned char *cp, int len)
120713e3f4d6SMark Murray {
120813e3f4d6SMark Murray struct spc *spcp;
120913e3f4d6SMark Murray int func,level;
121013e3f4d6SMark Murray
121113e3f4d6SMark Murray slc_start_reply();
121213e3f4d6SMark Murray
121313e3f4d6SMark Murray for (; len >= 3; len -=3, cp +=3) {
121413e3f4d6SMark Murray
121513e3f4d6SMark Murray func = cp[SLC_FUNC];
121613e3f4d6SMark Murray
121713e3f4d6SMark Murray if (func == 0) {
121813e3f4d6SMark Murray /*
121913e3f4d6SMark Murray * Client side: always ignore 0 function.
122013e3f4d6SMark Murray */
122113e3f4d6SMark Murray continue;
122213e3f4d6SMark Murray }
122313e3f4d6SMark Murray if (func > NSLC) {
122413e3f4d6SMark Murray if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
122513e3f4d6SMark Murray slc_add_reply(func, SLC_NOSUPPORT, 0);
122613e3f4d6SMark Murray continue;
122713e3f4d6SMark Murray }
122813e3f4d6SMark Murray
122913e3f4d6SMark Murray spcp = &spc_data[func];
123013e3f4d6SMark Murray
123113e3f4d6SMark Murray level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
123213e3f4d6SMark Murray
123313e3f4d6SMark Murray if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
123413e3f4d6SMark Murray ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
123513e3f4d6SMark Murray continue;
123613e3f4d6SMark Murray }
123713e3f4d6SMark Murray
123813e3f4d6SMark Murray if (level == (SLC_DEFAULT|SLC_ACK)) {
123913e3f4d6SMark Murray /*
124013e3f4d6SMark Murray * This is an error condition, the SLC_ACK
124113e3f4d6SMark Murray * bit should never be set for the SLC_DEFAULT
124213e3f4d6SMark Murray * level. Our best guess to recover is to
124313e3f4d6SMark Murray * ignore the SLC_ACK bit.
124413e3f4d6SMark Murray */
124513e3f4d6SMark Murray cp[SLC_FLAGS] &= ~SLC_ACK;
124613e3f4d6SMark Murray }
124713e3f4d6SMark Murray
124813e3f4d6SMark Murray if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
124913e3f4d6SMark Murray spcp->val = (cc_t)cp[SLC_VALUE];
125013e3f4d6SMark Murray spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
125113e3f4d6SMark Murray continue;
125213e3f4d6SMark Murray }
125313e3f4d6SMark Murray
125413e3f4d6SMark Murray level &= ~SLC_ACK;
125513e3f4d6SMark Murray
125613e3f4d6SMark Murray if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
125713e3f4d6SMark Murray spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
125813e3f4d6SMark Murray spcp->val = (cc_t)cp[SLC_VALUE];
125913e3f4d6SMark Murray }
126013e3f4d6SMark Murray if (level == SLC_DEFAULT) {
126113e3f4d6SMark Murray if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
126213e3f4d6SMark Murray spcp->flags = spcp->mylevel;
126313e3f4d6SMark Murray else
126413e3f4d6SMark Murray spcp->flags = SLC_NOSUPPORT;
126513e3f4d6SMark Murray }
126613e3f4d6SMark Murray slc_add_reply(func, spcp->flags, spcp->val);
126713e3f4d6SMark Murray }
126813e3f4d6SMark Murray slc_end_reply();
126913e3f4d6SMark Murray if (slc_update())
127013e3f4d6SMark Murray setconnmode(1); /* set the new character values */
127113e3f4d6SMark Murray }
127213e3f4d6SMark Murray
127313e3f4d6SMark Murray void
slc_check()127413e3f4d6SMark Murray slc_check()
127513e3f4d6SMark Murray {
127613e3f4d6SMark Murray struct spc *spcp;
127713e3f4d6SMark Murray
127813e3f4d6SMark Murray slc_start_reply();
127913e3f4d6SMark Murray for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
128013e3f4d6SMark Murray if (spcp->valp && spcp->val != *spcp->valp) {
128113e3f4d6SMark Murray spcp->val = *spcp->valp;
128213e3f4d6SMark Murray if (spcp->val == (cc_t)(_POSIX_VDISABLE))
128313e3f4d6SMark Murray spcp->flags = SLC_NOSUPPORT;
128413e3f4d6SMark Murray else
128513e3f4d6SMark Murray spcp->flags = spcp->mylevel;
128613e3f4d6SMark Murray slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
128713e3f4d6SMark Murray }
128813e3f4d6SMark Murray }
128913e3f4d6SMark Murray slc_end_reply();
129013e3f4d6SMark Murray setconnmode(1);
129113e3f4d6SMark Murray }
129213e3f4d6SMark Murray
129313e3f4d6SMark Murray
129413e3f4d6SMark Murray unsigned char slc_reply[128];
1295c19800e8SDoug Rabson unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
129613e3f4d6SMark Murray unsigned char *slc_replyp;
129713e3f4d6SMark Murray
129813e3f4d6SMark Murray void
slc_start_reply()129913e3f4d6SMark Murray slc_start_reply()
130013e3f4d6SMark Murray {
130113e3f4d6SMark Murray slc_replyp = slc_reply;
130213e3f4d6SMark Murray *slc_replyp++ = IAC;
130313e3f4d6SMark Murray *slc_replyp++ = SB;
130413e3f4d6SMark Murray *slc_replyp++ = TELOPT_LINEMODE;
130513e3f4d6SMark Murray *slc_replyp++ = LM_SLC;
130613e3f4d6SMark Murray }
130713e3f4d6SMark Murray
130813e3f4d6SMark Murray void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)130913e3f4d6SMark Murray slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
131013e3f4d6SMark Murray {
1311c19800e8SDoug Rabson /* A sequence of up to 6 bytes my be written for this member of the SLC
1312c19800e8SDoug Rabson * suboption list by this function. The end of negotiation command,
1313c19800e8SDoug Rabson * which is written by slc_end_reply(), will require 2 additional
1314c19800e8SDoug Rabson * bytes. Do not proceed unless there is sufficient space for these
1315c19800e8SDoug Rabson * items.
1316c19800e8SDoug Rabson */
1317c19800e8SDoug Rabson if (&slc_replyp[6+2] > slc_reply_eom)
1318c19800e8SDoug Rabson return;
131913e3f4d6SMark Murray if ((*slc_replyp++ = func) == IAC)
132013e3f4d6SMark Murray *slc_replyp++ = IAC;
132113e3f4d6SMark Murray if ((*slc_replyp++ = flags) == IAC)
132213e3f4d6SMark Murray *slc_replyp++ = IAC;
132313e3f4d6SMark Murray if ((*slc_replyp++ = (unsigned char)value) == IAC)
132413e3f4d6SMark Murray *slc_replyp++ = IAC;
132513e3f4d6SMark Murray }
132613e3f4d6SMark Murray
132713e3f4d6SMark Murray void
slc_end_reply()132813e3f4d6SMark Murray slc_end_reply()
132913e3f4d6SMark Murray {
133013e3f4d6SMark Murray int len;
133113e3f4d6SMark Murray
1332c19800e8SDoug Rabson /* The end of negotiation command requires 2 bytes. */
1333c19800e8SDoug Rabson if (&slc_replyp[2] > slc_reply_eom)
1334c19800e8SDoug Rabson return;
133513e3f4d6SMark Murray *slc_replyp++ = IAC;
133613e3f4d6SMark Murray *slc_replyp++ = SE;
133713e3f4d6SMark Murray len = slc_replyp - slc_reply;
133813e3f4d6SMark Murray if (len <= 6)
133913e3f4d6SMark Murray return;
134013e3f4d6SMark Murray if (NETROOM() > len) {
134113e3f4d6SMark Murray ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
134213e3f4d6SMark Murray printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
134313e3f4d6SMark Murray }
134413e3f4d6SMark Murray /*@*/else printf("slc_end_reply: not enough room\n");
134513e3f4d6SMark Murray }
134613e3f4d6SMark Murray
134713e3f4d6SMark Murray int
slc_update()134813e3f4d6SMark Murray slc_update()
134913e3f4d6SMark Murray {
135013e3f4d6SMark Murray struct spc *spcp;
135113e3f4d6SMark Murray int need_update = 0;
135213e3f4d6SMark Murray
135313e3f4d6SMark Murray for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
135413e3f4d6SMark Murray if (!(spcp->flags&SLC_ACK))
135513e3f4d6SMark Murray continue;
135613e3f4d6SMark Murray spcp->flags &= ~SLC_ACK;
135713e3f4d6SMark Murray if (spcp->valp && (*spcp->valp != spcp->val)) {
135813e3f4d6SMark Murray *spcp->valp = spcp->val;
135913e3f4d6SMark Murray need_update = 1;
136013e3f4d6SMark Murray }
136113e3f4d6SMark Murray }
136213e3f4d6SMark Murray return(need_update);
136313e3f4d6SMark Murray }
136413e3f4d6SMark Murray
136513e3f4d6SMark Murray #ifdef OLD_ENVIRON
136613e3f4d6SMark Murray # define old_env_var OLD_ENV_VAR
136713e3f4d6SMark Murray # define old_env_value OLD_ENV_VALUE
136813e3f4d6SMark Murray #endif
136913e3f4d6SMark Murray
137013e3f4d6SMark Murray void
env_opt(unsigned char * buf,int len)137113e3f4d6SMark Murray env_opt(unsigned char *buf, int len)
137213e3f4d6SMark Murray {
137313e3f4d6SMark Murray unsigned char *ep = 0, *epc = 0;
137413e3f4d6SMark Murray int i;
137513e3f4d6SMark Murray
137613e3f4d6SMark Murray switch(buf[0]&0xff) {
137713e3f4d6SMark Murray case TELQUAL_SEND:
137813e3f4d6SMark Murray env_opt_start();
137913e3f4d6SMark Murray if (len == 1) {
138013e3f4d6SMark Murray env_opt_add(NULL);
138113e3f4d6SMark Murray } else for (i = 1; i < len; i++) {
138213e3f4d6SMark Murray switch (buf[i]&0xff) {
138313e3f4d6SMark Murray #ifdef OLD_ENVIRON
138413e3f4d6SMark Murray case OLD_ENV_VAR:
138513e3f4d6SMark Murray case OLD_ENV_VALUE:
138613e3f4d6SMark Murray /*
138713e3f4d6SMark Murray * Although OLD_ENV_VALUE is not legal, we will
138813e3f4d6SMark Murray * still recognize it, just in case it is an
138913e3f4d6SMark Murray * old server that has VAR & VALUE mixed up...
139013e3f4d6SMark Murray */
139113e3f4d6SMark Murray /* FALL THROUGH */
139213e3f4d6SMark Murray #else
139313e3f4d6SMark Murray case NEW_ENV_VAR:
139413e3f4d6SMark Murray #endif
139513e3f4d6SMark Murray case ENV_USERVAR:
139613e3f4d6SMark Murray if (ep) {
139713e3f4d6SMark Murray *epc = 0;
139813e3f4d6SMark Murray env_opt_add(ep);
139913e3f4d6SMark Murray }
140013e3f4d6SMark Murray ep = epc = &buf[i+1];
140113e3f4d6SMark Murray break;
140213e3f4d6SMark Murray case ENV_ESC:
140313e3f4d6SMark Murray i++;
140413e3f4d6SMark Murray /*FALL THROUGH*/
140513e3f4d6SMark Murray default:
140613e3f4d6SMark Murray if (epc)
140713e3f4d6SMark Murray *epc++ = buf[i];
140813e3f4d6SMark Murray break;
140913e3f4d6SMark Murray }
141013e3f4d6SMark Murray }
141113e3f4d6SMark Murray if (ep) {
141213e3f4d6SMark Murray *epc = 0;
141313e3f4d6SMark Murray env_opt_add(ep);
141413e3f4d6SMark Murray }
141513e3f4d6SMark Murray env_opt_end(1);
141613e3f4d6SMark Murray break;
141713e3f4d6SMark Murray
141813e3f4d6SMark Murray case TELQUAL_IS:
141913e3f4d6SMark Murray case TELQUAL_INFO:
142013e3f4d6SMark Murray /* Ignore for now. We shouldn't get it anyway. */
142113e3f4d6SMark Murray break;
142213e3f4d6SMark Murray
142313e3f4d6SMark Murray default:
142413e3f4d6SMark Murray break;
142513e3f4d6SMark Murray }
142613e3f4d6SMark Murray }
142713e3f4d6SMark Murray
1428c19800e8SDoug Rabson #define OPT_REPLY_SIZE (2 * SUBBUFSIZE)
142913e3f4d6SMark Murray unsigned char *opt_reply;
143013e3f4d6SMark Murray unsigned char *opt_replyp;
143113e3f4d6SMark Murray unsigned char *opt_replyend;
143213e3f4d6SMark Murray
143313e3f4d6SMark Murray void
env_opt_start()143413e3f4d6SMark Murray env_opt_start()
143513e3f4d6SMark Murray {
143613e3f4d6SMark Murray if (opt_reply) {
143713e3f4d6SMark Murray void *tmp = realloc (opt_reply, OPT_REPLY_SIZE);
143813e3f4d6SMark Murray if (tmp != NULL) {
143913e3f4d6SMark Murray opt_reply = tmp;
144013e3f4d6SMark Murray } else {
144113e3f4d6SMark Murray free (opt_reply);
144213e3f4d6SMark Murray opt_reply = NULL;
144313e3f4d6SMark Murray }
144413e3f4d6SMark Murray } else
144513e3f4d6SMark Murray opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
144613e3f4d6SMark Murray if (opt_reply == NULL) {
144713e3f4d6SMark Murray /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
144813e3f4d6SMark Murray opt_reply = opt_replyp = opt_replyend = NULL;
144913e3f4d6SMark Murray return;
145013e3f4d6SMark Murray }
145113e3f4d6SMark Murray opt_replyp = opt_reply;
145213e3f4d6SMark Murray opt_replyend = opt_reply + OPT_REPLY_SIZE;
145313e3f4d6SMark Murray *opt_replyp++ = IAC;
145413e3f4d6SMark Murray *opt_replyp++ = SB;
145513e3f4d6SMark Murray *opt_replyp++ = telopt_environ;
145613e3f4d6SMark Murray *opt_replyp++ = TELQUAL_IS;
145713e3f4d6SMark Murray }
145813e3f4d6SMark Murray
145913e3f4d6SMark Murray void
env_opt_start_info()146013e3f4d6SMark Murray env_opt_start_info()
146113e3f4d6SMark Murray {
146213e3f4d6SMark Murray env_opt_start();
146313e3f4d6SMark Murray if (opt_replyp)
146413e3f4d6SMark Murray opt_replyp[-1] = TELQUAL_INFO;
146513e3f4d6SMark Murray }
146613e3f4d6SMark Murray
146713e3f4d6SMark Murray void
env_opt_add(unsigned char * ep)146813e3f4d6SMark Murray env_opt_add(unsigned char *ep)
146913e3f4d6SMark Murray {
147013e3f4d6SMark Murray unsigned char *vp, c;
147113e3f4d6SMark Murray
147213e3f4d6SMark Murray if (opt_reply == NULL) /*XXX*/
147313e3f4d6SMark Murray return; /*XXX*/
147413e3f4d6SMark Murray
147513e3f4d6SMark Murray if (ep == NULL || *ep == '\0') {
147613e3f4d6SMark Murray /* Send user defined variables first. */
147713e3f4d6SMark Murray env_default(1, 0);
147813e3f4d6SMark Murray while ((ep = env_default(0, 0)))
147913e3f4d6SMark Murray env_opt_add(ep);
148013e3f4d6SMark Murray
148113e3f4d6SMark Murray /* Now add the list of well know variables. */
148213e3f4d6SMark Murray env_default(1, 1);
148313e3f4d6SMark Murray while ((ep = env_default(0, 1)))
148413e3f4d6SMark Murray env_opt_add(ep);
148513e3f4d6SMark Murray return;
148613e3f4d6SMark Murray }
148713e3f4d6SMark Murray vp = env_getvalue(ep);
1488c19800e8SDoug Rabson if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
1489c19800e8SDoug Rabson 2 * strlen((char *)ep) + 6 > opt_replyend)
149013e3f4d6SMark Murray {
149113e3f4d6SMark Murray int len;
149213e3f4d6SMark Murray void *tmp;
149313e3f4d6SMark Murray opt_replyend += OPT_REPLY_SIZE;
149413e3f4d6SMark Murray len = opt_replyend - opt_reply;
149513e3f4d6SMark Murray tmp = realloc(opt_reply, len);
149613e3f4d6SMark Murray if (tmp == NULL) {
149713e3f4d6SMark Murray /*@*/ printf("env_opt_add: realloc() failed!!!\n");
149813e3f4d6SMark Murray opt_reply = opt_replyp = opt_replyend = NULL;
149913e3f4d6SMark Murray return;
150013e3f4d6SMark Murray }
150113e3f4d6SMark Murray opt_reply = tmp;
150213e3f4d6SMark Murray opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
150313e3f4d6SMark Murray opt_replyend = opt_reply + len;
150413e3f4d6SMark Murray }
150513e3f4d6SMark Murray if (opt_welldefined((char *)ep)) {
150613e3f4d6SMark Murray #ifdef OLD_ENVIRON
150713e3f4d6SMark Murray if (telopt_environ == TELOPT_OLD_ENVIRON)
150813e3f4d6SMark Murray *opt_replyp++ = old_env_var;
150913e3f4d6SMark Murray else
151013e3f4d6SMark Murray #endif
151113e3f4d6SMark Murray *opt_replyp++ = NEW_ENV_VAR;
151213e3f4d6SMark Murray } else
151313e3f4d6SMark Murray *opt_replyp++ = ENV_USERVAR;
151413e3f4d6SMark Murray for (;;) {
151513e3f4d6SMark Murray while ((c = *ep++)) {
1516c19800e8SDoug Rabson if (opt_replyp + (2 + 2) > opt_replyend)
1517c19800e8SDoug Rabson return;
151813e3f4d6SMark Murray switch(c&0xff) {
151913e3f4d6SMark Murray case IAC:
152013e3f4d6SMark Murray *opt_replyp++ = IAC;
152113e3f4d6SMark Murray break;
152213e3f4d6SMark Murray case NEW_ENV_VAR:
152313e3f4d6SMark Murray case NEW_ENV_VALUE:
152413e3f4d6SMark Murray case ENV_ESC:
152513e3f4d6SMark Murray case ENV_USERVAR:
152613e3f4d6SMark Murray *opt_replyp++ = ENV_ESC;
152713e3f4d6SMark Murray break;
152813e3f4d6SMark Murray }
152913e3f4d6SMark Murray *opt_replyp++ = c;
153013e3f4d6SMark Murray }
153113e3f4d6SMark Murray if ((ep = vp)) {
1532c19800e8SDoug Rabson if (opt_replyp + (1 + 2 + 2) > opt_replyend)
1533c19800e8SDoug Rabson return;
153413e3f4d6SMark Murray #ifdef OLD_ENVIRON
153513e3f4d6SMark Murray if (telopt_environ == TELOPT_OLD_ENVIRON)
153613e3f4d6SMark Murray *opt_replyp++ = old_env_value;
153713e3f4d6SMark Murray else
153813e3f4d6SMark Murray #endif
153913e3f4d6SMark Murray *opt_replyp++ = NEW_ENV_VALUE;
154013e3f4d6SMark Murray vp = NULL;
154113e3f4d6SMark Murray } else
154213e3f4d6SMark Murray break;
154313e3f4d6SMark Murray }
154413e3f4d6SMark Murray }
154513e3f4d6SMark Murray
154613e3f4d6SMark Murray int
opt_welldefined(char * ep)154713e3f4d6SMark Murray opt_welldefined(char *ep)
154813e3f4d6SMark Murray {
154913e3f4d6SMark Murray if ((strcmp(ep, "USER") == 0) ||
155013e3f4d6SMark Murray (strcmp(ep, "DISPLAY") == 0) ||
155113e3f4d6SMark Murray (strcmp(ep, "PRINTER") == 0) ||
155213e3f4d6SMark Murray (strcmp(ep, "SYSTEMTYPE") == 0) ||
155313e3f4d6SMark Murray (strcmp(ep, "JOB") == 0) ||
155413e3f4d6SMark Murray (strcmp(ep, "ACCT") == 0))
155513e3f4d6SMark Murray return(1);
155613e3f4d6SMark Murray return(0);
155713e3f4d6SMark Murray }
155813e3f4d6SMark Murray
155913e3f4d6SMark Murray void
env_opt_end(int emptyok)156013e3f4d6SMark Murray env_opt_end(int emptyok)
156113e3f4d6SMark Murray {
156213e3f4d6SMark Murray int len;
156313e3f4d6SMark Murray
1564c19800e8SDoug Rabson if (opt_replyp + 2 > opt_replyend)
1565c19800e8SDoug Rabson return;
1566c19800e8SDoug Rabson len = opt_replyp + 2 - opt_reply;
156713e3f4d6SMark Murray if (emptyok || len > 6) {
156813e3f4d6SMark Murray *opt_replyp++ = IAC;
156913e3f4d6SMark Murray *opt_replyp++ = SE;
157013e3f4d6SMark Murray if (NETROOM() > len) {
157113e3f4d6SMark Murray ring_supply_data(&netoring, opt_reply, len);
157213e3f4d6SMark Murray printsub('>', &opt_reply[2], len - 2);
157313e3f4d6SMark Murray }
157413e3f4d6SMark Murray /*@*/ else printf("slc_end_reply: not enough room\n");
157513e3f4d6SMark Murray }
157613e3f4d6SMark Murray if (opt_reply) {
157713e3f4d6SMark Murray free(opt_reply);
157813e3f4d6SMark Murray opt_reply = opt_replyp = opt_replyend = NULL;
157913e3f4d6SMark Murray }
158013e3f4d6SMark Murray }
158113e3f4d6SMark Murray
158213e3f4d6SMark Murray
158313e3f4d6SMark Murray
158413e3f4d6SMark Murray int
telrcv(void)158513e3f4d6SMark Murray telrcv(void)
158613e3f4d6SMark Murray {
158713e3f4d6SMark Murray int c;
158813e3f4d6SMark Murray int scc;
158913e3f4d6SMark Murray unsigned char *sbp = NULL;
159013e3f4d6SMark Murray int count;
159113e3f4d6SMark Murray int returnValue = 0;
159213e3f4d6SMark Murray
159313e3f4d6SMark Murray scc = 0;
159413e3f4d6SMark Murray count = 0;
159513e3f4d6SMark Murray while (TTYROOM() > 2) {
159613e3f4d6SMark Murray if (scc == 0) {
159713e3f4d6SMark Murray if (count) {
159813e3f4d6SMark Murray ring_consumed(&netiring, count);
159913e3f4d6SMark Murray returnValue = 1;
160013e3f4d6SMark Murray count = 0;
160113e3f4d6SMark Murray }
160213e3f4d6SMark Murray sbp = netiring.consume;
160313e3f4d6SMark Murray scc = ring_full_consecutive(&netiring);
160413e3f4d6SMark Murray if (scc == 0) {
160513e3f4d6SMark Murray /* No more data coming in */
160613e3f4d6SMark Murray break;
160713e3f4d6SMark Murray }
160813e3f4d6SMark Murray }
160913e3f4d6SMark Murray
161013e3f4d6SMark Murray c = *sbp++ & 0xff, scc--; count++;
161113e3f4d6SMark Murray #if defined(ENCRYPTION)
161213e3f4d6SMark Murray if (decrypt_input)
161313e3f4d6SMark Murray c = (*decrypt_input)(c);
161413e3f4d6SMark Murray #endif
161513e3f4d6SMark Murray
161613e3f4d6SMark Murray switch (telrcv_state) {
161713e3f4d6SMark Murray
161813e3f4d6SMark Murray case TS_CR:
161913e3f4d6SMark Murray telrcv_state = TS_DATA;
162013e3f4d6SMark Murray if (c == '\0') {
162113e3f4d6SMark Murray break; /* Ignore \0 after CR */
162213e3f4d6SMark Murray }
162313e3f4d6SMark Murray else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
162413e3f4d6SMark Murray TTYADD(c);
162513e3f4d6SMark Murray break;
162613e3f4d6SMark Murray }
162713e3f4d6SMark Murray /* Else, fall through */
162813e3f4d6SMark Murray
162913e3f4d6SMark Murray case TS_DATA:
163013e3f4d6SMark Murray if (c == IAC) {
163113e3f4d6SMark Murray telrcv_state = TS_IAC;
163213e3f4d6SMark Murray break;
163313e3f4d6SMark Murray }
163413e3f4d6SMark Murray /*
163513e3f4d6SMark Murray * The 'crmod' hack (see following) is needed
163613e3f4d6SMark Murray * since we can't set CRMOD on output only.
163713e3f4d6SMark Murray * Machines like MULTICS like to send \r without
163813e3f4d6SMark Murray * \n; since we must turn off CRMOD to get proper
163913e3f4d6SMark Murray * input, the mapping is done here (sigh).
164013e3f4d6SMark Murray */
164113e3f4d6SMark Murray if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
164213e3f4d6SMark Murray if (scc > 0) {
164313e3f4d6SMark Murray c = *sbp&0xff;
164413e3f4d6SMark Murray #if defined(ENCRYPTION)
164513e3f4d6SMark Murray if (decrypt_input)
164613e3f4d6SMark Murray c = (*decrypt_input)(c);
164713e3f4d6SMark Murray #endif
164813e3f4d6SMark Murray if (c == 0) {
164913e3f4d6SMark Murray sbp++, scc--; count++;
165013e3f4d6SMark Murray /* a "true" CR */
165113e3f4d6SMark Murray TTYADD('\r');
165213e3f4d6SMark Murray } else if (my_want_state_is_dont(TELOPT_ECHO) &&
165313e3f4d6SMark Murray (c == '\n')) {
165413e3f4d6SMark Murray sbp++, scc--; count++;
165513e3f4d6SMark Murray TTYADD('\n');
165613e3f4d6SMark Murray } else {
165713e3f4d6SMark Murray #if defined(ENCRYPTION)
165813e3f4d6SMark Murray if (decrypt_input)
165913e3f4d6SMark Murray (*decrypt_input)(-1);
166013e3f4d6SMark Murray #endif
166113e3f4d6SMark Murray
166213e3f4d6SMark Murray TTYADD('\r');
166313e3f4d6SMark Murray if (crmod) {
166413e3f4d6SMark Murray TTYADD('\n');
166513e3f4d6SMark Murray }
166613e3f4d6SMark Murray }
166713e3f4d6SMark Murray } else {
166813e3f4d6SMark Murray telrcv_state = TS_CR;
166913e3f4d6SMark Murray TTYADD('\r');
167013e3f4d6SMark Murray if (crmod) {
167113e3f4d6SMark Murray TTYADD('\n');
167213e3f4d6SMark Murray }
167313e3f4d6SMark Murray }
167413e3f4d6SMark Murray } else {
167513e3f4d6SMark Murray TTYADD(c);
167613e3f4d6SMark Murray }
167713e3f4d6SMark Murray continue;
167813e3f4d6SMark Murray
167913e3f4d6SMark Murray case TS_IAC:
168013e3f4d6SMark Murray process_iac:
168113e3f4d6SMark Murray switch (c) {
168213e3f4d6SMark Murray
168313e3f4d6SMark Murray case WILL:
168413e3f4d6SMark Murray telrcv_state = TS_WILL;
168513e3f4d6SMark Murray continue;
168613e3f4d6SMark Murray
168713e3f4d6SMark Murray case WONT:
168813e3f4d6SMark Murray telrcv_state = TS_WONT;
168913e3f4d6SMark Murray continue;
169013e3f4d6SMark Murray
169113e3f4d6SMark Murray case DO:
169213e3f4d6SMark Murray telrcv_state = TS_DO;
169313e3f4d6SMark Murray continue;
169413e3f4d6SMark Murray
169513e3f4d6SMark Murray case DONT:
169613e3f4d6SMark Murray telrcv_state = TS_DONT;
169713e3f4d6SMark Murray continue;
169813e3f4d6SMark Murray
169913e3f4d6SMark Murray case DM:
170013e3f4d6SMark Murray /*
170113e3f4d6SMark Murray * We may have missed an urgent notification,
170213e3f4d6SMark Murray * so make sure we flush whatever is in the
170313e3f4d6SMark Murray * buffer currently.
170413e3f4d6SMark Murray */
170513e3f4d6SMark Murray printoption("RCVD", IAC, DM);
170613e3f4d6SMark Murray SYNCHing = 1;
170713e3f4d6SMark Murray ttyflush(1);
170813e3f4d6SMark Murray SYNCHing = stilloob();
170913e3f4d6SMark Murray settimer(gotDM);
171013e3f4d6SMark Murray break;
171113e3f4d6SMark Murray
171213e3f4d6SMark Murray case SB:
171313e3f4d6SMark Murray SB_CLEAR();
171413e3f4d6SMark Murray telrcv_state = TS_SB;
171513e3f4d6SMark Murray continue;
171613e3f4d6SMark Murray
171713e3f4d6SMark Murray
171813e3f4d6SMark Murray case IAC:
171913e3f4d6SMark Murray TTYADD(IAC);
172013e3f4d6SMark Murray break;
172113e3f4d6SMark Murray
172213e3f4d6SMark Murray case NOP:
172313e3f4d6SMark Murray case GA:
172413e3f4d6SMark Murray default:
172513e3f4d6SMark Murray printoption("RCVD", IAC, c);
172613e3f4d6SMark Murray break;
172713e3f4d6SMark Murray }
172813e3f4d6SMark Murray telrcv_state = TS_DATA;
172913e3f4d6SMark Murray continue;
173013e3f4d6SMark Murray
173113e3f4d6SMark Murray case TS_WILL:
173213e3f4d6SMark Murray printoption("RCVD", WILL, c);
173313e3f4d6SMark Murray willoption(c);
173413e3f4d6SMark Murray telrcv_state = TS_DATA;
173513e3f4d6SMark Murray continue;
173613e3f4d6SMark Murray
173713e3f4d6SMark Murray case TS_WONT:
173813e3f4d6SMark Murray printoption("RCVD", WONT, c);
173913e3f4d6SMark Murray wontoption(c);
174013e3f4d6SMark Murray telrcv_state = TS_DATA;
174113e3f4d6SMark Murray continue;
174213e3f4d6SMark Murray
174313e3f4d6SMark Murray case TS_DO:
174413e3f4d6SMark Murray printoption("RCVD", DO, c);
174513e3f4d6SMark Murray dooption(c);
174613e3f4d6SMark Murray if (c == TELOPT_NAWS) {
174713e3f4d6SMark Murray sendnaws();
174813e3f4d6SMark Murray } else if (c == TELOPT_LFLOW) {
174913e3f4d6SMark Murray localflow = 1;
175013e3f4d6SMark Murray setcommandmode();
175113e3f4d6SMark Murray setconnmode(0);
175213e3f4d6SMark Murray }
175313e3f4d6SMark Murray telrcv_state = TS_DATA;
175413e3f4d6SMark Murray continue;
175513e3f4d6SMark Murray
175613e3f4d6SMark Murray case TS_DONT:
175713e3f4d6SMark Murray printoption("RCVD", DONT, c);
175813e3f4d6SMark Murray dontoption(c);
175913e3f4d6SMark Murray flushline = 1;
176013e3f4d6SMark Murray setconnmode(0); /* set new tty mode (maybe) */
176113e3f4d6SMark Murray telrcv_state = TS_DATA;
176213e3f4d6SMark Murray continue;
176313e3f4d6SMark Murray
176413e3f4d6SMark Murray case TS_SB:
176513e3f4d6SMark Murray if (c == IAC) {
176613e3f4d6SMark Murray telrcv_state = TS_SE;
176713e3f4d6SMark Murray } else {
176813e3f4d6SMark Murray SB_ACCUM(c);
176913e3f4d6SMark Murray }
177013e3f4d6SMark Murray continue;
177113e3f4d6SMark Murray
177213e3f4d6SMark Murray case TS_SE:
177313e3f4d6SMark Murray if (c != SE) {
177413e3f4d6SMark Murray if (c != IAC) {
177513e3f4d6SMark Murray /*
177613e3f4d6SMark Murray * This is an error. We only expect to get
177713e3f4d6SMark Murray * "IAC IAC" or "IAC SE". Several things may
1778c19800e8SDoug Rabson * have happened. An IAC was not doubled, the
177913e3f4d6SMark Murray * IAC SE was left off, or another option got
178013e3f4d6SMark Murray * inserted into the suboption are all possibilities.
178113e3f4d6SMark Murray * If we assume that the IAC was not doubled,
178213e3f4d6SMark Murray * and really the IAC SE was left off, we could
1783c19800e8SDoug Rabson * get into an infinite loop here. So, instead,
178413e3f4d6SMark Murray * we terminate the suboption, and process the
178513e3f4d6SMark Murray * partial suboption if we can.
178613e3f4d6SMark Murray */
178713e3f4d6SMark Murray SB_ACCUM(IAC);
178813e3f4d6SMark Murray SB_ACCUM(c);
178913e3f4d6SMark Murray subpointer -= 2;
179013e3f4d6SMark Murray SB_TERM();
179113e3f4d6SMark Murray
179213e3f4d6SMark Murray printoption("In SUBOPTION processing, RCVD", IAC, c);
179313e3f4d6SMark Murray suboption(); /* handle sub-option */
179413e3f4d6SMark Murray telrcv_state = TS_IAC;
179513e3f4d6SMark Murray goto process_iac;
179613e3f4d6SMark Murray }
179713e3f4d6SMark Murray SB_ACCUM(c);
179813e3f4d6SMark Murray telrcv_state = TS_SB;
179913e3f4d6SMark Murray } else {
180013e3f4d6SMark Murray SB_ACCUM(IAC);
180113e3f4d6SMark Murray SB_ACCUM(SE);
180213e3f4d6SMark Murray subpointer -= 2;
180313e3f4d6SMark Murray SB_TERM();
180413e3f4d6SMark Murray suboption(); /* handle sub-option */
180513e3f4d6SMark Murray telrcv_state = TS_DATA;
180613e3f4d6SMark Murray }
180713e3f4d6SMark Murray }
180813e3f4d6SMark Murray }
180913e3f4d6SMark Murray if (count)
181013e3f4d6SMark Murray ring_consumed(&netiring, count);
181113e3f4d6SMark Murray return returnValue||count;
181213e3f4d6SMark Murray }
181313e3f4d6SMark Murray
181413e3f4d6SMark Murray static int bol = 1, local = 0;
181513e3f4d6SMark Murray
181613e3f4d6SMark Murray int
rlogin_susp(void)181713e3f4d6SMark Murray rlogin_susp(void)
181813e3f4d6SMark Murray {
181913e3f4d6SMark Murray if (local) {
182013e3f4d6SMark Murray local = 0;
182113e3f4d6SMark Murray bol = 1;
182213e3f4d6SMark Murray command(0, "z\n", 2);
182313e3f4d6SMark Murray return(1);
182413e3f4d6SMark Murray }
182513e3f4d6SMark Murray return(0);
182613e3f4d6SMark Murray }
182713e3f4d6SMark Murray
182813e3f4d6SMark Murray static int
telsnd()182913e3f4d6SMark Murray telsnd()
183013e3f4d6SMark Murray {
183113e3f4d6SMark Murray int tcc;
183213e3f4d6SMark Murray int count;
183313e3f4d6SMark Murray int returnValue = 0;
183413e3f4d6SMark Murray unsigned char *tbp = NULL;
183513e3f4d6SMark Murray
183613e3f4d6SMark Murray tcc = 0;
183713e3f4d6SMark Murray count = 0;
183813e3f4d6SMark Murray while (NETROOM() > 2) {
183913e3f4d6SMark Murray int sc;
184013e3f4d6SMark Murray int c;
184113e3f4d6SMark Murray
184213e3f4d6SMark Murray if (tcc == 0) {
184313e3f4d6SMark Murray if (count) {
184413e3f4d6SMark Murray ring_consumed(&ttyiring, count);
184513e3f4d6SMark Murray returnValue = 1;
184613e3f4d6SMark Murray count = 0;
184713e3f4d6SMark Murray }
184813e3f4d6SMark Murray tbp = ttyiring.consume;
184913e3f4d6SMark Murray tcc = ring_full_consecutive(&ttyiring);
185013e3f4d6SMark Murray if (tcc == 0) {
185113e3f4d6SMark Murray break;
185213e3f4d6SMark Murray }
185313e3f4d6SMark Murray }
185413e3f4d6SMark Murray c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
185513e3f4d6SMark Murray if (rlogin != _POSIX_VDISABLE) {
185613e3f4d6SMark Murray if (bol) {
185713e3f4d6SMark Murray bol = 0;
185813e3f4d6SMark Murray if (sc == rlogin) {
185913e3f4d6SMark Murray local = 1;
186013e3f4d6SMark Murray continue;
186113e3f4d6SMark Murray }
186213e3f4d6SMark Murray } else if (local) {
186313e3f4d6SMark Murray local = 0;
186413e3f4d6SMark Murray if (sc == '.' || c == termEofChar) {
186513e3f4d6SMark Murray bol = 1;
186613e3f4d6SMark Murray command(0, "close\n", 6);
186713e3f4d6SMark Murray continue;
186813e3f4d6SMark Murray }
186913e3f4d6SMark Murray if (sc == termSuspChar) {
187013e3f4d6SMark Murray bol = 1;
187113e3f4d6SMark Murray command(0, "z\n", 2);
187213e3f4d6SMark Murray continue;
187313e3f4d6SMark Murray }
187413e3f4d6SMark Murray if (sc == escape) {
187513e3f4d6SMark Murray command(0, (char *)tbp, tcc);
187613e3f4d6SMark Murray bol = 1;
187713e3f4d6SMark Murray count += tcc;
187813e3f4d6SMark Murray tcc = 0;
187913e3f4d6SMark Murray flushline = 1;
188013e3f4d6SMark Murray break;
188113e3f4d6SMark Murray }
188213e3f4d6SMark Murray if (sc != rlogin) {
188313e3f4d6SMark Murray ++tcc;
188413e3f4d6SMark Murray --tbp;
188513e3f4d6SMark Murray --count;
188613e3f4d6SMark Murray c = sc = rlogin;
188713e3f4d6SMark Murray }
188813e3f4d6SMark Murray }
188913e3f4d6SMark Murray if ((sc == '\n') || (sc == '\r'))
189013e3f4d6SMark Murray bol = 1;
189113e3f4d6SMark Murray } else if (sc == escape) {
189213e3f4d6SMark Murray /*
189313e3f4d6SMark Murray * Double escape is a pass through of a single escape character.
189413e3f4d6SMark Murray */
189513e3f4d6SMark Murray if (tcc && strip(*tbp) == escape) {
189613e3f4d6SMark Murray tbp++;
189713e3f4d6SMark Murray tcc--;
189813e3f4d6SMark Murray count++;
189913e3f4d6SMark Murray bol = 0;
190013e3f4d6SMark Murray } else {
190113e3f4d6SMark Murray command(0, (char *)tbp, tcc);
190213e3f4d6SMark Murray bol = 1;
190313e3f4d6SMark Murray count += tcc;
190413e3f4d6SMark Murray tcc = 0;
190513e3f4d6SMark Murray flushline = 1;
190613e3f4d6SMark Murray break;
190713e3f4d6SMark Murray }
190813e3f4d6SMark Murray } else
190913e3f4d6SMark Murray bol = 0;
191013e3f4d6SMark Murray #ifdef KLUDGELINEMODE
191113e3f4d6SMark Murray if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
191213e3f4d6SMark Murray if (tcc > 0 && strip(*tbp) == echoc) {
191313e3f4d6SMark Murray tcc--; tbp++; count++;
191413e3f4d6SMark Murray } else {
191513e3f4d6SMark Murray dontlecho = !dontlecho;
191613e3f4d6SMark Murray settimer(echotoggle);
191713e3f4d6SMark Murray setconnmode(0);
191813e3f4d6SMark Murray flushline = 1;
191913e3f4d6SMark Murray break;
192013e3f4d6SMark Murray }
192113e3f4d6SMark Murray }
192213e3f4d6SMark Murray #endif
192313e3f4d6SMark Murray if (MODE_LOCAL_CHARS(globalmode)) {
192413e3f4d6SMark Murray if (TerminalSpecialChars(sc) == 0) {
192513e3f4d6SMark Murray bol = 1;
192613e3f4d6SMark Murray break;
192713e3f4d6SMark Murray }
192813e3f4d6SMark Murray }
192913e3f4d6SMark Murray if (my_want_state_is_wont(TELOPT_BINARY)) {
193013e3f4d6SMark Murray switch (c) {
193113e3f4d6SMark Murray case '\n':
193213e3f4d6SMark Murray /*
193313e3f4d6SMark Murray * If we are in CRMOD mode (\r ==> \n)
193413e3f4d6SMark Murray * on our local machine, then probably
193513e3f4d6SMark Murray * a newline (unix) is CRLF (TELNET).
193613e3f4d6SMark Murray */
193713e3f4d6SMark Murray if (MODE_LOCAL_CHARS(globalmode)) {
193813e3f4d6SMark Murray NETADD('\r');
193913e3f4d6SMark Murray }
194013e3f4d6SMark Murray NETADD('\n');
194113e3f4d6SMark Murray bol = flushline = 1;
194213e3f4d6SMark Murray break;
194313e3f4d6SMark Murray case '\r':
194413e3f4d6SMark Murray if (!crlf) {
194513e3f4d6SMark Murray NET2ADD('\r', '\0');
194613e3f4d6SMark Murray } else {
194713e3f4d6SMark Murray NET2ADD('\r', '\n');
194813e3f4d6SMark Murray }
194913e3f4d6SMark Murray bol = flushline = 1;
195013e3f4d6SMark Murray break;
195113e3f4d6SMark Murray case IAC:
195213e3f4d6SMark Murray NET2ADD(IAC, IAC);
195313e3f4d6SMark Murray break;
195413e3f4d6SMark Murray default:
195513e3f4d6SMark Murray NETADD(c);
195613e3f4d6SMark Murray break;
195713e3f4d6SMark Murray }
195813e3f4d6SMark Murray } else if (c == IAC) {
195913e3f4d6SMark Murray NET2ADD(IAC, IAC);
196013e3f4d6SMark Murray } else {
196113e3f4d6SMark Murray NETADD(c);
196213e3f4d6SMark Murray }
196313e3f4d6SMark Murray }
196413e3f4d6SMark Murray if (count)
196513e3f4d6SMark Murray ring_consumed(&ttyiring, count);
196613e3f4d6SMark Murray return returnValue||count; /* Non-zero if we did anything */
196713e3f4d6SMark Murray }
196813e3f4d6SMark Murray
196913e3f4d6SMark Murray /*
197013e3f4d6SMark Murray * Scheduler()
197113e3f4d6SMark Murray *
197213e3f4d6SMark Murray * Try to do something.
197313e3f4d6SMark Murray *
197413e3f4d6SMark Murray * If we do something useful, return 1; else return 0.
197513e3f4d6SMark Murray *
197613e3f4d6SMark Murray */
197713e3f4d6SMark Murray
197813e3f4d6SMark Murray
19794137ff4cSJacques Vidrine int
Scheduler(int block)198013e3f4d6SMark Murray Scheduler(int block) /* should we block in the select ? */
198113e3f4d6SMark Murray {
198213e3f4d6SMark Murray /* One wants to be a bit careful about setting returnValue
198313e3f4d6SMark Murray * to one, since a one implies we did some useful work,
198413e3f4d6SMark Murray * and therefore probably won't be called to block next
198513e3f4d6SMark Murray * time (TN3270 mode only).
198613e3f4d6SMark Murray */
198713e3f4d6SMark Murray int returnValue;
198813e3f4d6SMark Murray int netin, netout, netex, ttyin, ttyout;
198913e3f4d6SMark Murray
199013e3f4d6SMark Murray /* Decide which rings should be processed */
199113e3f4d6SMark Murray
199213e3f4d6SMark Murray netout = ring_full_count(&netoring) &&
199313e3f4d6SMark Murray (flushline ||
199413e3f4d6SMark Murray (my_want_state_is_wont(TELOPT_LINEMODE)
199513e3f4d6SMark Murray #ifdef KLUDGELINEMODE
199613e3f4d6SMark Murray && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
199713e3f4d6SMark Murray #endif
199813e3f4d6SMark Murray ) ||
199913e3f4d6SMark Murray my_want_state_is_will(TELOPT_BINARY));
200013e3f4d6SMark Murray ttyout = ring_full_count(&ttyoring);
200113e3f4d6SMark Murray
200213e3f4d6SMark Murray ttyin = ring_empty_count(&ttyiring);
200313e3f4d6SMark Murray
200413e3f4d6SMark Murray netin = !ISend && ring_empty_count(&netiring);
200513e3f4d6SMark Murray
200613e3f4d6SMark Murray netex = !SYNCHing;
200713e3f4d6SMark Murray
200813e3f4d6SMark Murray /* If we have seen a signal recently, reset things */
200913e3f4d6SMark Murray
20104137ff4cSJacques Vidrine if (scheduler_lockout_tty) {
20114137ff4cSJacques Vidrine ttyin = ttyout = 0;
20124137ff4cSJacques Vidrine }
20134137ff4cSJacques Vidrine
201413e3f4d6SMark Murray /* Call to system code to process rings */
201513e3f4d6SMark Murray
201613e3f4d6SMark Murray returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
201713e3f4d6SMark Murray
201813e3f4d6SMark Murray /* Now, look at the input rings, looking for work to do. */
201913e3f4d6SMark Murray
202013e3f4d6SMark Murray if (ring_full_count(&ttyiring)) {
202113e3f4d6SMark Murray returnValue |= telsnd();
202213e3f4d6SMark Murray }
202313e3f4d6SMark Murray
202413e3f4d6SMark Murray if (ring_full_count(&netiring)) {
202513e3f4d6SMark Murray returnValue |= telrcv();
202613e3f4d6SMark Murray }
202713e3f4d6SMark Murray return returnValue;
202813e3f4d6SMark Murray }
202913e3f4d6SMark Murray
2030c19800e8SDoug Rabson extern int auth_has_failed; /* XXX should be somewhere else */
2031c19800e8SDoug Rabson
203213e3f4d6SMark Murray /*
203313e3f4d6SMark Murray * Select from tty and network...
203413e3f4d6SMark Murray */
203513e3f4d6SMark Murray void
my_telnet(char * user)203613e3f4d6SMark Murray my_telnet(char *user)
203713e3f4d6SMark Murray {
20384137ff4cSJacques Vidrine int printed_encrypt = 0;
20394137ff4cSJacques Vidrine
204013e3f4d6SMark Murray sys_telnet_init();
204113e3f4d6SMark Murray
204213e3f4d6SMark Murray #if defined(AUTHENTICATION) || defined(ENCRYPTION)
204313e3f4d6SMark Murray {
204413e3f4d6SMark Murray static char local_host[256] = { 0 };
204513e3f4d6SMark Murray
204613e3f4d6SMark Murray if (!local_host[0]) {
204713e3f4d6SMark Murray /* XXX - should be k_gethostname? */
204813e3f4d6SMark Murray gethostname(local_host, sizeof(local_host));
204913e3f4d6SMark Murray local_host[sizeof(local_host)-1] = 0;
205013e3f4d6SMark Murray }
205113e3f4d6SMark Murray auth_encrypt_init(local_host, hostname, "TELNET", 0);
205213e3f4d6SMark Murray auth_encrypt_user(user);
205313e3f4d6SMark Murray }
205413e3f4d6SMark Murray #endif
205513e3f4d6SMark Murray if (telnetport) {
205613e3f4d6SMark Murray #if defined(AUTHENTICATION)
205713e3f4d6SMark Murray if (autologin)
205813e3f4d6SMark Murray send_will(TELOPT_AUTHENTICATION, 1);
205913e3f4d6SMark Murray #endif
206013e3f4d6SMark Murray #if defined(ENCRYPTION)
206113e3f4d6SMark Murray send_do(TELOPT_ENCRYPT, 1);
206213e3f4d6SMark Murray send_will(TELOPT_ENCRYPT, 1);
206313e3f4d6SMark Murray #endif
206413e3f4d6SMark Murray send_do(TELOPT_SGA, 1);
206513e3f4d6SMark Murray send_will(TELOPT_TTYPE, 1);
206613e3f4d6SMark Murray send_will(TELOPT_NAWS, 1);
206713e3f4d6SMark Murray send_will(TELOPT_TSPEED, 1);
206813e3f4d6SMark Murray send_will(TELOPT_LFLOW, 1);
206913e3f4d6SMark Murray send_will(TELOPT_LINEMODE, 1);
207013e3f4d6SMark Murray send_will(TELOPT_NEW_ENVIRON, 1);
207113e3f4d6SMark Murray send_do(TELOPT_STATUS, 1);
207213e3f4d6SMark Murray if (env_getvalue((unsigned char *)"DISPLAY"))
207313e3f4d6SMark Murray send_will(TELOPT_XDISPLOC, 1);
207413e3f4d6SMark Murray if (binary)
207513e3f4d6SMark Murray tel_enter_binary(binary);
207613e3f4d6SMark Murray }
207713e3f4d6SMark Murray
20784137ff4cSJacques Vidrine #ifdef ENCRYPTION
20794137ff4cSJacques Vidrine /*
20804137ff4cSJacques Vidrine * Note: we assume a tie to the authentication option here. This
20814137ff4cSJacques Vidrine * is necessary so that authentication fails, we don't spin
20824137ff4cSJacques Vidrine * forever.
20834137ff4cSJacques Vidrine */
20848373020dSJacques Vidrine if (telnetport && wantencryption) {
20854137ff4cSJacques Vidrine time_t timeout = time(0) + 60;
20864137ff4cSJacques Vidrine
20874137ff4cSJacques Vidrine send_do(TELOPT_ENCRYPT, 1);
20884137ff4cSJacques Vidrine send_will(TELOPT_ENCRYPT, 1);
20894137ff4cSJacques Vidrine while (1) {
20904137ff4cSJacques Vidrine if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
20918373020dSJacques Vidrine if (wantencryption == -1) {
20928373020dSJacques Vidrine break;
20938373020dSJacques Vidrine } else {
20944137ff4cSJacques Vidrine printf("\nServer refused to negotiate authentication,\n");
20954137ff4cSJacques Vidrine printf("which is required for encryption.\n");
20964137ff4cSJacques Vidrine Exit(1);
20974137ff4cSJacques Vidrine }
20988373020dSJacques Vidrine }
20994137ff4cSJacques Vidrine if (auth_has_failed) {
2100c19800e8SDoug Rabson printf("\nAuthentication negotiation has failed,\n");
21014137ff4cSJacques Vidrine printf("which is required for encryption.\n");
21024137ff4cSJacques Vidrine Exit(1);
21034137ff4cSJacques Vidrine }
21044137ff4cSJacques Vidrine if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
21054137ff4cSJacques Vidrine my_want_state_is_wont(TELOPT_ENCRYPT)) {
21064137ff4cSJacques Vidrine printf("\nServer refused to negotiate encryption.\n");
21074137ff4cSJacques Vidrine Exit(1);
21084137ff4cSJacques Vidrine }
21094137ff4cSJacques Vidrine if (encrypt_is_encrypting())
21104137ff4cSJacques Vidrine break;
21114137ff4cSJacques Vidrine if (time(0) > timeout) {
21124137ff4cSJacques Vidrine printf("\nEncryption could not be enabled.\n");
21134137ff4cSJacques Vidrine Exit(1);
21144137ff4cSJacques Vidrine }
21154137ff4cSJacques Vidrine if (printed_encrypt == 0) {
21164137ff4cSJacques Vidrine printed_encrypt = 1;
21174137ff4cSJacques Vidrine printf("Waiting for encryption to be negotiated...\n");
21184137ff4cSJacques Vidrine /*
21194137ff4cSJacques Vidrine * Turn on MODE_TRAPSIG and then turn off localchars
21204137ff4cSJacques Vidrine * so that ^C will cause telnet to exit.
21214137ff4cSJacques Vidrine */
21224137ff4cSJacques Vidrine TerminalNewMode(getconnmode()|MODE_TRAPSIG);
21234137ff4cSJacques Vidrine intr_waiting = 1;
21244137ff4cSJacques Vidrine }
21254137ff4cSJacques Vidrine if (intr_happened) {
21264137ff4cSJacques Vidrine printf("\nUser interrupt.\n");
21274137ff4cSJacques Vidrine Exit(1);
21284137ff4cSJacques Vidrine }
2129c19800e8SDoug Rabson if (telnet_spin()) {
2130c19800e8SDoug Rabson printf("\nServer disconnected.\n");
2131c19800e8SDoug Rabson Exit(1);
2132c19800e8SDoug Rabson }
2133c19800e8SDoug Rabson
21344137ff4cSJacques Vidrine }
21354137ff4cSJacques Vidrine if (printed_encrypt) {
21368373020dSJacques Vidrine printf("Encryption negotiated.\n");
21374137ff4cSJacques Vidrine intr_waiting = 0;
21384137ff4cSJacques Vidrine setconnmode(0);
21394137ff4cSJacques Vidrine }
21404137ff4cSJacques Vidrine }
21414137ff4cSJacques Vidrine #endif
21424137ff4cSJacques Vidrine
214313e3f4d6SMark Murray for (;;) {
214413e3f4d6SMark Murray int schedValue;
214513e3f4d6SMark Murray
214613e3f4d6SMark Murray while ((schedValue = Scheduler(0)) != 0) {
214713e3f4d6SMark Murray if (schedValue == -1) {
214813e3f4d6SMark Murray setcommandmode();
214913e3f4d6SMark Murray return;
215013e3f4d6SMark Murray }
215113e3f4d6SMark Murray }
215213e3f4d6SMark Murray
215313e3f4d6SMark Murray if (Scheduler(1) == -1) {
215413e3f4d6SMark Murray setcommandmode();
215513e3f4d6SMark Murray return;
215613e3f4d6SMark Murray }
215713e3f4d6SMark Murray }
215813e3f4d6SMark Murray }
215913e3f4d6SMark Murray
216013e3f4d6SMark Murray /*
216113e3f4d6SMark Murray * netclear()
216213e3f4d6SMark Murray *
216313e3f4d6SMark Murray * We are about to do a TELNET SYNCH operation. Clear
216413e3f4d6SMark Murray * the path to the network.
216513e3f4d6SMark Murray *
216613e3f4d6SMark Murray * Things are a bit tricky since we may have sent the first
216713e3f4d6SMark Murray * byte or so of a previous TELNET command into the network.
216813e3f4d6SMark Murray * So, we have to scan the network buffer from the beginning
216913e3f4d6SMark Murray * until we are up to where we want to be.
217013e3f4d6SMark Murray *
217113e3f4d6SMark Murray * A side effect of what we do, just to keep things
217213e3f4d6SMark Murray * simple, is to clear the urgent data pointer. The principal
217313e3f4d6SMark Murray * caller should be setting the urgent data pointer AFTER calling
217413e3f4d6SMark Murray * us in any case.
217513e3f4d6SMark Murray */
217613e3f4d6SMark Murray
217713e3f4d6SMark Murray static void
netclear()217813e3f4d6SMark Murray netclear()
217913e3f4d6SMark Murray {
218013e3f4d6SMark Murray #if 0 /* XXX */
218113e3f4d6SMark Murray char *thisitem, *next;
218213e3f4d6SMark Murray char *good;
218313e3f4d6SMark Murray #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
218413e3f4d6SMark Murray ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
218513e3f4d6SMark Murray
218613e3f4d6SMark Murray thisitem = netobuf;
218713e3f4d6SMark Murray
218813e3f4d6SMark Murray while ((next = nextitem(thisitem)) <= netobuf.send) {
218913e3f4d6SMark Murray thisitem = next;
219013e3f4d6SMark Murray }
219113e3f4d6SMark Murray
219213e3f4d6SMark Murray /* Now, thisitem is first before/at boundary. */
219313e3f4d6SMark Murray
219413e3f4d6SMark Murray good = netobuf; /* where the good bytes go */
219513e3f4d6SMark Murray
219613e3f4d6SMark Murray while (netoring.add > thisitem) {
219713e3f4d6SMark Murray if (wewant(thisitem)) {
219813e3f4d6SMark Murray int length;
219913e3f4d6SMark Murray
220013e3f4d6SMark Murray next = thisitem;
220113e3f4d6SMark Murray do {
220213e3f4d6SMark Murray next = nextitem(next);
220313e3f4d6SMark Murray } while (wewant(next) && (nfrontp > next));
220413e3f4d6SMark Murray length = next-thisitem;
220513e3f4d6SMark Murray memmove(good, thisitem, length);
220613e3f4d6SMark Murray good += length;
220713e3f4d6SMark Murray thisitem = next;
220813e3f4d6SMark Murray } else {
220913e3f4d6SMark Murray thisitem = nextitem(thisitem);
221013e3f4d6SMark Murray }
221113e3f4d6SMark Murray }
221213e3f4d6SMark Murray
221313e3f4d6SMark Murray #endif /* 0 */
221413e3f4d6SMark Murray }
221513e3f4d6SMark Murray
221613e3f4d6SMark Murray /*
221713e3f4d6SMark Murray * These routines add various telnet commands to the data stream.
221813e3f4d6SMark Murray */
221913e3f4d6SMark Murray
222013e3f4d6SMark Murray static void
doflush()222113e3f4d6SMark Murray doflush()
222213e3f4d6SMark Murray {
222313e3f4d6SMark Murray NET2ADD(IAC, DO);
222413e3f4d6SMark Murray NETADD(TELOPT_TM);
222513e3f4d6SMark Murray flushline = 1;
222613e3f4d6SMark Murray flushout = 1;
222713e3f4d6SMark Murray ttyflush(1); /* Flush/drop output */
222813e3f4d6SMark Murray /* do printoption AFTER flush, otherwise the output gets tossed... */
222913e3f4d6SMark Murray printoption("SENT", DO, TELOPT_TM);
223013e3f4d6SMark Murray }
223113e3f4d6SMark Murray
223213e3f4d6SMark Murray void
xmitAO(void)223313e3f4d6SMark Murray xmitAO(void)
223413e3f4d6SMark Murray {
223513e3f4d6SMark Murray NET2ADD(IAC, AO);
223613e3f4d6SMark Murray printoption("SENT", IAC, AO);
223713e3f4d6SMark Murray if (autoflush) {
223813e3f4d6SMark Murray doflush();
223913e3f4d6SMark Murray }
224013e3f4d6SMark Murray }
224113e3f4d6SMark Murray
224213e3f4d6SMark Murray
224313e3f4d6SMark Murray void
xmitEL(void)224413e3f4d6SMark Murray xmitEL(void)
224513e3f4d6SMark Murray {
224613e3f4d6SMark Murray NET2ADD(IAC, EL);
224713e3f4d6SMark Murray printoption("SENT", IAC, EL);
224813e3f4d6SMark Murray }
224913e3f4d6SMark Murray
225013e3f4d6SMark Murray void
xmitEC(void)225113e3f4d6SMark Murray xmitEC(void)
225213e3f4d6SMark Murray {
225313e3f4d6SMark Murray NET2ADD(IAC, EC);
225413e3f4d6SMark Murray printoption("SENT", IAC, EC);
225513e3f4d6SMark Murray }
225613e3f4d6SMark Murray
225713e3f4d6SMark Murray
225813e3f4d6SMark Murray int
dosynch()225913e3f4d6SMark Murray dosynch()
226013e3f4d6SMark Murray {
226113e3f4d6SMark Murray netclear(); /* clear the path to the network */
226213e3f4d6SMark Murray NETADD(IAC);
226313e3f4d6SMark Murray setneturg();
226413e3f4d6SMark Murray NETADD(DM);
226513e3f4d6SMark Murray printoption("SENT", IAC, DM);
226613e3f4d6SMark Murray return 1;
226713e3f4d6SMark Murray }
226813e3f4d6SMark Murray
226913e3f4d6SMark Murray int want_status_response = 0;
227013e3f4d6SMark Murray
227113e3f4d6SMark Murray int
get_status()227213e3f4d6SMark Murray get_status()
227313e3f4d6SMark Murray {
227413e3f4d6SMark Murray unsigned char tmp[16];
227513e3f4d6SMark Murray unsigned char *cp;
227613e3f4d6SMark Murray
227713e3f4d6SMark Murray if (my_want_state_is_dont(TELOPT_STATUS)) {
227813e3f4d6SMark Murray printf("Remote side does not support STATUS option\n");
227913e3f4d6SMark Murray return 0;
228013e3f4d6SMark Murray }
228113e3f4d6SMark Murray cp = tmp;
228213e3f4d6SMark Murray
228313e3f4d6SMark Murray *cp++ = IAC;
228413e3f4d6SMark Murray *cp++ = SB;
228513e3f4d6SMark Murray *cp++ = TELOPT_STATUS;
228613e3f4d6SMark Murray *cp++ = TELQUAL_SEND;
228713e3f4d6SMark Murray *cp++ = IAC;
228813e3f4d6SMark Murray *cp++ = SE;
228913e3f4d6SMark Murray if (NETROOM() >= cp - tmp) {
229013e3f4d6SMark Murray ring_supply_data(&netoring, tmp, cp-tmp);
229113e3f4d6SMark Murray printsub('>', tmp+2, cp - tmp - 2);
229213e3f4d6SMark Murray }
229313e3f4d6SMark Murray ++want_status_response;
229413e3f4d6SMark Murray return 1;
229513e3f4d6SMark Murray }
229613e3f4d6SMark Murray
229713e3f4d6SMark Murray void
intp(void)229813e3f4d6SMark Murray intp(void)
229913e3f4d6SMark Murray {
230013e3f4d6SMark Murray NET2ADD(IAC, IP);
230113e3f4d6SMark Murray printoption("SENT", IAC, IP);
230213e3f4d6SMark Murray flushline = 1;
230313e3f4d6SMark Murray if (autoflush) {
230413e3f4d6SMark Murray doflush();
230513e3f4d6SMark Murray }
230613e3f4d6SMark Murray if (autosynch) {
230713e3f4d6SMark Murray dosynch();
230813e3f4d6SMark Murray }
230913e3f4d6SMark Murray }
231013e3f4d6SMark Murray
231113e3f4d6SMark Murray void
sendbrk(void)231213e3f4d6SMark Murray sendbrk(void)
231313e3f4d6SMark Murray {
231413e3f4d6SMark Murray NET2ADD(IAC, BREAK);
231513e3f4d6SMark Murray printoption("SENT", IAC, BREAK);
231613e3f4d6SMark Murray flushline = 1;
231713e3f4d6SMark Murray if (autoflush) {
231813e3f4d6SMark Murray doflush();
231913e3f4d6SMark Murray }
232013e3f4d6SMark Murray if (autosynch) {
232113e3f4d6SMark Murray dosynch();
232213e3f4d6SMark Murray }
232313e3f4d6SMark Murray }
232413e3f4d6SMark Murray
232513e3f4d6SMark Murray void
sendabort(void)232613e3f4d6SMark Murray sendabort(void)
232713e3f4d6SMark Murray {
232813e3f4d6SMark Murray NET2ADD(IAC, ABORT);
232913e3f4d6SMark Murray printoption("SENT", IAC, ABORT);
233013e3f4d6SMark Murray flushline = 1;
233113e3f4d6SMark Murray if (autoflush) {
233213e3f4d6SMark Murray doflush();
233313e3f4d6SMark Murray }
233413e3f4d6SMark Murray if (autosynch) {
233513e3f4d6SMark Murray dosynch();
233613e3f4d6SMark Murray }
233713e3f4d6SMark Murray }
233813e3f4d6SMark Murray
233913e3f4d6SMark Murray void
sendsusp(void)234013e3f4d6SMark Murray sendsusp(void)
234113e3f4d6SMark Murray {
234213e3f4d6SMark Murray NET2ADD(IAC, SUSP);
234313e3f4d6SMark Murray printoption("SENT", IAC, SUSP);
234413e3f4d6SMark Murray flushline = 1;
234513e3f4d6SMark Murray if (autoflush) {
234613e3f4d6SMark Murray doflush();
234713e3f4d6SMark Murray }
234813e3f4d6SMark Murray if (autosynch) {
234913e3f4d6SMark Murray dosynch();
235013e3f4d6SMark Murray }
235113e3f4d6SMark Murray }
235213e3f4d6SMark Murray
235313e3f4d6SMark Murray void
sendeof(void)235413e3f4d6SMark Murray sendeof(void)
235513e3f4d6SMark Murray {
235613e3f4d6SMark Murray NET2ADD(IAC, xEOF);
235713e3f4d6SMark Murray printoption("SENT", IAC, xEOF);
235813e3f4d6SMark Murray }
235913e3f4d6SMark Murray
236013e3f4d6SMark Murray void
sendayt(void)236113e3f4d6SMark Murray sendayt(void)
236213e3f4d6SMark Murray {
236313e3f4d6SMark Murray NET2ADD(IAC, AYT);
236413e3f4d6SMark Murray printoption("SENT", IAC, AYT);
236513e3f4d6SMark Murray }
236613e3f4d6SMark Murray
236713e3f4d6SMark Murray /*
236813e3f4d6SMark Murray * Send a window size update to the remote system.
236913e3f4d6SMark Murray */
237013e3f4d6SMark Murray
237113e3f4d6SMark Murray void
sendnaws()237213e3f4d6SMark Murray sendnaws()
237313e3f4d6SMark Murray {
237413e3f4d6SMark Murray long rows, cols;
237513e3f4d6SMark Murray unsigned char tmp[16];
237613e3f4d6SMark Murray unsigned char *cp;
237713e3f4d6SMark Murray
237813e3f4d6SMark Murray if (my_state_is_wont(TELOPT_NAWS))
237913e3f4d6SMark Murray return;
238013e3f4d6SMark Murray
23814137ff4cSJacques Vidrine #undef PUTSHORT
238213e3f4d6SMark Murray #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
238313e3f4d6SMark Murray if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
238413e3f4d6SMark Murray
238513e3f4d6SMark Murray if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
238613e3f4d6SMark Murray return;
238713e3f4d6SMark Murray }
238813e3f4d6SMark Murray
238913e3f4d6SMark Murray cp = tmp;
239013e3f4d6SMark Murray
239113e3f4d6SMark Murray *cp++ = IAC;
239213e3f4d6SMark Murray *cp++ = SB;
239313e3f4d6SMark Murray *cp++ = TELOPT_NAWS;
239413e3f4d6SMark Murray PUTSHORT(cp, cols);
239513e3f4d6SMark Murray PUTSHORT(cp, rows);
239613e3f4d6SMark Murray *cp++ = IAC;
239713e3f4d6SMark Murray *cp++ = SE;
239813e3f4d6SMark Murray if (NETROOM() >= cp - tmp) {
239913e3f4d6SMark Murray ring_supply_data(&netoring, tmp, cp-tmp);
240013e3f4d6SMark Murray printsub('>', tmp+2, cp - tmp - 2);
240113e3f4d6SMark Murray }
240213e3f4d6SMark Murray }
240313e3f4d6SMark Murray
240413e3f4d6SMark Murray void
tel_enter_binary(int rw)240513e3f4d6SMark Murray tel_enter_binary(int rw)
240613e3f4d6SMark Murray {
240713e3f4d6SMark Murray if (rw&1)
240813e3f4d6SMark Murray send_do(TELOPT_BINARY, 1);
240913e3f4d6SMark Murray if (rw&2)
241013e3f4d6SMark Murray send_will(TELOPT_BINARY, 1);
241113e3f4d6SMark Murray }
241213e3f4d6SMark Murray
241313e3f4d6SMark Murray void
tel_leave_binary(int rw)241413e3f4d6SMark Murray tel_leave_binary(int rw)
241513e3f4d6SMark Murray {
241613e3f4d6SMark Murray if (rw&1)
241713e3f4d6SMark Murray send_dont(TELOPT_BINARY, 1);
241813e3f4d6SMark Murray if (rw&2)
241913e3f4d6SMark Murray send_wont(TELOPT_BINARY, 1);
242013e3f4d6SMark Murray }
2421