133685Sbostic /* 245232Sborman * Copyright (c) 1988, 1990 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 542770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 711758Ssam 821580Sdist #ifndef lint 9*46808Sdab static char sccsid[] = "@(#)telnet.c 5.52 (Berkeley) 03/01/91"; 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 36*46808Sdab static unsigned char subbuffer[SUBBUFSIZE], 37*46808Sdab *subpointer, *subend; /* buffer for sub-options */ 3827676Sminshall #define SB_CLEAR() subpointer = subbuffer; 39*46808Sdab #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 4027676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4127676Sminshall *subpointer++ = (c); \ 4227676Sminshall } 4327676Sminshall 44*46808Sdab #define SB_GET() ((*subpointer++)&0xff) 45*46808Sdab #define SB_PEEK() ((*subpointer)&0xff) 46*46808Sdab #define SB_EOF() (subpointer >= subend) 47*46808Sdab #define SB_LEN() (subend - subpointer) 48*46808Sdab 4937226Sminshall char options[256]; /* The combined options */ 5038689Sborman char do_dont_resp[256]; 5138689Sborman char will_wont_resp[256]; 526000Sroot 5332377Sminshall int 54*46808Sdab eight = 0, 55*46808Sdab autologin = 0, /* Autologin anyone? */ 5632377Sminshall connected, 5732377Sminshall showoptions, 5832377Sminshall In3270, /* Are we in 3270 mode? */ 5932377Sminshall ISend, /* trying to send network data in */ 6032377Sminshall debug = 0, 6132377Sminshall crmod, 6232377Sminshall netdata, /* Print out network data flow */ 6332377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 6434848Sminshall #if defined(TN3270) 6536241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 6636241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 6732377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 6834848Sminshall #endif /* defined(TN3270) */ 6933286Sminshall telnetport, 7032531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 7132531Sminshall flushout, /* flush output */ 7232531Sminshall autoflush = 0, /* flush output when interrupting? */ 7332531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 7437219Sminshall localflow, /* we handle flow control locally */ 7532531Sminshall localchars, /* we recognize interrupt/quit */ 7632531Sminshall donelclchars, /* the user has set "localchars" */ 7732531Sminshall donebinarytoggle, /* the user has put us in binary */ 7832531Sminshall dontlecho, /* do we suppress local echoing right now? */ 7932531Sminshall globalmode; 8027088Sminshall 8144360Sborman char *prompt = 0; 826000Sroot 8344360Sborman cc_t escape; 84*46808Sdab cc_t rlogin; 8544360Sborman #ifdef KLUDGELINEMODE 8644360Sborman cc_t echoc; 8744360Sborman #endif 8827186Sminshall 8927186Sminshall /* 906000Sroot * Telnet receiver states for fsm 916000Sroot */ 926000Sroot #define TS_DATA 0 936000Sroot #define TS_IAC 1 946000Sroot #define TS_WILL 2 956000Sroot #define TS_WONT 3 966000Sroot #define TS_DO 4 976000Sroot #define TS_DONT 5 9827021Sminshall #define TS_CR 6 9927676Sminshall #define TS_SB 7 /* sub-option collection */ 10027676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1016000Sroot 10232377Sminshall static int telrcv_state; 1036000Sroot 10432377Sminshall jmp_buf toplevel = { 0 }; 10532377Sminshall jmp_buf peerdied; 1066000Sroot 10732377Sminshall int flushline; 10838811Sborman int linemode; 10927021Sminshall 11038689Sborman #ifdef KLUDGELINEMODE 11138689Sborman int kludgelinemode = 1; 11238689Sborman #endif 11338689Sborman 11432377Sminshall /* 11532377Sminshall * The following are some clocks used to decide how to interpret 11632377Sminshall * the relationship between various variables. 11732377Sminshall */ 1186000Sroot 11932377Sminshall Clocks clocks; 12032377Sminshall 12138689Sborman #ifdef notdef 12232377Sminshall Modelist modelist[] = { 12332377Sminshall { "telnet command mode", COMMAND_LINE }, 12432377Sminshall { "character-at-a-time mode", 0 }, 12532377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 12632377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 12732377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 12832377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 12932377Sminshall { "3270 mode", 0 }, 13032377Sminshall }; 13138689Sborman #endif 1326000Sroot 13332377Sminshall 13432377Sminshall /* 13532377Sminshall * Initialize telnet environment. 13632377Sminshall */ 1376000Sroot 138*46808Sdab void 13932377Sminshall init_telnet() 14032377Sminshall { 14144360Sborman env_init(); 14244360Sborman 14332377Sminshall SB_CLEAR(); 14437226Sminshall ClearArray(options); 1456000Sroot 14637219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 147*46808Sdab #if defined(ENCRYPT) || defined(AUTHENTICATE) 148*46808Sdab auth_encrypt_connect(connected); 149*46808Sdab #endif 1506000Sroot 15132377Sminshall SYNCHing = 0; 1526000Sroot 15332377Sminshall /* Don't change NetTrace */ 1546000Sroot 15532377Sminshall escape = CONTROL(']'); 156*46808Sdab rlogin = _POSIX_VDISABLE; 15744360Sborman #ifdef KLUDGELINEMODE 15832377Sminshall echoc = CONTROL('E'); 15944360Sborman #endif 1606000Sroot 16132377Sminshall flushline = 1; 16232377Sminshall telrcv_state = TS_DATA; 16332377Sminshall } 16432554Sminshall 1656000Sroot 16644360Sborman #ifdef notdef 16732554Sminshall #include <varargs.h> 1686000Sroot 169*46808Sdab /*VARARGS*/ 170*46808Sdab static void 17132554Sminshall printring(va_alist) 172*46808Sdab va_dcl 17332554Sminshall { 17432554Sminshall va_list ap; 17532554Sminshall char buffer[100]; /* where things go */ 17632554Sminshall char *ptr; 17732554Sminshall char *format; 17832554Sminshall char *string; 17932554Sminshall Ring *ring; 18032554Sminshall int i; 18132554Sminshall 18232554Sminshall va_start(ap); 18332554Sminshall 18432554Sminshall ring = va_arg(ap, Ring *); 18532554Sminshall format = va_arg(ap, char *); 18632554Sminshall ptr = buffer; 18732554Sminshall 18832554Sminshall while ((i = *format++) != 0) { 18932554Sminshall if (i == '%') { 19032554Sminshall i = *format++; 19132554Sminshall switch (i) { 19232554Sminshall case 'c': 19332554Sminshall *ptr++ = va_arg(ap, int); 19432554Sminshall break; 19532554Sminshall case 's': 19632554Sminshall string = va_arg(ap, char *); 19732554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19832554Sminshall ring_supply_data(ring, string, strlen(string)); 19932554Sminshall ptr = buffer; 20032554Sminshall break; 20132554Sminshall case 0: 20232554Sminshall ExitString("printring: trailing %%.\n", 1); 20332554Sminshall /*NOTREACHED*/ 20432554Sminshall default: 20532554Sminshall ExitString("printring: unknown format character.\n", 1); 20632554Sminshall /*NOTREACHED*/ 20732554Sminshall } 20832554Sminshall } else { 20932554Sminshall *ptr++ = i; 21032554Sminshall } 21132554Sminshall } 21232554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21332554Sminshall } 21444360Sborman #endif 21532554Sminshall 21637226Sminshall /* 21737226Sminshall * These routines are in charge of sending option negotiations 21837226Sminshall * to the other side. 21937226Sminshall * 22037226Sminshall * The basic idea is that we send the negotiation if either side 22137226Sminshall * is in disagreement as to what the current state should be. 22237226Sminshall */ 22332554Sminshall 224*46808Sdab void 22538689Sborman send_do(c, init) 226*46808Sdab register int c, init; 2276000Sroot { 22838689Sborman if (init) { 22938689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 23038689Sborman my_want_state_is_do(c)) 23138689Sborman return; 23238689Sborman set_my_want_state_do(c); 23338689Sborman do_dont_resp[c]++; 23437226Sminshall } 23538689Sborman NET2ADD(IAC, DO); 23638689Sborman NETADD(c); 237*46808Sdab printoption("SENT", DO, c); 23837226Sminshall } 23937226Sminshall 240*46808Sdab void 24138689Sborman send_dont(c, init) 242*46808Sdab register int c, init; 24337226Sminshall { 24438689Sborman if (init) { 24538689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 24638689Sborman my_want_state_is_dont(c)) 24738689Sborman return; 24838689Sborman set_my_want_state_dont(c); 24938689Sborman do_dont_resp[c]++; 25037226Sminshall } 25138689Sborman NET2ADD(IAC, DONT); 25238689Sborman NETADD(c); 253*46808Sdab printoption("SENT", DONT, c); 25437226Sminshall } 25537226Sminshall 256*46808Sdab void 25738689Sborman send_will(c, init) 258*46808Sdab register int c, init; 25937226Sminshall { 26038689Sborman if (init) { 26138689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 26238689Sborman my_want_state_is_will(c)) 26338689Sborman return; 26438689Sborman set_my_want_state_will(c); 26538689Sborman will_wont_resp[c]++; 26637226Sminshall } 26738689Sborman NET2ADD(IAC, WILL); 26838689Sborman NETADD(c); 269*46808Sdab printoption("SENT", WILL, c); 27037226Sminshall } 27137226Sminshall 272*46808Sdab void 27338689Sborman send_wont(c, init) 274*46808Sdab register int c, init; 27537226Sminshall { 27638689Sborman if (init) { 27738689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 27838689Sborman my_want_state_is_wont(c)) 27938689Sborman return; 28038689Sborman set_my_want_state_wont(c); 28138689Sborman will_wont_resp[c]++; 28237226Sminshall } 28338689Sborman NET2ADD(IAC, WONT); 28438689Sborman NETADD(c); 285*46808Sdab printoption("SENT", WONT, c); 28637226Sminshall } 28737226Sminshall 28837226Sminshall 289*46808Sdab void 29037226Sminshall willoption(option) 29137226Sminshall int option; 29237226Sminshall { 29338689Sborman int new_state_ok = 0; 2946000Sroot 29538689Sborman if (do_dont_resp[option]) { 29638689Sborman --do_dont_resp[option]; 29738689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 29838689Sborman --do_dont_resp[option]; 29938689Sborman } 30037226Sminshall 30138689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 3026000Sroot 30338689Sborman switch (option) { 30438689Sborman 30538689Sborman case TELOPT_ECHO: 30638689Sborman # if defined(TN3270) 30738689Sborman /* 30838689Sborman * The following is a pain in the rear-end. 30938689Sborman * Various IBM servers (some versions of Wiscnet, 31038689Sborman * possibly Fibronics/Spartacus, and who knows who 31138689Sborman * else) will NOT allow us to send "DO SGA" too early 31238689Sborman * in the setup proceedings. On the other hand, 31338689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31438689Sborman * So, we are stuck. Empirically (but, based on 31538689Sborman * a VERY small sample), the IBM servers don't send 31638689Sborman * out anything about ECHO, so we postpone our sending 31738689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 31838689Sborman * DO send). 31938689Sborman */ 32038689Sborman { 32138689Sborman if (askedSGA == 0) { 32238689Sborman askedSGA = 1; 32338689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32438689Sborman send_do(TELOPT_SGA, 1); 32532377Sminshall } 32632377Sminshall } 32738689Sborman /* Fall through */ 32838689Sborman case TELOPT_EOR: 32938908Sborman #endif /* defined(TN3270) */ 33038689Sborman case TELOPT_BINARY: 33138689Sborman case TELOPT_SGA: 33227110Sminshall settimer(modenegotiated); 33338908Sborman /* FALL THROUGH */ 33438908Sborman case TELOPT_STATUS: 335*46808Sdab #if defined(AUTHENTICATE) 336*46808Sdab case TELOPT_AUTHENTICATION: 337*46808Sdab #endif 338*46808Sdab #if defined(ENCRYPT) 339*46808Sdab case TELOPT_ENCRYPT: 340*46808Sdab #endif 34138689Sborman new_state_ok = 1; 3426000Sroot break; 3436000Sroot 34438689Sborman case TELOPT_TM: 34538689Sborman if (flushout) 34638689Sborman flushout = 0; 34738689Sborman /* 34838689Sborman * Special case for TM. If we get back a WILL, 34938689Sborman * pretend we got back a WONT. 35038689Sborman */ 35138689Sborman set_my_want_state_dont(option); 35238689Sborman set_my_state_dont(option); 35327110Sminshall return; /* Never reply to TM will's/wont's */ 3546000Sroot 35538689Sborman case TELOPT_LINEMODE: 35638689Sborman default: 3576000Sroot break; 35838689Sborman } 35938689Sborman 36038689Sborman if (new_state_ok) { 36138689Sborman set_my_want_state_do(option); 36238689Sborman send_do(option, 0); 36338689Sborman setconnmode(0); /* possibly set new tty mode */ 36438689Sborman } else { 36538689Sborman do_dont_resp[option]++; 36638689Sborman send_dont(option, 0); 36738689Sborman } 3686000Sroot } 36938689Sborman set_my_state_do(option); 370*46808Sdab #if defined(ENCRYPT) 371*46808Sdab if (option == TELOPT_ENCRYPT) 372*46808Sdab encrypt_send_support(); 373*46808Sdab #endif 3746000Sroot } 3756000Sroot 376*46808Sdab void 37737226Sminshall wontoption(option) 37837226Sminshall int option; 3796000Sroot { 38038689Sborman if (do_dont_resp[option]) { 38138689Sborman --do_dont_resp[option]; 38238689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 38338689Sborman --do_dont_resp[option]; 38438689Sborman } 38537226Sminshall 38638689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3876000Sroot 38838689Sborman switch (option) { 38938689Sborman 39038689Sborman #ifdef KLUDGELINEMODE 39138689Sborman case TELOPT_SGA: 39238689Sborman if (!kludgelinemode) 39338689Sborman break; 39438689Sborman /* FALL THROUGH */ 39538689Sborman #endif 39638689Sborman case TELOPT_ECHO: 39727110Sminshall settimer(modenegotiated); 3986000Sroot break; 3996000Sroot 40038689Sborman case TELOPT_TM: 40138689Sborman if (flushout) 40238689Sborman flushout = 0; 40338689Sborman set_my_want_state_dont(option); 40438689Sborman set_my_state_dont(option); 40527110Sminshall return; /* Never reply to TM will's/wont's */ 40627110Sminshall 40738689Sborman default: 40838689Sborman break; 40938689Sborman } 41038689Sborman set_my_want_state_dont(option); 41144360Sborman if (my_state_is_do(option)) 41244360Sborman send_dont(option, 0); 41338689Sborman setconnmode(0); /* Set new tty mode */ 41438689Sborman } else if (option == TELOPT_TM) { 41538689Sborman /* 41638689Sborman * Special case for TM. 41738689Sborman */ 41838689Sborman if (flushout) 41938689Sborman flushout = 0; 42038689Sborman set_my_want_state_dont(option); 4216000Sroot } 42238689Sborman set_my_state_dont(option); 4236000Sroot } 4246000Sroot 425*46808Sdab static void 4266000Sroot dooption(option) 4276000Sroot int option; 4286000Sroot { 42938689Sborman int new_state_ok = 0; 4306000Sroot 43138689Sborman if (will_wont_resp[option]) { 43238689Sborman --will_wont_resp[option]; 43338689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 43438689Sborman --will_wont_resp[option]; 43538689Sborman } 43637226Sminshall 43738689Sborman if (will_wont_resp[option] == 0) { 43838689Sborman if (my_want_state_is_wont(option)) { 4396000Sroot 44038689Sborman switch (option) { 44138689Sborman 44238689Sborman case TELOPT_TM: 44338689Sborman /* 44438689Sborman * Special case for TM. We send a WILL, but pretend 44538689Sborman * we sent WONT. 44638689Sborman */ 44738689Sborman send_will(option, 0); 44838689Sborman set_my_want_state_wont(TELOPT_TM); 44938689Sborman set_my_state_wont(TELOPT_TM); 45038689Sborman return; 45138689Sborman 45232377Sminshall # if defined(TN3270) 45338689Sborman case TELOPT_EOR: /* end of record */ 45438908Sborman # endif /* defined(TN3270) */ 45538689Sborman case TELOPT_BINARY: /* binary mode */ 45638689Sborman case TELOPT_NAWS: /* window size */ 45738689Sborman case TELOPT_TSPEED: /* terminal speed */ 45838689Sborman case TELOPT_LFLOW: /* local flow control */ 45938689Sborman case TELOPT_TTYPE: /* terminal type option */ 46038689Sborman case TELOPT_SGA: /* no big deal */ 46144360Sborman case TELOPT_ENVIRON: /* environment variable option */ 462*46808Sdab #if defined(ENCRYPT) 463*46808Sdab case TELOPT_ENCRYPT: /* encryption variable option */ 464*46808Sdab #endif 46538689Sborman new_state_ok = 1; 4666000Sroot break; 467*46808Sdab #if defined(AUTHENTICATE) 468*46808Sdab case TELOPT_AUTHENTICATION: 469*46808Sdab if (autologin) 470*46808Sdab new_state_ok = 1; 471*46808Sdab break; 472*46808Sdab #endif 4736000Sroot 47444360Sborman case TELOPT_XDISPLOC: /* X Display location */ 475*46808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 47644360Sborman new_state_ok = 1; 47744360Sborman break; 47844360Sborman 47938689Sborman case TELOPT_LINEMODE: 48038689Sborman #ifdef KLUDGELINEMODE 48138689Sborman kludgelinemode = 0; 48244360Sborman send_do(TELOPT_SGA, 1); 48338689Sborman #endif 48438689Sborman set_my_want_state_will(TELOPT_LINEMODE); 48538689Sborman send_will(option, 0); 48638689Sborman set_my_state_will(TELOPT_LINEMODE); 48738689Sborman slc_init(); 48838689Sborman return; 48938689Sborman 49038689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 49138689Sborman default: 4926000Sroot break; 49338689Sborman } 49438689Sborman 49538689Sborman if (new_state_ok) { 49638689Sborman set_my_want_state_will(option); 49738689Sborman send_will(option, 0); 49845232Sborman setconnmode(0); /* Set new tty mode */ 49938689Sborman } else { 50038689Sborman will_wont_resp[option]++; 50138689Sborman send_wont(option, 0); 50238689Sborman } 50338689Sborman } else { 50438689Sborman /* 50538689Sborman * Handle options that need more things done after the 50638689Sborman * other side has acknowledged the option. 50738689Sborman */ 50838689Sborman switch (option) { 50938689Sborman case TELOPT_LINEMODE: 51038689Sborman #ifdef KLUDGELINEMODE 51138689Sborman kludgelinemode = 0; 51244360Sborman send_do(TELOPT_SGA, 1); 51338689Sborman #endif 51438689Sborman set_my_state_will(option); 51538689Sborman slc_init(); 51644360Sborman send_do(TELOPT_SGA, 0); 51738689Sborman return; 51838689Sborman } 51938689Sborman } 5206000Sroot } 52138689Sborman set_my_state_will(option); 5226000Sroot } 52327676Sminshall 524*46808Sdab static void 52538689Sborman dontoption(option) 52638689Sborman int option; 52738689Sborman { 52838689Sborman 52938689Sborman if (will_wont_resp[option]) { 53038689Sborman --will_wont_resp[option]; 53138689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 53238689Sborman --will_wont_resp[option]; 53338689Sborman } 53438689Sborman 53538689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 53638811Sborman switch (option) { 53738811Sborman case TELOPT_LINEMODE: 53838811Sborman linemode = 0; /* put us back to the default state */ 53938811Sborman break; 54038811Sborman } 54138689Sborman /* we always accept a DONT */ 54238689Sborman set_my_want_state_wont(option); 54344360Sborman if (my_state_is_will(option)) 54444360Sborman send_wont(option, 0); 54539529Sborman setconnmode(0); /* Set new tty mode */ 54638689Sborman } 54738689Sborman set_my_state_wont(option); 54838689Sborman } 54938689Sborman 55027676Sminshall /* 55138908Sborman * Given a buffer returned by tgetent(), this routine will turn 55238908Sborman * the pipe seperated list of names in the buffer into an array 55338908Sborman * of pointers to null terminated names. We toss out any bad, 55438908Sborman * duplicate, or verbose names (names with spaces). 55538908Sborman */ 55638908Sborman 557*46808Sdab static char *name_unknown = "UNKNOWN"; 558*46808Sdab static char *unknown[] = { 0, 0 }; 55938908Sborman 560*46808Sdab char ** 56138908Sborman mklist(buf, name) 562*46808Sdab char *buf, *name; 56338908Sborman { 56438908Sborman register int n; 565*46808Sdab register char c, *cp, **argvp, *cp2, **argv, **avt; 56638908Sborman 56738908Sborman if (name) { 568*46808Sdab if (strlen(name) > 40) { 56938908Sborman name = 0; 570*46808Sdab unknown[0] = name_unknown; 571*46808Sdab } else { 57238908Sborman unknown[0] = name; 57338908Sborman upcase(name); 57438908Sborman } 575*46808Sdab } else 576*46808Sdab unknown[0] = name_unknown; 57738908Sborman /* 57838908Sborman * Count up the number of names. 57938908Sborman */ 58038908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 58138908Sborman if (*cp == '|') 58238908Sborman n++; 58338908Sborman } 58438908Sborman /* 58538908Sborman * Allocate an array to put the name pointers into 58638908Sborman */ 58738908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 58838908Sborman if (argv == 0) 58938908Sborman return(unknown); 59038908Sborman 59138908Sborman /* 59238908Sborman * Fill up the array of pointers to names. 59338908Sborman */ 59438908Sborman *argv = 0; 59538908Sborman argvp = argv+1; 59638908Sborman n = 0; 59738908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 59838908Sborman if (c == '|' || c == ':') { 59938908Sborman *cp++ = '\0'; 60038908Sborman /* 60138908Sborman * Skip entries that have spaces or are over 40 60238908Sborman * characters long. If this is our environment 60338908Sborman * name, then put it up front. Otherwise, as 60438908Sborman * long as this is not a duplicate name (case 60538908Sborman * insensitive) add it to the list. 60638908Sborman */ 60738908Sborman if (n || (cp - cp2 > 41)) 60838908Sborman ; 60938908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 61038908Sborman *argv = cp2; 61138908Sborman else if (is_unique(cp2, argv+1, argvp)) 61238908Sborman *argvp++ = cp2; 61338908Sborman if (c == ':') 61438908Sborman break; 61538908Sborman /* 61638908Sborman * Skip multiple delimiters. Reset cp2 to 61738908Sborman * the beginning of the next name. Reset n, 61838908Sborman * the flag for names with spaces. 61938908Sborman */ 62038908Sborman while ((c = *cp) == '|') 62138908Sborman cp++; 62238908Sborman cp2 = cp; 62338908Sborman n = 0; 62438908Sborman } 62538908Sborman /* 62638908Sborman * Skip entries with spaces or non-ascii values. 62738908Sborman * Convert lower case letters to upper case. 62838908Sborman */ 62938908Sborman if ((c == ' ') || !isascii(c)) 63038908Sborman n = 1; 63138908Sborman else if (islower(c)) 63238908Sborman *cp = toupper(c); 63338908Sborman } 63438908Sborman 63538908Sborman /* 63638908Sborman * Check for an old V6 2 character name. If the second 63738908Sborman * name points to the beginning of the buffer, and is 63838908Sborman * only 2 characters long, move it to the end of the array. 63938908Sborman */ 64038908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 641*46808Sdab --argvp; 642*46808Sdab for (avt = &argv[1]; avt < argvp; avt++) 643*46808Sdab *avt = *(avt+1); 64438908Sborman *argvp++ = buf; 64538908Sborman } 64638908Sborman 64738908Sborman /* 64838908Sborman * Duplicate last name, for TTYPE option, and null 64938908Sborman * terminate the array. If we didn't find a match on 65038908Sborman * our terminal name, put that name at the beginning. 65138908Sborman */ 65238908Sborman cp = *(argvp-1); 65338908Sborman *argvp++ = cp; 65438908Sborman *argvp = 0; 65538908Sborman 65638908Sborman if (*argv == 0) { 65738908Sborman if (name) 65838908Sborman *argv = name; 659*46808Sdab else { 660*46808Sdab --argvp; 661*46808Sdab for (avt = argv; avt < argvp; avt++) 662*46808Sdab *avt = *(avt+1); 663*46808Sdab } 66438908Sborman } 66538908Sborman if (*argv) 66638908Sborman return(argv); 66738908Sborman else 66838908Sborman return(unknown); 66938908Sborman } 67038908Sborman 671*46808Sdab int 67238908Sborman is_unique(name, as, ae) 673*46808Sdab register char *name, **as, **ae; 67438908Sborman { 67538908Sborman register char **ap; 67638908Sborman register int n; 67738908Sborman 67838908Sborman n = strlen(name) + 1; 67938908Sborman for (ap = as; ap < ae; ap++) 68038908Sborman if (strncasecmp(*ap, name, n) == 0) 68138908Sborman return(0); 68238908Sborman return (1); 68338908Sborman } 68438908Sborman 68538908Sborman #ifdef TERMCAP 68639529Sborman char termbuf[1024]; 687*46808Sdab 688*46808Sdab /*ARGSUSED*/ 689*46808Sdab int 69038908Sborman setupterm(tname, fd, errp) 691*46808Sdab char *tname; 692*46808Sdab int fd, *errp; 69338908Sborman { 69439529Sborman if (tgetent(termbuf, tname) == 1) { 69539529Sborman termbuf[1023] = '\0'; 69638908Sborman if (errp) 69738908Sborman *errp = 1; 69838908Sborman return(0); 69938908Sborman } 70038908Sborman if (errp) 70138908Sborman *errp = 0; 70238908Sborman return(-1); 70338908Sborman } 70439529Sborman #else 70539529Sborman #define termbuf ttytype 70639529Sborman extern char ttytype[]; 70738908Sborman #endif 70838908Sborman 709*46808Sdab int resettermname = 1; 710*46808Sdab 711*46808Sdab char * 71238908Sborman gettermname() 71338908Sborman { 71438908Sborman char *tname; 715*46808Sdab static char **tnamep = 0; 71638908Sborman static char **next; 71738908Sborman int err; 71838908Sborman 719*46808Sdab if (resettermname) { 720*46808Sdab resettermname = 0; 721*46808Sdab if (tnamep && tnamep != unknown) 722*46808Sdab free(tnamep); 723*46808Sdab if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && 72438908Sborman (setupterm(tname, 1, &err) == 0)) { 72539529Sborman tnamep = mklist(termbuf, tname); 72638908Sborman } else { 72738908Sborman if (tname && (strlen(tname) <= 40)) { 72838908Sborman unknown[0] = tname; 72938908Sborman upcase(tname); 730*46808Sdab } else 731*46808Sdab unknown[0] = name_unknown; 73238908Sborman tnamep = unknown; 73338908Sborman } 73438908Sborman next = tnamep; 73538908Sborman } 73638908Sborman if (*next == 0) 73738908Sborman next = tnamep; 73838908Sborman return(*next++); 73938908Sborman } 74038908Sborman /* 74127676Sminshall * suboption() 74227676Sminshall * 74327676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 74427676Sminshall * side. 74527676Sminshall * 74627676Sminshall * Currently we recognize: 74727676Sminshall * 74827676Sminshall * Terminal type, send request. 74937219Sminshall * Terminal speed (send request). 75037219Sminshall * Local flow control (is request). 75138689Sborman * Linemode 75227676Sminshall */ 75327676Sminshall 754*46808Sdab static void 75527676Sminshall suboption() 75627676Sminshall { 757*46808Sdab printsub('<', subbuffer, SB_LEN()+2); 758*46808Sdab switch (SB_GET()) { 75927676Sminshall case TELOPT_TTYPE: 76038689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 76138689Sborman return; 762*46808Sdab if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 763*46808Sdab return; 76427676Sminshall } else { 76527676Sminshall char *name; 766*46808Sdab unsigned char temp[50]; 76727676Sminshall int len; 76827676Sminshall 76932377Sminshall #if defined(TN3270) 77032531Sminshall if (tn3270_ttype()) { 77132377Sminshall return; 77232377Sminshall } 77332377Sminshall #endif /* defined(TN3270) */ 77438908Sborman name = gettermname(); 77538908Sborman len = strlen(name) + 4 + 2; 77638908Sborman if (len < NETROOM()) { 777*46808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 77838908Sborman TELQUAL_IS, name, IAC, SE); 77938689Sborman ring_supply_data(&netoring, temp, len); 78038908Sborman printsub('>', &temp[2], len-2); 78132377Sminshall } else { 78237226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 78332377Sminshall /*NOTREACHED*/ 78427676Sminshall } 78527676Sminshall } 78637219Sminshall break; 78737219Sminshall case TELOPT_TSPEED: 78838689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 78938689Sborman return; 790*46808Sdab if (SB_EOF()) 791*46808Sdab return; 792*46808Sdab if (SB_GET() == TELQUAL_SEND) { 79345232Sborman long ospeed, ispeed; 794*46808Sdab unsigned char temp[50]; 79537219Sminshall int len; 79627676Sminshall 79737219Sminshall TerminalSpeeds(&ispeed, &ospeed); 79837219Sminshall 799*46808Sdab sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 80038689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 801*46808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 80237219Sminshall 80338689Sborman if (len < NETROOM()) { 80438689Sborman ring_supply_data(&netoring, temp, len); 80538689Sborman printsub('>', temp+2, len - 2); 80637219Sminshall } 80744360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 80837219Sminshall } 80937219Sminshall break; 81037219Sminshall case TELOPT_LFLOW: 81138689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 81238689Sborman return; 813*46808Sdab if (SB_EOF()) 814*46808Sdab return; 815*46808Sdab switch(SB_GET()) { 816*46808Sdab case 1: 81737219Sminshall localflow = 1; 818*46808Sdab break; 819*46808Sdab case 0: 82037219Sminshall localflow = 0; 821*46808Sdab break; 822*46808Sdab default: 823*46808Sdab return; 82437219Sminshall } 82537219Sminshall setcommandmode(); 82638689Sborman setconnmode(0); 82737219Sminshall break; 82838689Sborman 82938689Sborman case TELOPT_LINEMODE: 83038689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 83138689Sborman return; 832*46808Sdab if (SB_EOF()) 833*46808Sdab return; 834*46808Sdab switch (SB_GET()) { 83538689Sborman case WILL: 836*46808Sdab lm_will(subpointer, SB_LEN()); 83738689Sborman break; 83838689Sborman case WONT: 839*46808Sdab lm_wont(subpointer, SB_LEN()); 84038689Sborman break; 84138689Sborman case DO: 842*46808Sdab lm_do(subpointer, SB_LEN()); 84338689Sborman break; 84438689Sborman case DONT: 845*46808Sdab lm_dont(subpointer, SB_LEN()); 84638689Sborman break; 84738689Sborman case LM_SLC: 848*46808Sdab slc(subpointer, SB_LEN()); 84938689Sborman break; 85038689Sborman case LM_MODE: 851*46808Sdab lm_mode(subpointer, SB_LEN(), 0); 85238689Sborman break; 85338689Sborman default: 85444360Sborman break; 85544360Sborman } 85644360Sborman break; 85744360Sborman 85844360Sborman case TELOPT_ENVIRON: 859*46808Sdab if (SB_EOF()) 860*46808Sdab return; 861*46808Sdab switch(SB_PEEK()) { 86244360Sborman case TELQUAL_IS: 86344360Sborman case TELQUAL_INFO: 86444360Sborman if (my_want_state_is_dont(TELOPT_ENVIRON)) 86544360Sborman return; 86644360Sborman break; 86744360Sborman case TELQUAL_SEND: 86844360Sborman if (my_want_state_is_wont(TELOPT_ENVIRON)) { 86944360Sborman return; 87044360Sborman } 87144360Sborman break; 87244360Sborman default: 87344360Sborman return; 87444360Sborman } 875*46808Sdab env_opt(subpointer, SB_LEN()); 87644360Sborman break; 87744360Sborman 87844360Sborman case TELOPT_XDISPLOC: 87944360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC)) 88044360Sborman return; 881*46808Sdab if (SB_EOF()) 882*46808Sdab return; 883*46808Sdab if (SB_GET() == TELQUAL_SEND) { 884*46808Sdab unsigned char temp[50], *dp; 88544360Sborman int len; 88644360Sborman 887*46808Sdab if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { 88844360Sborman /* 88944360Sborman * Something happened, we no longer have a DISPLAY 89044360Sborman * variable. So, turn off the option. 89144360Sborman */ 89244360Sborman send_wont(TELOPT_XDISPLOC, 1); 89338689Sborman break; 89444360Sborman } 895*46808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 89644360Sborman TELQUAL_IS, dp, IAC, SE); 897*46808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 89844360Sborman 89944360Sborman if (len < NETROOM()) { 90044360Sborman ring_supply_data(&netoring, temp, len); 90144360Sborman printsub('>', temp+2, len - 2); 90244360Sborman } 90344360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 90438689Sborman } 90544360Sborman break; 90643319Skfall 907*46808Sdab #if defined(AUTHENTICATE) 908*46808Sdab case TELOPT_AUTHENTICATION: { 909*46808Sdab if (!autologin) 910*46808Sdab break; 911*46808Sdab if (SB_EOF()) 912*46808Sdab return; 913*46808Sdab switch(SB_GET()) { 914*46808Sdab case TELQUAL_IS: 915*46808Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 916*46808Sdab return; 917*46808Sdab auth_is(subpointer, SB_LEN()); 918*46808Sdab break; 919*46808Sdab case TELQUAL_SEND: 920*46808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 921*46808Sdab return; 922*46808Sdab auth_send(subpointer, SB_LEN()); 923*46808Sdab break; 924*46808Sdab case TELQUAL_REPLY: 925*46808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 926*46808Sdab return; 927*46808Sdab auth_reply(subpointer, SB_LEN()); 928*46808Sdab break; 92943319Skfall } 930*46808Sdab } 931*46808Sdab break; 93243319Skfall #endif 933*46808Sdab #if defined(ENCRYPT) 934*46808Sdab case TELOPT_ENCRYPT: 935*46808Sdab if (SB_EOF()) 936*46808Sdab return; 937*46808Sdab switch(SB_GET()) { 938*46808Sdab case ENCRYPT_START: 939*46808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 940*46808Sdab return; 941*46808Sdab encrypt_start(); 942*46808Sdab break; 943*46808Sdab case ENCRYPT_END: 944*46808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 945*46808Sdab return; 946*46808Sdab encrypt_end(); 947*46808Sdab break; 948*46808Sdab case ENCRYPT_SUPPORT: 949*46808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 950*46808Sdab return; 951*46808Sdab encrypt_support(subpointer, SB_LEN()); 952*46808Sdab break; 953*46808Sdab case ENCRYPT_REQSTART: 954*46808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 955*46808Sdab return; 956*46808Sdab encrypt_request_start(); 957*46808Sdab break; 958*46808Sdab case ENCRYPT_REQEND: 959*46808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 960*46808Sdab return; 961*46808Sdab /* 962*46808Sdab * We can always send an REQEND so that we cannot 963*46808Sdab * get stuck encrypting. We should only get this 964*46808Sdab * if we have been able to get in the correct mode 965*46808Sdab * anyhow. 966*46808Sdab */ 967*46808Sdab encrypt_request_end(); 968*46808Sdab break; 969*46808Sdab case ENCRYPT_IS: 970*46808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 971*46808Sdab return; 972*46808Sdab encrypt_is(subpointer, SB_LEN()); 973*46808Sdab break; 974*46808Sdab case ENCRYPT_REPLY: 975*46808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 976*46808Sdab return; 977*46808Sdab encrypt_reply(subpointer, SB_LEN()); 978*46808Sdab break; 979*46808Sdab default: 980*46808Sdab break; 981*46808Sdab } 982*46808Sdab break; 98343319Skfall #endif 98427676Sminshall default: 98527676Sminshall break; 98627676Sminshall } 98727676Sminshall } 98838689Sborman 989*46808Sdab static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 99038689Sborman 991*46808Sdab void 99238689Sborman lm_will(cmd, len) 993*46808Sdab unsigned char *cmd; 994*46808Sdab int len; 99538689Sborman { 99644360Sborman if (len < 1) { 99744360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 99844360Sborman return; 99944360Sborman } 100038689Sborman switch(cmd[0]) { 100138689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 100238689Sborman default: 100338689Sborman str_lm[3] = DONT; 100438689Sborman str_lm[4] = cmd[0]; 100538689Sborman if (NETROOM() > sizeof(str_lm)) { 100638689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 100738689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 100838689Sborman } 100938689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 101038689Sborman break; 101138689Sborman } 101238689Sborman } 101338689Sborman 1014*46808Sdab void 101538689Sborman lm_wont(cmd, len) 1016*46808Sdab unsigned char *cmd; 1017*46808Sdab int len; 101838689Sborman { 101944360Sborman if (len < 1) { 102044360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 102144360Sborman return; 102244360Sborman } 102338689Sborman switch(cmd[0]) { 102438689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 102538689Sborman default: 102638689Sborman /* We are always DONT, so don't respond */ 102738689Sborman return; 102838689Sborman } 102938689Sborman } 103038689Sborman 1031*46808Sdab void 103238689Sborman lm_do(cmd, len) 1033*46808Sdab unsigned char *cmd; 1034*46808Sdab int len; 103538689Sborman { 103644360Sborman if (len < 1) { 103744360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 103844360Sborman return; 103944360Sborman } 104038689Sborman switch(cmd[0]) { 104138689Sborman case LM_FORWARDMASK: 104238689Sborman default: 104338689Sborman str_lm[3] = WONT; 104438689Sborman str_lm[4] = cmd[0]; 104538689Sborman if (NETROOM() > sizeof(str_lm)) { 104638689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 104738689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 104838689Sborman } 104938689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 105038689Sborman break; 105138689Sborman } 105238689Sborman } 105338689Sborman 1054*46808Sdab void 105538689Sborman lm_dont(cmd, len) 1056*46808Sdab unsigned char *cmd; 1057*46808Sdab int len; 105838689Sborman { 105944360Sborman if (len < 1) { 106044360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 106144360Sborman return; 106244360Sborman } 106338689Sborman switch(cmd[0]) { 106438689Sborman case LM_FORWARDMASK: 106538689Sborman default: 106638689Sborman /* we are always WONT, so don't respond */ 106738689Sborman break; 106838689Sborman } 106938689Sborman } 107038689Sborman 1071*46808Sdab static unsigned char str_lm_mode[] = { 1072*46808Sdab IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 1073*46808Sdab }; 107438689Sborman 1075*46808Sdab void 107638689Sborman lm_mode(cmd, len, init) 1077*46808Sdab unsigned char *cmd; 1078*46808Sdab int len, init; 107938689Sborman { 108038689Sborman if (len != 1) 108138689Sborman return; 108244360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 108338689Sborman return; 108438689Sborman if (*cmd&MODE_ACK) 108538689Sborman return; 108644360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK); 108738689Sborman str_lm_mode[4] = linemode; 108838689Sborman if (!init) 108938689Sborman str_lm_mode[4] |= MODE_ACK; 109038689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 109138689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 109238689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 109338689Sborman } 109438689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 109538689Sborman setconnmode(0); /* set changed mode */ 109638689Sborman } 109738689Sborman 109832377Sminshall 109927088Sminshall 110038689Sborman /* 110138689Sborman * slc() 110238689Sborman * Handle special character suboption of LINEMODE. 110338689Sborman */ 110438689Sborman 110538689Sborman struct spc { 110640245Sborman cc_t val; 110740245Sborman cc_t *valp; 110838689Sborman char flags; /* Current flags & level */ 110938689Sborman char mylevel; /* Maximum level & flags */ 111038689Sborman } spc_data[NSLC+1]; 111138689Sborman 111238689Sborman #define SLC_IMPORT 0 111338689Sborman #define SLC_EXPORT 1 111438689Sborman #define SLC_RVALUE 2 111538689Sborman static int slc_mode = SLC_EXPORT; 111638689Sborman 1117*46808Sdab void 111838689Sborman slc_init() 111938689Sborman { 112038689Sborman register struct spc *spcp; 112138689Sborman 112238689Sborman localchars = 1; 112338689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 112438689Sborman spcp->val = 0; 112538689Sborman spcp->valp = 0; 112638689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 112738689Sborman } 112838689Sborman 112938689Sborman #define initfunc(func, flags) { \ 113038689Sborman spcp = &spc_data[func]; \ 113138689Sborman if (spcp->valp = tcval(func)) { \ 113238689Sborman spcp->val = *spcp->valp; \ 113338689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 113438689Sborman } else { \ 113538689Sborman spcp->val = 0; \ 113638689Sborman spcp->mylevel = SLC_DEFAULT; \ 113738689Sborman } \ 113838689Sborman } 113938689Sborman 114038689Sborman initfunc(SLC_SYNCH, 0); 114138689Sborman /* No BRK */ 114238689Sborman initfunc(SLC_AO, 0); 114338689Sborman initfunc(SLC_AYT, 0); 114438689Sborman /* No EOR */ 114538689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 114638689Sborman initfunc(SLC_EOF, 0); 114739529Sborman #ifndef SYSV_TERMIO 114838689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 114938689Sborman #endif 115038689Sborman initfunc(SLC_EC, 0); 115138689Sborman initfunc(SLC_EL, 0); 115239529Sborman #ifndef SYSV_TERMIO 115338689Sborman initfunc(SLC_EW, 0); 115438689Sborman initfunc(SLC_RP, 0); 115538689Sborman initfunc(SLC_LNEXT, 0); 115638689Sborman #endif 115738689Sborman initfunc(SLC_XON, 0); 115838689Sborman initfunc(SLC_XOFF, 0); 115939529Sborman #ifdef SYSV_TERMIO 116038689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 116138689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 116238689Sborman #endif 116344360Sborman initfunc(SLC_FORW1, 0); 116444360Sborman #ifdef USE_TERMIO 116544360Sborman initfunc(SLC_FORW2, 0); 116638689Sborman /* No FORW2 */ 116744360Sborman #endif 116838689Sborman 116938689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 117038689Sborman #undef initfunc 117138689Sborman 117238689Sborman if (slc_mode == SLC_EXPORT) 117338689Sborman slc_export(); 117438689Sborman else 117538689Sborman slc_import(1); 117638689Sborman 117738689Sborman } 117838689Sborman 1179*46808Sdab void 118038689Sborman slcstate() 118138689Sborman { 118238689Sborman printf("Special characters are %s values\n", 118338689Sborman slc_mode == SLC_IMPORT ? "remote default" : 118438689Sborman slc_mode == SLC_EXPORT ? "local" : 118538689Sborman "remote"); 118638689Sborman } 118738689Sborman 1188*46808Sdab void 118938689Sborman slc_mode_export() 119038689Sborman { 119138689Sborman slc_mode = SLC_EXPORT; 119238689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 119338689Sborman slc_export(); 119438689Sborman } 119538689Sborman 1196*46808Sdab void 119738689Sborman slc_mode_import(def) 1198*46808Sdab int def; 119938689Sborman { 120038689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 120138689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 120238689Sborman slc_import(def); 120338689Sborman } 120438689Sborman 1205*46808Sdab unsigned char slc_import_val[] = { 120638689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 120738689Sborman }; 1208*46808Sdab unsigned char slc_import_def[] = { 120938689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 121038689Sborman }; 121138689Sborman 1212*46808Sdab void 121338689Sborman slc_import(def) 1214*46808Sdab int def; 121538689Sborman { 121638689Sborman if (NETROOM() > sizeof(slc_import_val)) { 121738689Sborman if (def) { 121838689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 121938689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 122038689Sborman } else { 122138689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 122238689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 122338689Sborman } 122438689Sborman } 122538689Sborman /*@*/ else printf("slc_import: not enough room\n"); 122638689Sborman } 122738689Sborman 1228*46808Sdab void 122938689Sborman slc_export() 123038689Sborman { 123138689Sborman register struct spc *spcp; 123238689Sborman 123338689Sborman TerminalDefaultChars(); 123438689Sborman 123538689Sborman slc_start_reply(); 123638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 123738689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 123845232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 123945232Sborman spcp->flags = SLC_NOSUPPORT; 124045232Sborman else 124145232Sborman spcp->flags = spcp->mylevel; 124238689Sborman if (spcp->valp) 124338689Sborman spcp->val = *spcp->valp; 124445232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 124538689Sborman } 124638689Sborman } 124738689Sborman slc_end_reply(); 1248*46808Sdab (void)slc_update(); 1249*46808Sdab setconnmode(1); /* Make sure the character values are set */ 125038689Sborman } 125138689Sborman 1252*46808Sdab void 125338689Sborman slc(cp, len) 1254*46808Sdab register unsigned char *cp; 1255*46808Sdab int len; 125638689Sborman { 125738689Sborman register struct spc *spcp; 125838689Sborman register int func,level; 125938689Sborman 126038689Sborman slc_start_reply(); 126138689Sborman 126238689Sborman for (; len >= 3; len -=3, cp +=3) { 126338689Sborman 126438689Sborman func = cp[SLC_FUNC]; 126538689Sborman 126638689Sborman if (func == 0) { 126738689Sborman /* 126838689Sborman * Client side: always ignore 0 function. 126938689Sborman */ 127038689Sborman continue; 127138689Sborman } 127238689Sborman if (func > NSLC) { 127345232Sborman if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 127438689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 127538689Sborman continue; 127638689Sborman } 127738689Sborman 127838689Sborman spcp = &spc_data[func]; 127938689Sborman 128038689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 128138689Sborman 128240245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 128338689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 128438689Sborman continue; 128538689Sborman } 128638689Sborman 128738689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 128838689Sborman /* 128938689Sborman * This is an error condition, the SLC_ACK 129038689Sborman * bit should never be set for the SLC_DEFAULT 129138689Sborman * level. Our best guess to recover is to 129238689Sborman * ignore the SLC_ACK bit. 129338689Sborman */ 129438689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 129538689Sborman } 129638689Sborman 129738689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 129840245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 129938689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 130038689Sborman continue; 130138689Sborman } 130238689Sborman 130338689Sborman level &= ~SLC_ACK; 130438689Sborman 130538689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 130638689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 130740245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 130838689Sborman } 130938689Sborman if (level == SLC_DEFAULT) { 131038689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 131138689Sborman spcp->flags = spcp->mylevel; 131238689Sborman else 131338689Sborman spcp->flags = SLC_NOSUPPORT; 131438689Sborman } 131538689Sborman slc_add_reply(func, spcp->flags, spcp->val); 131638689Sborman } 131738689Sborman slc_end_reply(); 131838689Sborman if (slc_update()) 131938689Sborman setconnmode(1); /* set the new character values */ 132038689Sborman } 132138689Sborman 1322*46808Sdab void 132338689Sborman slc_check() 132438689Sborman { 132538689Sborman register struct spc *spcp; 132638689Sborman 132738689Sborman slc_start_reply(); 132838689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 132938689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 133038689Sborman spcp->val = *spcp->valp; 133145232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 133245232Sborman spcp->flags = SLC_NOSUPPORT; 133345232Sborman else 133445232Sborman spcp->flags = spcp->mylevel; 133545232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 133638689Sborman } 133738689Sborman } 133838689Sborman slc_end_reply(); 133938689Sborman setconnmode(1); 134038689Sborman } 134138689Sborman 134238689Sborman 134338689Sborman unsigned char slc_reply[128]; 134438689Sborman unsigned char *slc_replyp; 1345*46808Sdab 1346*46808Sdab void 134738689Sborman slc_start_reply() 134838689Sborman { 134938689Sborman slc_replyp = slc_reply; 135038689Sborman *slc_replyp++ = IAC; 135138689Sborman *slc_replyp++ = SB; 135238689Sborman *slc_replyp++ = TELOPT_LINEMODE; 135338689Sborman *slc_replyp++ = LM_SLC; 135438689Sborman } 135538689Sborman 1356*46808Sdab void 135738689Sborman slc_add_reply(func, flags, value) 1358*46808Sdab unsigned char func; 1359*46808Sdab unsigned char flags; 1360*46808Sdab cc_t value; 136138689Sborman { 136238689Sborman if ((*slc_replyp++ = func) == IAC) 136338689Sborman *slc_replyp++ = IAC; 136438689Sborman if ((*slc_replyp++ = flags) == IAC) 136538689Sborman *slc_replyp++ = IAC; 136640245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 136738689Sborman *slc_replyp++ = IAC; 136838689Sborman } 136938689Sborman 1370*46808Sdab void 137138689Sborman slc_end_reply() 137238689Sborman { 137338689Sborman register int len; 137438689Sborman 137538689Sborman *slc_replyp++ = IAC; 137638689Sborman *slc_replyp++ = SE; 137738689Sborman len = slc_replyp - slc_reply; 137838689Sborman if (len <= 6) 137938689Sborman return; 138038689Sborman if (NETROOM() > len) { 138138689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 138238689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 138338689Sborman } 138438689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 138538689Sborman } 138638689Sborman 1387*46808Sdab int 138838689Sborman slc_update() 138938689Sborman { 139038689Sborman register struct spc *spcp; 139138689Sborman int need_update = 0; 139238689Sborman 139338689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 139438689Sborman if (!(spcp->flags&SLC_ACK)) 139538689Sborman continue; 139638689Sborman spcp->flags &= ~SLC_ACK; 139738689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 139838689Sborman *spcp->valp = spcp->val; 139938689Sborman need_update = 1; 140038689Sborman } 140138689Sborman } 140238689Sborman return(need_update); 140338689Sborman } 140438689Sborman 1405*46808Sdab void 140644360Sborman env_opt(buf, len) 1407*46808Sdab register unsigned char *buf; 1408*46808Sdab register int len; 140944360Sborman { 1410*46808Sdab register unsigned char *ep = 0, *epc = 0; 141144360Sborman register int i; 141244360Sborman 141345232Sborman switch(buf[0]&0xff) { 141444360Sborman case TELQUAL_SEND: 141544360Sborman env_opt_start(); 141644360Sborman if (len == 1) { 141744360Sborman env_opt_add(NULL); 141844360Sborman } else for (i = 1; i < len; i++) { 141945232Sborman switch (buf[i]&0xff) { 142044360Sborman case ENV_VALUE: 142144360Sborman if (ep) { 142244360Sborman *epc = 0; 142344360Sborman env_opt_add(ep); 142444360Sborman } 142544360Sborman ep = epc = &buf[i+1]; 142644360Sborman break; 142744360Sborman case ENV_ESC: 142844360Sborman i++; 142944360Sborman /*FALL THROUGH*/ 143044360Sborman default: 143144360Sborman if (epc) 143244360Sborman *epc++ = buf[i]; 143344360Sborman break; 143444360Sborman } 143544360Sborman if (ep) { 143644360Sborman *epc = 0; 143744360Sborman env_opt_add(ep); 143844360Sborman } 143944360Sborman } 144044360Sborman env_opt_end(1); 144144360Sborman break; 144244360Sborman 144344360Sborman case TELQUAL_IS: 144444360Sborman case TELQUAL_INFO: 144544360Sborman /* Ignore for now. We shouldn't get it anyway. */ 144644360Sborman break; 144744360Sborman 144844360Sborman default: 144944360Sborman break; 145044360Sborman } 145144360Sborman } 145244360Sborman 145344360Sborman #define OPT_REPLY_SIZE 256 145444360Sborman unsigned char *opt_reply; 145544360Sborman unsigned char *opt_replyp; 145644360Sborman unsigned char *opt_replyend; 145744360Sborman 1458*46808Sdab void 145944360Sborman env_opt_start() 146044360Sborman { 146144360Sborman if (opt_reply) 146244360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 146344360Sborman else 146444360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 146544360Sborman if (opt_reply == NULL) { 146644360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 146744360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 146844360Sborman return; 146944360Sborman } 147044360Sborman opt_replyp = opt_reply; 147144360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 147244360Sborman *opt_replyp++ = IAC; 147344360Sborman *opt_replyp++ = SB; 147444360Sborman *opt_replyp++ = TELOPT_ENVIRON; 147544360Sborman *opt_replyp++ = TELQUAL_IS; 147644360Sborman } 147744360Sborman 1478*46808Sdab void 147944360Sborman env_opt_start_info() 148044360Sborman { 148144360Sborman env_opt_start(); 148244360Sborman if (opt_replyp) 148344360Sborman opt_replyp[-1] = TELQUAL_INFO; 148444360Sborman } 148544360Sborman 1486*46808Sdab void 148744360Sborman env_opt_add(ep) 1488*46808Sdab register unsigned char *ep; 148944360Sborman { 1490*46808Sdab register unsigned char *vp, c; 149144360Sborman 149244360Sborman if (opt_reply == NULL) /*XXX*/ 149344360Sborman return; /*XXX*/ 149444360Sborman 149544360Sborman if (ep == NULL || *ep == '\0') { 149644360Sborman env_default(1); 149744360Sborman while (ep = env_default(0)) 149844360Sborman env_opt_add(ep); 149944360Sborman return; 150044360Sborman } 150144360Sborman vp = env_getvalue(ep); 1502*46808Sdab if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 1503*46808Sdab strlen((char *)ep) + 6 > opt_replyend) 1504*46808Sdab { 150544360Sborman register int len; 150644360Sborman opt_replyend += OPT_REPLY_SIZE; 150744360Sborman len = opt_replyend - opt_reply; 150844360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 150944360Sborman if (opt_reply == NULL) { 151044360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 151144360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 151244360Sborman return; 151344360Sborman } 151444360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 151544360Sborman opt_replyend = opt_reply + len; 151644360Sborman } 151744360Sborman *opt_replyp++ = ENV_VAR; 151844360Sborman for (;;) { 151944360Sborman while (c = *ep++) { 152045232Sborman switch(c&0xff) { 152144360Sborman case IAC: 152244360Sborman *opt_replyp++ = IAC; 152344360Sborman break; 152444360Sborman case ENV_VALUE: 152544360Sborman case ENV_VAR: 152644360Sborman case ENV_ESC: 152744360Sborman *opt_replyp++ = ENV_ESC; 152844360Sborman break; 152944360Sborman } 153044360Sborman *opt_replyp++ = c; 153144360Sborman } 153244360Sborman if (ep = vp) { 153344360Sborman *opt_replyp++ = ENV_VALUE; 153444360Sborman vp = NULL; 153544360Sborman } else 153644360Sborman break; 153744360Sborman } 153844360Sborman } 153944360Sborman 1540*46808Sdab void 154144360Sborman env_opt_end(emptyok) 1542*46808Sdab register int emptyok; 154344360Sborman { 154444360Sborman register int len; 154544360Sborman 154644360Sborman len = opt_replyp - opt_reply + 2; 154744360Sborman if (emptyok || len > 6) { 154844360Sborman *opt_replyp++ = IAC; 154944360Sborman *opt_replyp++ = SE; 155044360Sborman if (NETROOM() > len) { 155144360Sborman ring_supply_data(&netoring, opt_reply, len); 155244360Sborman printsub('>', &opt_reply[2], len - 2); 155344360Sborman } 155444360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 155544360Sborman } 155644360Sborman if (opt_reply) { 155744360Sborman free(opt_reply); 155844360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 155944360Sborman } 156044360Sborman } 156144360Sborman 156238689Sborman 156338689Sborman 1564*46808Sdab int 156532377Sminshall telrcv() 156627110Sminshall { 156732377Sminshall register int c; 156832385Sminshall register int scc; 1569*46808Sdab register unsigned char *sbp; 157032385Sminshall int count; 157132385Sminshall int returnValue = 0; 157227088Sminshall 157332385Sminshall scc = 0; 157432385Sminshall count = 0; 157532385Sminshall while (TTYROOM() > 2) { 157632385Sminshall if (scc == 0) { 157732385Sminshall if (count) { 157832528Sminshall ring_consumed(&netiring, count); 157932385Sminshall returnValue = 1; 158032385Sminshall count = 0; 158132385Sminshall } 158232528Sminshall sbp = netiring.consume; 158332528Sminshall scc = ring_full_consecutive(&netiring); 158432385Sminshall if (scc == 0) { 158532385Sminshall /* No more data coming in */ 158632385Sminshall break; 158732385Sminshall } 158832385Sminshall } 158932385Sminshall 159032385Sminshall c = *sbp++ & 0xff, scc--; count++; 1591*46808Sdab #if defined(ENCRYPT) 1592*46808Sdab if (decrypt_input) 1593*46808Sdab c = (*decrypt_input)(c); 1594*46808Sdab #endif 159532385Sminshall 159632377Sminshall switch (telrcv_state) { 159727110Sminshall 159832377Sminshall case TS_CR: 159932377Sminshall telrcv_state = TS_DATA; 160035518Sminshall if (c == '\0') { 160135518Sminshall break; /* Ignore \0 after CR */ 160239529Sborman } 160339529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 160435518Sminshall TTYADD(c); 160535518Sminshall break; 160632377Sminshall } 160735518Sminshall /* Else, fall through */ 160827088Sminshall 160932377Sminshall case TS_DATA: 161032377Sminshall if (c == IAC) { 161132377Sminshall telrcv_state = TS_IAC; 161233804Sminshall break; 161332377Sminshall } 161432377Sminshall # if defined(TN3270) 161532377Sminshall if (In3270) { 161632377Sminshall *Ifrontp++ = c; 161732385Sminshall while (scc > 0) { 161832385Sminshall c = *sbp++ & 0377, scc--; count++; 1619*46808Sdab #if defined(ENCRYPT) 1620*46808Sdab if (decrypt_input) 1621*46808Sdab c = (*decrypt_input)(c); 1622*46808Sdab #endif 162332377Sminshall if (c == IAC) { 162432377Sminshall telrcv_state = TS_IAC; 162534304Sminshall break; 162632377Sminshall } 162732377Sminshall *Ifrontp++ = c; 162832377Sminshall } 162932377Sminshall } else 163032377Sminshall # endif /* defined(TN3270) */ 163135518Sminshall /* 163235518Sminshall * The 'crmod' hack (see following) is needed 163335518Sminshall * since we can't * set CRMOD on output only. 163435518Sminshall * Machines like MULTICS like to send \r without 163535518Sminshall * \n; since we must turn off CRMOD to get proper 163635518Sminshall * input, the mapping is done here (sigh). 163735518Sminshall */ 163838689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 163935518Sminshall if (scc > 0) { 164035518Sminshall c = *sbp&0xff; 1641*46808Sdab #if defined(ENCRYPT) 1642*46808Sdab if (decrypt_input) 1643*46808Sdab c = (*decrypt_input)(c); 1644*46808Sdab #endif 164535518Sminshall if (c == 0) { 164635518Sminshall sbp++, scc--; count++; 164735518Sminshall /* a "true" CR */ 164832377Sminshall TTYADD('\r'); 164938689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 165035518Sminshall (c == '\n')) { 165135518Sminshall sbp++, scc--; count++; 165232377Sminshall TTYADD('\n'); 165335518Sminshall } else { 1654*46808Sdab #if defined(ENCRYPT) 1655*46808Sdab if (decrypt_input) 1656*46808Sdab (*decrypt_input)(-1); 1657*46808Sdab #endif 1658*46808Sdab 165935518Sminshall TTYADD('\r'); 166035518Sminshall if (crmod) { 166135518Sminshall TTYADD('\n'); 166232377Sminshall } 166332377Sminshall } 166435518Sminshall } else { 166535518Sminshall telrcv_state = TS_CR; 166635518Sminshall TTYADD('\r'); 166735518Sminshall if (crmod) { 166835518Sminshall TTYADD('\n'); 166935518Sminshall } 167032377Sminshall } 167132377Sminshall } else { 167232377Sminshall TTYADD(c); 167332377Sminshall } 167432377Sminshall continue; 167527088Sminshall 167632377Sminshall case TS_IAC: 167738689Sborman process_iac: 167832377Sminshall switch (c) { 167932377Sminshall 168032377Sminshall case WILL: 168132377Sminshall telrcv_state = TS_WILL; 168232377Sminshall continue; 168327261Sminshall 168432377Sminshall case WONT: 168532377Sminshall telrcv_state = TS_WONT; 168632377Sminshall continue; 168727261Sminshall 168832377Sminshall case DO: 168932377Sminshall telrcv_state = TS_DO; 169032377Sminshall continue; 169127261Sminshall 169232377Sminshall case DONT: 169332377Sminshall telrcv_state = TS_DONT; 169432377Sminshall continue; 169527261Sminshall 169632377Sminshall case DM: 169732377Sminshall /* 169832377Sminshall * We may have missed an urgent notification, 169932377Sminshall * so make sure we flush whatever is in the 170032377Sminshall * buffer currently. 170132377Sminshall */ 1702*46808Sdab printoption("RCVD", IAC, DM); 170332377Sminshall SYNCHing = 1; 170444360Sborman (void) ttyflush(1); 170532554Sminshall SYNCHing = stilloob(); 170632377Sminshall settimer(gotDM); 170732377Sminshall break; 170827088Sminshall 170932377Sminshall case SB: 171032377Sminshall SB_CLEAR(); 171132377Sminshall telrcv_state = TS_SB; 171232377Sminshall continue; 171327261Sminshall 171432377Sminshall # if defined(TN3270) 171532377Sminshall case EOR: 171632377Sminshall if (In3270) { 171732377Sminshall if (Ibackp == Ifrontp) { 171832377Sminshall Ibackp = Ifrontp = Ibuf; 171932377Sminshall ISend = 0; /* should have been! */ 172032377Sminshall } else { 172144360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 172232377Sminshall ISend = 1; 172327088Sminshall } 172427088Sminshall } 1725*46808Sdab printoption("RCVD", IAC, EOR); 172627088Sminshall break; 172732377Sminshall # endif /* defined(TN3270) */ 172832377Sminshall 172932377Sminshall case IAC: 173032377Sminshall # if !defined(TN3270) 173132377Sminshall TTYADD(IAC); 173232377Sminshall # else /* !defined(TN3270) */ 173332377Sminshall if (In3270) { 173432377Sminshall *Ifrontp++ = IAC; 173532377Sminshall } else { 173632377Sminshall TTYADD(IAC); 173732377Sminshall } 173832377Sminshall # endif /* !defined(TN3270) */ 173927088Sminshall break; 174032377Sminshall 174144360Sborman case NOP: 174244360Sborman case GA: 174327088Sminshall default: 1744*46808Sdab printoption("RCVD", IAC, c); 174527088Sminshall break; 174627088Sminshall } 174732377Sminshall telrcv_state = TS_DATA; 174832377Sminshall continue; 174927088Sminshall 175032377Sminshall case TS_WILL: 1751*46808Sdab printoption("RCVD", WILL, c); 175238689Sborman willoption(c); 175332377Sminshall SetIn3270(); 175432377Sminshall telrcv_state = TS_DATA; 175532377Sminshall continue; 175627110Sminshall 175732377Sminshall case TS_WONT: 1758*46808Sdab printoption("RCVD", WONT, c); 175938689Sborman wontoption(c); 176032377Sminshall SetIn3270(); 176132377Sminshall telrcv_state = TS_DATA; 176232377Sminshall continue; 176327088Sminshall 176432377Sminshall case TS_DO: 1765*46808Sdab printoption("RCVD", DO, c); 176637226Sminshall dooption(c); 176732377Sminshall SetIn3270(); 176837219Sminshall if (c == TELOPT_NAWS) { 176937219Sminshall sendnaws(); 177037219Sminshall } else if (c == TELOPT_LFLOW) { 177137219Sminshall localflow = 1; 177237219Sminshall setcommandmode(); 177338689Sborman setconnmode(0); 177437219Sminshall } 177532377Sminshall telrcv_state = TS_DATA; 177632377Sminshall continue; 177727088Sminshall 177832377Sminshall case TS_DONT: 1779*46808Sdab printoption("RCVD", DONT, c); 178038689Sborman dontoption(c); 178137226Sminshall flushline = 1; 178238689Sborman setconnmode(0); /* set new tty mode (maybe) */ 178332377Sminshall SetIn3270(); 178432377Sminshall telrcv_state = TS_DATA; 178532377Sminshall continue; 178627088Sminshall 178732377Sminshall case TS_SB: 178832377Sminshall if (c == IAC) { 178932377Sminshall telrcv_state = TS_SE; 179032377Sminshall } else { 179132377Sminshall SB_ACCUM(c); 179232377Sminshall } 179332377Sminshall continue; 179427088Sminshall 179532377Sminshall case TS_SE: 179632377Sminshall if (c != SE) { 179732377Sminshall if (c != IAC) { 179838689Sborman /* 179938689Sborman * This is an error. We only expect to get 180038689Sborman * "IAC IAC" or "IAC SE". Several things may 180138689Sborman * have happend. An IAC was not doubled, the 180238689Sborman * IAC SE was left off, or another option got 180338689Sborman * inserted into the suboption are all possibilities. 180438689Sborman * If we assume that the IAC was not doubled, 180538689Sborman * and really the IAC SE was left off, we could 180638689Sborman * get into an infinate loop here. So, instead, 180738689Sborman * we terminate the suboption, and process the 180838689Sborman * partial suboption if we can. 180938689Sborman */ 181032377Sminshall SB_ACCUM(IAC); 181138689Sborman SB_ACCUM(c); 1812*46808Sdab subpointer -= 2; 1813*46808Sdab SB_TERM(); 1814*46808Sdab 1815*46808Sdab printoption("In SUBOPTION processing, RCVD", IAC, c); 181638689Sborman suboption(); /* handle sub-option */ 181738689Sborman SetIn3270(); 181838689Sborman telrcv_state = TS_IAC; 181938689Sborman goto process_iac; 182032377Sminshall } 182132377Sminshall SB_ACCUM(c); 182232377Sminshall telrcv_state = TS_SB; 182332377Sminshall } else { 182438689Sborman SB_ACCUM(IAC); 182538689Sborman SB_ACCUM(SE); 1826*46808Sdab subpointer -= 2; 1827*46808Sdab SB_TERM(); 182832377Sminshall suboption(); /* handle sub-option */ 182932377Sminshall SetIn3270(); 183032377Sminshall telrcv_state = TS_DATA; 183132377Sminshall } 183227088Sminshall } 183327088Sminshall } 183432667Sminshall if (count) 183532667Sminshall ring_consumed(&netiring, count); 183632385Sminshall return returnValue||count; 183727088Sminshall } 183832385Sminshall 1839*46808Sdab static int bol = 1, local = 0; 1840*46808Sdab 1841*46808Sdab int 1842*46808Sdab rlogin_susp() 1843*46808Sdab { 1844*46808Sdab if (local) { 1845*46808Sdab local = 0; 1846*46808Sdab bol = 1; 1847*46808Sdab command(0, "z\n", 2); 1848*46808Sdab return(1); 1849*46808Sdab } 1850*46808Sdab return(0); 1851*46808Sdab } 1852*46808Sdab 1853*46808Sdab static int 185432554Sminshall telsnd() 185532385Sminshall { 185632385Sminshall int tcc; 185732385Sminshall int count; 185832385Sminshall int returnValue = 0; 1859*46808Sdab unsigned char *tbp; 186032385Sminshall 186132385Sminshall tcc = 0; 186232385Sminshall count = 0; 186332385Sminshall while (NETROOM() > 2) { 186432385Sminshall register int sc; 186532385Sminshall register int c; 186632385Sminshall 186732385Sminshall if (tcc == 0) { 186832385Sminshall if (count) { 186932528Sminshall ring_consumed(&ttyiring, count); 187032385Sminshall returnValue = 1; 187132385Sminshall count = 0; 187232385Sminshall } 187332528Sminshall tbp = ttyiring.consume; 187432528Sminshall tcc = ring_full_consecutive(&ttyiring); 187532385Sminshall if (tcc == 0) { 187632385Sminshall break; 187732385Sminshall } 187832385Sminshall } 187932385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 1880*46808Sdab if (rlogin != _POSIX_VDISABLE) { 1881*46808Sdab if (bol) { 1882*46808Sdab bol = 0; 1883*46808Sdab if (sc == rlogin) { 1884*46808Sdab local = 1; 1885*46808Sdab continue; 1886*46808Sdab } 1887*46808Sdab } else if (local) { 1888*46808Sdab local = 0; 1889*46808Sdab if (sc == '.' || c == termEofChar) { 1890*46808Sdab bol = 1; 1891*46808Sdab command(0, "close\n", 6); 1892*46808Sdab continue; 1893*46808Sdab } 1894*46808Sdab if (sc == termSuspChar) { 1895*46808Sdab bol = 1; 1896*46808Sdab command(0, "z\n", 2); 1897*46808Sdab continue; 1898*46808Sdab } 1899*46808Sdab if (sc == escape) { 1900*46808Sdab command(0, (char *)tbp, tcc); 1901*46808Sdab bol = 1; 1902*46808Sdab count += tcc; 1903*46808Sdab tcc = 0; 1904*46808Sdab flushline = 1; 1905*46808Sdab break; 1906*46808Sdab } 1907*46808Sdab if (sc != rlogin) { 1908*46808Sdab ++tcc; 1909*46808Sdab --tbp; 1910*46808Sdab --count; 1911*46808Sdab c = sc = rlogin; 1912*46808Sdab } 1913*46808Sdab } 1914*46808Sdab if ((sc == '\n') || (sc == '\r')) 1915*46808Sdab bol = 1; 1916*46808Sdab } else if (sc == escape) { 191738689Sborman /* 191838689Sborman * Double escape is a pass through of a single escape character. 191938689Sborman */ 192038689Sborman if (tcc && strip(*tbp) == escape) { 192138689Sborman tbp++; 192238689Sborman tcc--; 192338689Sborman count++; 1924*46808Sdab bol = 0; 192538689Sborman } else { 1926*46808Sdab command(0, (char *)tbp, tcc); 1927*46808Sdab bol = 1; 192838689Sborman count += tcc; 192938689Sborman tcc = 0; 193038689Sborman flushline = 1; 193138689Sborman break; 193238689Sborman } 1933*46808Sdab } else 1934*46808Sdab bol = 0; 193538689Sborman #ifdef KLUDGELINEMODE 193638689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 193732385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 193832385Sminshall tcc--; tbp++; count++; 193932385Sminshall } else { 194032385Sminshall dontlecho = !dontlecho; 194132385Sminshall settimer(echotoggle); 194238689Sborman setconnmode(0); 194332385Sminshall flushline = 1; 194432385Sminshall break; 194532385Sminshall } 194632385Sminshall } 194738689Sborman #endif 194838689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 194932385Sminshall if (TerminalSpecialChars(sc) == 0) { 1950*46808Sdab bol = 1; 195132385Sminshall break; 195232385Sminshall } 195332385Sminshall } 195438689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 195532385Sminshall switch (c) { 195632385Sminshall case '\n': 195732385Sminshall /* 195832385Sminshall * If we are in CRMOD mode (\r ==> \n) 195932385Sminshall * on our local machine, then probably 196032385Sminshall * a newline (unix) is CRLF (TELNET). 196132385Sminshall */ 196232385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 196332385Sminshall NETADD('\r'); 196432385Sminshall } 196532385Sminshall NETADD('\n'); 1966*46808Sdab bol = flushline = 1; 196732385Sminshall break; 196832385Sminshall case '\r': 196932385Sminshall if (!crlf) { 197032385Sminshall NET2ADD('\r', '\0'); 197132385Sminshall } else { 197232385Sminshall NET2ADD('\r', '\n'); 197332385Sminshall } 1974*46808Sdab bol = flushline = 1; 197532385Sminshall break; 197632385Sminshall case IAC: 197732385Sminshall NET2ADD(IAC, IAC); 197832385Sminshall break; 197932385Sminshall default: 198032385Sminshall NETADD(c); 198132385Sminshall break; 198232385Sminshall } 198332385Sminshall } else if (c == IAC) { 198432385Sminshall NET2ADD(IAC, IAC); 198532385Sminshall } else { 198632385Sminshall NETADD(c); 198732385Sminshall } 198832385Sminshall } 198932667Sminshall if (count) 199032667Sminshall ring_consumed(&ttyiring, count); 199132385Sminshall return returnValue||count; /* Non-zero if we did anything */ 199232385Sminshall } 199332377Sminshall 199427088Sminshall /* 199532377Sminshall * Scheduler() 199632377Sminshall * 199732377Sminshall * Try to do something. 199832377Sminshall * 199932377Sminshall * If we do something useful, return 1; else return 0. 200032377Sminshall * 200127110Sminshall */ 200227110Sminshall 200327110Sminshall 2004*46808Sdab int 200532377Sminshall Scheduler(block) 2006*46808Sdab int block; /* should we block in the select ? */ 200727110Sminshall { 200832377Sminshall /* One wants to be a bit careful about setting returnValue 200932377Sminshall * to one, since a one implies we did some useful work, 201032377Sminshall * and therefore probably won't be called to block next 201132377Sminshall * time (TN3270 mode only). 201232377Sminshall */ 201332531Sminshall int returnValue; 201432531Sminshall int netin, netout, netex, ttyin, ttyout; 201527110Sminshall 201632531Sminshall /* Decide which rings should be processed */ 201732531Sminshall 201832531Sminshall netout = ring_full_count(&netoring) && 201938689Sborman (flushline || 202038689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 202138689Sborman #ifdef KLUDGELINEMODE 202238689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 202338689Sborman #endif 202438689Sborman ) || 202538689Sborman my_want_state_is_will(TELOPT_BINARY)); 202632531Sminshall ttyout = ring_full_count(&ttyoring); 202732531Sminshall 202832377Sminshall #if defined(TN3270) 202932531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 203032377Sminshall #else /* defined(TN3270) */ 203132531Sminshall ttyin = ring_empty_count(&ttyiring); 203232377Sminshall #endif /* defined(TN3270) */ 203332531Sminshall 203432531Sminshall #if defined(TN3270) 203532531Sminshall netin = ring_empty_count(&netiring); 203632377Sminshall # else /* !defined(TN3270) */ 203732531Sminshall netin = !ISend && ring_empty_count(&netiring); 203832377Sminshall # endif /* !defined(TN3270) */ 203932531Sminshall 204032531Sminshall netex = !SYNCHing; 204132531Sminshall 204232531Sminshall /* If we have seen a signal recently, reset things */ 204332377Sminshall # if defined(TN3270) && defined(unix) 204432377Sminshall if (HaveInput) { 204532377Sminshall HaveInput = 0; 204644360Sborman (void) signal(SIGIO, inputAvailable); 204732377Sminshall } 204832377Sminshall #endif /* defined(TN3270) && defined(unix) */ 204932377Sminshall 205032531Sminshall /* Call to system code to process rings */ 205127178Sminshall 205232531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 205327178Sminshall 205432531Sminshall /* Now, look at the input rings, looking for work to do. */ 205532377Sminshall 205632531Sminshall if (ring_full_count(&ttyiring)) { 205732377Sminshall # if defined(TN3270) 205832377Sminshall if (In3270) { 205934848Sminshall int c; 206034848Sminshall 206133804Sminshall c = DataFromTerminal(ttyiring.consume, 206232528Sminshall ring_full_consecutive(&ttyiring)); 206332377Sminshall if (c) { 206432377Sminshall returnValue = 1; 206532667Sminshall ring_consumed(&ttyiring, c); 206632377Sminshall } 206732377Sminshall } else { 206832377Sminshall # endif /* defined(TN3270) */ 206932554Sminshall returnValue |= telsnd(); 207032377Sminshall # if defined(TN3270) 207127178Sminshall } 207232531Sminshall # endif /* defined(TN3270) */ 207327178Sminshall } 207432377Sminshall 207532528Sminshall if (ring_full_count(&netiring)) { 207632377Sminshall # if !defined(TN3270) 207732385Sminshall returnValue |= telrcv(); 207832377Sminshall # else /* !defined(TN3270) */ 207932377Sminshall returnValue = Push3270(); 208032377Sminshall # endif /* !defined(TN3270) */ 208132377Sminshall } 208232377Sminshall return returnValue; 208327178Sminshall } 208427178Sminshall 208527178Sminshall /* 208632377Sminshall * Select from tty and network... 208727088Sminshall */ 2088*46808Sdab void 2089*46808Sdab telnet(user) 2090*46808Sdab char *user; 209127088Sminshall { 209232531Sminshall sys_telnet_init(); 209327088Sminshall 2094*46808Sdab #if defined(ENCRYPT) || defined(AUTHENTICATE) 2095*46808Sdab { 2096*46808Sdab static char local_host[256] = { 0 }; 2097*46808Sdab int len = sizeof(local_host); 2098*46808Sdab 2099*46808Sdab if (!local_host[0]) { 2100*46808Sdab gethostname(local_host, &len); 2101*46808Sdab local_host[sizeof(local_host)-1] = 0; 2102*46808Sdab } 2103*46808Sdab auth_encrypt_init(local_host, hostname, "TELNET", 0); 2104*46808Sdab auth_encrypt_user(user); 2105*46808Sdab } 2106*46808Sdab #endif 210732377Sminshall # if !defined(TN3270) 210832377Sminshall if (telnetport) { 2109*46808Sdab #if defined(AUTHENTICATE) 2110*46808Sdab if (autologin) 2111*46808Sdab send_will(TELOPT_AUTHENTICATION, 1); 2112*46808Sdab #endif 2113*46808Sdab #if defined(ENCRYPT) 2114*46808Sdab send_do(TELOPT_ENCRYPT, 1); 2115*46808Sdab send_will(TELOPT_ENCRYPT, 1); 2116*46808Sdab #endif 211738689Sborman send_do(TELOPT_SGA, 1); 211838689Sborman send_will(TELOPT_TTYPE, 1); 211938689Sborman send_will(TELOPT_NAWS, 1); 212038689Sborman send_will(TELOPT_TSPEED, 1); 212138689Sborman send_will(TELOPT_LFLOW, 1); 212238689Sborman send_will(TELOPT_LINEMODE, 1); 2123*46808Sdab send_will(TELOPT_ENVIRON, 1); 212438908Sborman send_do(TELOPT_STATUS, 1); 2125*46808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 212644360Sborman send_will(TELOPT_XDISPLOC, 1); 2127*46808Sdab if (eight) 2128*46808Sdab tel_enter_binary(eight); 212927178Sminshall } 213032377Sminshall # endif /* !defined(TN3270) */ 213127088Sminshall 213232377Sminshall # if !defined(TN3270) 213332377Sminshall for (;;) { 213432385Sminshall int schedValue; 213532385Sminshall 213632385Sminshall while ((schedValue = Scheduler(0)) != 0) { 213732385Sminshall if (schedValue == -1) { 213832385Sminshall setcommandmode(); 213932385Sminshall return; 214032385Sminshall } 214132385Sminshall } 214232385Sminshall 214332531Sminshall if (Scheduler(1) == -1) { 214432377Sminshall setcommandmode(); 214532377Sminshall return; 214632377Sminshall } 214732377Sminshall } 214832377Sminshall # else /* !defined(TN3270) */ 214932377Sminshall for (;;) { 215032377Sminshall int schedValue; 215127088Sminshall 215232377Sminshall while (!In3270 && !shell_active) { 215332531Sminshall if (Scheduler(1) == -1) { 215432377Sminshall setcommandmode(); 215532377Sminshall return; 215632377Sminshall } 215727088Sminshall } 215832377Sminshall 215932377Sminshall while ((schedValue = Scheduler(0)) != 0) { 216032377Sminshall if (schedValue == -1) { 216132377Sminshall setcommandmode(); 216232377Sminshall return; 216332377Sminshall } 216427088Sminshall } 216532377Sminshall /* If there is data waiting to go out to terminal, don't 216632377Sminshall * schedule any more data for the terminal. 216732377Sminshall */ 216834304Sminshall if (ring_full_count(&ttyoring)) { 216932377Sminshall schedValue = 1; 217027088Sminshall } else { 217132377Sminshall if (shell_active) { 217232377Sminshall if (shell_continue() == 0) { 217332377Sminshall ConnectScreen(); 217427088Sminshall } 217532377Sminshall } else if (In3270) { 217632377Sminshall schedValue = DoTerminalOutput(); 217732377Sminshall } 217827088Sminshall } 217932377Sminshall if (schedValue && (shell_active == 0)) { 218032531Sminshall if (Scheduler(1) == -1) { 218132377Sminshall setcommandmode(); 218232377Sminshall return; 218332377Sminshall } 218427088Sminshall } 218532377Sminshall } 218632377Sminshall # endif /* !defined(TN3270) */ 218727088Sminshall } 218832377Sminshall 218934848Sminshall #if 0 /* XXX - this not being in is a bug */ 219027088Sminshall /* 219132554Sminshall * nextitem() 219232554Sminshall * 219332554Sminshall * Return the address of the next "item" in the TELNET data 219432554Sminshall * stream. This will be the address of the next character if 219532554Sminshall * the current address is a user data character, or it will 219632554Sminshall * be the address of the character following the TELNET command 219732554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 219832554Sminshall * character. 219932554Sminshall */ 220032554Sminshall 2201*46808Sdab static char * 220232554Sminshall nextitem(current) 2203*46808Sdab char *current; 220432554Sminshall { 220532554Sminshall if ((*current&0xff) != IAC) { 220632554Sminshall return current+1; 220732554Sminshall } 220832554Sminshall switch (*(current+1)&0xff) { 220932554Sminshall case DO: 221032554Sminshall case DONT: 221132554Sminshall case WILL: 221232554Sminshall case WONT: 221332554Sminshall return current+3; 221432554Sminshall case SB: /* loop forever looking for the SE */ 221532554Sminshall { 221632554Sminshall register char *look = current+2; 221732554Sminshall 221832554Sminshall for (;;) { 221932554Sminshall if ((*look++&0xff) == IAC) { 222032554Sminshall if ((*look++&0xff) == SE) { 222132554Sminshall return look; 222232554Sminshall } 222332554Sminshall } 222432554Sminshall } 222532554Sminshall } 222632554Sminshall default: 222732554Sminshall return current+2; 222832554Sminshall } 222932554Sminshall } 223034848Sminshall #endif /* 0 */ 223132554Sminshall 223232554Sminshall /* 223332554Sminshall * netclear() 223432554Sminshall * 223532554Sminshall * We are about to do a TELNET SYNCH operation. Clear 223632554Sminshall * the path to the network. 223732554Sminshall * 223832554Sminshall * Things are a bit tricky since we may have sent the first 223932554Sminshall * byte or so of a previous TELNET command into the network. 224032554Sminshall * So, we have to scan the network buffer from the beginning 224132554Sminshall * until we are up to where we want to be. 224232554Sminshall * 224332554Sminshall * A side effect of what we do, just to keep things 224432554Sminshall * simple, is to clear the urgent data pointer. The principal 224532554Sminshall * caller should be setting the urgent data pointer AFTER calling 224632554Sminshall * us in any case. 224732554Sminshall */ 224832554Sminshall 2249*46808Sdab static void 225032554Sminshall netclear() 225132554Sminshall { 225232554Sminshall #if 0 /* XXX */ 225332554Sminshall register char *thisitem, *next; 225432554Sminshall char *good; 225532554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 225632554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 225732554Sminshall 225832554Sminshall thisitem = netobuf; 225932554Sminshall 226032554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 226132554Sminshall thisitem = next; 226232554Sminshall } 226332554Sminshall 226432554Sminshall /* Now, thisitem is first before/at boundary. */ 226532554Sminshall 226632554Sminshall good = netobuf; /* where the good bytes go */ 226732554Sminshall 226832554Sminshall while (netoring.add > thisitem) { 226932554Sminshall if (wewant(thisitem)) { 227032554Sminshall int length; 227132554Sminshall 227232554Sminshall next = thisitem; 227332554Sminshall do { 227432554Sminshall next = nextitem(next); 227532554Sminshall } while (wewant(next) && (nfrontp > next)); 227632554Sminshall length = next-thisitem; 227732554Sminshall memcpy(good, thisitem, length); 227832554Sminshall good += length; 227932554Sminshall thisitem = next; 228032554Sminshall } else { 228132554Sminshall thisitem = nextitem(thisitem); 228232554Sminshall } 228332554Sminshall } 228432554Sminshall 228532554Sminshall #endif /* 0 */ 228632554Sminshall } 228732554Sminshall 228832554Sminshall /* 228932377Sminshall * These routines add various telnet commands to the data stream. 229027088Sminshall */ 229132377Sminshall 2292*46808Sdab static void 229332554Sminshall doflush() 229432554Sminshall { 229532554Sminshall NET2ADD(IAC, DO); 229632554Sminshall NETADD(TELOPT_TM); 229732554Sminshall flushline = 1; 229832554Sminshall flushout = 1; 229944360Sborman (void) ttyflush(1); /* Flush/drop output */ 230032554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 2301*46808Sdab printoption("SENT", DO, TELOPT_TM); 230232554Sminshall } 230332554Sminshall 2304*46808Sdab void 230532377Sminshall xmitAO() 230627088Sminshall { 230732377Sminshall NET2ADD(IAC, AO); 2308*46808Sdab printoption("SENT", IAC, AO); 230932377Sminshall if (autoflush) { 231032377Sminshall doflush(); 231132377Sminshall } 231232377Sminshall } 231327088Sminshall 231432377Sminshall 2315*46808Sdab void 231632377Sminshall xmitEL() 231727088Sminshall { 231832377Sminshall NET2ADD(IAC, EL); 2319*46808Sdab printoption("SENT", IAC, EL); 232027088Sminshall } 232127088Sminshall 2322*46808Sdab void 232332377Sminshall xmitEC() 232427088Sminshall { 232532377Sminshall NET2ADD(IAC, EC); 2326*46808Sdab printoption("SENT", IAC, EC); 232727088Sminshall } 232827088Sminshall 232932377Sminshall 2330*46808Sdab int 233132377Sminshall dosynch() 233227088Sminshall { 233332377Sminshall netclear(); /* clear the path to the network */ 233433294Sminshall NETADD(IAC); 233533294Sminshall setneturg(); 233633294Sminshall NETADD(DM); 2337*46808Sdab printoption("SENT", IAC, DM); 2338*46808Sdab return 1; 233927088Sminshall } 234027088Sminshall 2341*46808Sdab int want_status_response = 0; 2342*46808Sdab 2343*46808Sdab int 234438908Sborman get_status() 234538908Sborman { 2346*46808Sdab unsigned char tmp[16]; 2347*46808Sdab register unsigned char *cp; 234838908Sborman 234938908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 235038908Sborman printf("Remote side does not support STATUS option\n"); 2351*46808Sdab return 0; 235238908Sborman } 235338908Sborman cp = tmp; 235438908Sborman 235538908Sborman *cp++ = IAC; 235638908Sborman *cp++ = SB; 235738908Sborman *cp++ = TELOPT_STATUS; 235838908Sborman *cp++ = TELQUAL_SEND; 235938908Sborman *cp++ = IAC; 236038908Sborman *cp++ = SE; 236138908Sborman if (NETROOM() >= cp - tmp) { 236238908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 236338908Sborman printsub('>', tmp+2, cp - tmp - 2); 236438908Sborman } 2365*46808Sdab ++want_status_response; 2366*46808Sdab return 1; 236738908Sborman } 236838908Sborman 2369*46808Sdab void 237032377Sminshall intp() 237127088Sminshall { 237232377Sminshall NET2ADD(IAC, IP); 2373*46808Sdab printoption("SENT", IAC, IP); 237432377Sminshall flushline = 1; 237532377Sminshall if (autoflush) { 237632377Sminshall doflush(); 237732377Sminshall } 237832377Sminshall if (autosynch) { 237932377Sminshall dosynch(); 238032377Sminshall } 238127088Sminshall } 238227186Sminshall 2383*46808Sdab void 238432377Sminshall sendbrk() 238527186Sminshall { 238632377Sminshall NET2ADD(IAC, BREAK); 2387*46808Sdab printoption("SENT", IAC, BREAK); 238832377Sminshall flushline = 1; 238932377Sminshall if (autoflush) { 239032377Sminshall doflush(); 239132377Sminshall } 239232377Sminshall if (autosynch) { 239332377Sminshall dosynch(); 239432377Sminshall } 239527186Sminshall } 239638689Sborman 2397*46808Sdab void 239838689Sborman sendabort() 239938689Sborman { 240038689Sborman NET2ADD(IAC, ABORT); 2401*46808Sdab printoption("SENT", IAC, ABORT); 240238689Sborman flushline = 1; 240338689Sborman if (autoflush) { 240438689Sborman doflush(); 240538689Sborman } 240638689Sborman if (autosynch) { 240738689Sborman dosynch(); 240838689Sborman } 240938689Sborman } 241038689Sborman 2411*46808Sdab void 241238689Sborman sendsusp() 241338689Sborman { 241438689Sborman NET2ADD(IAC, SUSP); 2415*46808Sdab printoption("SENT", IAC, SUSP); 241638689Sborman flushline = 1; 241738689Sborman if (autoflush) { 241838689Sborman doflush(); 241938689Sborman } 242038689Sborman if (autosynch) { 242138689Sborman dosynch(); 242238689Sborman } 242338689Sborman } 242438689Sborman 2425*46808Sdab void 242638689Sborman sendeof() 242738689Sborman { 242838908Sborman NET2ADD(IAC, xEOF); 2429*46808Sdab printoption("SENT", IAC, xEOF); 243038689Sborman } 243138689Sborman 2432*46808Sdab void 243345232Sborman sendayt() 243445232Sborman { 243545232Sborman NET2ADD(IAC, AYT); 2436*46808Sdab printoption("SENT", IAC, AYT); 243745232Sborman } 243845232Sborman 243937219Sminshall /* 244037219Sminshall * Send a window size update to the remote system. 244137219Sminshall */ 244237219Sminshall 2443*46808Sdab void 244437219Sminshall sendnaws() 244537219Sminshall { 244637219Sminshall long rows, cols; 244738689Sborman unsigned char tmp[16]; 244838689Sborman register unsigned char *cp; 244937219Sminshall 245038689Sborman if (my_state_is_wont(TELOPT_NAWS)) 245138689Sborman return; 245237219Sminshall 245338689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 245438689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 245538689Sborman 245637219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 245737219Sminshall return; 245837219Sminshall } 245937219Sminshall 246038689Sborman cp = tmp; 246138689Sborman 246238689Sborman *cp++ = IAC; 246338689Sborman *cp++ = SB; 246438689Sborman *cp++ = TELOPT_NAWS; 246538689Sborman PUTSHORT(cp, cols); 246638689Sborman PUTSHORT(cp, rows); 246738689Sborman *cp++ = IAC; 246838689Sborman *cp++ = SE; 246938689Sborman if (NETROOM() >= cp - tmp) { 247038689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 247138689Sborman printsub('>', tmp+2, cp - tmp - 2); 247237219Sminshall } 247337219Sminshall } 247437226Sminshall 2475*46808Sdab void 247638908Sborman tel_enter_binary(rw) 2477*46808Sdab int rw; 247837226Sminshall { 247938908Sborman if (rw&1) 248038908Sborman send_do(TELOPT_BINARY, 1); 248138908Sborman if (rw&2) 248238908Sborman send_will(TELOPT_BINARY, 1); 248337226Sminshall } 248437226Sminshall 2485*46808Sdab void 248638908Sborman tel_leave_binary(rw) 2487*46808Sdab int rw; 248837226Sminshall { 248938908Sborman if (rw&1) 249038908Sborman send_dont(TELOPT_BINARY, 1); 249138908Sborman if (rw&2) 249238908Sborman send_wont(TELOPT_BINARY, 1); 249337226Sminshall } 2494