133685Sbostic /*
262313Sbostic * Copyright (c) 1988, 1990, 1993
362313Sbostic * The Regents of the University of California. All rights reserved.
433685Sbostic *
542770Sbostic * %sccs.include.redist.c%
633685Sbostic */
711758Ssam
821580Sdist #ifndef lint
9*69785Sdab static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 05/30/95";
1033685Sbostic #endif /* not lint */
1121580Sdist
129217Ssam #include <sys/types.h>
139217Ssam
1432377Sminshall #if defined(unix)
1533804Sminshall #include <signal.h>
1632377Sminshall /* By the way, we need to include curses.h before telnet.h since,
1732377Sminshall * among other things, telnet.h #defines 'DO', which is a variable
1832377Sminshall * declared in curses.h.
1932377Sminshall */
2032377Sminshall #endif /* defined(unix) */
2132377Sminshall
2212212Ssam #include <arpa/telnet.h>
2332377Sminshall
2438908Sborman #include <ctype.h>
2538908Sborman
2632381Sminshall #include "ring.h"
2732381Sminshall
2832377Sminshall #include "defines.h"
2932377Sminshall #include "externs.h"
3032377Sminshall #include "types.h"
3132377Sminshall #include "general.h"
3227178Sminshall
3327178Sminshall
3468586Sdab #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
356000Sroot
3646808Sdab static unsigned char subbuffer[SUBBUFSIZE],
3746808Sdab *subpointer, *subend; /* buffer for sub-options */
3827676Sminshall #define SB_CLEAR() subpointer = subbuffer;
3946808Sdab #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
4027676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
4127676Sminshall *subpointer++ = (c); \
4227676Sminshall }
4327676Sminshall
4446808Sdab #define SB_GET() ((*subpointer++)&0xff)
4546808Sdab #define SB_PEEK() ((*subpointer)&0xff)
4646808Sdab #define SB_EOF() (subpointer >= subend)
4746808Sdab #define SB_LEN() (subend - subpointer)
4846808Sdab
4937226Sminshall char options[256]; /* The combined options */
5038689Sborman char do_dont_resp[256];
5138689Sborman char will_wont_resp[256];
526000Sroot
5332377Sminshall int
5446808Sdab eight = 0,
5546808Sdab autologin = 0, /* Autologin anyone? */
5647608Sdab skiprc = 0,
5732377Sminshall connected,
5832377Sminshall showoptions,
5932377Sminshall In3270, /* Are we in 3270 mode? */
6032377Sminshall ISend, /* trying to send network data in */
6132377Sminshall debug = 0,
6232377Sminshall crmod,
6332377Sminshall netdata, /* Print out network data flow */
6432377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
6534848Sminshall #if defined(TN3270)
6636241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */
6736241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */
6832377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */
6934848Sminshall #endif /* defined(TN3270) */
7033286Sminshall telnetport,
7132531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */
7232531Sminshall flushout, /* flush output */
7332531Sminshall autoflush = 0, /* flush output when interrupting? */
7432531Sminshall autosynch, /* send interrupt characters with SYNCH? */
7537219Sminshall localflow, /* we handle flow control locally */
7657213Sdab restartany, /* if flow control enabled, restart on any character */
7732531Sminshall localchars, /* we recognize interrupt/quit */
7832531Sminshall donelclchars, /* the user has set "localchars" */
7932531Sminshall donebinarytoggle, /* the user has put us in binary */
8032531Sminshall dontlecho, /* do we suppress local echoing right now? */
8132531Sminshall globalmode;
8227088Sminshall
8344360Sborman char *prompt = 0;
846000Sroot
8544360Sborman cc_t escape;
8646808Sdab cc_t rlogin;
8744360Sborman #ifdef KLUDGELINEMODE
8844360Sborman cc_t echoc;
8944360Sborman #endif
9027186Sminshall
9127186Sminshall /*
926000Sroot * Telnet receiver states for fsm
936000Sroot */
946000Sroot #define TS_DATA 0
956000Sroot #define TS_IAC 1
966000Sroot #define TS_WILL 2
976000Sroot #define TS_WONT 3
986000Sroot #define TS_DO 4
996000Sroot #define TS_DONT 5
10027021Sminshall #define TS_CR 6
10127676Sminshall #define TS_SB 7 /* sub-option collection */
10227676Sminshall #define TS_SE 8 /* looking for sub-option end */
1036000Sroot
10432377Sminshall static int telrcv_state;
10565157Sdab #ifdef OLD_ENVIRON
10665157Sdab unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
10765157Sdab #else
10865157Sdab # define telopt_environ TELOPT_NEW_ENVIRON
10965157Sdab #endif
1106000Sroot
11132377Sminshall jmp_buf toplevel = { 0 };
11232377Sminshall jmp_buf peerdied;
1136000Sroot
11432377Sminshall int flushline;
11538811Sborman int linemode;
11627021Sminshall
11738689Sborman #ifdef KLUDGELINEMODE
11838689Sborman int kludgelinemode = 1;
11938689Sborman #endif
12038689Sborman
12132377Sminshall /*
12232377Sminshall * The following are some clocks used to decide how to interpret
12332377Sminshall * the relationship between various variables.
12432377Sminshall */
1256000Sroot
12632377Sminshall Clocks clocks;
12732377Sminshall
12838689Sborman #ifdef notdef
12932377Sminshall Modelist modelist[] = {
13032377Sminshall { "telnet command mode", COMMAND_LINE },
13132377Sminshall { "character-at-a-time mode", 0 },
13232377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
13332377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
13432377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
13532377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
13632377Sminshall { "3270 mode", 0 },
13732377Sminshall };
13838689Sborman #endif
1396000Sroot
14032377Sminshall
14132377Sminshall /*
14232377Sminshall * Initialize telnet environment.
14332377Sminshall */
1446000Sroot
14546808Sdab void
init_telnet()14632377Sminshall init_telnet()
14732377Sminshall {
14844360Sborman env_init();
14944360Sborman
15032377Sminshall SB_CLEAR();
15137226Sminshall ClearArray(options);
1526000Sroot
15337219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0;
154*69785Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION)
15546808Sdab auth_encrypt_connect(connected);
15660149Sdab #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
15757213Sdab restartany = -1;
1586000Sroot
15932377Sminshall SYNCHing = 0;
1606000Sroot
16132377Sminshall /* Don't change NetTrace */
1626000Sroot
16332377Sminshall escape = CONTROL(']');
16446808Sdab rlogin = _POSIX_VDISABLE;
16544360Sborman #ifdef KLUDGELINEMODE
16632377Sminshall echoc = CONTROL('E');
16744360Sborman #endif
1686000Sroot
16932377Sminshall flushline = 1;
17032377Sminshall telrcv_state = TS_DATA;
17132377Sminshall }
17232554Sminshall
1736000Sroot
17444360Sborman #ifdef notdef
17532554Sminshall #include <varargs.h>
1766000Sroot
17746808Sdab /*VARARGS*/
17846808Sdab static void
printring(va_alist)17932554Sminshall printring(va_alist)
18046808Sdab va_dcl
18132554Sminshall {
18232554Sminshall va_list ap;
18332554Sminshall char buffer[100]; /* where things go */
18432554Sminshall char *ptr;
18532554Sminshall char *format;
18632554Sminshall char *string;
18732554Sminshall Ring *ring;
18832554Sminshall int i;
18932554Sminshall
19032554Sminshall va_start(ap);
19132554Sminshall
19232554Sminshall ring = va_arg(ap, Ring *);
19332554Sminshall format = va_arg(ap, char *);
19432554Sminshall ptr = buffer;
19532554Sminshall
19632554Sminshall while ((i = *format++) != 0) {
19732554Sminshall if (i == '%') {
19832554Sminshall i = *format++;
19932554Sminshall switch (i) {
20032554Sminshall case 'c':
20132554Sminshall *ptr++ = va_arg(ap, int);
20232554Sminshall break;
20332554Sminshall case 's':
20432554Sminshall string = va_arg(ap, char *);
20532554Sminshall ring_supply_data(ring, buffer, ptr-buffer);
20632554Sminshall ring_supply_data(ring, string, strlen(string));
20732554Sminshall ptr = buffer;
20832554Sminshall break;
20932554Sminshall case 0:
21032554Sminshall ExitString("printring: trailing %%.\n", 1);
21132554Sminshall /*NOTREACHED*/
21232554Sminshall default:
21332554Sminshall ExitString("printring: unknown format character.\n", 1);
21432554Sminshall /*NOTREACHED*/
21532554Sminshall }
21632554Sminshall } else {
21732554Sminshall *ptr++ = i;
21832554Sminshall }
21932554Sminshall }
22032554Sminshall ring_supply_data(ring, buffer, ptr-buffer);
22132554Sminshall }
22244360Sborman #endif
22332554Sminshall
22437226Sminshall /*
22537226Sminshall * These routines are in charge of sending option negotiations
22637226Sminshall * to the other side.
22737226Sminshall *
22837226Sminshall * The basic idea is that we send the negotiation if either side
22937226Sminshall * is in disagreement as to what the current state should be.
23037226Sminshall */
23132554Sminshall
23246808Sdab void
send_do(c,init)23338689Sborman send_do(c, init)
23446808Sdab register int c, init;
2356000Sroot {
23638689Sborman if (init) {
23738689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
23838689Sborman my_want_state_is_do(c))
23938689Sborman return;
24038689Sborman set_my_want_state_do(c);
24138689Sborman do_dont_resp[c]++;
24237226Sminshall }
24338689Sborman NET2ADD(IAC, DO);
24438689Sborman NETADD(c);
24546808Sdab printoption("SENT", DO, c);
24637226Sminshall }
24737226Sminshall
24846808Sdab void
send_dont(c,init)24938689Sborman send_dont(c, init)
25046808Sdab register int c, init;
25137226Sminshall {
25238689Sborman if (init) {
25338689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
25438689Sborman my_want_state_is_dont(c))
25538689Sborman return;
25638689Sborman set_my_want_state_dont(c);
25738689Sborman do_dont_resp[c]++;
25837226Sminshall }
25938689Sborman NET2ADD(IAC, DONT);
26038689Sborman NETADD(c);
26146808Sdab printoption("SENT", DONT, c);
26237226Sminshall }
26337226Sminshall
26446808Sdab void
send_will(c,init)26538689Sborman send_will(c, init)
26646808Sdab register int c, init;
26737226Sminshall {
26838689Sborman if (init) {
26938689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
27038689Sborman my_want_state_is_will(c))
27138689Sborman return;
27238689Sborman set_my_want_state_will(c);
27338689Sborman will_wont_resp[c]++;
27437226Sminshall }
27538689Sborman NET2ADD(IAC, WILL);
27638689Sborman NETADD(c);
27746808Sdab printoption("SENT", WILL, c);
27837226Sminshall }
27937226Sminshall
28046808Sdab void
send_wont(c,init)28138689Sborman send_wont(c, init)
28246808Sdab register int c, init;
28337226Sminshall {
28438689Sborman if (init) {
28538689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
28638689Sborman my_want_state_is_wont(c))
28738689Sborman return;
28838689Sborman set_my_want_state_wont(c);
28938689Sborman will_wont_resp[c]++;
29037226Sminshall }
29138689Sborman NET2ADD(IAC, WONT);
29238689Sborman NETADD(c);
29346808Sdab printoption("SENT", WONT, c);
29437226Sminshall }
29537226Sminshall
29637226Sminshall
29746808Sdab void
willoption(option)29837226Sminshall willoption(option)
29937226Sminshall int option;
30037226Sminshall {
30138689Sborman int new_state_ok = 0;
3026000Sroot
30338689Sborman if (do_dont_resp[option]) {
30438689Sborman --do_dont_resp[option];
30538689Sborman if (do_dont_resp[option] && my_state_is_do(option))
30638689Sborman --do_dont_resp[option];
30738689Sborman }
30837226Sminshall
30938689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
3106000Sroot
31138689Sborman switch (option) {
31238689Sborman
31338689Sborman case TELOPT_ECHO:
31438689Sborman # if defined(TN3270)
31538689Sborman /*
31638689Sborman * The following is a pain in the rear-end.
31738689Sborman * Various IBM servers (some versions of Wiscnet,
31838689Sborman * possibly Fibronics/Spartacus, and who knows who
31938689Sborman * else) will NOT allow us to send "DO SGA" too early
32038689Sborman * in the setup proceedings. On the other hand,
32138689Sborman * 4.2 servers (telnetd) won't set SGA correctly.
32238689Sborman * So, we are stuck. Empirically (but, based on
32338689Sborman * a VERY small sample), the IBM servers don't send
32438689Sborman * out anything about ECHO, so we postpone our sending
32538689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
32638689Sborman * DO send).
32738689Sborman */
32838689Sborman {
32938689Sborman if (askedSGA == 0) {
33038689Sborman askedSGA = 1;
33138689Sborman if (my_want_state_is_dont(TELOPT_SGA))
33238689Sborman send_do(TELOPT_SGA, 1);
33332377Sminshall }
33432377Sminshall }
33538689Sborman /* Fall through */
33638689Sborman case TELOPT_EOR:
33738908Sborman #endif /* defined(TN3270) */
33838689Sborman case TELOPT_BINARY:
33938689Sborman case TELOPT_SGA:
34027110Sminshall settimer(modenegotiated);
34138908Sborman /* FALL THROUGH */
34238908Sborman case TELOPT_STATUS:
34357213Sdab #if defined(AUTHENTICATION)
34446808Sdab case TELOPT_AUTHENTICATION:
34546808Sdab #endif
34660149Sdab #ifdef ENCRYPTION
34746808Sdab case TELOPT_ENCRYPT:
34860149Sdab #endif /* ENCRYPTION */
34938689Sborman new_state_ok = 1;
3506000Sroot break;
3516000Sroot
35238689Sborman case TELOPT_TM:
35338689Sborman if (flushout)
35438689Sborman flushout = 0;
35538689Sborman /*
35638689Sborman * Special case for TM. If we get back a WILL,
35738689Sborman * pretend we got back a WONT.
35838689Sborman */
35938689Sborman set_my_want_state_dont(option);
36038689Sborman set_my_state_dont(option);
36127110Sminshall return; /* Never reply to TM will's/wont's */
3626000Sroot
36338689Sborman case TELOPT_LINEMODE:
36438689Sborman default:
3656000Sroot break;
36638689Sborman }
36738689Sborman
36838689Sborman if (new_state_ok) {
36938689Sborman set_my_want_state_do(option);
37038689Sborman send_do(option, 0);
37138689Sborman setconnmode(0); /* possibly set new tty mode */
37238689Sborman } else {
37338689Sborman do_dont_resp[option]++;
37438689Sborman send_dont(option, 0);
37538689Sborman }
3766000Sroot }
37738689Sborman set_my_state_do(option);
37860149Sdab #ifdef ENCRYPTION
37946808Sdab if (option == TELOPT_ENCRYPT)
38046808Sdab encrypt_send_support();
38160149Sdab #endif /* ENCRYPTION */
3826000Sroot }
3836000Sroot
38446808Sdab void
wontoption(option)38537226Sminshall wontoption(option)
38637226Sminshall int option;
3876000Sroot {
38838689Sborman if (do_dont_resp[option]) {
38938689Sborman --do_dont_resp[option];
39038689Sborman if (do_dont_resp[option] && my_state_is_dont(option))
39138689Sborman --do_dont_resp[option];
39238689Sborman }
39337226Sminshall
39438689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
3956000Sroot
39638689Sborman switch (option) {
39738689Sborman
39838689Sborman #ifdef KLUDGELINEMODE
39938689Sborman case TELOPT_SGA:
40038689Sborman if (!kludgelinemode)
40138689Sborman break;
40238689Sborman /* FALL THROUGH */
40338689Sborman #endif
40438689Sborman case TELOPT_ECHO:
40527110Sminshall settimer(modenegotiated);
4066000Sroot break;
4076000Sroot
40838689Sborman case TELOPT_TM:
40938689Sborman if (flushout)
41038689Sborman flushout = 0;
41138689Sborman set_my_want_state_dont(option);
41238689Sborman set_my_state_dont(option);
41327110Sminshall return; /* Never reply to TM will's/wont's */
41427110Sminshall
41538689Sborman default:
41638689Sborman break;
41738689Sborman }
41838689Sborman set_my_want_state_dont(option);
41944360Sborman if (my_state_is_do(option))
42044360Sborman send_dont(option, 0);
42138689Sborman setconnmode(0); /* Set new tty mode */
42238689Sborman } else if (option == TELOPT_TM) {
42338689Sborman /*
42438689Sborman * Special case for TM.
42538689Sborman */
42638689Sborman if (flushout)
42738689Sborman flushout = 0;
42838689Sborman set_my_want_state_dont(option);
4296000Sroot }
43038689Sborman set_my_state_dont(option);
4316000Sroot }
4326000Sroot
43346808Sdab static void
dooption(option)4346000Sroot dooption(option)
4356000Sroot int option;
4366000Sroot {
43738689Sborman int new_state_ok = 0;
4386000Sroot
43938689Sborman if (will_wont_resp[option]) {
44038689Sborman --will_wont_resp[option];
44138689Sborman if (will_wont_resp[option] && my_state_is_will(option))
44238689Sborman --will_wont_resp[option];
44338689Sborman }
44437226Sminshall
44538689Sborman if (will_wont_resp[option] == 0) {
44638689Sborman if (my_want_state_is_wont(option)) {
4476000Sroot
44838689Sborman switch (option) {
44938689Sborman
45038689Sborman case TELOPT_TM:
45138689Sborman /*
45238689Sborman * Special case for TM. We send a WILL, but pretend
45338689Sborman * we sent WONT.
45438689Sborman */
45538689Sborman send_will(option, 0);
45638689Sborman set_my_want_state_wont(TELOPT_TM);
45738689Sborman set_my_state_wont(TELOPT_TM);
45838689Sborman return;
45938689Sborman
46032377Sminshall # if defined(TN3270)
46138689Sborman case TELOPT_EOR: /* end of record */
46238908Sborman # endif /* defined(TN3270) */
46338689Sborman case TELOPT_BINARY: /* binary mode */
46438689Sborman case TELOPT_NAWS: /* window size */
46538689Sborman case TELOPT_TSPEED: /* terminal speed */
46638689Sborman case TELOPT_LFLOW: /* local flow control */
46738689Sborman case TELOPT_TTYPE: /* terminal type option */
46838689Sborman case TELOPT_SGA: /* no big deal */
46960149Sdab #ifdef ENCRYPTION
47046808Sdab case TELOPT_ENCRYPT: /* encryption variable option */
47160149Sdab #endif /* ENCRYPTION */
47238689Sborman new_state_ok = 1;
4736000Sroot break;
47465157Sdab
47565157Sdab case TELOPT_NEW_ENVIRON: /* New environment variable option */
47665157Sdab #ifdef OLD_ENVIRON
47765157Sdab if (my_state_is_will(TELOPT_OLD_ENVIRON))
47865157Sdab send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
47965157Sdab goto env_common;
48065157Sdab case TELOPT_OLD_ENVIRON: /* Old environment variable option */
48165157Sdab if (my_state_is_will(TELOPT_NEW_ENVIRON))
48265157Sdab break; /* Don't enable if new one is in use! */
48365157Sdab env_common:
48465157Sdab telopt_environ = option;
48565157Sdab #endif
48665157Sdab new_state_ok = 1;
48765157Sdab break;
48865157Sdab
48957213Sdab #if defined(AUTHENTICATION)
49046808Sdab case TELOPT_AUTHENTICATION:
49146808Sdab if (autologin)
49246808Sdab new_state_ok = 1;
49346808Sdab break;
49446808Sdab #endif
4956000Sroot
49644360Sborman case TELOPT_XDISPLOC: /* X Display location */
49746808Sdab if (env_getvalue((unsigned char *)"DISPLAY"))
49844360Sborman new_state_ok = 1;
49944360Sborman break;
50044360Sborman
50138689Sborman case TELOPT_LINEMODE:
50238689Sborman #ifdef KLUDGELINEMODE
50338689Sborman kludgelinemode = 0;
50444360Sborman send_do(TELOPT_SGA, 1);
50538689Sborman #endif
50638689Sborman set_my_want_state_will(TELOPT_LINEMODE);
50738689Sborman send_will(option, 0);
50838689Sborman set_my_state_will(TELOPT_LINEMODE);
50938689Sborman slc_init();
51038689Sborman return;
51138689Sborman
51238689Sborman case TELOPT_ECHO: /* We're never going to echo... */
51338689Sborman default:
5146000Sroot break;
51538689Sborman }
51638689Sborman
51738689Sborman if (new_state_ok) {
51838689Sborman set_my_want_state_will(option);
51938689Sborman send_will(option, 0);
52045232Sborman setconnmode(0); /* Set new tty mode */
52138689Sborman } else {
52238689Sborman will_wont_resp[option]++;
52338689Sborman send_wont(option, 0);
52438689Sborman }
52538689Sborman } else {
52638689Sborman /*
52738689Sborman * Handle options that need more things done after the
52838689Sborman * other side has acknowledged the option.
52938689Sborman */
53038689Sborman switch (option) {
53138689Sborman case TELOPT_LINEMODE:
53238689Sborman #ifdef KLUDGELINEMODE
53338689Sborman kludgelinemode = 0;
53444360Sborman send_do(TELOPT_SGA, 1);
53538689Sborman #endif
53638689Sborman set_my_state_will(option);
53738689Sborman slc_init();
53844360Sborman send_do(TELOPT_SGA, 0);
53938689Sborman return;
54038689Sborman }
54138689Sborman }
5426000Sroot }
54338689Sborman set_my_state_will(option);
5446000Sroot }
54527676Sminshall
54646808Sdab static void
dontoption(option)54738689Sborman dontoption(option)
54838689Sborman int option;
54938689Sborman {
55038689Sborman
55138689Sborman if (will_wont_resp[option]) {
55238689Sborman --will_wont_resp[option];
55338689Sborman if (will_wont_resp[option] && my_state_is_wont(option))
55438689Sborman --will_wont_resp[option];
55538689Sborman }
55638689Sborman
55738689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
55838811Sborman switch (option) {
55938811Sborman case TELOPT_LINEMODE:
56038811Sborman linemode = 0; /* put us back to the default state */
56138811Sborman break;
56265157Sdab #ifdef OLD_ENVIRON
56365157Sdab case TELOPT_NEW_ENVIRON:
56465157Sdab /*
56565157Sdab * The new environ option wasn't recognized, try
56665157Sdab * the old one.
56765157Sdab */
56865157Sdab send_will(TELOPT_OLD_ENVIRON, 1);
56965157Sdab telopt_environ = TELOPT_OLD_ENVIRON;
57065157Sdab break;
57165157Sdab #endif
57238811Sborman }
57338689Sborman /* we always accept a DONT */
57438689Sborman set_my_want_state_wont(option);
57544360Sborman if (my_state_is_will(option))
57644360Sborman send_wont(option, 0);
57739529Sborman setconnmode(0); /* Set new tty mode */
57838689Sborman }
57938689Sborman set_my_state_wont(option);
58038689Sborman }
58138689Sborman
58227676Sminshall /*
58338908Sborman * Given a buffer returned by tgetent(), this routine will turn
58438908Sborman * the pipe seperated list of names in the buffer into an array
58538908Sborman * of pointers to null terminated names. We toss out any bad,
58638908Sborman * duplicate, or verbose names (names with spaces).
58738908Sborman */
58838908Sborman
58946808Sdab static char *name_unknown = "UNKNOWN";
59046808Sdab static char *unknown[] = { 0, 0 };
59138908Sborman
59246808Sdab char **
mklist(buf,name)59338908Sborman mklist(buf, name)
59446808Sdab char *buf, *name;
59538908Sborman {
59638908Sborman register int n;
59746808Sdab register char c, *cp, **argvp, *cp2, **argv, **avt;
59838908Sborman
59938908Sborman if (name) {
600*69785Sdab if ((int)strlen(name) > 40) {
60138908Sborman name = 0;
60246808Sdab unknown[0] = name_unknown;
60346808Sdab } else {
60438908Sborman unknown[0] = name;
60538908Sborman upcase(name);
60638908Sborman }
60746808Sdab } else
60846808Sdab unknown[0] = name_unknown;
60938908Sborman /*
61038908Sborman * Count up the number of names.
61138908Sborman */
61238908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
61338908Sborman if (*cp == '|')
61438908Sborman n++;
61538908Sborman }
61638908Sborman /*
61738908Sborman * Allocate an array to put the name pointers into
61838908Sborman */
61938908Sborman argv = (char **)malloc((n+3)*sizeof(char *));
62038908Sborman if (argv == 0)
62138908Sborman return(unknown);
62238908Sborman
62338908Sborman /*
62438908Sborman * Fill up the array of pointers to names.
62538908Sborman */
62638908Sborman *argv = 0;
62738908Sborman argvp = argv+1;
62838908Sborman n = 0;
62938908Sborman for (cp = cp2 = buf; (c = *cp); cp++) {
63038908Sborman if (c == '|' || c == ':') {
63138908Sborman *cp++ = '\0';
63238908Sborman /*
63338908Sborman * Skip entries that have spaces or are over 40
63438908Sborman * characters long. If this is our environment
63538908Sborman * name, then put it up front. Otherwise, as
63638908Sborman * long as this is not a duplicate name (case
63738908Sborman * insensitive) add it to the list.
63838908Sborman */
63938908Sborman if (n || (cp - cp2 > 41))
64038908Sborman ;
64138908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
64238908Sborman *argv = cp2;
64338908Sborman else if (is_unique(cp2, argv+1, argvp))
64438908Sborman *argvp++ = cp2;
64538908Sborman if (c == ':')
64638908Sborman break;
64738908Sborman /*
64838908Sborman * Skip multiple delimiters. Reset cp2 to
64938908Sborman * the beginning of the next name. Reset n,
65038908Sborman * the flag for names with spaces.
65138908Sborman */
65238908Sborman while ((c = *cp) == '|')
65338908Sborman cp++;
65438908Sborman cp2 = cp;
65538908Sborman n = 0;
65638908Sborman }
65738908Sborman /*
65838908Sborman * Skip entries with spaces or non-ascii values.
65938908Sborman * Convert lower case letters to upper case.
66038908Sborman */
66138908Sborman if ((c == ' ') || !isascii(c))
66238908Sborman n = 1;
66338908Sborman else if (islower(c))
66438908Sborman *cp = toupper(c);
66538908Sborman }
666*69785Sdab
66738908Sborman /*
66838908Sborman * Check for an old V6 2 character name. If the second
66938908Sborman * name points to the beginning of the buffer, and is
67038908Sborman * only 2 characters long, move it to the end of the array.
67138908Sborman */
67238908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
67346808Sdab --argvp;
67446808Sdab for (avt = &argv[1]; avt < argvp; avt++)
67546808Sdab *avt = *(avt+1);
67638908Sborman *argvp++ = buf;
67738908Sborman }
67838908Sborman
67938908Sborman /*
68038908Sborman * Duplicate last name, for TTYPE option, and null
68138908Sborman * terminate the array. If we didn't find a match on
68238908Sborman * our terminal name, put that name at the beginning.
68338908Sborman */
68438908Sborman cp = *(argvp-1);
68538908Sborman *argvp++ = cp;
68638908Sborman *argvp = 0;
68738908Sborman
68838908Sborman if (*argv == 0) {
68938908Sborman if (name)
69038908Sborman *argv = name;
69146808Sdab else {
69246808Sdab --argvp;
69346808Sdab for (avt = argv; avt < argvp; avt++)
69446808Sdab *avt = *(avt+1);
69546808Sdab }
69638908Sborman }
69738908Sborman if (*argv)
69838908Sborman return(argv);
69938908Sborman else
70038908Sborman return(unknown);
70138908Sborman }
70238908Sborman
70346808Sdab int
is_unique(name,as,ae)70438908Sborman is_unique(name, as, ae)
70546808Sdab register char *name, **as, **ae;
70638908Sborman {
70738908Sborman register char **ap;
70838908Sborman register int n;
70938908Sborman
71038908Sborman n = strlen(name) + 1;
71138908Sborman for (ap = as; ap < ae; ap++)
71238908Sborman if (strncasecmp(*ap, name, n) == 0)
71338908Sborman return(0);
71438908Sborman return (1);
71538908Sborman }
71638908Sborman
71738908Sborman #ifdef TERMCAP
71839529Sborman char termbuf[1024];
71946808Sdab
72046808Sdab /*ARGSUSED*/
72146808Sdab int
setupterm(tname,fd,errp)72238908Sborman setupterm(tname, fd, errp)
72346808Sdab char *tname;
72446808Sdab int fd, *errp;
72538908Sborman {
72639529Sborman if (tgetent(termbuf, tname) == 1) {
72739529Sborman termbuf[1023] = '\0';
72838908Sborman if (errp)
72938908Sborman *errp = 1;
73038908Sborman return(0);
73138908Sborman }
73238908Sborman if (errp)
73338908Sborman *errp = 0;
73438908Sborman return(-1);
73538908Sborman }
73639529Sborman #else
73739529Sborman #define termbuf ttytype
73839529Sborman extern char ttytype[];
73938908Sborman #endif
74038908Sborman
74146808Sdab int resettermname = 1;
74246808Sdab
74346808Sdab char *
gettermname()74438908Sborman gettermname()
74538908Sborman {
74638908Sborman char *tname;
74746808Sdab static char **tnamep = 0;
74838908Sborman static char **next;
74938908Sborman int err;
75038908Sborman
75146808Sdab if (resettermname) {
75246808Sdab resettermname = 0;
75346808Sdab if (tnamep && tnamep != unknown)
75446808Sdab free(tnamep);
75546808Sdab if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
75638908Sborman (setupterm(tname, 1, &err) == 0)) {
75739529Sborman tnamep = mklist(termbuf, tname);
75838908Sborman } else {
759*69785Sdab if (tname && ((int)strlen(tname) <= 40)) {
76038908Sborman unknown[0] = tname;
76138908Sborman upcase(tname);
76246808Sdab } else
76346808Sdab unknown[0] = name_unknown;
76438908Sborman tnamep = unknown;
76538908Sborman }
76638908Sborman next = tnamep;
76738908Sborman }
76838908Sborman if (*next == 0)
76938908Sborman next = tnamep;
77038908Sborman return(*next++);
77138908Sborman }
77238908Sborman /*
77327676Sminshall * suboption()
77427676Sminshall *
77527676Sminshall * Look at the sub-option buffer, and try to be helpful to the other
77627676Sminshall * side.
77727676Sminshall *
77827676Sminshall * Currently we recognize:
77927676Sminshall *
78027676Sminshall * Terminal type, send request.
78137219Sminshall * Terminal speed (send request).
78237219Sminshall * Local flow control (is request).
78338689Sborman * Linemode
78427676Sminshall */
78527676Sminshall
78646808Sdab static void
suboption()78727676Sminshall suboption()
78827676Sminshall {
78965157Sdab unsigned char subchar;
79065157Sdab
79146808Sdab printsub('<', subbuffer, SB_LEN()+2);
79265157Sdab switch (subchar = SB_GET()) {
79327676Sminshall case TELOPT_TTYPE:
79438689Sborman if (my_want_state_is_wont(TELOPT_TTYPE))
79538689Sborman return;
79646808Sdab if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
79746808Sdab return;
79827676Sminshall } else {
79927676Sminshall char *name;
80046808Sdab unsigned char temp[50];
80127676Sminshall int len;
80227676Sminshall
80332377Sminshall #if defined(TN3270)
80432531Sminshall if (tn3270_ttype()) {
80532377Sminshall return;
80632377Sminshall }
80732377Sminshall #endif /* defined(TN3270) */
80838908Sborman name = gettermname();
80938908Sborman len = strlen(name) + 4 + 2;
81038908Sborman if (len < NETROOM()) {
81146808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
81238908Sborman TELQUAL_IS, name, IAC, SE);
81338689Sborman ring_supply_data(&netoring, temp, len);
81438908Sborman printsub('>', &temp[2], len-2);
81532377Sminshall } else {
81637226Sminshall ExitString("No room in buffer for terminal type.\n", 1);
81732377Sminshall /*NOTREACHED*/
81827676Sminshall }
81927676Sminshall }
82037219Sminshall break;
82137219Sminshall case TELOPT_TSPEED:
82238689Sborman if (my_want_state_is_wont(TELOPT_TSPEED))
82338689Sborman return;
82446808Sdab if (SB_EOF())
82546808Sdab return;
82646808Sdab if (SB_GET() == TELQUAL_SEND) {
82745232Sborman long ospeed, ispeed;
82846808Sdab unsigned char temp[50];
82937219Sminshall int len;
83027676Sminshall
83137219Sminshall TerminalSpeeds(&ispeed, &ospeed);
83237219Sminshall
83346808Sdab sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
83438689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE);
83546808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
83637219Sminshall
83738689Sborman if (len < NETROOM()) {
83838689Sborman ring_supply_data(&netoring, temp, len);
83938689Sborman printsub('>', temp+2, len - 2);
84037219Sminshall }
84144360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n");
84237219Sminshall }
84337219Sminshall break;
84437219Sminshall case TELOPT_LFLOW:
84538689Sborman if (my_want_state_is_wont(TELOPT_LFLOW))
84638689Sborman return;
84746808Sdab if (SB_EOF())
84846808Sdab return;
84946808Sdab switch(SB_GET()) {
85057213Sdab case LFLOW_RESTART_ANY:
85157213Sdab restartany = 1;
85257213Sdab break;
85357213Sdab case LFLOW_RESTART_XON:
85457213Sdab restartany = 0;
85557213Sdab break;
85657213Sdab case LFLOW_ON:
85737219Sminshall localflow = 1;
85846808Sdab break;
85957213Sdab case LFLOW_OFF:
86037219Sminshall localflow = 0;
86146808Sdab break;
86246808Sdab default:
86346808Sdab return;
86437219Sminshall }
86537219Sminshall setcommandmode();
86638689Sborman setconnmode(0);
86737219Sminshall break;
86838689Sborman
86938689Sborman case TELOPT_LINEMODE:
87038689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE))
87138689Sborman return;
87246808Sdab if (SB_EOF())
87346808Sdab return;
87446808Sdab switch (SB_GET()) {
87538689Sborman case WILL:
87646808Sdab lm_will(subpointer, SB_LEN());
87738689Sborman break;
87838689Sborman case WONT:
87946808Sdab lm_wont(subpointer, SB_LEN());
88038689Sborman break;
88138689Sborman case DO:
88246808Sdab lm_do(subpointer, SB_LEN());
88338689Sborman break;
88438689Sborman case DONT:
88546808Sdab lm_dont(subpointer, SB_LEN());
88638689Sborman break;
88738689Sborman case LM_SLC:
88846808Sdab slc(subpointer, SB_LEN());
88938689Sborman break;
89038689Sborman case LM_MODE:
89146808Sdab lm_mode(subpointer, SB_LEN(), 0);
89238689Sborman break;
89338689Sborman default:
89444360Sborman break;
89544360Sborman }
89644360Sborman break;
89744360Sborman
89865157Sdab #ifdef OLD_ENVIRON
89965157Sdab case TELOPT_OLD_ENVIRON:
90065157Sdab #endif
90165157Sdab case TELOPT_NEW_ENVIRON:
90246808Sdab if (SB_EOF())
90346808Sdab return;
90446808Sdab switch(SB_PEEK()) {
90544360Sborman case TELQUAL_IS:
90644360Sborman case TELQUAL_INFO:
90765157Sdab if (my_want_state_is_dont(subchar))
90844360Sborman return;
90944360Sborman break;
91044360Sborman case TELQUAL_SEND:
91165157Sdab if (my_want_state_is_wont(subchar)) {
91244360Sborman return;
91344360Sborman }
91444360Sborman break;
91544360Sborman default:
91644360Sborman return;
91744360Sborman }
91846808Sdab env_opt(subpointer, SB_LEN());
91944360Sborman break;
92044360Sborman
92144360Sborman case TELOPT_XDISPLOC:
92244360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC))
92344360Sborman return;
92446808Sdab if (SB_EOF())
92546808Sdab return;
92646808Sdab if (SB_GET() == TELQUAL_SEND) {
92746808Sdab unsigned char temp[50], *dp;
92844360Sborman int len;
92944360Sborman
93046808Sdab if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
93144360Sborman /*
93244360Sborman * Something happened, we no longer have a DISPLAY
93344360Sborman * variable. So, turn off the option.
93444360Sborman */
93544360Sborman send_wont(TELOPT_XDISPLOC, 1);
93638689Sborman break;
93744360Sborman }
93846808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
93944360Sborman TELQUAL_IS, dp, IAC, SE);
94046808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
94144360Sborman
94244360Sborman if (len < NETROOM()) {
94344360Sborman ring_supply_data(&netoring, temp, len);
94444360Sborman printsub('>', temp+2, len - 2);
94544360Sborman }
94644360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n");
94738689Sborman }
94844360Sborman break;
94943319Skfall
95057213Sdab #if defined(AUTHENTICATION)
95146808Sdab case TELOPT_AUTHENTICATION: {
95246808Sdab if (!autologin)
95346808Sdab break;
95446808Sdab if (SB_EOF())
95546808Sdab return;
95646808Sdab switch(SB_GET()) {
95746808Sdab case TELQUAL_IS:
95846808Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
95946808Sdab return;
96046808Sdab auth_is(subpointer, SB_LEN());
96146808Sdab break;
96246808Sdab case TELQUAL_SEND:
96346808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
96446808Sdab return;
96546808Sdab auth_send(subpointer, SB_LEN());
96646808Sdab break;
96746808Sdab case TELQUAL_REPLY:
96846808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
96946808Sdab return;
97046808Sdab auth_reply(subpointer, SB_LEN());
97146808Sdab break;
97247608Sdab case TELQUAL_NAME:
97347608Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
97447608Sdab return;
97547608Sdab auth_name(subpointer, SB_LEN());
97647608Sdab break;
97743319Skfall }
97846808Sdab }
97946808Sdab break;
98043319Skfall #endif
98160149Sdab #ifdef ENCRYPTION
98246808Sdab case TELOPT_ENCRYPT:
98346808Sdab if (SB_EOF())
98446808Sdab return;
98546808Sdab switch(SB_GET()) {
98646808Sdab case ENCRYPT_START:
98746808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT))
98846808Sdab return;
98947608Sdab encrypt_start(subpointer, SB_LEN());
99046808Sdab break;
99146808Sdab case ENCRYPT_END:
99246808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT))
99346808Sdab return;
99446808Sdab encrypt_end();
99546808Sdab break;
99646808Sdab case ENCRYPT_SUPPORT:
99746808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT))
99846808Sdab return;
99946808Sdab encrypt_support(subpointer, SB_LEN());
100046808Sdab break;
100146808Sdab case ENCRYPT_REQSTART:
100246808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT))
100346808Sdab return;
100447608Sdab encrypt_request_start(subpointer, SB_LEN());
100546808Sdab break;
100646808Sdab case ENCRYPT_REQEND:
100746808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT))
100846808Sdab return;
100946808Sdab /*
101046808Sdab * We can always send an REQEND so that we cannot
101146808Sdab * get stuck encrypting. We should only get this
101246808Sdab * if we have been able to get in the correct mode
101346808Sdab * anyhow.
101446808Sdab */
101546808Sdab encrypt_request_end();
101646808Sdab break;
101746808Sdab case ENCRYPT_IS:
101846808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT))
101946808Sdab return;
102046808Sdab encrypt_is(subpointer, SB_LEN());
102146808Sdab break;
102246808Sdab case ENCRYPT_REPLY:
102346808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT))
102446808Sdab return;
102546808Sdab encrypt_reply(subpointer, SB_LEN());
102646808Sdab break;
102747608Sdab case ENCRYPT_ENC_KEYID:
102847608Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT))
102947608Sdab return;
103047608Sdab encrypt_enc_keyid(subpointer, SB_LEN());
103147608Sdab break;
103247608Sdab case ENCRYPT_DEC_KEYID:
103347608Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT))
103447608Sdab return;
103547608Sdab encrypt_dec_keyid(subpointer, SB_LEN());
103647608Sdab break;
103746808Sdab default:
103846808Sdab break;
103946808Sdab }
104046808Sdab break;
104160149Sdab #endif /* ENCRYPTION */
104227676Sminshall default:
104327676Sminshall break;
104427676Sminshall }
104527676Sminshall }
104638689Sborman
104746808Sdab static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
104838689Sborman
104946808Sdab void
lm_will(cmd,len)105038689Sborman lm_will(cmd, len)
105146808Sdab unsigned char *cmd;
105246808Sdab int len;
105338689Sborman {
105444360Sborman if (len < 1) {
105544360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
105644360Sborman return;
105744360Sborman }
105838689Sborman switch(cmd[0]) {
105938689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */
106038689Sborman default:
106138689Sborman str_lm[3] = DONT;
106238689Sborman str_lm[4] = cmd[0];
106338689Sborman if (NETROOM() > sizeof(str_lm)) {
106438689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm));
106538689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2);
106638689Sborman }
106738689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n");
106838689Sborman break;
106938689Sborman }
107038689Sborman }
107138689Sborman
107246808Sdab void
lm_wont(cmd,len)107338689Sborman lm_wont(cmd, len)
107446808Sdab unsigned char *cmd;
107546808Sdab int len;
107638689Sborman {
107744360Sborman if (len < 1) {
107844360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
107944360Sborman return;
108044360Sborman }
108138689Sborman switch(cmd[0]) {
108238689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */
108338689Sborman default:
108438689Sborman /* We are always DONT, so don't respond */
108538689Sborman return;
108638689Sborman }
108738689Sborman }
108838689Sborman
108946808Sdab void
lm_do(cmd,len)109038689Sborman lm_do(cmd, len)
109146808Sdab unsigned char *cmd;
109246808Sdab int len;
109338689Sborman {
109444360Sborman if (len < 1) {
109544360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
109644360Sborman return;
109744360Sborman }
109838689Sborman switch(cmd[0]) {
109938689Sborman case LM_FORWARDMASK:
110038689Sborman default:
110138689Sborman str_lm[3] = WONT;
110238689Sborman str_lm[4] = cmd[0];
110338689Sborman if (NETROOM() > sizeof(str_lm)) {
110438689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm));
110538689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2);
110638689Sborman }
110738689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n");
110838689Sborman break;
110938689Sborman }
111038689Sborman }
111138689Sborman
111246808Sdab void
lm_dont(cmd,len)111338689Sborman lm_dont(cmd, len)
111446808Sdab unsigned char *cmd;
111546808Sdab int len;
111638689Sborman {
111744360Sborman if (len < 1) {
111844360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
111944360Sborman return;
112044360Sborman }
112138689Sborman switch(cmd[0]) {
112238689Sborman case LM_FORWARDMASK:
112338689Sborman default:
112438689Sborman /* we are always WONT, so don't respond */
112538689Sborman break;
112638689Sborman }
112738689Sborman }
112838689Sborman
112946808Sdab static unsigned char str_lm_mode[] = {
113046808Sdab IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
113146808Sdab };
113238689Sborman
113346808Sdab void
lm_mode(cmd,len,init)113438689Sborman lm_mode(cmd, len, init)
113546808Sdab unsigned char *cmd;
113646808Sdab int len, init;
113738689Sborman {
113838689Sborman if (len != 1)
113938689Sborman return;
114044360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
114138689Sborman return;
114238689Sborman if (*cmd&MODE_ACK)
114338689Sborman return;
114444360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK);
114538689Sborman str_lm_mode[4] = linemode;
114638689Sborman if (!init)
114738689Sborman str_lm_mode[4] |= MODE_ACK;
114838689Sborman if (NETROOM() > sizeof(str_lm_mode)) {
114938689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
115038689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
115138689Sborman }
115238689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n");
115338689Sborman setconnmode(0); /* set changed mode */
115438689Sborman }
115538689Sborman
115632377Sminshall
115727088Sminshall
115838689Sborman /*
115938689Sborman * slc()
116038689Sborman * Handle special character suboption of LINEMODE.
116138689Sborman */
116238689Sborman
116338689Sborman struct spc {
116440245Sborman cc_t val;
116540245Sborman cc_t *valp;
116638689Sborman char flags; /* Current flags & level */
116738689Sborman char mylevel; /* Maximum level & flags */
116838689Sborman } spc_data[NSLC+1];
116938689Sborman
117038689Sborman #define SLC_IMPORT 0
117138689Sborman #define SLC_EXPORT 1
117238689Sborman #define SLC_RVALUE 2
117338689Sborman static int slc_mode = SLC_EXPORT;
117438689Sborman
117546808Sdab void
slc_init()117638689Sborman slc_init()
117738689Sborman {
117838689Sborman register struct spc *spcp;
117938689Sborman
118038689Sborman localchars = 1;
118138689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
118238689Sborman spcp->val = 0;
118338689Sborman spcp->valp = 0;
118438689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
118538689Sborman }
118638689Sborman
118738689Sborman #define initfunc(func, flags) { \
118838689Sborman spcp = &spc_data[func]; \
118938689Sborman if (spcp->valp = tcval(func)) { \
119038689Sborman spcp->val = *spcp->valp; \
119138689Sborman spcp->mylevel = SLC_VARIABLE|flags; \
119238689Sborman } else { \
119338689Sborman spcp->val = 0; \
119438689Sborman spcp->mylevel = SLC_DEFAULT; \
119538689Sborman } \
119638689Sborman }
119738689Sborman
119838689Sborman initfunc(SLC_SYNCH, 0);
119938689Sborman /* No BRK */
120038689Sborman initfunc(SLC_AO, 0);
120138689Sborman initfunc(SLC_AYT, 0);
120238689Sborman /* No EOR */
120338689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
120438689Sborman initfunc(SLC_EOF, 0);
120539529Sborman #ifndef SYSV_TERMIO
120638689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN);
120738689Sborman #endif
120838689Sborman initfunc(SLC_EC, 0);
120938689Sborman initfunc(SLC_EL, 0);
121039529Sborman #ifndef SYSV_TERMIO
121138689Sborman initfunc(SLC_EW, 0);
121238689Sborman initfunc(SLC_RP, 0);
121338689Sborman initfunc(SLC_LNEXT, 0);
121438689Sborman #endif
121538689Sborman initfunc(SLC_XON, 0);
121638689Sborman initfunc(SLC_XOFF, 0);
121739529Sborman #ifdef SYSV_TERMIO
121838689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
121938689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
122038689Sborman #endif
122144360Sborman initfunc(SLC_FORW1, 0);
122244360Sborman #ifdef USE_TERMIO
122344360Sborman initfunc(SLC_FORW2, 0);
122438689Sborman /* No FORW2 */
122544360Sborman #endif
122638689Sborman
122738689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
122838689Sborman #undef initfunc
122938689Sborman
123038689Sborman if (slc_mode == SLC_EXPORT)
123138689Sborman slc_export();
123238689Sborman else
123338689Sborman slc_import(1);
123438689Sborman
123538689Sborman }
123638689Sborman
123746808Sdab void
slcstate()123838689Sborman slcstate()
123938689Sborman {
124038689Sborman printf("Special characters are %s values\n",
124138689Sborman slc_mode == SLC_IMPORT ? "remote default" :
124238689Sborman slc_mode == SLC_EXPORT ? "local" :
124338689Sborman "remote");
124438689Sborman }
124538689Sborman
124646808Sdab void
slc_mode_export()124738689Sborman slc_mode_export()
124838689Sborman {
124938689Sborman slc_mode = SLC_EXPORT;
125038689Sborman if (my_state_is_will(TELOPT_LINEMODE))
125138689Sborman slc_export();
125238689Sborman }
125338689Sborman
125446808Sdab void
slc_mode_import(def)125538689Sborman slc_mode_import(def)
125646808Sdab int def;
125738689Sborman {
125838689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
125938689Sborman if (my_state_is_will(TELOPT_LINEMODE))
126038689Sborman slc_import(def);
126138689Sborman }
126238689Sborman
126346808Sdab unsigned char slc_import_val[] = {
126438689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
126538689Sborman };
126646808Sdab unsigned char slc_import_def[] = {
126738689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
126838689Sborman };
126938689Sborman
127046808Sdab void
slc_import(def)127138689Sborman slc_import(def)
127246808Sdab int def;
127338689Sborman {
127438689Sborman if (NETROOM() > sizeof(slc_import_val)) {
127538689Sborman if (def) {
127638689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
127738689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
127838689Sborman } else {
127938689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
128038689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
128138689Sborman }
128238689Sborman }
128338689Sborman /*@*/ else printf("slc_import: not enough room\n");
128438689Sborman }
128538689Sborman
128646808Sdab void
slc_export()128738689Sborman slc_export()
128838689Sborman {
128938689Sborman register struct spc *spcp;
129038689Sborman
129138689Sborman TerminalDefaultChars();
129238689Sborman
129338689Sborman slc_start_reply();
129438689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
129538689Sborman if (spcp->mylevel != SLC_NOSUPPORT) {
129645232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE))
129745232Sborman spcp->flags = SLC_NOSUPPORT;
129845232Sborman else
129945232Sborman spcp->flags = spcp->mylevel;
130038689Sborman if (spcp->valp)
130138689Sborman spcp->val = *spcp->valp;
130245232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
130338689Sborman }
130438689Sborman }
130538689Sborman slc_end_reply();
130646808Sdab (void)slc_update();
130746808Sdab setconnmode(1); /* Make sure the character values are set */
130838689Sborman }
130938689Sborman
131046808Sdab void
slc(cp,len)131138689Sborman slc(cp, len)
131246808Sdab register unsigned char *cp;
131346808Sdab int len;
131438689Sborman {
131538689Sborman register struct spc *spcp;
131638689Sborman register int func,level;
131738689Sborman
131838689Sborman slc_start_reply();
131938689Sborman
132038689Sborman for (; len >= 3; len -=3, cp +=3) {
132138689Sborman
132238689Sborman func = cp[SLC_FUNC];
132338689Sborman
132438689Sborman if (func == 0) {
132538689Sborman /*
132638689Sborman * Client side: always ignore 0 function.
132738689Sborman */
132838689Sborman continue;
132938689Sborman }
133038689Sborman if (func > NSLC) {
133145232Sborman if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
133238689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0);
133338689Sborman continue;
133438689Sborman }
133538689Sborman
133638689Sborman spcp = &spc_data[func];
133738689Sborman
133838689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
133938689Sborman
134040245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
134138689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
134238689Sborman continue;
134338689Sborman }
134438689Sborman
134538689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) {
134638689Sborman /*
134738689Sborman * This is an error condition, the SLC_ACK
134838689Sborman * bit should never be set for the SLC_DEFAULT
134938689Sborman * level. Our best guess to recover is to
135038689Sborman * ignore the SLC_ACK bit.
135138689Sborman */
135238689Sborman cp[SLC_FLAGS] &= ~SLC_ACK;
135338689Sborman }
135438689Sborman
135538689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
135640245Sborman spcp->val = (cc_t)cp[SLC_VALUE];
135738689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
135838689Sborman continue;
135938689Sborman }
136038689Sborman
136138689Sborman level &= ~SLC_ACK;
136238689Sborman
136338689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
136438689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
136540245Sborman spcp->val = (cc_t)cp[SLC_VALUE];
136638689Sborman }
136738689Sborman if (level == SLC_DEFAULT) {
136838689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
136938689Sborman spcp->flags = spcp->mylevel;
137038689Sborman else
137138689Sborman spcp->flags = SLC_NOSUPPORT;
137238689Sborman }
137338689Sborman slc_add_reply(func, spcp->flags, spcp->val);
137438689Sborman }
137538689Sborman slc_end_reply();
137638689Sborman if (slc_update())
137738689Sborman setconnmode(1); /* set the new character values */
137838689Sborman }
137938689Sborman
138046808Sdab void
slc_check()138138689Sborman slc_check()
138238689Sborman {
138338689Sborman register struct spc *spcp;
138438689Sborman
138538689Sborman slc_start_reply();
138638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
138738689Sborman if (spcp->valp && spcp->val != *spcp->valp) {
138838689Sborman spcp->val = *spcp->valp;
138945232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE))
139045232Sborman spcp->flags = SLC_NOSUPPORT;
139145232Sborman else
139245232Sborman spcp->flags = spcp->mylevel;
139345232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
139438689Sborman }
139538689Sborman }
139638689Sborman slc_end_reply();
139738689Sborman setconnmode(1);
139838689Sborman }
139938689Sborman
140038689Sborman
140138689Sborman unsigned char slc_reply[128];
140238689Sborman unsigned char *slc_replyp;
140346808Sdab
140446808Sdab void
slc_start_reply()140538689Sborman slc_start_reply()
140638689Sborman {
140738689Sborman slc_replyp = slc_reply;
140838689Sborman *slc_replyp++ = IAC;
140938689Sborman *slc_replyp++ = SB;
141038689Sborman *slc_replyp++ = TELOPT_LINEMODE;
141138689Sborman *slc_replyp++ = LM_SLC;
141238689Sborman }
141338689Sborman
141446808Sdab void
slc_add_reply(func,flags,value)141538689Sborman slc_add_reply(func, flags, value)
141646808Sdab unsigned char func;
141746808Sdab unsigned char flags;
141846808Sdab cc_t value;
141938689Sborman {
142038689Sborman if ((*slc_replyp++ = func) == IAC)
142138689Sborman *slc_replyp++ = IAC;
142238689Sborman if ((*slc_replyp++ = flags) == IAC)
142338689Sborman *slc_replyp++ = IAC;
142440245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC)
142538689Sborman *slc_replyp++ = IAC;
142638689Sborman }
142738689Sborman
142846808Sdab void
slc_end_reply()142938689Sborman slc_end_reply()
143038689Sborman {
143138689Sborman register int len;
143238689Sborman
143338689Sborman *slc_replyp++ = IAC;
143438689Sborman *slc_replyp++ = SE;
143538689Sborman len = slc_replyp - slc_reply;
143638689Sborman if (len <= 6)
143738689Sborman return;
143838689Sborman if (NETROOM() > len) {
143938689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
144038689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
144138689Sborman }
144238689Sborman /*@*/else printf("slc_end_reply: not enough room\n");
144338689Sborman }
144438689Sborman
144546808Sdab int
slc_update()144638689Sborman slc_update()
144738689Sborman {
144838689Sborman register struct spc *spcp;
144938689Sborman int need_update = 0;
145038689Sborman
145138689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
145238689Sborman if (!(spcp->flags&SLC_ACK))
145338689Sborman continue;
145438689Sborman spcp->flags &= ~SLC_ACK;
145538689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) {
145638689Sborman *spcp->valp = spcp->val;
145738689Sborman need_update = 1;
145838689Sborman }
145938689Sborman }
146038689Sborman return(need_update);
146138689Sborman }
146238689Sborman
146365157Sdab #ifdef OLD_ENVIRON
146465157Sdab # ifdef ENV_HACK
146558972Sdab /*
146658972Sdab * Earlier version of telnet/telnetd from the BSD code had
146758972Sdab * the definitions of VALUE and VAR reversed. To ensure
146858972Sdab * maximum interoperability, we assume that the server is
146958972Sdab * an older BSD server, until proven otherwise. The newer
147058972Sdab * BSD servers should be able to handle either definition,
147158972Sdab * so it is better to use the wrong values if we don't
147258972Sdab * know what type of server it is.
147358972Sdab */
147458972Sdab int env_auto = 1;
147565157Sdab int old_env_var = OLD_ENV_VAR;
147665157Sdab int old_env_value = OLD_ENV_VALUE;
147765157Sdab # else
147865157Sdab # define old_env_var OLD_ENV_VAR
147965157Sdab # define old_env_value OLD_ENV_VALUE
148065157Sdab # endif
148158972Sdab #endif
148258972Sdab
148346808Sdab void
env_opt(buf,len)148444360Sborman env_opt(buf, len)
148546808Sdab register unsigned char *buf;
148646808Sdab register int len;
148744360Sborman {
148846808Sdab register unsigned char *ep = 0, *epc = 0;
148944360Sborman register int i;
149044360Sborman
149145232Sborman switch(buf[0]&0xff) {
149244360Sborman case TELQUAL_SEND:
149344360Sborman env_opt_start();
149444360Sborman if (len == 1) {
149544360Sborman env_opt_add(NULL);
149644360Sborman } else for (i = 1; i < len; i++) {
149745232Sborman switch (buf[i]&0xff) {
149865157Sdab #ifdef OLD_ENVIRON
149965157Sdab case OLD_ENV_VAR:
150065157Sdab # ifdef ENV_HACK
150165157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON
150265157Sdab && env_auto) {
150365157Sdab /* Server has the same definitions */
150465157Sdab old_env_var = OLD_ENV_VAR;
150565157Sdab old_env_value = OLD_ENV_VALUE;
150658972Sdab }
150758972Sdab /* FALL THROUGH */
150865157Sdab # endif
150965157Sdab case OLD_ENV_VALUE:
151058972Sdab /*
151165157Sdab * Although OLD_ENV_VALUE is not legal, we will
151258972Sdab * still recognize it, just in case it is an
151358972Sdab * old server that has VAR & VALUE mixed up...
151458972Sdab */
151558972Sdab /* FALL THROUGH */
151665157Sdab #else
151765157Sdab case NEW_ENV_VAR:
151865157Sdab #endif
151958972Sdab case ENV_USERVAR:
152044360Sborman if (ep) {
152144360Sborman *epc = 0;
152244360Sborman env_opt_add(ep);
152344360Sborman }
152444360Sborman ep = epc = &buf[i+1];
152544360Sborman break;
152644360Sborman case ENV_ESC:
152744360Sborman i++;
152844360Sborman /*FALL THROUGH*/
152944360Sborman default:
153044360Sborman if (epc)
153144360Sborman *epc++ = buf[i];
153244360Sborman break;
153344360Sborman }
153444360Sborman }
153558972Sdab if (ep) {
153658972Sdab *epc = 0;
153758972Sdab env_opt_add(ep);
153858972Sdab }
153944360Sborman env_opt_end(1);
154044360Sborman break;
154144360Sborman
154244360Sborman case TELQUAL_IS:
154344360Sborman case TELQUAL_INFO:
154444360Sborman /* Ignore for now. We shouldn't get it anyway. */
154544360Sborman break;
154644360Sborman
154744360Sborman default:
154844360Sborman break;
154944360Sborman }
155044360Sborman }
155144360Sborman
155244360Sborman #define OPT_REPLY_SIZE 256
155344360Sborman unsigned char *opt_reply;
155444360Sborman unsigned char *opt_replyp;
155544360Sborman unsigned char *opt_replyend;
155644360Sborman
155746808Sdab void
env_opt_start()155844360Sborman env_opt_start()
155944360Sborman {
156044360Sborman if (opt_reply)
156144360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
156244360Sborman else
156344360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
156444360Sborman if (opt_reply == NULL) {
156544360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
156644360Sborman opt_reply = opt_replyp = opt_replyend = NULL;
156744360Sborman return;
156844360Sborman }
156944360Sborman opt_replyp = opt_reply;
157044360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE;
157144360Sborman *opt_replyp++ = IAC;
157244360Sborman *opt_replyp++ = SB;
157365157Sdab *opt_replyp++ = telopt_environ;
157444360Sborman *opt_replyp++ = TELQUAL_IS;
157544360Sborman }
157644360Sborman
157746808Sdab void
env_opt_start_info()157844360Sborman env_opt_start_info()
157944360Sborman {
158044360Sborman env_opt_start();
158144360Sborman if (opt_replyp)
158244360Sborman opt_replyp[-1] = TELQUAL_INFO;
158344360Sborman }
158444360Sborman
158546808Sdab void
env_opt_add(ep)158644360Sborman env_opt_add(ep)
158746808Sdab register unsigned char *ep;
158844360Sborman {
158946808Sdab register unsigned char *vp, c;
159044360Sborman
159144360Sborman if (opt_reply == NULL) /*XXX*/
159244360Sborman return; /*XXX*/
159344360Sborman
159444360Sborman if (ep == NULL || *ep == '\0') {
159557213Sdab /* Send user defined variables first. */
159657213Sdab env_default(1, 0);
159757213Sdab while (ep = env_default(0, 0))
159844360Sborman env_opt_add(ep);
159957213Sdab
160057213Sdab /* Now add the list of well know variables. */
160157213Sdab env_default(1, 1);
160257213Sdab while (ep = env_default(0, 1))
160357213Sdab env_opt_add(ep);
160444360Sborman return;
160544360Sborman }
160644360Sborman vp = env_getvalue(ep);
160746808Sdab if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
160846808Sdab strlen((char *)ep) + 6 > opt_replyend)
160946808Sdab {
161044360Sborman register int len;
161144360Sborman opt_replyend += OPT_REPLY_SIZE;
161244360Sborman len = opt_replyend - opt_reply;
161344360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len);
161444360Sborman if (opt_reply == NULL) {
161544360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n");
161644360Sborman opt_reply = opt_replyp = opt_replyend = NULL;
161744360Sborman return;
161844360Sborman }
161944360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
162044360Sborman opt_replyend = opt_reply + len;
162144360Sborman }
162257213Sdab if (opt_welldefined(ep))
162365157Sdab #ifdef OLD_ENVIRON
162465157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON)
162565157Sdab *opt_replyp++ = old_env_var;
162665157Sdab else
162765157Sdab #endif
162865157Sdab *opt_replyp++ = NEW_ENV_VAR;
162957213Sdab else
163057213Sdab *opt_replyp++ = ENV_USERVAR;
163144360Sborman for (;;) {
163244360Sborman while (c = *ep++) {
163345232Sborman switch(c&0xff) {
163444360Sborman case IAC:
163544360Sborman *opt_replyp++ = IAC;
163644360Sborman break;
163765157Sdab case NEW_ENV_VAR:
163865157Sdab case NEW_ENV_VALUE:
163944360Sborman case ENV_ESC:
164057213Sdab case ENV_USERVAR:
164144360Sborman *opt_replyp++ = ENV_ESC;
164244360Sborman break;
164344360Sborman }
164444360Sborman *opt_replyp++ = c;
164544360Sborman }
164644360Sborman if (ep = vp) {
164765157Sdab #ifdef OLD_ENVIRON
164865157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON)
164965157Sdab *opt_replyp++ = old_env_value;
165065157Sdab else
165165157Sdab #endif
165265157Sdab *opt_replyp++ = NEW_ENV_VALUE;
165344360Sborman vp = NULL;
165444360Sborman } else
165544360Sborman break;
165644360Sborman }
165744360Sborman }
165844360Sborman
165957213Sdab int
opt_welldefined(ep)166057213Sdab opt_welldefined(ep)
166157213Sdab char *ep;
166257213Sdab {
166357213Sdab if ((strcmp(ep, "USER") == 0) ||
166457213Sdab (strcmp(ep, "DISPLAY") == 0) ||
166557213Sdab (strcmp(ep, "PRINTER") == 0) ||
166657213Sdab (strcmp(ep, "SYSTEMTYPE") == 0) ||
166757213Sdab (strcmp(ep, "JOB") == 0) ||
166857213Sdab (strcmp(ep, "ACCT") == 0))
166957213Sdab return(1);
167057213Sdab return(0);
167157213Sdab }
167246808Sdab void
env_opt_end(emptyok)167344360Sborman env_opt_end(emptyok)
167446808Sdab register int emptyok;
167544360Sborman {
167644360Sborman register int len;
167744360Sborman
167844360Sborman len = opt_replyp - opt_reply + 2;
167944360Sborman if (emptyok || len > 6) {
168044360Sborman *opt_replyp++ = IAC;
168144360Sborman *opt_replyp++ = SE;
168244360Sborman if (NETROOM() > len) {
168344360Sborman ring_supply_data(&netoring, opt_reply, len);
168444360Sborman printsub('>', &opt_reply[2], len - 2);
168544360Sborman }
168644360Sborman /*@*/ else printf("slc_end_reply: not enough room\n");
168744360Sborman }
168844360Sborman if (opt_reply) {
168944360Sborman free(opt_reply);
169044360Sborman opt_reply = opt_replyp = opt_replyend = NULL;
169144360Sborman }
169244360Sborman }
169344360Sborman
169438689Sborman
169538689Sborman
169646808Sdab int
telrcv()169732377Sminshall telrcv()
169827110Sminshall {
169932377Sminshall register int c;
170032385Sminshall register int scc;
170146808Sdab register unsigned char *sbp;
170232385Sminshall int count;
170332385Sminshall int returnValue = 0;
170427088Sminshall
170532385Sminshall scc = 0;
170632385Sminshall count = 0;
170732385Sminshall while (TTYROOM() > 2) {
170832385Sminshall if (scc == 0) {
170932385Sminshall if (count) {
171032528Sminshall ring_consumed(&netiring, count);
171132385Sminshall returnValue = 1;
171232385Sminshall count = 0;
171332385Sminshall }
171432528Sminshall sbp = netiring.consume;
171532528Sminshall scc = ring_full_consecutive(&netiring);
171632385Sminshall if (scc == 0) {
171732385Sminshall /* No more data coming in */
171832385Sminshall break;
171932385Sminshall }
172032385Sminshall }
172132385Sminshall
172232385Sminshall c = *sbp++ & 0xff, scc--; count++;
172360149Sdab #ifdef ENCRYPTION
172446808Sdab if (decrypt_input)
172546808Sdab c = (*decrypt_input)(c);
172660149Sdab #endif /* ENCRYPTION */
172732385Sminshall
172832377Sminshall switch (telrcv_state) {
172927110Sminshall
173032377Sminshall case TS_CR:
173132377Sminshall telrcv_state = TS_DATA;
173235518Sminshall if (c == '\0') {
173335518Sminshall break; /* Ignore \0 after CR */
173439529Sborman }
173539529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
173635518Sminshall TTYADD(c);
173735518Sminshall break;
173832377Sminshall }
173935518Sminshall /* Else, fall through */
174027088Sminshall
174132377Sminshall case TS_DATA:
174232377Sminshall if (c == IAC) {
174332377Sminshall telrcv_state = TS_IAC;
174433804Sminshall break;
174532377Sminshall }
174632377Sminshall # if defined(TN3270)
174732377Sminshall if (In3270) {
174832377Sminshall *Ifrontp++ = c;
174932385Sminshall while (scc > 0) {
175032385Sminshall c = *sbp++ & 0377, scc--; count++;
175160149Sdab #ifdef ENCRYPTION
175246808Sdab if (decrypt_input)
175346808Sdab c = (*decrypt_input)(c);
175460149Sdab #endif /* ENCRYPTION */
175532377Sminshall if (c == IAC) {
175632377Sminshall telrcv_state = TS_IAC;
175734304Sminshall break;
175832377Sminshall }
175932377Sminshall *Ifrontp++ = c;
176032377Sminshall }
176132377Sminshall } else
176232377Sminshall # endif /* defined(TN3270) */
176335518Sminshall /*
176435518Sminshall * The 'crmod' hack (see following) is needed
176535518Sminshall * since we can't * set CRMOD on output only.
176635518Sminshall * Machines like MULTICS like to send \r without
176735518Sminshall * \n; since we must turn off CRMOD to get proper
176835518Sminshall * input, the mapping is done here (sigh).
176935518Sminshall */
177038689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
177135518Sminshall if (scc > 0) {
177235518Sminshall c = *sbp&0xff;
177360149Sdab #ifdef ENCRYPTION
177446808Sdab if (decrypt_input)
177546808Sdab c = (*decrypt_input)(c);
177660149Sdab #endif /* ENCRYPTION */
177735518Sminshall if (c == 0) {
177835518Sminshall sbp++, scc--; count++;
177935518Sminshall /* a "true" CR */
178032377Sminshall TTYADD('\r');
178138689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) &&
178235518Sminshall (c == '\n')) {
178335518Sminshall sbp++, scc--; count++;
178432377Sminshall TTYADD('\n');
178535518Sminshall } else {
178660149Sdab #ifdef ENCRYPTION
1787*69785Sdab if (decrypt_input)
178846808Sdab (*decrypt_input)(-1);
178960149Sdab #endif /* ENCRYPTION */
179046808Sdab
179135518Sminshall TTYADD('\r');
179235518Sminshall if (crmod) {
179335518Sminshall TTYADD('\n');
179432377Sminshall }
179532377Sminshall }
179635518Sminshall } else {
179735518Sminshall telrcv_state = TS_CR;
179835518Sminshall TTYADD('\r');
179935518Sminshall if (crmod) {
180035518Sminshall TTYADD('\n');
180135518Sminshall }
180232377Sminshall }
180332377Sminshall } else {
180432377Sminshall TTYADD(c);
180532377Sminshall }
180632377Sminshall continue;
180727088Sminshall
180832377Sminshall case TS_IAC:
180938689Sborman process_iac:
181032377Sminshall switch (c) {
1811*69785Sdab
181232377Sminshall case WILL:
181332377Sminshall telrcv_state = TS_WILL;
181432377Sminshall continue;
181527261Sminshall
181632377Sminshall case WONT:
181732377Sminshall telrcv_state = TS_WONT;
181832377Sminshall continue;
181927261Sminshall
182032377Sminshall case DO:
182132377Sminshall telrcv_state = TS_DO;
182232377Sminshall continue;
182327261Sminshall
182432377Sminshall case DONT:
182532377Sminshall telrcv_state = TS_DONT;
182632377Sminshall continue;
182727261Sminshall
182832377Sminshall case DM:
182932377Sminshall /*
183032377Sminshall * We may have missed an urgent notification,
183132377Sminshall * so make sure we flush whatever is in the
183232377Sminshall * buffer currently.
183332377Sminshall */
183446808Sdab printoption("RCVD", IAC, DM);
183532377Sminshall SYNCHing = 1;
183644360Sborman (void) ttyflush(1);
183732554Sminshall SYNCHing = stilloob();
183832377Sminshall settimer(gotDM);
183932377Sminshall break;
184027088Sminshall
184132377Sminshall case SB:
184232377Sminshall SB_CLEAR();
184332377Sminshall telrcv_state = TS_SB;
184432377Sminshall continue;
184527261Sminshall
184632377Sminshall # if defined(TN3270)
184732377Sminshall case EOR:
184832377Sminshall if (In3270) {
184932377Sminshall if (Ibackp == Ifrontp) {
185032377Sminshall Ibackp = Ifrontp = Ibuf;
185132377Sminshall ISend = 0; /* should have been! */
185232377Sminshall } else {
185344360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
185432377Sminshall ISend = 1;
185527088Sminshall }
185627088Sminshall }
185746808Sdab printoption("RCVD", IAC, EOR);
185827088Sminshall break;
185932377Sminshall # endif /* defined(TN3270) */
186032377Sminshall
186132377Sminshall case IAC:
186232377Sminshall # if !defined(TN3270)
186332377Sminshall TTYADD(IAC);
186432377Sminshall # else /* !defined(TN3270) */
186532377Sminshall if (In3270) {
186632377Sminshall *Ifrontp++ = IAC;
186732377Sminshall } else {
186832377Sminshall TTYADD(IAC);
186932377Sminshall }
187032377Sminshall # endif /* !defined(TN3270) */
187127088Sminshall break;
187232377Sminshall
187344360Sborman case NOP:
187444360Sborman case GA:
187527088Sminshall default:
187646808Sdab printoption("RCVD", IAC, c);
187727088Sminshall break;
187827088Sminshall }
187932377Sminshall telrcv_state = TS_DATA;
188032377Sminshall continue;
188127088Sminshall
188232377Sminshall case TS_WILL:
188346808Sdab printoption("RCVD", WILL, c);
188438689Sborman willoption(c);
188532377Sminshall SetIn3270();
188632377Sminshall telrcv_state = TS_DATA;
188732377Sminshall continue;
188827110Sminshall
188932377Sminshall case TS_WONT:
189046808Sdab printoption("RCVD", WONT, c);
189138689Sborman wontoption(c);
189232377Sminshall SetIn3270();
189332377Sminshall telrcv_state = TS_DATA;
189432377Sminshall continue;
189527088Sminshall
189632377Sminshall case TS_DO:
189746808Sdab printoption("RCVD", DO, c);
189837226Sminshall dooption(c);
189932377Sminshall SetIn3270();
190037219Sminshall if (c == TELOPT_NAWS) {
190137219Sminshall sendnaws();
190237219Sminshall } else if (c == TELOPT_LFLOW) {
190337219Sminshall localflow = 1;
190437219Sminshall setcommandmode();
190538689Sborman setconnmode(0);
190637219Sminshall }
190732377Sminshall telrcv_state = TS_DATA;
190832377Sminshall continue;
190927088Sminshall
191032377Sminshall case TS_DONT:
191146808Sdab printoption("RCVD", DONT, c);
191238689Sborman dontoption(c);
191337226Sminshall flushline = 1;
191438689Sborman setconnmode(0); /* set new tty mode (maybe) */
191532377Sminshall SetIn3270();
191632377Sminshall telrcv_state = TS_DATA;
191732377Sminshall continue;
191827088Sminshall
191932377Sminshall case TS_SB:
192032377Sminshall if (c == IAC) {
192132377Sminshall telrcv_state = TS_SE;
192232377Sminshall } else {
192332377Sminshall SB_ACCUM(c);
192432377Sminshall }
192532377Sminshall continue;
192627088Sminshall
192732377Sminshall case TS_SE:
192832377Sminshall if (c != SE) {
192932377Sminshall if (c != IAC) {
193038689Sborman /*
193138689Sborman * This is an error. We only expect to get
193238689Sborman * "IAC IAC" or "IAC SE". Several things may
193338689Sborman * have happend. An IAC was not doubled, the
193438689Sborman * IAC SE was left off, or another option got
193538689Sborman * inserted into the suboption are all possibilities.
193638689Sborman * If we assume that the IAC was not doubled,
193738689Sborman * and really the IAC SE was left off, we could
193838689Sborman * get into an infinate loop here. So, instead,
193938689Sborman * we terminate the suboption, and process the
194038689Sborman * partial suboption if we can.
194138689Sborman */
194232377Sminshall SB_ACCUM(IAC);
194338689Sborman SB_ACCUM(c);
194446808Sdab subpointer -= 2;
194546808Sdab SB_TERM();
194646808Sdab
194746808Sdab printoption("In SUBOPTION processing, RCVD", IAC, c);
194838689Sborman suboption(); /* handle sub-option */
194938689Sborman SetIn3270();
195038689Sborman telrcv_state = TS_IAC;
195138689Sborman goto process_iac;
195232377Sminshall }
195332377Sminshall SB_ACCUM(c);
195432377Sminshall telrcv_state = TS_SB;
195532377Sminshall } else {
195638689Sborman SB_ACCUM(IAC);
195738689Sborman SB_ACCUM(SE);
195846808Sdab subpointer -= 2;
195946808Sdab SB_TERM();
196032377Sminshall suboption(); /* handle sub-option */
196132377Sminshall SetIn3270();
196232377Sminshall telrcv_state = TS_DATA;
196332377Sminshall }
196427088Sminshall }
196527088Sminshall }
196632667Sminshall if (count)
196732667Sminshall ring_consumed(&netiring, count);
196832385Sminshall return returnValue||count;
196927088Sminshall }
197032385Sminshall
197146808Sdab static int bol = 1, local = 0;
197246808Sdab
197346808Sdab int
rlogin_susp()197446808Sdab rlogin_susp()
197546808Sdab {
197646808Sdab if (local) {
197746808Sdab local = 0;
197846808Sdab bol = 1;
197946808Sdab command(0, "z\n", 2);
198046808Sdab return(1);
198146808Sdab }
198246808Sdab return(0);
198346808Sdab }
198446808Sdab
198546808Sdab static int
telsnd()198632554Sminshall telsnd()
198732385Sminshall {
198832385Sminshall int tcc;
198932385Sminshall int count;
199032385Sminshall int returnValue = 0;
199146808Sdab unsigned char *tbp;
199232385Sminshall
199332385Sminshall tcc = 0;
199432385Sminshall count = 0;
199532385Sminshall while (NETROOM() > 2) {
199632385Sminshall register int sc;
199732385Sminshall register int c;
199832385Sminshall
199932385Sminshall if (tcc == 0) {
200032385Sminshall if (count) {
200132528Sminshall ring_consumed(&ttyiring, count);
200232385Sminshall returnValue = 1;
200332385Sminshall count = 0;
200432385Sminshall }
200532528Sminshall tbp = ttyiring.consume;
200632528Sminshall tcc = ring_full_consecutive(&ttyiring);
200732385Sminshall if (tcc == 0) {
200832385Sminshall break;
200932385Sminshall }
201032385Sminshall }
201132385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
201246808Sdab if (rlogin != _POSIX_VDISABLE) {
201346808Sdab if (bol) {
201446808Sdab bol = 0;
201546808Sdab if (sc == rlogin) {
201646808Sdab local = 1;
201746808Sdab continue;
201846808Sdab }
201946808Sdab } else if (local) {
202046808Sdab local = 0;
202146808Sdab if (sc == '.' || c == termEofChar) {
202246808Sdab bol = 1;
202346808Sdab command(0, "close\n", 6);
202446808Sdab continue;
202546808Sdab }
202646808Sdab if (sc == termSuspChar) {
202746808Sdab bol = 1;
202846808Sdab command(0, "z\n", 2);
202946808Sdab continue;
203046808Sdab }
203146808Sdab if (sc == escape) {
203246808Sdab command(0, (char *)tbp, tcc);
203346808Sdab bol = 1;
203446808Sdab count += tcc;
203546808Sdab tcc = 0;
203646808Sdab flushline = 1;
203746808Sdab break;
203846808Sdab }
203946808Sdab if (sc != rlogin) {
204046808Sdab ++tcc;
204146808Sdab --tbp;
204246808Sdab --count;
204346808Sdab c = sc = rlogin;
204446808Sdab }
204546808Sdab }
204646808Sdab if ((sc == '\n') || (sc == '\r'))
204746808Sdab bol = 1;
204846808Sdab } else if (sc == escape) {
204938689Sborman /*
205038689Sborman * Double escape is a pass through of a single escape character.
205138689Sborman */
205238689Sborman if (tcc && strip(*tbp) == escape) {
205338689Sborman tbp++;
205438689Sborman tcc--;
205538689Sborman count++;
205646808Sdab bol = 0;
205738689Sborman } else {
205846808Sdab command(0, (char *)tbp, tcc);
205946808Sdab bol = 1;
206038689Sborman count += tcc;
206138689Sborman tcc = 0;
206238689Sborman flushline = 1;
206338689Sborman break;
206438689Sborman }
206546808Sdab } else
206646808Sdab bol = 0;
206738689Sborman #ifdef KLUDGELINEMODE
206838689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
206932385Sminshall if (tcc > 0 && strip(*tbp) == echoc) {
207032385Sminshall tcc--; tbp++; count++;
207132385Sminshall } else {
207232385Sminshall dontlecho = !dontlecho;
207332385Sminshall settimer(echotoggle);
207438689Sborman setconnmode(0);
207532385Sminshall flushline = 1;
207632385Sminshall break;
207732385Sminshall }
207832385Sminshall }
207938689Sborman #endif
208038689Sborman if (MODE_LOCAL_CHARS(globalmode)) {
208132385Sminshall if (TerminalSpecialChars(sc) == 0) {
208246808Sdab bol = 1;
208332385Sminshall break;
208432385Sminshall }
208532385Sminshall }
208638689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) {
208732385Sminshall switch (c) {
208832385Sminshall case '\n':
208932385Sminshall /*
209032385Sminshall * If we are in CRMOD mode (\r ==> \n)
209132385Sminshall * on our local machine, then probably
209232385Sminshall * a newline (unix) is CRLF (TELNET).
209332385Sminshall */
209432385Sminshall if (MODE_LOCAL_CHARS(globalmode)) {
209532385Sminshall NETADD('\r');
209632385Sminshall }
209732385Sminshall NETADD('\n');
209846808Sdab bol = flushline = 1;
209932385Sminshall break;
210032385Sminshall case '\r':
210132385Sminshall if (!crlf) {
210232385Sminshall NET2ADD('\r', '\0');
210332385Sminshall } else {
210432385Sminshall NET2ADD('\r', '\n');
210532385Sminshall }
210646808Sdab bol = flushline = 1;
210732385Sminshall break;
210832385Sminshall case IAC:
210932385Sminshall NET2ADD(IAC, IAC);
211032385Sminshall break;
211132385Sminshall default:
211232385Sminshall NETADD(c);
211332385Sminshall break;
211432385Sminshall }
211532385Sminshall } else if (c == IAC) {
211632385Sminshall NET2ADD(IAC, IAC);
211732385Sminshall } else {
211832385Sminshall NETADD(c);
211932385Sminshall }
212032385Sminshall }
212132667Sminshall if (count)
212232667Sminshall ring_consumed(&ttyiring, count);
212332385Sminshall return returnValue||count; /* Non-zero if we did anything */
212432385Sminshall }
212532377Sminshall
212627088Sminshall /*
212732377Sminshall * Scheduler()
212832377Sminshall *
212932377Sminshall * Try to do something.
213032377Sminshall *
213132377Sminshall * If we do something useful, return 1; else return 0.
213232377Sminshall *
213327110Sminshall */
213427110Sminshall
213527110Sminshall
213646808Sdab int
Scheduler(block)213732377Sminshall Scheduler(block)
213846808Sdab int block; /* should we block in the select ? */
213927110Sminshall {
214032377Sminshall /* One wants to be a bit careful about setting returnValue
214132377Sminshall * to one, since a one implies we did some useful work,
214232377Sminshall * and therefore probably won't be called to block next
214332377Sminshall * time (TN3270 mode only).
214432377Sminshall */
214532531Sminshall int returnValue;
214632531Sminshall int netin, netout, netex, ttyin, ttyout;
214727110Sminshall
214832531Sminshall /* Decide which rings should be processed */
214932531Sminshall
215032531Sminshall netout = ring_full_count(&netoring) &&
215138689Sborman (flushline ||
215238689Sborman (my_want_state_is_wont(TELOPT_LINEMODE)
215338689Sborman #ifdef KLUDGELINEMODE
215438689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
215538689Sborman #endif
215638689Sborman ) ||
215738689Sborman my_want_state_is_will(TELOPT_BINARY));
215832531Sminshall ttyout = ring_full_count(&ttyoring);
215932531Sminshall
216032377Sminshall #if defined(TN3270)
216132531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
216232377Sminshall #else /* defined(TN3270) */
216332531Sminshall ttyin = ring_empty_count(&ttyiring);
216432377Sminshall #endif /* defined(TN3270) */
216532531Sminshall
216632531Sminshall #if defined(TN3270)
216732531Sminshall netin = ring_empty_count(&netiring);
216832377Sminshall # else /* !defined(TN3270) */
216932531Sminshall netin = !ISend && ring_empty_count(&netiring);
217032377Sminshall # endif /* !defined(TN3270) */
217132531Sminshall
217232531Sminshall netex = !SYNCHing;
217332531Sminshall
217432531Sminshall /* If we have seen a signal recently, reset things */
217532377Sminshall # if defined(TN3270) && defined(unix)
217632377Sminshall if (HaveInput) {
217732377Sminshall HaveInput = 0;
217844360Sborman (void) signal(SIGIO, inputAvailable);
217932377Sminshall }
218032377Sminshall #endif /* defined(TN3270) && defined(unix) */
218132377Sminshall
218232531Sminshall /* Call to system code to process rings */
218327178Sminshall
218432531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
218527178Sminshall
218632531Sminshall /* Now, look at the input rings, looking for work to do. */
218732377Sminshall
218832531Sminshall if (ring_full_count(&ttyiring)) {
218932377Sminshall # if defined(TN3270)
219032377Sminshall if (In3270) {
219134848Sminshall int c;
219234848Sminshall
219333804Sminshall c = DataFromTerminal(ttyiring.consume,
219432528Sminshall ring_full_consecutive(&ttyiring));
219532377Sminshall if (c) {
219632377Sminshall returnValue = 1;
2197*69785Sdab ring_consumed(&ttyiring, c);
219832377Sminshall }
219932377Sminshall } else {
220032377Sminshall # endif /* defined(TN3270) */
220132554Sminshall returnValue |= telsnd();
220232377Sminshall # if defined(TN3270)
220327178Sminshall }
220432531Sminshall # endif /* defined(TN3270) */
220527178Sminshall }
220632377Sminshall
220732528Sminshall if (ring_full_count(&netiring)) {
220832377Sminshall # if !defined(TN3270)
220932385Sminshall returnValue |= telrcv();
221032377Sminshall # else /* !defined(TN3270) */
221132377Sminshall returnValue = Push3270();
221232377Sminshall # endif /* !defined(TN3270) */
221332377Sminshall }
221432377Sminshall return returnValue;
221527178Sminshall }
221627178Sminshall
221727178Sminshall /*
221832377Sminshall * Select from tty and network...
221927088Sminshall */
222046808Sdab void
telnet(user)222146808Sdab telnet(user)
222246808Sdab char *user;
222327088Sminshall {
222432531Sminshall sys_telnet_init();
222527088Sminshall
2226*69785Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION)
222746808Sdab {
222846808Sdab static char local_host[256] = { 0 };
222946808Sdab
223046808Sdab if (!local_host[0]) {
223157213Sdab gethostname(local_host, sizeof(local_host));
223246808Sdab local_host[sizeof(local_host)-1] = 0;
223346808Sdab }
223446808Sdab auth_encrypt_init(local_host, hostname, "TELNET", 0);
223546808Sdab auth_encrypt_user(user);
223646808Sdab }
223760149Sdab #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
223832377Sminshall # if !defined(TN3270)
223932377Sminshall if (telnetport) {
224057213Sdab #if defined(AUTHENTICATION)
224146808Sdab if (autologin)
224246808Sdab send_will(TELOPT_AUTHENTICATION, 1);
224346808Sdab #endif
224460149Sdab #ifdef ENCRYPTION
224546808Sdab send_do(TELOPT_ENCRYPT, 1);
224646808Sdab send_will(TELOPT_ENCRYPT, 1);
224760149Sdab #endif /* ENCRYPTION */
224838689Sborman send_do(TELOPT_SGA, 1);
224938689Sborman send_will(TELOPT_TTYPE, 1);
225038689Sborman send_will(TELOPT_NAWS, 1);
225138689Sborman send_will(TELOPT_TSPEED, 1);
225238689Sborman send_will(TELOPT_LFLOW, 1);
225338689Sborman send_will(TELOPT_LINEMODE, 1);
225465157Sdab send_will(TELOPT_NEW_ENVIRON, 1);
225538908Sborman send_do(TELOPT_STATUS, 1);
225646808Sdab if (env_getvalue((unsigned char *)"DISPLAY"))
225744360Sborman send_will(TELOPT_XDISPLOC, 1);
225846808Sdab if (eight)
225946808Sdab tel_enter_binary(eight);
226027178Sminshall }
226132377Sminshall # endif /* !defined(TN3270) */
226227088Sminshall
226332377Sminshall # if !defined(TN3270)
226432377Sminshall for (;;) {
226532385Sminshall int schedValue;
226632385Sminshall
226732385Sminshall while ((schedValue = Scheduler(0)) != 0) {
226832385Sminshall if (schedValue == -1) {
226932385Sminshall setcommandmode();
227032385Sminshall return;
227132385Sminshall }
227232385Sminshall }
227332385Sminshall
227432531Sminshall if (Scheduler(1) == -1) {
227532377Sminshall setcommandmode();
227632377Sminshall return;
227732377Sminshall }
227832377Sminshall }
227932377Sminshall # else /* !defined(TN3270) */
228032377Sminshall for (;;) {
228132377Sminshall int schedValue;
228227088Sminshall
228332377Sminshall while (!In3270 && !shell_active) {
228432531Sminshall if (Scheduler(1) == -1) {
228532377Sminshall setcommandmode();
228632377Sminshall return;
228732377Sminshall }
228827088Sminshall }
228932377Sminshall
229032377Sminshall while ((schedValue = Scheduler(0)) != 0) {
229132377Sminshall if (schedValue == -1) {
229232377Sminshall setcommandmode();
229332377Sminshall return;
229432377Sminshall }
229527088Sminshall }
229632377Sminshall /* If there is data waiting to go out to terminal, don't
229732377Sminshall * schedule any more data for the terminal.
229832377Sminshall */
229934304Sminshall if (ring_full_count(&ttyoring)) {
230032377Sminshall schedValue = 1;
230127088Sminshall } else {
230232377Sminshall if (shell_active) {
230332377Sminshall if (shell_continue() == 0) {
230432377Sminshall ConnectScreen();
230527088Sminshall }
230632377Sminshall } else if (In3270) {
230732377Sminshall schedValue = DoTerminalOutput();
230832377Sminshall }
230927088Sminshall }
231032377Sminshall if (schedValue && (shell_active == 0)) {
231132531Sminshall if (Scheduler(1) == -1) {
231232377Sminshall setcommandmode();
231332377Sminshall return;
231432377Sminshall }
231527088Sminshall }
231632377Sminshall }
231732377Sminshall # endif /* !defined(TN3270) */
231827088Sminshall }
231932377Sminshall
232034848Sminshall #if 0 /* XXX - this not being in is a bug */
232127088Sminshall /*
232232554Sminshall * nextitem()
232332554Sminshall *
232432554Sminshall * Return the address of the next "item" in the TELNET data
232532554Sminshall * stream. This will be the address of the next character if
232632554Sminshall * the current address is a user data character, or it will
232732554Sminshall * be the address of the character following the TELNET command
232832554Sminshall * if the current address is a TELNET IAC ("I Am a Command")
232932554Sminshall * character.
233032554Sminshall */
233132554Sminshall
233246808Sdab static char *
233332554Sminshall nextitem(current)
233446808Sdab char *current;
233532554Sminshall {
233632554Sminshall if ((*current&0xff) != IAC) {
233732554Sminshall return current+1;
233832554Sminshall }
233932554Sminshall switch (*(current+1)&0xff) {
234032554Sminshall case DO:
234132554Sminshall case DONT:
234232554Sminshall case WILL:
234332554Sminshall case WONT:
234432554Sminshall return current+3;
234532554Sminshall case SB: /* loop forever looking for the SE */
234632554Sminshall {
234732554Sminshall register char *look = current+2;
234832554Sminshall
234932554Sminshall for (;;) {
235032554Sminshall if ((*look++&0xff) == IAC) {
235132554Sminshall if ((*look++&0xff) == SE) {
235232554Sminshall return look;
235332554Sminshall }
235432554Sminshall }
235532554Sminshall }
235632554Sminshall }
235732554Sminshall default:
235832554Sminshall return current+2;
235932554Sminshall }
236032554Sminshall }
236134848Sminshall #endif /* 0 */
236232554Sminshall
236332554Sminshall /*
236432554Sminshall * netclear()
236532554Sminshall *
236632554Sminshall * We are about to do a TELNET SYNCH operation. Clear
236732554Sminshall * the path to the network.
236832554Sminshall *
236932554Sminshall * Things are a bit tricky since we may have sent the first
237032554Sminshall * byte or so of a previous TELNET command into the network.
237132554Sminshall * So, we have to scan the network buffer from the beginning
237232554Sminshall * until we are up to where we want to be.
237332554Sminshall *
237432554Sminshall * A side effect of what we do, just to keep things
237532554Sminshall * simple, is to clear the urgent data pointer. The principal
237632554Sminshall * caller should be setting the urgent data pointer AFTER calling
237732554Sminshall * us in any case.
237832554Sminshall */
237932554Sminshall
238046808Sdab static void
netclear()238132554Sminshall netclear()
238232554Sminshall {
238332554Sminshall #if 0 /* XXX */
238432554Sminshall register char *thisitem, *next;
238532554Sminshall char *good;
238632554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
238732554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
238832554Sminshall
238932554Sminshall thisitem = netobuf;
239032554Sminshall
239132554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) {
239232554Sminshall thisitem = next;
239332554Sminshall }
239432554Sminshall
239532554Sminshall /* Now, thisitem is first before/at boundary. */
239632554Sminshall
239732554Sminshall good = netobuf; /* where the good bytes go */
239832554Sminshall
239932554Sminshall while (netoring.add > thisitem) {
240032554Sminshall if (wewant(thisitem)) {
240132554Sminshall int length;
240232554Sminshall
240332554Sminshall next = thisitem;
240432554Sminshall do {
240532554Sminshall next = nextitem(next);
240632554Sminshall } while (wewant(next) && (nfrontp > next));
240732554Sminshall length = next-thisitem;
2408*69785Sdab memmove(good, thisitem, length);
240932554Sminshall good += length;
241032554Sminshall thisitem = next;
241132554Sminshall } else {
241232554Sminshall thisitem = nextitem(thisitem);
241332554Sminshall }
241432554Sminshall }
241532554Sminshall
241632554Sminshall #endif /* 0 */
241732554Sminshall }
241832554Sminshall
241932554Sminshall /*
242032377Sminshall * These routines add various telnet commands to the data stream.
242127088Sminshall */
242232377Sminshall
242346808Sdab static void
doflush()242432554Sminshall doflush()
242532554Sminshall {
242632554Sminshall NET2ADD(IAC, DO);
242732554Sminshall NETADD(TELOPT_TM);
242832554Sminshall flushline = 1;
242932554Sminshall flushout = 1;
243044360Sborman (void) ttyflush(1); /* Flush/drop output */
243132554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */
243246808Sdab printoption("SENT", DO, TELOPT_TM);
243332554Sminshall }
243432554Sminshall
243546808Sdab void
xmitAO()243632377Sminshall xmitAO()
243727088Sminshall {
243832377Sminshall NET2ADD(IAC, AO);
243946808Sdab printoption("SENT", IAC, AO);
244032377Sminshall if (autoflush) {
244132377Sminshall doflush();
244232377Sminshall }
244332377Sminshall }
244427088Sminshall
244532377Sminshall
244646808Sdab void
xmitEL()244732377Sminshall xmitEL()
244827088Sminshall {
244932377Sminshall NET2ADD(IAC, EL);
245046808Sdab printoption("SENT", IAC, EL);
245127088Sminshall }
245227088Sminshall
245346808Sdab void
xmitEC()245432377Sminshall xmitEC()
245527088Sminshall {
245632377Sminshall NET2ADD(IAC, EC);
245746808Sdab printoption("SENT", IAC, EC);
245827088Sminshall }
245927088Sminshall
246032377Sminshall
246146808Sdab int
dosynch()246232377Sminshall dosynch()
246327088Sminshall {
246432377Sminshall netclear(); /* clear the path to the network */
246533294Sminshall NETADD(IAC);
246633294Sminshall setneturg();
246733294Sminshall NETADD(DM);
246846808Sdab printoption("SENT", IAC, DM);
246946808Sdab return 1;
247027088Sminshall }
247127088Sminshall
247246808Sdab int want_status_response = 0;
247346808Sdab
247446808Sdab int
get_status()247538908Sborman get_status()
247638908Sborman {
247746808Sdab unsigned char tmp[16];
247846808Sdab register unsigned char *cp;
247938908Sborman
248038908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) {
248138908Sborman printf("Remote side does not support STATUS option\n");
248246808Sdab return 0;
248338908Sborman }
248438908Sborman cp = tmp;
248538908Sborman
248638908Sborman *cp++ = IAC;
248738908Sborman *cp++ = SB;
248838908Sborman *cp++ = TELOPT_STATUS;
248938908Sborman *cp++ = TELQUAL_SEND;
249038908Sborman *cp++ = IAC;
249138908Sborman *cp++ = SE;
249238908Sborman if (NETROOM() >= cp - tmp) {
249338908Sborman ring_supply_data(&netoring, tmp, cp-tmp);
249438908Sborman printsub('>', tmp+2, cp - tmp - 2);
249538908Sborman }
249646808Sdab ++want_status_response;
249746808Sdab return 1;
249838908Sborman }
249938908Sborman
250046808Sdab void
intp()250132377Sminshall intp()
250227088Sminshall {
250332377Sminshall NET2ADD(IAC, IP);
250446808Sdab printoption("SENT", IAC, IP);
250532377Sminshall flushline = 1;
250632377Sminshall if (autoflush) {
250732377Sminshall doflush();
250832377Sminshall }
250932377Sminshall if (autosynch) {
251032377Sminshall dosynch();
251132377Sminshall }
251227088Sminshall }
251327186Sminshall
251446808Sdab void
sendbrk()251532377Sminshall sendbrk()
251627186Sminshall {
251732377Sminshall NET2ADD(IAC, BREAK);
251846808Sdab printoption("SENT", IAC, BREAK);
251932377Sminshall flushline = 1;
252032377Sminshall if (autoflush) {
252132377Sminshall doflush();
252232377Sminshall }
252332377Sminshall if (autosynch) {
252432377Sminshall dosynch();
252532377Sminshall }
252627186Sminshall }
252738689Sborman
252846808Sdab void
sendabort()252938689Sborman sendabort()
253038689Sborman {
253138689Sborman NET2ADD(IAC, ABORT);
253246808Sdab printoption("SENT", IAC, ABORT);
253338689Sborman flushline = 1;
253438689Sborman if (autoflush) {
253538689Sborman doflush();
253638689Sborman }
253738689Sborman if (autosynch) {
253838689Sborman dosynch();
253938689Sborman }
254038689Sborman }
254138689Sborman
254246808Sdab void
sendsusp()254338689Sborman sendsusp()
254438689Sborman {
254538689Sborman NET2ADD(IAC, SUSP);
254646808Sdab printoption("SENT", IAC, SUSP);
254738689Sborman flushline = 1;
254838689Sborman if (autoflush) {
254938689Sborman doflush();
255038689Sborman }
255138689Sborman if (autosynch) {
255238689Sborman dosynch();
255338689Sborman }
255438689Sborman }
255538689Sborman
255646808Sdab void
sendeof()255738689Sborman sendeof()
255838689Sborman {
255938908Sborman NET2ADD(IAC, xEOF);
256046808Sdab printoption("SENT", IAC, xEOF);
256138689Sborman }
256238689Sborman
256346808Sdab void
sendayt()256445232Sborman sendayt()
256545232Sborman {
256645232Sborman NET2ADD(IAC, AYT);
256746808Sdab printoption("SENT", IAC, AYT);
256845232Sborman }
256945232Sborman
257037219Sminshall /*
257137219Sminshall * Send a window size update to the remote system.
257237219Sminshall */
257337219Sminshall
257446808Sdab void
sendnaws()257537219Sminshall sendnaws()
257637219Sminshall {
257737219Sminshall long rows, cols;
257838689Sborman unsigned char tmp[16];
257938689Sborman register unsigned char *cp;
258037219Sminshall
258138689Sborman if (my_state_is_wont(TELOPT_NAWS))
258238689Sborman return;
258337219Sminshall
258438689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
258538689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
258638689Sborman
258737219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
258837219Sminshall return;
258937219Sminshall }
259037219Sminshall
259138689Sborman cp = tmp;
259238689Sborman
259338689Sborman *cp++ = IAC;
259438689Sborman *cp++ = SB;
259538689Sborman *cp++ = TELOPT_NAWS;
259638689Sborman PUTSHORT(cp, cols);
259738689Sborman PUTSHORT(cp, rows);
259838689Sborman *cp++ = IAC;
259938689Sborman *cp++ = SE;
260038689Sborman if (NETROOM() >= cp - tmp) {
260138689Sborman ring_supply_data(&netoring, tmp, cp-tmp);
260238689Sborman printsub('>', tmp+2, cp - tmp - 2);
260337219Sminshall }
260437219Sminshall }
260537226Sminshall
260646808Sdab void
tel_enter_binary(rw)260738908Sborman tel_enter_binary(rw)
260846808Sdab int rw;
260937226Sminshall {
261038908Sborman if (rw&1)
261138908Sborman send_do(TELOPT_BINARY, 1);
261238908Sborman if (rw&2)
261338908Sborman send_will(TELOPT_BINARY, 1);
261437226Sminshall }
261537226Sminshall
261646808Sdab void
tel_leave_binary(rw)261738908Sborman tel_leave_binary(rw)
261846808Sdab int rw;
261937226Sminshall {
262038908Sborman if (rw&1)
262138908Sborman send_dont(TELOPT_BINARY, 1);
262238908Sborman if (rw&2)
262338908Sborman send_wont(TELOPT_BINARY, 1);
262437226Sminshall }
2625