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*65157Sdab static char sccsid[] = "@(#)telnet.c 8.2 (Berkeley) 12/15/93"; 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 3427228Sminshall #define strip(x) ((x)&0x7f) 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; 105*65157Sdab #ifdef OLD_ENVIRON 106*65157Sdab unsigned char telopt_environ = TELOPT_NEW_ENVIRON; 107*65157Sdab #else 108*65157Sdab # define telopt_environ TELOPT_NEW_ENVIRON 109*65157Sdab #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 14632377Sminshall init_telnet() 14732377Sminshall { 14844360Sborman env_init(); 14944360Sborman 15032377Sminshall SB_CLEAR(); 15137226Sminshall ClearArray(options); 1526000Sroot 15337219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 15460149Sdab #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 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 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 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 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 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 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 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 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; 474*65157Sdab 475*65157Sdab case TELOPT_NEW_ENVIRON: /* New environment variable option */ 476*65157Sdab #ifdef OLD_ENVIRON 477*65157Sdab if (my_state_is_will(TELOPT_OLD_ENVIRON)) 478*65157Sdab send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ 479*65157Sdab goto env_common; 480*65157Sdab case TELOPT_OLD_ENVIRON: /* Old environment variable option */ 481*65157Sdab if (my_state_is_will(TELOPT_NEW_ENVIRON)) 482*65157Sdab break; /* Don't enable if new one is in use! */ 483*65157Sdab env_common: 484*65157Sdab telopt_environ = option; 485*65157Sdab #endif 486*65157Sdab new_state_ok = 1; 487*65157Sdab break; 488*65157Sdab 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 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; 562*65157Sdab #ifdef OLD_ENVIRON 563*65157Sdab case TELOPT_NEW_ENVIRON: 564*65157Sdab /* 565*65157Sdab * The new environ option wasn't recognized, try 566*65157Sdab * the old one. 567*65157Sdab */ 568*65157Sdab send_will(TELOPT_OLD_ENVIRON, 1); 569*65157Sdab telopt_environ = TELOPT_OLD_ENVIRON; 570*65157Sdab break; 571*65157Sdab #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 ** 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) { 60046808Sdab if (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 } 66638908Sborman 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 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 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 * 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 { 75938908Sborman if (tname && (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 78727676Sminshall suboption() 78827676Sminshall { 789*65157Sdab unsigned char subchar; 790*65157Sdab 79146808Sdab printsub('<', subbuffer, SB_LEN()+2); 792*65157Sdab 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 898*65157Sdab #ifdef OLD_ENVIRON 899*65157Sdab case TELOPT_OLD_ENVIRON: 900*65157Sdab #endif 901*65157Sdab case TELOPT_NEW_ENVIRON: 90246808Sdab if (SB_EOF()) 90346808Sdab return; 90446808Sdab switch(SB_PEEK()) { 90544360Sborman case TELQUAL_IS: 90644360Sborman case TELQUAL_INFO: 907*65157Sdab if (my_want_state_is_dont(subchar)) 90844360Sborman return; 90944360Sborman break; 91044360Sborman case TELQUAL_SEND: 911*65157Sdab 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1463*65157Sdab #ifdef OLD_ENVIRON 1464*65157Sdab # 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; 1475*65157Sdab int old_env_var = OLD_ENV_VAR; 1476*65157Sdab int old_env_value = OLD_ENV_VALUE; 1477*65157Sdab # else 1478*65157Sdab # define old_env_var OLD_ENV_VAR 1479*65157Sdab # define old_env_value OLD_ENV_VALUE 1480*65157Sdab # endif 148158972Sdab #endif 148258972Sdab 148346808Sdab void 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) { 1498*65157Sdab #ifdef OLD_ENVIRON 1499*65157Sdab case OLD_ENV_VAR: 1500*65157Sdab # ifdef ENV_HACK 1501*65157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON 1502*65157Sdab && env_auto) { 1503*65157Sdab /* Server has the same definitions */ 1504*65157Sdab old_env_var = OLD_ENV_VAR; 1505*65157Sdab old_env_value = OLD_ENV_VALUE; 150658972Sdab } 150758972Sdab /* FALL THROUGH */ 1508*65157Sdab # endif 1509*65157Sdab case OLD_ENV_VALUE: 151058972Sdab /* 1511*65157Sdab * 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 */ 1516*65157Sdab #else 1517*65157Sdab case NEW_ENV_VAR: 1518*65157Sdab #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 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; 1573*65157Sdab *opt_replyp++ = telopt_environ; 157444360Sborman *opt_replyp++ = TELQUAL_IS; 157544360Sborman } 157644360Sborman 157746808Sdab void 157844360Sborman env_opt_start_info() 157944360Sborman { 158044360Sborman env_opt_start(); 158144360Sborman if (opt_replyp) 158244360Sborman opt_replyp[-1] = TELQUAL_INFO; 158344360Sborman } 158444360Sborman 158546808Sdab void 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)) 1623*65157Sdab #ifdef OLD_ENVIRON 1624*65157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON) 1625*65157Sdab *opt_replyp++ = old_env_var; 1626*65157Sdab else 1627*65157Sdab #endif 1628*65157Sdab *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; 1637*65157Sdab case NEW_ENV_VAR: 1638*65157Sdab 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) { 1647*65157Sdab #ifdef OLD_ENVIRON 1648*65157Sdab if (telopt_environ == TELOPT_OLD_ENVIRON) 1649*65157Sdab *opt_replyp++ = old_env_value; 1650*65157Sdab else 1651*65157Sdab #endif 1652*65157Sdab *opt_replyp++ = NEW_ENV_VALUE; 165344360Sborman vp = NULL; 165444360Sborman } else 165544360Sborman break; 165644360Sborman } 165744360Sborman } 165844360Sborman 165957213Sdab int 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 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 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 178746808Sdab 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) { 181132377Sminshall 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 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 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 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; 219732667Sminshall 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 222146808Sdab telnet(user) 222246808Sdab char *user; 222327088Sminshall { 222432531Sminshall sys_telnet_init(); 222527088Sminshall 222660149Sdab #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); 2254*65157Sdab 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 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; 240832554Sminshall memcpy(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 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 243632377Sminshall xmitAO() 243727088Sminshall { 243832377Sminshall NET2ADD(IAC, AO); 243946808Sdab printoption("SENT", IAC, AO); 244032377Sminshall if (autoflush) { 244132377Sminshall doflush(); 244232377Sminshall } 244332377Sminshall } 244427088Sminshall 244532377Sminshall 244646808Sdab void 244732377Sminshall xmitEL() 244827088Sminshall { 244932377Sminshall NET2ADD(IAC, EL); 245046808Sdab printoption("SENT", IAC, EL); 245127088Sminshall } 245227088Sminshall 245346808Sdab void 245432377Sminshall xmitEC() 245527088Sminshall { 245632377Sminshall NET2ADD(IAC, EC); 245746808Sdab printoption("SENT", IAC, EC); 245827088Sminshall } 245927088Sminshall 246032377Sminshall 246146808Sdab int 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 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 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 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 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 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 255738689Sborman sendeof() 255838689Sborman { 255938908Sborman NET2ADD(IAC, xEOF); 256046808Sdab printoption("SENT", IAC, xEOF); 256138689Sborman } 256238689Sborman 256346808Sdab void 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 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 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 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