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*47608Sdab static char sccsid[] = "@(#)telnet.c 5.53 (Berkeley) 03/22/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 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? */ 56*47608Sdab 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 */ 7632531Sminshall localchars, /* we recognize interrupt/quit */ 7732531Sminshall donelclchars, /* the user has set "localchars" */ 7832531Sminshall donebinarytoggle, /* the user has put us in binary */ 7932531Sminshall dontlecho, /* do we suppress local echoing right now? */ 8032531Sminshall globalmode; 8127088Sminshall 8244360Sborman char *prompt = 0; 836000Sroot 8444360Sborman cc_t escape; 8546808Sdab cc_t rlogin; 8644360Sborman #ifdef KLUDGELINEMODE 8744360Sborman cc_t echoc; 8844360Sborman #endif 8927186Sminshall 9027186Sminshall /* 916000Sroot * Telnet receiver states for fsm 926000Sroot */ 936000Sroot #define TS_DATA 0 946000Sroot #define TS_IAC 1 956000Sroot #define TS_WILL 2 966000Sroot #define TS_WONT 3 976000Sroot #define TS_DO 4 986000Sroot #define TS_DONT 5 9927021Sminshall #define TS_CR 6 10027676Sminshall #define TS_SB 7 /* sub-option collection */ 10127676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1026000Sroot 10332377Sminshall static int telrcv_state; 1046000Sroot 10532377Sminshall jmp_buf toplevel = { 0 }; 10632377Sminshall jmp_buf peerdied; 1076000Sroot 10832377Sminshall int flushline; 10938811Sborman int linemode; 11027021Sminshall 11138689Sborman #ifdef KLUDGELINEMODE 11238689Sborman int kludgelinemode = 1; 11338689Sborman #endif 11438689Sborman 11532377Sminshall /* 11632377Sminshall * The following are some clocks used to decide how to interpret 11732377Sminshall * the relationship between various variables. 11832377Sminshall */ 1196000Sroot 12032377Sminshall Clocks clocks; 12132377Sminshall 12238689Sborman #ifdef notdef 12332377Sminshall Modelist modelist[] = { 12432377Sminshall { "telnet command mode", COMMAND_LINE }, 12532377Sminshall { "character-at-a-time mode", 0 }, 12632377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 12732377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 12832377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 12932377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 13032377Sminshall { "3270 mode", 0 }, 13132377Sminshall }; 13238689Sborman #endif 1336000Sroot 13432377Sminshall 13532377Sminshall /* 13632377Sminshall * Initialize telnet environment. 13732377Sminshall */ 1386000Sroot 13946808Sdab void 14032377Sminshall init_telnet() 14132377Sminshall { 14244360Sborman env_init(); 14344360Sborman 14432377Sminshall SB_CLEAR(); 14537226Sminshall ClearArray(options); 1466000Sroot 14737219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 14846808Sdab #if defined(ENCRYPT) || defined(AUTHENTICATE) 14946808Sdab auth_encrypt_connect(connected); 15046808Sdab #endif 1516000Sroot 15232377Sminshall SYNCHing = 0; 1536000Sroot 15432377Sminshall /* Don't change NetTrace */ 1556000Sroot 15632377Sminshall escape = CONTROL(']'); 15746808Sdab rlogin = _POSIX_VDISABLE; 15844360Sborman #ifdef KLUDGELINEMODE 15932377Sminshall echoc = CONTROL('E'); 16044360Sborman #endif 1616000Sroot 16232377Sminshall flushline = 1; 16332377Sminshall telrcv_state = TS_DATA; 16432377Sminshall } 16532554Sminshall 1666000Sroot 16744360Sborman #ifdef notdef 16832554Sminshall #include <varargs.h> 1696000Sroot 17046808Sdab /*VARARGS*/ 17146808Sdab static void 17232554Sminshall printring(va_alist) 17346808Sdab va_dcl 17432554Sminshall { 17532554Sminshall va_list ap; 17632554Sminshall char buffer[100]; /* where things go */ 17732554Sminshall char *ptr; 17832554Sminshall char *format; 17932554Sminshall char *string; 18032554Sminshall Ring *ring; 18132554Sminshall int i; 18232554Sminshall 18332554Sminshall va_start(ap); 18432554Sminshall 18532554Sminshall ring = va_arg(ap, Ring *); 18632554Sminshall format = va_arg(ap, char *); 18732554Sminshall ptr = buffer; 18832554Sminshall 18932554Sminshall while ((i = *format++) != 0) { 19032554Sminshall if (i == '%') { 19132554Sminshall i = *format++; 19232554Sminshall switch (i) { 19332554Sminshall case 'c': 19432554Sminshall *ptr++ = va_arg(ap, int); 19532554Sminshall break; 19632554Sminshall case 's': 19732554Sminshall string = va_arg(ap, char *); 19832554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19932554Sminshall ring_supply_data(ring, string, strlen(string)); 20032554Sminshall ptr = buffer; 20132554Sminshall break; 20232554Sminshall case 0: 20332554Sminshall ExitString("printring: trailing %%.\n", 1); 20432554Sminshall /*NOTREACHED*/ 20532554Sminshall default: 20632554Sminshall ExitString("printring: unknown format character.\n", 1); 20732554Sminshall /*NOTREACHED*/ 20832554Sminshall } 20932554Sminshall } else { 21032554Sminshall *ptr++ = i; 21132554Sminshall } 21232554Sminshall } 21332554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21432554Sminshall } 21544360Sborman #endif 21632554Sminshall 21737226Sminshall /* 21837226Sminshall * These routines are in charge of sending option negotiations 21937226Sminshall * to the other side. 22037226Sminshall * 22137226Sminshall * The basic idea is that we send the negotiation if either side 22237226Sminshall * is in disagreement as to what the current state should be. 22337226Sminshall */ 22432554Sminshall 22546808Sdab void 22638689Sborman send_do(c, init) 22746808Sdab register int c, init; 2286000Sroot { 22938689Sborman if (init) { 23038689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 23138689Sborman my_want_state_is_do(c)) 23238689Sborman return; 23338689Sborman set_my_want_state_do(c); 23438689Sborman do_dont_resp[c]++; 23537226Sminshall } 23638689Sborman NET2ADD(IAC, DO); 23738689Sborman NETADD(c); 23846808Sdab printoption("SENT", DO, c); 23937226Sminshall } 24037226Sminshall 24146808Sdab void 24238689Sborman send_dont(c, init) 24346808Sdab register int c, init; 24437226Sminshall { 24538689Sborman if (init) { 24638689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 24738689Sborman my_want_state_is_dont(c)) 24838689Sborman return; 24938689Sborman set_my_want_state_dont(c); 25038689Sborman do_dont_resp[c]++; 25137226Sminshall } 25238689Sborman NET2ADD(IAC, DONT); 25338689Sborman NETADD(c); 25446808Sdab printoption("SENT", DONT, c); 25537226Sminshall } 25637226Sminshall 25746808Sdab void 25838689Sborman send_will(c, init) 25946808Sdab register int c, init; 26037226Sminshall { 26138689Sborman if (init) { 26238689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 26338689Sborman my_want_state_is_will(c)) 26438689Sborman return; 26538689Sborman set_my_want_state_will(c); 26638689Sborman will_wont_resp[c]++; 26737226Sminshall } 26838689Sborman NET2ADD(IAC, WILL); 26938689Sborman NETADD(c); 27046808Sdab printoption("SENT", WILL, c); 27137226Sminshall } 27237226Sminshall 27346808Sdab void 27438689Sborman send_wont(c, init) 27546808Sdab register int c, init; 27637226Sminshall { 27738689Sborman if (init) { 27838689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 27938689Sborman my_want_state_is_wont(c)) 28038689Sborman return; 28138689Sborman set_my_want_state_wont(c); 28238689Sborman will_wont_resp[c]++; 28337226Sminshall } 28438689Sborman NET2ADD(IAC, WONT); 28538689Sborman NETADD(c); 28646808Sdab printoption("SENT", WONT, c); 28737226Sminshall } 28837226Sminshall 28937226Sminshall 29046808Sdab void 29137226Sminshall willoption(option) 29237226Sminshall int option; 29337226Sminshall { 29438689Sborman int new_state_ok = 0; 2956000Sroot 29638689Sborman if (do_dont_resp[option]) { 29738689Sborman --do_dont_resp[option]; 29838689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 29938689Sborman --do_dont_resp[option]; 30038689Sborman } 30137226Sminshall 30238689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 3036000Sroot 30438689Sborman switch (option) { 30538689Sborman 30638689Sborman case TELOPT_ECHO: 30738689Sborman # if defined(TN3270) 30838689Sborman /* 30938689Sborman * The following is a pain in the rear-end. 31038689Sborman * Various IBM servers (some versions of Wiscnet, 31138689Sborman * possibly Fibronics/Spartacus, and who knows who 31238689Sborman * else) will NOT allow us to send "DO SGA" too early 31338689Sborman * in the setup proceedings. On the other hand, 31438689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31538689Sborman * So, we are stuck. Empirically (but, based on 31638689Sborman * a VERY small sample), the IBM servers don't send 31738689Sborman * out anything about ECHO, so we postpone our sending 31838689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 31938689Sborman * DO send). 32038689Sborman */ 32138689Sborman { 32238689Sborman if (askedSGA == 0) { 32338689Sborman askedSGA = 1; 32438689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32538689Sborman send_do(TELOPT_SGA, 1); 32632377Sminshall } 32732377Sminshall } 32838689Sborman /* Fall through */ 32938689Sborman case TELOPT_EOR: 33038908Sborman #endif /* defined(TN3270) */ 33138689Sborman case TELOPT_BINARY: 33238689Sborman case TELOPT_SGA: 33327110Sminshall settimer(modenegotiated); 33438908Sborman /* FALL THROUGH */ 33538908Sborman case TELOPT_STATUS: 33646808Sdab #if defined(AUTHENTICATE) 33746808Sdab case TELOPT_AUTHENTICATION: 33846808Sdab #endif 33946808Sdab #if defined(ENCRYPT) 34046808Sdab case TELOPT_ENCRYPT: 34146808Sdab #endif 34238689Sborman new_state_ok = 1; 3436000Sroot break; 3446000Sroot 34538689Sborman case TELOPT_TM: 34638689Sborman if (flushout) 34738689Sborman flushout = 0; 34838689Sborman /* 34938689Sborman * Special case for TM. If we get back a WILL, 35038689Sborman * pretend we got back a WONT. 35138689Sborman */ 35238689Sborman set_my_want_state_dont(option); 35338689Sborman set_my_state_dont(option); 35427110Sminshall return; /* Never reply to TM will's/wont's */ 3556000Sroot 35638689Sborman case TELOPT_LINEMODE: 35738689Sborman default: 3586000Sroot break; 35938689Sborman } 36038689Sborman 36138689Sborman if (new_state_ok) { 36238689Sborman set_my_want_state_do(option); 36338689Sborman send_do(option, 0); 36438689Sborman setconnmode(0); /* possibly set new tty mode */ 36538689Sborman } else { 36638689Sborman do_dont_resp[option]++; 36738689Sborman send_dont(option, 0); 36838689Sborman } 3696000Sroot } 37038689Sborman set_my_state_do(option); 37146808Sdab #if defined(ENCRYPT) 37246808Sdab if (option == TELOPT_ENCRYPT) 37346808Sdab encrypt_send_support(); 37446808Sdab #endif 3756000Sroot } 3766000Sroot 37746808Sdab void 37837226Sminshall wontoption(option) 37937226Sminshall int option; 3806000Sroot { 38138689Sborman if (do_dont_resp[option]) { 38238689Sborman --do_dont_resp[option]; 38338689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 38438689Sborman --do_dont_resp[option]; 38538689Sborman } 38637226Sminshall 38738689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3886000Sroot 38938689Sborman switch (option) { 39038689Sborman 39138689Sborman #ifdef KLUDGELINEMODE 39238689Sborman case TELOPT_SGA: 39338689Sborman if (!kludgelinemode) 39438689Sborman break; 39538689Sborman /* FALL THROUGH */ 39638689Sborman #endif 39738689Sborman case TELOPT_ECHO: 39827110Sminshall settimer(modenegotiated); 3996000Sroot break; 4006000Sroot 40138689Sborman case TELOPT_TM: 40238689Sborman if (flushout) 40338689Sborman flushout = 0; 40438689Sborman set_my_want_state_dont(option); 40538689Sborman set_my_state_dont(option); 40627110Sminshall return; /* Never reply to TM will's/wont's */ 40727110Sminshall 40838689Sborman default: 40938689Sborman break; 41038689Sborman } 41138689Sborman set_my_want_state_dont(option); 41244360Sborman if (my_state_is_do(option)) 41344360Sborman send_dont(option, 0); 41438689Sborman setconnmode(0); /* Set new tty mode */ 41538689Sborman } else if (option == TELOPT_TM) { 41638689Sborman /* 41738689Sborman * Special case for TM. 41838689Sborman */ 41938689Sborman if (flushout) 42038689Sborman flushout = 0; 42138689Sborman set_my_want_state_dont(option); 4226000Sroot } 42338689Sborman set_my_state_dont(option); 4246000Sroot } 4256000Sroot 42646808Sdab static void 4276000Sroot dooption(option) 4286000Sroot int option; 4296000Sroot { 43038689Sborman int new_state_ok = 0; 4316000Sroot 43238689Sborman if (will_wont_resp[option]) { 43338689Sborman --will_wont_resp[option]; 43438689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 43538689Sborman --will_wont_resp[option]; 43638689Sborman } 43737226Sminshall 43838689Sborman if (will_wont_resp[option] == 0) { 43938689Sborman if (my_want_state_is_wont(option)) { 4406000Sroot 44138689Sborman switch (option) { 44238689Sborman 44338689Sborman case TELOPT_TM: 44438689Sborman /* 44538689Sborman * Special case for TM. We send a WILL, but pretend 44638689Sborman * we sent WONT. 44738689Sborman */ 44838689Sborman send_will(option, 0); 44938689Sborman set_my_want_state_wont(TELOPT_TM); 45038689Sborman set_my_state_wont(TELOPT_TM); 45138689Sborman return; 45238689Sborman 45332377Sminshall # if defined(TN3270) 45438689Sborman case TELOPT_EOR: /* end of record */ 45538908Sborman # endif /* defined(TN3270) */ 45638689Sborman case TELOPT_BINARY: /* binary mode */ 45738689Sborman case TELOPT_NAWS: /* window size */ 45838689Sborman case TELOPT_TSPEED: /* terminal speed */ 45938689Sborman case TELOPT_LFLOW: /* local flow control */ 46038689Sborman case TELOPT_TTYPE: /* terminal type option */ 46138689Sborman case TELOPT_SGA: /* no big deal */ 46244360Sborman case TELOPT_ENVIRON: /* environment variable option */ 46346808Sdab #if defined(ENCRYPT) 46446808Sdab case TELOPT_ENCRYPT: /* encryption variable option */ 46546808Sdab #endif 46638689Sborman new_state_ok = 1; 4676000Sroot break; 46846808Sdab #if defined(AUTHENTICATE) 46946808Sdab case TELOPT_AUTHENTICATION: 47046808Sdab if (autologin) 47146808Sdab new_state_ok = 1; 47246808Sdab break; 47346808Sdab #endif 4746000Sroot 47544360Sborman case TELOPT_XDISPLOC: /* X Display location */ 47646808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 47744360Sborman new_state_ok = 1; 47844360Sborman break; 47944360Sborman 48038689Sborman case TELOPT_LINEMODE: 48138689Sborman #ifdef KLUDGELINEMODE 48238689Sborman kludgelinemode = 0; 48344360Sborman send_do(TELOPT_SGA, 1); 48438689Sborman #endif 48538689Sborman set_my_want_state_will(TELOPT_LINEMODE); 48638689Sborman send_will(option, 0); 48738689Sborman set_my_state_will(TELOPT_LINEMODE); 48838689Sborman slc_init(); 48938689Sborman return; 49038689Sborman 49138689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 49238689Sborman default: 4936000Sroot break; 49438689Sborman } 49538689Sborman 49638689Sborman if (new_state_ok) { 49738689Sborman set_my_want_state_will(option); 49838689Sborman send_will(option, 0); 49945232Sborman setconnmode(0); /* Set new tty mode */ 50038689Sborman } else { 50138689Sborman will_wont_resp[option]++; 50238689Sborman send_wont(option, 0); 50338689Sborman } 50438689Sborman } else { 50538689Sborman /* 50638689Sborman * Handle options that need more things done after the 50738689Sborman * other side has acknowledged the option. 50838689Sborman */ 50938689Sborman switch (option) { 51038689Sborman case TELOPT_LINEMODE: 51138689Sborman #ifdef KLUDGELINEMODE 51238689Sborman kludgelinemode = 0; 51344360Sborman send_do(TELOPT_SGA, 1); 51438689Sborman #endif 51538689Sborman set_my_state_will(option); 51638689Sborman slc_init(); 51744360Sborman send_do(TELOPT_SGA, 0); 51838689Sborman return; 51938689Sborman } 52038689Sborman } 5216000Sroot } 52238689Sborman set_my_state_will(option); 5236000Sroot } 52427676Sminshall 52546808Sdab static void 52638689Sborman dontoption(option) 52738689Sborman int option; 52838689Sborman { 52938689Sborman 53038689Sborman if (will_wont_resp[option]) { 53138689Sborman --will_wont_resp[option]; 53238689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 53338689Sborman --will_wont_resp[option]; 53438689Sborman } 53538689Sborman 53638689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 53738811Sborman switch (option) { 53838811Sborman case TELOPT_LINEMODE: 53938811Sborman linemode = 0; /* put us back to the default state */ 54038811Sborman break; 54138811Sborman } 54238689Sborman /* we always accept a DONT */ 54338689Sborman set_my_want_state_wont(option); 54444360Sborman if (my_state_is_will(option)) 54544360Sborman send_wont(option, 0); 54639529Sborman setconnmode(0); /* Set new tty mode */ 54738689Sborman } 54838689Sborman set_my_state_wont(option); 54938689Sborman } 55038689Sborman 55127676Sminshall /* 55238908Sborman * Given a buffer returned by tgetent(), this routine will turn 55338908Sborman * the pipe seperated list of names in the buffer into an array 55438908Sborman * of pointers to null terminated names. We toss out any bad, 55538908Sborman * duplicate, or verbose names (names with spaces). 55638908Sborman */ 55738908Sborman 55846808Sdab static char *name_unknown = "UNKNOWN"; 55946808Sdab static char *unknown[] = { 0, 0 }; 56038908Sborman 56146808Sdab char ** 56238908Sborman mklist(buf, name) 56346808Sdab char *buf, *name; 56438908Sborman { 56538908Sborman register int n; 56646808Sdab register char c, *cp, **argvp, *cp2, **argv, **avt; 56738908Sborman 56838908Sborman if (name) { 56946808Sdab if (strlen(name) > 40) { 57038908Sborman name = 0; 57146808Sdab unknown[0] = name_unknown; 57246808Sdab } else { 57338908Sborman unknown[0] = name; 57438908Sborman upcase(name); 57538908Sborman } 57646808Sdab } else 57746808Sdab unknown[0] = name_unknown; 57838908Sborman /* 57938908Sborman * Count up the number of names. 58038908Sborman */ 58138908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 58238908Sborman if (*cp == '|') 58338908Sborman n++; 58438908Sborman } 58538908Sborman /* 58638908Sborman * Allocate an array to put the name pointers into 58738908Sborman */ 58838908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 58938908Sborman if (argv == 0) 59038908Sborman return(unknown); 59138908Sborman 59238908Sborman /* 59338908Sborman * Fill up the array of pointers to names. 59438908Sborman */ 59538908Sborman *argv = 0; 59638908Sborman argvp = argv+1; 59738908Sborman n = 0; 59838908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 59938908Sborman if (c == '|' || c == ':') { 60038908Sborman *cp++ = '\0'; 60138908Sborman /* 60238908Sborman * Skip entries that have spaces or are over 40 60338908Sborman * characters long. If this is our environment 60438908Sborman * name, then put it up front. Otherwise, as 60538908Sborman * long as this is not a duplicate name (case 60638908Sborman * insensitive) add it to the list. 60738908Sborman */ 60838908Sborman if (n || (cp - cp2 > 41)) 60938908Sborman ; 61038908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 61138908Sborman *argv = cp2; 61238908Sborman else if (is_unique(cp2, argv+1, argvp)) 61338908Sborman *argvp++ = cp2; 61438908Sborman if (c == ':') 61538908Sborman break; 61638908Sborman /* 61738908Sborman * Skip multiple delimiters. Reset cp2 to 61838908Sborman * the beginning of the next name. Reset n, 61938908Sborman * the flag for names with spaces. 62038908Sborman */ 62138908Sborman while ((c = *cp) == '|') 62238908Sborman cp++; 62338908Sborman cp2 = cp; 62438908Sborman n = 0; 62538908Sborman } 62638908Sborman /* 62738908Sborman * Skip entries with spaces or non-ascii values. 62838908Sborman * Convert lower case letters to upper case. 62938908Sborman */ 63038908Sborman if ((c == ' ') || !isascii(c)) 63138908Sborman n = 1; 63238908Sborman else if (islower(c)) 63338908Sborman *cp = toupper(c); 63438908Sborman } 63538908Sborman 63638908Sborman /* 63738908Sborman * Check for an old V6 2 character name. If the second 63838908Sborman * name points to the beginning of the buffer, and is 63938908Sborman * only 2 characters long, move it to the end of the array. 64038908Sborman */ 64138908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 64246808Sdab --argvp; 64346808Sdab for (avt = &argv[1]; avt < argvp; avt++) 64446808Sdab *avt = *(avt+1); 64538908Sborman *argvp++ = buf; 64638908Sborman } 64738908Sborman 64838908Sborman /* 64938908Sborman * Duplicate last name, for TTYPE option, and null 65038908Sborman * terminate the array. If we didn't find a match on 65138908Sborman * our terminal name, put that name at the beginning. 65238908Sborman */ 65338908Sborman cp = *(argvp-1); 65438908Sborman *argvp++ = cp; 65538908Sborman *argvp = 0; 65638908Sborman 65738908Sborman if (*argv == 0) { 65838908Sborman if (name) 65938908Sborman *argv = name; 66046808Sdab else { 66146808Sdab --argvp; 66246808Sdab for (avt = argv; avt < argvp; avt++) 66346808Sdab *avt = *(avt+1); 66446808Sdab } 66538908Sborman } 66638908Sborman if (*argv) 66738908Sborman return(argv); 66838908Sborman else 66938908Sborman return(unknown); 67038908Sborman } 67138908Sborman 67246808Sdab int 67338908Sborman is_unique(name, as, ae) 67446808Sdab register char *name, **as, **ae; 67538908Sborman { 67638908Sborman register char **ap; 67738908Sborman register int n; 67838908Sborman 67938908Sborman n = strlen(name) + 1; 68038908Sborman for (ap = as; ap < ae; ap++) 68138908Sborman if (strncasecmp(*ap, name, n) == 0) 68238908Sborman return(0); 68338908Sborman return (1); 68438908Sborman } 68538908Sborman 68638908Sborman #ifdef TERMCAP 68739529Sborman char termbuf[1024]; 68846808Sdab 68946808Sdab /*ARGSUSED*/ 69046808Sdab int 69138908Sborman setupterm(tname, fd, errp) 69246808Sdab char *tname; 69346808Sdab int fd, *errp; 69438908Sborman { 69539529Sborman if (tgetent(termbuf, tname) == 1) { 69639529Sborman termbuf[1023] = '\0'; 69738908Sborman if (errp) 69838908Sborman *errp = 1; 69938908Sborman return(0); 70038908Sborman } 70138908Sborman if (errp) 70238908Sborman *errp = 0; 70338908Sborman return(-1); 70438908Sborman } 70539529Sborman #else 70639529Sborman #define termbuf ttytype 70739529Sborman extern char ttytype[]; 70838908Sborman #endif 70938908Sborman 71046808Sdab int resettermname = 1; 71146808Sdab 71246808Sdab char * 71338908Sborman gettermname() 71438908Sborman { 71538908Sborman char *tname; 71646808Sdab static char **tnamep = 0; 71738908Sborman static char **next; 71838908Sborman int err; 71938908Sborman 72046808Sdab if (resettermname) { 72146808Sdab resettermname = 0; 72246808Sdab if (tnamep && tnamep != unknown) 72346808Sdab free(tnamep); 72446808Sdab if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && 72538908Sborman (setupterm(tname, 1, &err) == 0)) { 72639529Sborman tnamep = mklist(termbuf, tname); 72738908Sborman } else { 72838908Sborman if (tname && (strlen(tname) <= 40)) { 72938908Sborman unknown[0] = tname; 73038908Sborman upcase(tname); 73146808Sdab } else 73246808Sdab unknown[0] = name_unknown; 73338908Sborman tnamep = unknown; 73438908Sborman } 73538908Sborman next = tnamep; 73638908Sborman } 73738908Sborman if (*next == 0) 73838908Sborman next = tnamep; 73938908Sborman return(*next++); 74038908Sborman } 74138908Sborman /* 74227676Sminshall * suboption() 74327676Sminshall * 74427676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 74527676Sminshall * side. 74627676Sminshall * 74727676Sminshall * Currently we recognize: 74827676Sminshall * 74927676Sminshall * Terminal type, send request. 75037219Sminshall * Terminal speed (send request). 75137219Sminshall * Local flow control (is request). 75238689Sborman * Linemode 75327676Sminshall */ 75427676Sminshall 75546808Sdab static void 75627676Sminshall suboption() 75727676Sminshall { 75846808Sdab printsub('<', subbuffer, SB_LEN()+2); 75946808Sdab switch (SB_GET()) { 76027676Sminshall case TELOPT_TTYPE: 76138689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 76238689Sborman return; 76346808Sdab if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 76446808Sdab return; 76527676Sminshall } else { 76627676Sminshall char *name; 76746808Sdab unsigned char temp[50]; 76827676Sminshall int len; 76927676Sminshall 77032377Sminshall #if defined(TN3270) 77132531Sminshall if (tn3270_ttype()) { 77232377Sminshall return; 77332377Sminshall } 77432377Sminshall #endif /* defined(TN3270) */ 77538908Sborman name = gettermname(); 77638908Sborman len = strlen(name) + 4 + 2; 77738908Sborman if (len < NETROOM()) { 77846808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 77938908Sborman TELQUAL_IS, name, IAC, SE); 78038689Sborman ring_supply_data(&netoring, temp, len); 78138908Sborman printsub('>', &temp[2], len-2); 78232377Sminshall } else { 78337226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 78432377Sminshall /*NOTREACHED*/ 78527676Sminshall } 78627676Sminshall } 78737219Sminshall break; 78837219Sminshall case TELOPT_TSPEED: 78938689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 79038689Sborman return; 79146808Sdab if (SB_EOF()) 79246808Sdab return; 79346808Sdab if (SB_GET() == TELQUAL_SEND) { 79445232Sborman long ospeed, ispeed; 79546808Sdab unsigned char temp[50]; 79637219Sminshall int len; 79727676Sminshall 79837219Sminshall TerminalSpeeds(&ispeed, &ospeed); 79937219Sminshall 80046808Sdab sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 80138689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 80246808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 80337219Sminshall 80438689Sborman if (len < NETROOM()) { 80538689Sborman ring_supply_data(&netoring, temp, len); 80638689Sborman printsub('>', temp+2, len - 2); 80737219Sminshall } 80844360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 80937219Sminshall } 81037219Sminshall break; 81137219Sminshall case TELOPT_LFLOW: 81238689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 81338689Sborman return; 81446808Sdab if (SB_EOF()) 81546808Sdab return; 81646808Sdab switch(SB_GET()) { 81746808Sdab case 1: 81837219Sminshall localflow = 1; 81946808Sdab break; 82046808Sdab case 0: 82137219Sminshall localflow = 0; 82246808Sdab break; 82346808Sdab default: 82446808Sdab return; 82537219Sminshall } 82637219Sminshall setcommandmode(); 82738689Sborman setconnmode(0); 82837219Sminshall break; 82938689Sborman 83038689Sborman case TELOPT_LINEMODE: 83138689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 83238689Sborman return; 83346808Sdab if (SB_EOF()) 83446808Sdab return; 83546808Sdab switch (SB_GET()) { 83638689Sborman case WILL: 83746808Sdab lm_will(subpointer, SB_LEN()); 83838689Sborman break; 83938689Sborman case WONT: 84046808Sdab lm_wont(subpointer, SB_LEN()); 84138689Sborman break; 84238689Sborman case DO: 84346808Sdab lm_do(subpointer, SB_LEN()); 84438689Sborman break; 84538689Sborman case DONT: 84646808Sdab lm_dont(subpointer, SB_LEN()); 84738689Sborman break; 84838689Sborman case LM_SLC: 84946808Sdab slc(subpointer, SB_LEN()); 85038689Sborman break; 85138689Sborman case LM_MODE: 85246808Sdab lm_mode(subpointer, SB_LEN(), 0); 85338689Sborman break; 85438689Sborman default: 85544360Sborman break; 85644360Sborman } 85744360Sborman break; 85844360Sborman 85944360Sborman case TELOPT_ENVIRON: 86046808Sdab if (SB_EOF()) 86146808Sdab return; 86246808Sdab switch(SB_PEEK()) { 86344360Sborman case TELQUAL_IS: 86444360Sborman case TELQUAL_INFO: 86544360Sborman if (my_want_state_is_dont(TELOPT_ENVIRON)) 86644360Sborman return; 86744360Sborman break; 86844360Sborman case TELQUAL_SEND: 86944360Sborman if (my_want_state_is_wont(TELOPT_ENVIRON)) { 87044360Sborman return; 87144360Sborman } 87244360Sborman break; 87344360Sborman default: 87444360Sborman return; 87544360Sborman } 87646808Sdab env_opt(subpointer, SB_LEN()); 87744360Sborman break; 87844360Sborman 87944360Sborman case TELOPT_XDISPLOC: 88044360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC)) 88144360Sborman return; 88246808Sdab if (SB_EOF()) 88346808Sdab return; 88446808Sdab if (SB_GET() == TELQUAL_SEND) { 88546808Sdab unsigned char temp[50], *dp; 88644360Sborman int len; 88744360Sborman 88846808Sdab if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { 88944360Sborman /* 89044360Sborman * Something happened, we no longer have a DISPLAY 89144360Sborman * variable. So, turn off the option. 89244360Sborman */ 89344360Sborman send_wont(TELOPT_XDISPLOC, 1); 89438689Sborman break; 89544360Sborman } 89646808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 89744360Sborman TELQUAL_IS, dp, IAC, SE); 89846808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 89944360Sborman 90044360Sborman if (len < NETROOM()) { 90144360Sborman ring_supply_data(&netoring, temp, len); 90244360Sborman printsub('>', temp+2, len - 2); 90344360Sborman } 90444360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 90538689Sborman } 90644360Sborman break; 90743319Skfall 90846808Sdab #if defined(AUTHENTICATE) 90946808Sdab case TELOPT_AUTHENTICATION: { 91046808Sdab if (!autologin) 91146808Sdab break; 91246808Sdab if (SB_EOF()) 91346808Sdab return; 91446808Sdab switch(SB_GET()) { 91546808Sdab case TELQUAL_IS: 91646808Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 91746808Sdab return; 91846808Sdab auth_is(subpointer, SB_LEN()); 91946808Sdab break; 92046808Sdab case TELQUAL_SEND: 92146808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 92246808Sdab return; 92346808Sdab auth_send(subpointer, SB_LEN()); 92446808Sdab break; 92546808Sdab case TELQUAL_REPLY: 92646808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 92746808Sdab return; 92846808Sdab auth_reply(subpointer, SB_LEN()); 92946808Sdab break; 930*47608Sdab case TELQUAL_NAME: 931*47608Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 932*47608Sdab return; 933*47608Sdab auth_name(subpointer, SB_LEN()); 934*47608Sdab break; 93543319Skfall } 93646808Sdab } 93746808Sdab break; 93843319Skfall #endif 93946808Sdab #if defined(ENCRYPT) 94046808Sdab case TELOPT_ENCRYPT: 94146808Sdab if (SB_EOF()) 94246808Sdab return; 94346808Sdab switch(SB_GET()) { 94446808Sdab case ENCRYPT_START: 94546808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 94646808Sdab return; 947*47608Sdab encrypt_start(subpointer, SB_LEN()); 94846808Sdab break; 94946808Sdab case ENCRYPT_END: 95046808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 95146808Sdab return; 95246808Sdab encrypt_end(); 95346808Sdab break; 95446808Sdab case ENCRYPT_SUPPORT: 95546808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 95646808Sdab return; 95746808Sdab encrypt_support(subpointer, SB_LEN()); 95846808Sdab break; 95946808Sdab case ENCRYPT_REQSTART: 96046808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96146808Sdab return; 962*47608Sdab encrypt_request_start(subpointer, SB_LEN()); 96346808Sdab break; 96446808Sdab case ENCRYPT_REQEND: 96546808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96646808Sdab return; 96746808Sdab /* 96846808Sdab * We can always send an REQEND so that we cannot 96946808Sdab * get stuck encrypting. We should only get this 97046808Sdab * if we have been able to get in the correct mode 97146808Sdab * anyhow. 97246808Sdab */ 97346808Sdab encrypt_request_end(); 97446808Sdab break; 97546808Sdab case ENCRYPT_IS: 97646808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 97746808Sdab return; 97846808Sdab encrypt_is(subpointer, SB_LEN()); 97946808Sdab break; 98046808Sdab case ENCRYPT_REPLY: 98146808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 98246808Sdab return; 98346808Sdab encrypt_reply(subpointer, SB_LEN()); 98446808Sdab break; 985*47608Sdab case ENCRYPT_ENC_KEYID: 986*47608Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 987*47608Sdab return; 988*47608Sdab encrypt_enc_keyid(subpointer, SB_LEN()); 989*47608Sdab break; 990*47608Sdab case ENCRYPT_DEC_KEYID: 991*47608Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 992*47608Sdab return; 993*47608Sdab encrypt_dec_keyid(subpointer, SB_LEN()); 994*47608Sdab break; 99546808Sdab default: 99646808Sdab break; 99746808Sdab } 99846808Sdab break; 99943319Skfall #endif 100027676Sminshall default: 100127676Sminshall break; 100227676Sminshall } 100327676Sminshall } 100438689Sborman 100546808Sdab static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 100638689Sborman 100746808Sdab void 100838689Sborman lm_will(cmd, len) 100946808Sdab unsigned char *cmd; 101046808Sdab int len; 101138689Sborman { 101244360Sborman if (len < 1) { 101344360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 101444360Sborman return; 101544360Sborman } 101638689Sborman switch(cmd[0]) { 101738689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 101838689Sborman default: 101938689Sborman str_lm[3] = DONT; 102038689Sborman str_lm[4] = cmd[0]; 102138689Sborman if (NETROOM() > sizeof(str_lm)) { 102238689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 102338689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 102438689Sborman } 102538689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 102638689Sborman break; 102738689Sborman } 102838689Sborman } 102938689Sborman 103046808Sdab void 103138689Sborman lm_wont(cmd, len) 103246808Sdab unsigned char *cmd; 103346808Sdab int len; 103438689Sborman { 103544360Sborman if (len < 1) { 103644360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 103744360Sborman return; 103844360Sborman } 103938689Sborman switch(cmd[0]) { 104038689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 104138689Sborman default: 104238689Sborman /* We are always DONT, so don't respond */ 104338689Sborman return; 104438689Sborman } 104538689Sborman } 104638689Sborman 104746808Sdab void 104838689Sborman lm_do(cmd, len) 104946808Sdab unsigned char *cmd; 105046808Sdab int len; 105138689Sborman { 105244360Sborman if (len < 1) { 105344360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 105444360Sborman return; 105544360Sborman } 105638689Sborman switch(cmd[0]) { 105738689Sborman case LM_FORWARDMASK: 105838689Sborman default: 105938689Sborman str_lm[3] = WONT; 106038689Sborman str_lm[4] = cmd[0]; 106138689Sborman if (NETROOM() > sizeof(str_lm)) { 106238689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 106338689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 106438689Sborman } 106538689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 106638689Sborman break; 106738689Sborman } 106838689Sborman } 106938689Sborman 107046808Sdab void 107138689Sborman lm_dont(cmd, len) 107246808Sdab unsigned char *cmd; 107346808Sdab int len; 107438689Sborman { 107544360Sborman if (len < 1) { 107644360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 107744360Sborman return; 107844360Sborman } 107938689Sborman switch(cmd[0]) { 108038689Sborman case LM_FORWARDMASK: 108138689Sborman default: 108238689Sborman /* we are always WONT, so don't respond */ 108338689Sborman break; 108438689Sborman } 108538689Sborman } 108638689Sborman 108746808Sdab static unsigned char str_lm_mode[] = { 108846808Sdab IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 108946808Sdab }; 109038689Sborman 109146808Sdab void 109238689Sborman lm_mode(cmd, len, init) 109346808Sdab unsigned char *cmd; 109446808Sdab int len, init; 109538689Sborman { 109638689Sborman if (len != 1) 109738689Sborman return; 109844360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 109938689Sborman return; 110038689Sborman if (*cmd&MODE_ACK) 110138689Sborman return; 110244360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK); 110338689Sborman str_lm_mode[4] = linemode; 110438689Sborman if (!init) 110538689Sborman str_lm_mode[4] |= MODE_ACK; 110638689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 110738689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 110838689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 110938689Sborman } 111038689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 111138689Sborman setconnmode(0); /* set changed mode */ 111238689Sborman } 111338689Sborman 111432377Sminshall 111527088Sminshall 111638689Sborman /* 111738689Sborman * slc() 111838689Sborman * Handle special character suboption of LINEMODE. 111938689Sborman */ 112038689Sborman 112138689Sborman struct spc { 112240245Sborman cc_t val; 112340245Sborman cc_t *valp; 112438689Sborman char flags; /* Current flags & level */ 112538689Sborman char mylevel; /* Maximum level & flags */ 112638689Sborman } spc_data[NSLC+1]; 112738689Sborman 112838689Sborman #define SLC_IMPORT 0 112938689Sborman #define SLC_EXPORT 1 113038689Sborman #define SLC_RVALUE 2 113138689Sborman static int slc_mode = SLC_EXPORT; 113238689Sborman 113346808Sdab void 113438689Sborman slc_init() 113538689Sborman { 113638689Sborman register struct spc *spcp; 113738689Sborman 113838689Sborman localchars = 1; 113938689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 114038689Sborman spcp->val = 0; 114138689Sborman spcp->valp = 0; 114238689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 114338689Sborman } 114438689Sborman 114538689Sborman #define initfunc(func, flags) { \ 114638689Sborman spcp = &spc_data[func]; \ 114738689Sborman if (spcp->valp = tcval(func)) { \ 114838689Sborman spcp->val = *spcp->valp; \ 114938689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 115038689Sborman } else { \ 115138689Sborman spcp->val = 0; \ 115238689Sborman spcp->mylevel = SLC_DEFAULT; \ 115338689Sborman } \ 115438689Sborman } 115538689Sborman 115638689Sborman initfunc(SLC_SYNCH, 0); 115738689Sborman /* No BRK */ 115838689Sborman initfunc(SLC_AO, 0); 115938689Sborman initfunc(SLC_AYT, 0); 116038689Sborman /* No EOR */ 116138689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 116238689Sborman initfunc(SLC_EOF, 0); 116339529Sborman #ifndef SYSV_TERMIO 116438689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 116538689Sborman #endif 116638689Sborman initfunc(SLC_EC, 0); 116738689Sborman initfunc(SLC_EL, 0); 116839529Sborman #ifndef SYSV_TERMIO 116938689Sborman initfunc(SLC_EW, 0); 117038689Sborman initfunc(SLC_RP, 0); 117138689Sborman initfunc(SLC_LNEXT, 0); 117238689Sborman #endif 117338689Sborman initfunc(SLC_XON, 0); 117438689Sborman initfunc(SLC_XOFF, 0); 117539529Sborman #ifdef SYSV_TERMIO 117638689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 117738689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 117838689Sborman #endif 117944360Sborman initfunc(SLC_FORW1, 0); 118044360Sborman #ifdef USE_TERMIO 118144360Sborman initfunc(SLC_FORW2, 0); 118238689Sborman /* No FORW2 */ 118344360Sborman #endif 118438689Sborman 118538689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 118638689Sborman #undef initfunc 118738689Sborman 118838689Sborman if (slc_mode == SLC_EXPORT) 118938689Sborman slc_export(); 119038689Sborman else 119138689Sborman slc_import(1); 119238689Sborman 119338689Sborman } 119438689Sborman 119546808Sdab void 119638689Sborman slcstate() 119738689Sborman { 119838689Sborman printf("Special characters are %s values\n", 119938689Sborman slc_mode == SLC_IMPORT ? "remote default" : 120038689Sborman slc_mode == SLC_EXPORT ? "local" : 120138689Sborman "remote"); 120238689Sborman } 120338689Sborman 120446808Sdab void 120538689Sborman slc_mode_export() 120638689Sborman { 120738689Sborman slc_mode = SLC_EXPORT; 120838689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 120938689Sborman slc_export(); 121038689Sborman } 121138689Sborman 121246808Sdab void 121338689Sborman slc_mode_import(def) 121446808Sdab int def; 121538689Sborman { 121638689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 121738689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 121838689Sborman slc_import(def); 121938689Sborman } 122038689Sborman 122146808Sdab unsigned char slc_import_val[] = { 122238689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 122338689Sborman }; 122446808Sdab unsigned char slc_import_def[] = { 122538689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 122638689Sborman }; 122738689Sborman 122846808Sdab void 122938689Sborman slc_import(def) 123046808Sdab int def; 123138689Sborman { 123238689Sborman if (NETROOM() > sizeof(slc_import_val)) { 123338689Sborman if (def) { 123438689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 123538689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 123638689Sborman } else { 123738689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 123838689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 123938689Sborman } 124038689Sborman } 124138689Sborman /*@*/ else printf("slc_import: not enough room\n"); 124238689Sborman } 124338689Sborman 124446808Sdab void 124538689Sborman slc_export() 124638689Sborman { 124738689Sborman register struct spc *spcp; 124838689Sborman 124938689Sborman TerminalDefaultChars(); 125038689Sborman 125138689Sborman slc_start_reply(); 125238689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 125338689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 125445232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 125545232Sborman spcp->flags = SLC_NOSUPPORT; 125645232Sborman else 125745232Sborman spcp->flags = spcp->mylevel; 125838689Sborman if (spcp->valp) 125938689Sborman spcp->val = *spcp->valp; 126045232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 126138689Sborman } 126238689Sborman } 126338689Sborman slc_end_reply(); 126446808Sdab (void)slc_update(); 126546808Sdab setconnmode(1); /* Make sure the character values are set */ 126638689Sborman } 126738689Sborman 126846808Sdab void 126938689Sborman slc(cp, len) 127046808Sdab register unsigned char *cp; 127146808Sdab int len; 127238689Sborman { 127338689Sborman register struct spc *spcp; 127438689Sborman register int func,level; 127538689Sborman 127638689Sborman slc_start_reply(); 127738689Sborman 127838689Sborman for (; len >= 3; len -=3, cp +=3) { 127938689Sborman 128038689Sborman func = cp[SLC_FUNC]; 128138689Sborman 128238689Sborman if (func == 0) { 128338689Sborman /* 128438689Sborman * Client side: always ignore 0 function. 128538689Sborman */ 128638689Sborman continue; 128738689Sborman } 128838689Sborman if (func > NSLC) { 128945232Sborman if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 129038689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 129138689Sborman continue; 129238689Sborman } 129338689Sborman 129438689Sborman spcp = &spc_data[func]; 129538689Sborman 129638689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 129738689Sborman 129840245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 129938689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 130038689Sborman continue; 130138689Sborman } 130238689Sborman 130338689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 130438689Sborman /* 130538689Sborman * This is an error condition, the SLC_ACK 130638689Sborman * bit should never be set for the SLC_DEFAULT 130738689Sborman * level. Our best guess to recover is to 130838689Sborman * ignore the SLC_ACK bit. 130938689Sborman */ 131038689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 131138689Sborman } 131238689Sborman 131338689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 131440245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 131538689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 131638689Sborman continue; 131738689Sborman } 131838689Sborman 131938689Sborman level &= ~SLC_ACK; 132038689Sborman 132138689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 132238689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 132340245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 132438689Sborman } 132538689Sborman if (level == SLC_DEFAULT) { 132638689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 132738689Sborman spcp->flags = spcp->mylevel; 132838689Sborman else 132938689Sborman spcp->flags = SLC_NOSUPPORT; 133038689Sborman } 133138689Sborman slc_add_reply(func, spcp->flags, spcp->val); 133238689Sborman } 133338689Sborman slc_end_reply(); 133438689Sborman if (slc_update()) 133538689Sborman setconnmode(1); /* set the new character values */ 133638689Sborman } 133738689Sborman 133846808Sdab void 133938689Sborman slc_check() 134038689Sborman { 134138689Sborman register struct spc *spcp; 134238689Sborman 134338689Sborman slc_start_reply(); 134438689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 134538689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 134638689Sborman spcp->val = *spcp->valp; 134745232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 134845232Sborman spcp->flags = SLC_NOSUPPORT; 134945232Sborman else 135045232Sborman spcp->flags = spcp->mylevel; 135145232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 135238689Sborman } 135338689Sborman } 135438689Sborman slc_end_reply(); 135538689Sborman setconnmode(1); 135638689Sborman } 135738689Sborman 135838689Sborman 135938689Sborman unsigned char slc_reply[128]; 136038689Sborman unsigned char *slc_replyp; 136146808Sdab 136246808Sdab void 136338689Sborman slc_start_reply() 136438689Sborman { 136538689Sborman slc_replyp = slc_reply; 136638689Sborman *slc_replyp++ = IAC; 136738689Sborman *slc_replyp++ = SB; 136838689Sborman *slc_replyp++ = TELOPT_LINEMODE; 136938689Sborman *slc_replyp++ = LM_SLC; 137038689Sborman } 137138689Sborman 137246808Sdab void 137338689Sborman slc_add_reply(func, flags, value) 137446808Sdab unsigned char func; 137546808Sdab unsigned char flags; 137646808Sdab cc_t value; 137738689Sborman { 137838689Sborman if ((*slc_replyp++ = func) == IAC) 137938689Sborman *slc_replyp++ = IAC; 138038689Sborman if ((*slc_replyp++ = flags) == IAC) 138138689Sborman *slc_replyp++ = IAC; 138240245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 138338689Sborman *slc_replyp++ = IAC; 138438689Sborman } 138538689Sborman 138646808Sdab void 138738689Sborman slc_end_reply() 138838689Sborman { 138938689Sborman register int len; 139038689Sborman 139138689Sborman *slc_replyp++ = IAC; 139238689Sborman *slc_replyp++ = SE; 139338689Sborman len = slc_replyp - slc_reply; 139438689Sborman if (len <= 6) 139538689Sborman return; 139638689Sborman if (NETROOM() > len) { 139738689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 139838689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 139938689Sborman } 140038689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 140138689Sborman } 140238689Sborman 140346808Sdab int 140438689Sborman slc_update() 140538689Sborman { 140638689Sborman register struct spc *spcp; 140738689Sborman int need_update = 0; 140838689Sborman 140938689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 141038689Sborman if (!(spcp->flags&SLC_ACK)) 141138689Sborman continue; 141238689Sborman spcp->flags &= ~SLC_ACK; 141338689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 141438689Sborman *spcp->valp = spcp->val; 141538689Sborman need_update = 1; 141638689Sborman } 141738689Sborman } 141838689Sborman return(need_update); 141938689Sborman } 142038689Sborman 142146808Sdab void 142244360Sborman env_opt(buf, len) 142346808Sdab register unsigned char *buf; 142446808Sdab register int len; 142544360Sborman { 142646808Sdab register unsigned char *ep = 0, *epc = 0; 142744360Sborman register int i; 142844360Sborman 142945232Sborman switch(buf[0]&0xff) { 143044360Sborman case TELQUAL_SEND: 143144360Sborman env_opt_start(); 143244360Sborman if (len == 1) { 143344360Sborman env_opt_add(NULL); 143444360Sborman } else for (i = 1; i < len; i++) { 143545232Sborman switch (buf[i]&0xff) { 143644360Sborman case ENV_VALUE: 143744360Sborman if (ep) { 143844360Sborman *epc = 0; 143944360Sborman env_opt_add(ep); 144044360Sborman } 144144360Sborman ep = epc = &buf[i+1]; 144244360Sborman break; 144344360Sborman case ENV_ESC: 144444360Sborman i++; 144544360Sborman /*FALL THROUGH*/ 144644360Sborman default: 144744360Sborman if (epc) 144844360Sborman *epc++ = buf[i]; 144944360Sborman break; 145044360Sborman } 145144360Sborman if (ep) { 145244360Sborman *epc = 0; 145344360Sborman env_opt_add(ep); 145444360Sborman } 145544360Sborman } 145644360Sborman env_opt_end(1); 145744360Sborman break; 145844360Sborman 145944360Sborman case TELQUAL_IS: 146044360Sborman case TELQUAL_INFO: 146144360Sborman /* Ignore for now. We shouldn't get it anyway. */ 146244360Sborman break; 146344360Sborman 146444360Sborman default: 146544360Sborman break; 146644360Sborman } 146744360Sborman } 146844360Sborman 146944360Sborman #define OPT_REPLY_SIZE 256 147044360Sborman unsigned char *opt_reply; 147144360Sborman unsigned char *opt_replyp; 147244360Sborman unsigned char *opt_replyend; 147344360Sborman 147446808Sdab void 147544360Sborman env_opt_start() 147644360Sborman { 147744360Sborman if (opt_reply) 147844360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 147944360Sborman else 148044360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 148144360Sborman if (opt_reply == NULL) { 148244360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 148344360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 148444360Sborman return; 148544360Sborman } 148644360Sborman opt_replyp = opt_reply; 148744360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 148844360Sborman *opt_replyp++ = IAC; 148944360Sborman *opt_replyp++ = SB; 149044360Sborman *opt_replyp++ = TELOPT_ENVIRON; 149144360Sborman *opt_replyp++ = TELQUAL_IS; 149244360Sborman } 149344360Sborman 149446808Sdab void 149544360Sborman env_opt_start_info() 149644360Sborman { 149744360Sborman env_opt_start(); 149844360Sborman if (opt_replyp) 149944360Sborman opt_replyp[-1] = TELQUAL_INFO; 150044360Sborman } 150144360Sborman 150246808Sdab void 150344360Sborman env_opt_add(ep) 150446808Sdab register unsigned char *ep; 150544360Sborman { 150646808Sdab register unsigned char *vp, c; 150744360Sborman 150844360Sborman if (opt_reply == NULL) /*XXX*/ 150944360Sborman return; /*XXX*/ 151044360Sborman 151144360Sborman if (ep == NULL || *ep == '\0') { 151244360Sborman env_default(1); 151344360Sborman while (ep = env_default(0)) 151444360Sborman env_opt_add(ep); 151544360Sborman return; 151644360Sborman } 151744360Sborman vp = env_getvalue(ep); 151846808Sdab if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 151946808Sdab strlen((char *)ep) + 6 > opt_replyend) 152046808Sdab { 152144360Sborman register int len; 152244360Sborman opt_replyend += OPT_REPLY_SIZE; 152344360Sborman len = opt_replyend - opt_reply; 152444360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 152544360Sborman if (opt_reply == NULL) { 152644360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 152744360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 152844360Sborman return; 152944360Sborman } 153044360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 153144360Sborman opt_replyend = opt_reply + len; 153244360Sborman } 153344360Sborman *opt_replyp++ = ENV_VAR; 153444360Sborman for (;;) { 153544360Sborman while (c = *ep++) { 153645232Sborman switch(c&0xff) { 153744360Sborman case IAC: 153844360Sborman *opt_replyp++ = IAC; 153944360Sborman break; 154044360Sborman case ENV_VALUE: 154144360Sborman case ENV_VAR: 154244360Sborman case ENV_ESC: 154344360Sborman *opt_replyp++ = ENV_ESC; 154444360Sborman break; 154544360Sborman } 154644360Sborman *opt_replyp++ = c; 154744360Sborman } 154844360Sborman if (ep = vp) { 154944360Sborman *opt_replyp++ = ENV_VALUE; 155044360Sborman vp = NULL; 155144360Sborman } else 155244360Sborman break; 155344360Sborman } 155444360Sborman } 155544360Sborman 155646808Sdab void 155744360Sborman env_opt_end(emptyok) 155846808Sdab register int emptyok; 155944360Sborman { 156044360Sborman register int len; 156144360Sborman 156244360Sborman len = opt_replyp - opt_reply + 2; 156344360Sborman if (emptyok || len > 6) { 156444360Sborman *opt_replyp++ = IAC; 156544360Sborman *opt_replyp++ = SE; 156644360Sborman if (NETROOM() > len) { 156744360Sborman ring_supply_data(&netoring, opt_reply, len); 156844360Sborman printsub('>', &opt_reply[2], len - 2); 156944360Sborman } 157044360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 157144360Sborman } 157244360Sborman if (opt_reply) { 157344360Sborman free(opt_reply); 157444360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 157544360Sborman } 157644360Sborman } 157744360Sborman 157838689Sborman 157938689Sborman 158046808Sdab int 158132377Sminshall telrcv() 158227110Sminshall { 158332377Sminshall register int c; 158432385Sminshall register int scc; 158546808Sdab register unsigned char *sbp; 158632385Sminshall int count; 158732385Sminshall int returnValue = 0; 158827088Sminshall 158932385Sminshall scc = 0; 159032385Sminshall count = 0; 159132385Sminshall while (TTYROOM() > 2) { 159232385Sminshall if (scc == 0) { 159332385Sminshall if (count) { 159432528Sminshall ring_consumed(&netiring, count); 159532385Sminshall returnValue = 1; 159632385Sminshall count = 0; 159732385Sminshall } 159832528Sminshall sbp = netiring.consume; 159932528Sminshall scc = ring_full_consecutive(&netiring); 160032385Sminshall if (scc == 0) { 160132385Sminshall /* No more data coming in */ 160232385Sminshall break; 160332385Sminshall } 160432385Sminshall } 160532385Sminshall 160632385Sminshall c = *sbp++ & 0xff, scc--; count++; 160746808Sdab #if defined(ENCRYPT) 160846808Sdab if (decrypt_input) 160946808Sdab c = (*decrypt_input)(c); 161046808Sdab #endif 161132385Sminshall 161232377Sminshall switch (telrcv_state) { 161327110Sminshall 161432377Sminshall case TS_CR: 161532377Sminshall telrcv_state = TS_DATA; 161635518Sminshall if (c == '\0') { 161735518Sminshall break; /* Ignore \0 after CR */ 161839529Sborman } 161939529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 162035518Sminshall TTYADD(c); 162135518Sminshall break; 162232377Sminshall } 162335518Sminshall /* Else, fall through */ 162427088Sminshall 162532377Sminshall case TS_DATA: 162632377Sminshall if (c == IAC) { 162732377Sminshall telrcv_state = TS_IAC; 162833804Sminshall break; 162932377Sminshall } 163032377Sminshall # if defined(TN3270) 163132377Sminshall if (In3270) { 163232377Sminshall *Ifrontp++ = c; 163332385Sminshall while (scc > 0) { 163432385Sminshall c = *sbp++ & 0377, scc--; count++; 163546808Sdab #if defined(ENCRYPT) 163646808Sdab if (decrypt_input) 163746808Sdab c = (*decrypt_input)(c); 163846808Sdab #endif 163932377Sminshall if (c == IAC) { 164032377Sminshall telrcv_state = TS_IAC; 164134304Sminshall break; 164232377Sminshall } 164332377Sminshall *Ifrontp++ = c; 164432377Sminshall } 164532377Sminshall } else 164632377Sminshall # endif /* defined(TN3270) */ 164735518Sminshall /* 164835518Sminshall * The 'crmod' hack (see following) is needed 164935518Sminshall * since we can't * set CRMOD on output only. 165035518Sminshall * Machines like MULTICS like to send \r without 165135518Sminshall * \n; since we must turn off CRMOD to get proper 165235518Sminshall * input, the mapping is done here (sigh). 165335518Sminshall */ 165438689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 165535518Sminshall if (scc > 0) { 165635518Sminshall c = *sbp&0xff; 165746808Sdab #if defined(ENCRYPT) 165846808Sdab if (decrypt_input) 165946808Sdab c = (*decrypt_input)(c); 166046808Sdab #endif 166135518Sminshall if (c == 0) { 166235518Sminshall sbp++, scc--; count++; 166335518Sminshall /* a "true" CR */ 166432377Sminshall TTYADD('\r'); 166538689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 166635518Sminshall (c == '\n')) { 166735518Sminshall sbp++, scc--; count++; 166832377Sminshall TTYADD('\n'); 166935518Sminshall } else { 167046808Sdab #if defined(ENCRYPT) 167146808Sdab if (decrypt_input) 167246808Sdab (*decrypt_input)(-1); 167346808Sdab #endif 167446808Sdab 167535518Sminshall TTYADD('\r'); 167635518Sminshall if (crmod) { 167735518Sminshall TTYADD('\n'); 167832377Sminshall } 167932377Sminshall } 168035518Sminshall } else { 168135518Sminshall telrcv_state = TS_CR; 168235518Sminshall TTYADD('\r'); 168335518Sminshall if (crmod) { 168435518Sminshall TTYADD('\n'); 168535518Sminshall } 168632377Sminshall } 168732377Sminshall } else { 168832377Sminshall TTYADD(c); 168932377Sminshall } 169032377Sminshall continue; 169127088Sminshall 169232377Sminshall case TS_IAC: 169338689Sborman process_iac: 169432377Sminshall switch (c) { 169532377Sminshall 169632377Sminshall case WILL: 169732377Sminshall telrcv_state = TS_WILL; 169832377Sminshall continue; 169927261Sminshall 170032377Sminshall case WONT: 170132377Sminshall telrcv_state = TS_WONT; 170232377Sminshall continue; 170327261Sminshall 170432377Sminshall case DO: 170532377Sminshall telrcv_state = TS_DO; 170632377Sminshall continue; 170727261Sminshall 170832377Sminshall case DONT: 170932377Sminshall telrcv_state = TS_DONT; 171032377Sminshall continue; 171127261Sminshall 171232377Sminshall case DM: 171332377Sminshall /* 171432377Sminshall * We may have missed an urgent notification, 171532377Sminshall * so make sure we flush whatever is in the 171632377Sminshall * buffer currently. 171732377Sminshall */ 171846808Sdab printoption("RCVD", IAC, DM); 171932377Sminshall SYNCHing = 1; 172044360Sborman (void) ttyflush(1); 172132554Sminshall SYNCHing = stilloob(); 172232377Sminshall settimer(gotDM); 172332377Sminshall break; 172427088Sminshall 172532377Sminshall case SB: 172632377Sminshall SB_CLEAR(); 172732377Sminshall telrcv_state = TS_SB; 172832377Sminshall continue; 172927261Sminshall 173032377Sminshall # if defined(TN3270) 173132377Sminshall case EOR: 173232377Sminshall if (In3270) { 173332377Sminshall if (Ibackp == Ifrontp) { 173432377Sminshall Ibackp = Ifrontp = Ibuf; 173532377Sminshall ISend = 0; /* should have been! */ 173632377Sminshall } else { 173744360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 173832377Sminshall ISend = 1; 173927088Sminshall } 174027088Sminshall } 174146808Sdab printoption("RCVD", IAC, EOR); 174227088Sminshall break; 174332377Sminshall # endif /* defined(TN3270) */ 174432377Sminshall 174532377Sminshall case IAC: 174632377Sminshall # if !defined(TN3270) 174732377Sminshall TTYADD(IAC); 174832377Sminshall # else /* !defined(TN3270) */ 174932377Sminshall if (In3270) { 175032377Sminshall *Ifrontp++ = IAC; 175132377Sminshall } else { 175232377Sminshall TTYADD(IAC); 175332377Sminshall } 175432377Sminshall # endif /* !defined(TN3270) */ 175527088Sminshall break; 175632377Sminshall 175744360Sborman case NOP: 175844360Sborman case GA: 175927088Sminshall default: 176046808Sdab printoption("RCVD", IAC, c); 176127088Sminshall break; 176227088Sminshall } 176332377Sminshall telrcv_state = TS_DATA; 176432377Sminshall continue; 176527088Sminshall 176632377Sminshall case TS_WILL: 176746808Sdab printoption("RCVD", WILL, c); 176838689Sborman willoption(c); 176932377Sminshall SetIn3270(); 177032377Sminshall telrcv_state = TS_DATA; 177132377Sminshall continue; 177227110Sminshall 177332377Sminshall case TS_WONT: 177446808Sdab printoption("RCVD", WONT, c); 177538689Sborman wontoption(c); 177632377Sminshall SetIn3270(); 177732377Sminshall telrcv_state = TS_DATA; 177832377Sminshall continue; 177927088Sminshall 178032377Sminshall case TS_DO: 178146808Sdab printoption("RCVD", DO, c); 178237226Sminshall dooption(c); 178332377Sminshall SetIn3270(); 178437219Sminshall if (c == TELOPT_NAWS) { 178537219Sminshall sendnaws(); 178637219Sminshall } else if (c == TELOPT_LFLOW) { 178737219Sminshall localflow = 1; 178837219Sminshall setcommandmode(); 178938689Sborman setconnmode(0); 179037219Sminshall } 179132377Sminshall telrcv_state = TS_DATA; 179232377Sminshall continue; 179327088Sminshall 179432377Sminshall case TS_DONT: 179546808Sdab printoption("RCVD", DONT, c); 179638689Sborman dontoption(c); 179737226Sminshall flushline = 1; 179838689Sborman setconnmode(0); /* set new tty mode (maybe) */ 179932377Sminshall SetIn3270(); 180032377Sminshall telrcv_state = TS_DATA; 180132377Sminshall continue; 180227088Sminshall 180332377Sminshall case TS_SB: 180432377Sminshall if (c == IAC) { 180532377Sminshall telrcv_state = TS_SE; 180632377Sminshall } else { 180732377Sminshall SB_ACCUM(c); 180832377Sminshall } 180932377Sminshall continue; 181027088Sminshall 181132377Sminshall case TS_SE: 181232377Sminshall if (c != SE) { 181332377Sminshall if (c != IAC) { 181438689Sborman /* 181538689Sborman * This is an error. We only expect to get 181638689Sborman * "IAC IAC" or "IAC SE". Several things may 181738689Sborman * have happend. An IAC was not doubled, the 181838689Sborman * IAC SE was left off, or another option got 181938689Sborman * inserted into the suboption are all possibilities. 182038689Sborman * If we assume that the IAC was not doubled, 182138689Sborman * and really the IAC SE was left off, we could 182238689Sborman * get into an infinate loop here. So, instead, 182338689Sborman * we terminate the suboption, and process the 182438689Sborman * partial suboption if we can. 182538689Sborman */ 182632377Sminshall SB_ACCUM(IAC); 182738689Sborman SB_ACCUM(c); 182846808Sdab subpointer -= 2; 182946808Sdab SB_TERM(); 183046808Sdab 183146808Sdab printoption("In SUBOPTION processing, RCVD", IAC, c); 183238689Sborman suboption(); /* handle sub-option */ 183338689Sborman SetIn3270(); 183438689Sborman telrcv_state = TS_IAC; 183538689Sborman goto process_iac; 183632377Sminshall } 183732377Sminshall SB_ACCUM(c); 183832377Sminshall telrcv_state = TS_SB; 183932377Sminshall } else { 184038689Sborman SB_ACCUM(IAC); 184138689Sborman SB_ACCUM(SE); 184246808Sdab subpointer -= 2; 184346808Sdab SB_TERM(); 184432377Sminshall suboption(); /* handle sub-option */ 184532377Sminshall SetIn3270(); 184632377Sminshall telrcv_state = TS_DATA; 184732377Sminshall } 184827088Sminshall } 184927088Sminshall } 185032667Sminshall if (count) 185132667Sminshall ring_consumed(&netiring, count); 185232385Sminshall return returnValue||count; 185327088Sminshall } 185432385Sminshall 185546808Sdab static int bol = 1, local = 0; 185646808Sdab 185746808Sdab int 185846808Sdab rlogin_susp() 185946808Sdab { 186046808Sdab if (local) { 186146808Sdab local = 0; 186246808Sdab bol = 1; 186346808Sdab command(0, "z\n", 2); 186446808Sdab return(1); 186546808Sdab } 186646808Sdab return(0); 186746808Sdab } 186846808Sdab 186946808Sdab static int 187032554Sminshall telsnd() 187132385Sminshall { 187232385Sminshall int tcc; 187332385Sminshall int count; 187432385Sminshall int returnValue = 0; 187546808Sdab unsigned char *tbp; 187632385Sminshall 187732385Sminshall tcc = 0; 187832385Sminshall count = 0; 187932385Sminshall while (NETROOM() > 2) { 188032385Sminshall register int sc; 188132385Sminshall register int c; 188232385Sminshall 188332385Sminshall if (tcc == 0) { 188432385Sminshall if (count) { 188532528Sminshall ring_consumed(&ttyiring, count); 188632385Sminshall returnValue = 1; 188732385Sminshall count = 0; 188832385Sminshall } 188932528Sminshall tbp = ttyiring.consume; 189032528Sminshall tcc = ring_full_consecutive(&ttyiring); 189132385Sminshall if (tcc == 0) { 189232385Sminshall break; 189332385Sminshall } 189432385Sminshall } 189532385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 189646808Sdab if (rlogin != _POSIX_VDISABLE) { 189746808Sdab if (bol) { 189846808Sdab bol = 0; 189946808Sdab if (sc == rlogin) { 190046808Sdab local = 1; 190146808Sdab continue; 190246808Sdab } 190346808Sdab } else if (local) { 190446808Sdab local = 0; 190546808Sdab if (sc == '.' || c == termEofChar) { 190646808Sdab bol = 1; 190746808Sdab command(0, "close\n", 6); 190846808Sdab continue; 190946808Sdab } 191046808Sdab if (sc == termSuspChar) { 191146808Sdab bol = 1; 191246808Sdab command(0, "z\n", 2); 191346808Sdab continue; 191446808Sdab } 191546808Sdab if (sc == escape) { 191646808Sdab command(0, (char *)tbp, tcc); 191746808Sdab bol = 1; 191846808Sdab count += tcc; 191946808Sdab tcc = 0; 192046808Sdab flushline = 1; 192146808Sdab break; 192246808Sdab } 192346808Sdab if (sc != rlogin) { 192446808Sdab ++tcc; 192546808Sdab --tbp; 192646808Sdab --count; 192746808Sdab c = sc = rlogin; 192846808Sdab } 192946808Sdab } 193046808Sdab if ((sc == '\n') || (sc == '\r')) 193146808Sdab bol = 1; 193246808Sdab } else if (sc == escape) { 193338689Sborman /* 193438689Sborman * Double escape is a pass through of a single escape character. 193538689Sborman */ 193638689Sborman if (tcc && strip(*tbp) == escape) { 193738689Sborman tbp++; 193838689Sborman tcc--; 193938689Sborman count++; 194046808Sdab bol = 0; 194138689Sborman } else { 194246808Sdab command(0, (char *)tbp, tcc); 194346808Sdab bol = 1; 194438689Sborman count += tcc; 194538689Sborman tcc = 0; 194638689Sborman flushline = 1; 194738689Sborman break; 194838689Sborman } 194946808Sdab } else 195046808Sdab bol = 0; 195138689Sborman #ifdef KLUDGELINEMODE 195238689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 195332385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 195432385Sminshall tcc--; tbp++; count++; 195532385Sminshall } else { 195632385Sminshall dontlecho = !dontlecho; 195732385Sminshall settimer(echotoggle); 195838689Sborman setconnmode(0); 195932385Sminshall flushline = 1; 196032385Sminshall break; 196132385Sminshall } 196232385Sminshall } 196338689Sborman #endif 196438689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 196532385Sminshall if (TerminalSpecialChars(sc) == 0) { 196646808Sdab bol = 1; 196732385Sminshall break; 196832385Sminshall } 196932385Sminshall } 197038689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 197132385Sminshall switch (c) { 197232385Sminshall case '\n': 197332385Sminshall /* 197432385Sminshall * If we are in CRMOD mode (\r ==> \n) 197532385Sminshall * on our local machine, then probably 197632385Sminshall * a newline (unix) is CRLF (TELNET). 197732385Sminshall */ 197832385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 197932385Sminshall NETADD('\r'); 198032385Sminshall } 198132385Sminshall NETADD('\n'); 198246808Sdab bol = flushline = 1; 198332385Sminshall break; 198432385Sminshall case '\r': 198532385Sminshall if (!crlf) { 198632385Sminshall NET2ADD('\r', '\0'); 198732385Sminshall } else { 198832385Sminshall NET2ADD('\r', '\n'); 198932385Sminshall } 199046808Sdab bol = flushline = 1; 199132385Sminshall break; 199232385Sminshall case IAC: 199332385Sminshall NET2ADD(IAC, IAC); 199432385Sminshall break; 199532385Sminshall default: 199632385Sminshall NETADD(c); 199732385Sminshall break; 199832385Sminshall } 199932385Sminshall } else if (c == IAC) { 200032385Sminshall NET2ADD(IAC, IAC); 200132385Sminshall } else { 200232385Sminshall NETADD(c); 200332385Sminshall } 200432385Sminshall } 200532667Sminshall if (count) 200632667Sminshall ring_consumed(&ttyiring, count); 200732385Sminshall return returnValue||count; /* Non-zero if we did anything */ 200832385Sminshall } 200932377Sminshall 201027088Sminshall /* 201132377Sminshall * Scheduler() 201232377Sminshall * 201332377Sminshall * Try to do something. 201432377Sminshall * 201532377Sminshall * If we do something useful, return 1; else return 0. 201632377Sminshall * 201727110Sminshall */ 201827110Sminshall 201927110Sminshall 202046808Sdab int 202132377Sminshall Scheduler(block) 202246808Sdab int block; /* should we block in the select ? */ 202327110Sminshall { 202432377Sminshall /* One wants to be a bit careful about setting returnValue 202532377Sminshall * to one, since a one implies we did some useful work, 202632377Sminshall * and therefore probably won't be called to block next 202732377Sminshall * time (TN3270 mode only). 202832377Sminshall */ 202932531Sminshall int returnValue; 203032531Sminshall int netin, netout, netex, ttyin, ttyout; 203127110Sminshall 203232531Sminshall /* Decide which rings should be processed */ 203332531Sminshall 203432531Sminshall netout = ring_full_count(&netoring) && 203538689Sborman (flushline || 203638689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 203738689Sborman #ifdef KLUDGELINEMODE 203838689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 203938689Sborman #endif 204038689Sborman ) || 204138689Sborman my_want_state_is_will(TELOPT_BINARY)); 204232531Sminshall ttyout = ring_full_count(&ttyoring); 204332531Sminshall 204432377Sminshall #if defined(TN3270) 204532531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 204632377Sminshall #else /* defined(TN3270) */ 204732531Sminshall ttyin = ring_empty_count(&ttyiring); 204832377Sminshall #endif /* defined(TN3270) */ 204932531Sminshall 205032531Sminshall #if defined(TN3270) 205132531Sminshall netin = ring_empty_count(&netiring); 205232377Sminshall # else /* !defined(TN3270) */ 205332531Sminshall netin = !ISend && ring_empty_count(&netiring); 205432377Sminshall # endif /* !defined(TN3270) */ 205532531Sminshall 205632531Sminshall netex = !SYNCHing; 205732531Sminshall 205832531Sminshall /* If we have seen a signal recently, reset things */ 205932377Sminshall # if defined(TN3270) && defined(unix) 206032377Sminshall if (HaveInput) { 206132377Sminshall HaveInput = 0; 206244360Sborman (void) signal(SIGIO, inputAvailable); 206332377Sminshall } 206432377Sminshall #endif /* defined(TN3270) && defined(unix) */ 206532377Sminshall 206632531Sminshall /* Call to system code to process rings */ 206727178Sminshall 206832531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 206927178Sminshall 207032531Sminshall /* Now, look at the input rings, looking for work to do. */ 207132377Sminshall 207232531Sminshall if (ring_full_count(&ttyiring)) { 207332377Sminshall # if defined(TN3270) 207432377Sminshall if (In3270) { 207534848Sminshall int c; 207634848Sminshall 207733804Sminshall c = DataFromTerminal(ttyiring.consume, 207832528Sminshall ring_full_consecutive(&ttyiring)); 207932377Sminshall if (c) { 208032377Sminshall returnValue = 1; 208132667Sminshall ring_consumed(&ttyiring, c); 208232377Sminshall } 208332377Sminshall } else { 208432377Sminshall # endif /* defined(TN3270) */ 208532554Sminshall returnValue |= telsnd(); 208632377Sminshall # if defined(TN3270) 208727178Sminshall } 208832531Sminshall # endif /* defined(TN3270) */ 208927178Sminshall } 209032377Sminshall 209132528Sminshall if (ring_full_count(&netiring)) { 209232377Sminshall # if !defined(TN3270) 209332385Sminshall returnValue |= telrcv(); 209432377Sminshall # else /* !defined(TN3270) */ 209532377Sminshall returnValue = Push3270(); 209632377Sminshall # endif /* !defined(TN3270) */ 209732377Sminshall } 209832377Sminshall return returnValue; 209927178Sminshall } 210027178Sminshall 210127178Sminshall /* 210232377Sminshall * Select from tty and network... 210327088Sminshall */ 210446808Sdab void 210546808Sdab telnet(user) 210646808Sdab char *user; 210727088Sminshall { 210832531Sminshall sys_telnet_init(); 210927088Sminshall 211046808Sdab #if defined(ENCRYPT) || defined(AUTHENTICATE) 211146808Sdab { 211246808Sdab static char local_host[256] = { 0 }; 211346808Sdab int len = sizeof(local_host); 211446808Sdab 211546808Sdab if (!local_host[0]) { 211646808Sdab gethostname(local_host, &len); 211746808Sdab local_host[sizeof(local_host)-1] = 0; 211846808Sdab } 211946808Sdab auth_encrypt_init(local_host, hostname, "TELNET", 0); 212046808Sdab auth_encrypt_user(user); 212146808Sdab } 212246808Sdab #endif 212332377Sminshall # if !defined(TN3270) 212432377Sminshall if (telnetport) { 212546808Sdab #if defined(AUTHENTICATE) 212646808Sdab if (autologin) 212746808Sdab send_will(TELOPT_AUTHENTICATION, 1); 212846808Sdab #endif 212946808Sdab #if defined(ENCRYPT) 213046808Sdab send_do(TELOPT_ENCRYPT, 1); 213146808Sdab send_will(TELOPT_ENCRYPT, 1); 213246808Sdab #endif 213338689Sborman send_do(TELOPT_SGA, 1); 213438689Sborman send_will(TELOPT_TTYPE, 1); 213538689Sborman send_will(TELOPT_NAWS, 1); 213638689Sborman send_will(TELOPT_TSPEED, 1); 213738689Sborman send_will(TELOPT_LFLOW, 1); 213838689Sborman send_will(TELOPT_LINEMODE, 1); 213946808Sdab send_will(TELOPT_ENVIRON, 1); 214038908Sborman send_do(TELOPT_STATUS, 1); 214146808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 214244360Sborman send_will(TELOPT_XDISPLOC, 1); 214346808Sdab if (eight) 214446808Sdab tel_enter_binary(eight); 214527178Sminshall } 214632377Sminshall # endif /* !defined(TN3270) */ 214727088Sminshall 214832377Sminshall # if !defined(TN3270) 214932377Sminshall for (;;) { 215032385Sminshall int schedValue; 215132385Sminshall 215232385Sminshall while ((schedValue = Scheduler(0)) != 0) { 215332385Sminshall if (schedValue == -1) { 215432385Sminshall setcommandmode(); 215532385Sminshall return; 215632385Sminshall } 215732385Sminshall } 215832385Sminshall 215932531Sminshall if (Scheduler(1) == -1) { 216032377Sminshall setcommandmode(); 216132377Sminshall return; 216232377Sminshall } 216332377Sminshall } 216432377Sminshall # else /* !defined(TN3270) */ 216532377Sminshall for (;;) { 216632377Sminshall int schedValue; 216727088Sminshall 216832377Sminshall while (!In3270 && !shell_active) { 216932531Sminshall if (Scheduler(1) == -1) { 217032377Sminshall setcommandmode(); 217132377Sminshall return; 217232377Sminshall } 217327088Sminshall } 217432377Sminshall 217532377Sminshall while ((schedValue = Scheduler(0)) != 0) { 217632377Sminshall if (schedValue == -1) { 217732377Sminshall setcommandmode(); 217832377Sminshall return; 217932377Sminshall } 218027088Sminshall } 218132377Sminshall /* If there is data waiting to go out to terminal, don't 218232377Sminshall * schedule any more data for the terminal. 218332377Sminshall */ 218434304Sminshall if (ring_full_count(&ttyoring)) { 218532377Sminshall schedValue = 1; 218627088Sminshall } else { 218732377Sminshall if (shell_active) { 218832377Sminshall if (shell_continue() == 0) { 218932377Sminshall ConnectScreen(); 219027088Sminshall } 219132377Sminshall } else if (In3270) { 219232377Sminshall schedValue = DoTerminalOutput(); 219332377Sminshall } 219427088Sminshall } 219532377Sminshall if (schedValue && (shell_active == 0)) { 219632531Sminshall if (Scheduler(1) == -1) { 219732377Sminshall setcommandmode(); 219832377Sminshall return; 219932377Sminshall } 220027088Sminshall } 220132377Sminshall } 220232377Sminshall # endif /* !defined(TN3270) */ 220327088Sminshall } 220432377Sminshall 220534848Sminshall #if 0 /* XXX - this not being in is a bug */ 220627088Sminshall /* 220732554Sminshall * nextitem() 220832554Sminshall * 220932554Sminshall * Return the address of the next "item" in the TELNET data 221032554Sminshall * stream. This will be the address of the next character if 221132554Sminshall * the current address is a user data character, or it will 221232554Sminshall * be the address of the character following the TELNET command 221332554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 221432554Sminshall * character. 221532554Sminshall */ 221632554Sminshall 221746808Sdab static char * 221832554Sminshall nextitem(current) 221946808Sdab char *current; 222032554Sminshall { 222132554Sminshall if ((*current&0xff) != IAC) { 222232554Sminshall return current+1; 222332554Sminshall } 222432554Sminshall switch (*(current+1)&0xff) { 222532554Sminshall case DO: 222632554Sminshall case DONT: 222732554Sminshall case WILL: 222832554Sminshall case WONT: 222932554Sminshall return current+3; 223032554Sminshall case SB: /* loop forever looking for the SE */ 223132554Sminshall { 223232554Sminshall register char *look = current+2; 223332554Sminshall 223432554Sminshall for (;;) { 223532554Sminshall if ((*look++&0xff) == IAC) { 223632554Sminshall if ((*look++&0xff) == SE) { 223732554Sminshall return look; 223832554Sminshall } 223932554Sminshall } 224032554Sminshall } 224132554Sminshall } 224232554Sminshall default: 224332554Sminshall return current+2; 224432554Sminshall } 224532554Sminshall } 224634848Sminshall #endif /* 0 */ 224732554Sminshall 224832554Sminshall /* 224932554Sminshall * netclear() 225032554Sminshall * 225132554Sminshall * We are about to do a TELNET SYNCH operation. Clear 225232554Sminshall * the path to the network. 225332554Sminshall * 225432554Sminshall * Things are a bit tricky since we may have sent the first 225532554Sminshall * byte or so of a previous TELNET command into the network. 225632554Sminshall * So, we have to scan the network buffer from the beginning 225732554Sminshall * until we are up to where we want to be. 225832554Sminshall * 225932554Sminshall * A side effect of what we do, just to keep things 226032554Sminshall * simple, is to clear the urgent data pointer. The principal 226132554Sminshall * caller should be setting the urgent data pointer AFTER calling 226232554Sminshall * us in any case. 226332554Sminshall */ 226432554Sminshall 226546808Sdab static void 226632554Sminshall netclear() 226732554Sminshall { 226832554Sminshall #if 0 /* XXX */ 226932554Sminshall register char *thisitem, *next; 227032554Sminshall char *good; 227132554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 227232554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 227332554Sminshall 227432554Sminshall thisitem = netobuf; 227532554Sminshall 227632554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 227732554Sminshall thisitem = next; 227832554Sminshall } 227932554Sminshall 228032554Sminshall /* Now, thisitem is first before/at boundary. */ 228132554Sminshall 228232554Sminshall good = netobuf; /* where the good bytes go */ 228332554Sminshall 228432554Sminshall while (netoring.add > thisitem) { 228532554Sminshall if (wewant(thisitem)) { 228632554Sminshall int length; 228732554Sminshall 228832554Sminshall next = thisitem; 228932554Sminshall do { 229032554Sminshall next = nextitem(next); 229132554Sminshall } while (wewant(next) && (nfrontp > next)); 229232554Sminshall length = next-thisitem; 229332554Sminshall memcpy(good, thisitem, length); 229432554Sminshall good += length; 229532554Sminshall thisitem = next; 229632554Sminshall } else { 229732554Sminshall thisitem = nextitem(thisitem); 229832554Sminshall } 229932554Sminshall } 230032554Sminshall 230132554Sminshall #endif /* 0 */ 230232554Sminshall } 230332554Sminshall 230432554Sminshall /* 230532377Sminshall * These routines add various telnet commands to the data stream. 230627088Sminshall */ 230732377Sminshall 230846808Sdab static void 230932554Sminshall doflush() 231032554Sminshall { 231132554Sminshall NET2ADD(IAC, DO); 231232554Sminshall NETADD(TELOPT_TM); 231332554Sminshall flushline = 1; 231432554Sminshall flushout = 1; 231544360Sborman (void) ttyflush(1); /* Flush/drop output */ 231632554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 231746808Sdab printoption("SENT", DO, TELOPT_TM); 231832554Sminshall } 231932554Sminshall 232046808Sdab void 232132377Sminshall xmitAO() 232227088Sminshall { 232332377Sminshall NET2ADD(IAC, AO); 232446808Sdab printoption("SENT", IAC, AO); 232532377Sminshall if (autoflush) { 232632377Sminshall doflush(); 232732377Sminshall } 232832377Sminshall } 232927088Sminshall 233032377Sminshall 233146808Sdab void 233232377Sminshall xmitEL() 233327088Sminshall { 233432377Sminshall NET2ADD(IAC, EL); 233546808Sdab printoption("SENT", IAC, EL); 233627088Sminshall } 233727088Sminshall 233846808Sdab void 233932377Sminshall xmitEC() 234027088Sminshall { 234132377Sminshall NET2ADD(IAC, EC); 234246808Sdab printoption("SENT", IAC, EC); 234327088Sminshall } 234427088Sminshall 234532377Sminshall 234646808Sdab int 234732377Sminshall dosynch() 234827088Sminshall { 234932377Sminshall netclear(); /* clear the path to the network */ 235033294Sminshall NETADD(IAC); 235133294Sminshall setneturg(); 235233294Sminshall NETADD(DM); 235346808Sdab printoption("SENT", IAC, DM); 235446808Sdab return 1; 235527088Sminshall } 235627088Sminshall 235746808Sdab int want_status_response = 0; 235846808Sdab 235946808Sdab int 236038908Sborman get_status() 236138908Sborman { 236246808Sdab unsigned char tmp[16]; 236346808Sdab register unsigned char *cp; 236438908Sborman 236538908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 236638908Sborman printf("Remote side does not support STATUS option\n"); 236746808Sdab return 0; 236838908Sborman } 236938908Sborman cp = tmp; 237038908Sborman 237138908Sborman *cp++ = IAC; 237238908Sborman *cp++ = SB; 237338908Sborman *cp++ = TELOPT_STATUS; 237438908Sborman *cp++ = TELQUAL_SEND; 237538908Sborman *cp++ = IAC; 237638908Sborman *cp++ = SE; 237738908Sborman if (NETROOM() >= cp - tmp) { 237838908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 237938908Sborman printsub('>', tmp+2, cp - tmp - 2); 238038908Sborman } 238146808Sdab ++want_status_response; 238246808Sdab return 1; 238338908Sborman } 238438908Sborman 238546808Sdab void 238632377Sminshall intp() 238727088Sminshall { 238832377Sminshall NET2ADD(IAC, IP); 238946808Sdab printoption("SENT", IAC, IP); 239032377Sminshall flushline = 1; 239132377Sminshall if (autoflush) { 239232377Sminshall doflush(); 239332377Sminshall } 239432377Sminshall if (autosynch) { 239532377Sminshall dosynch(); 239632377Sminshall } 239727088Sminshall } 239827186Sminshall 239946808Sdab void 240032377Sminshall sendbrk() 240127186Sminshall { 240232377Sminshall NET2ADD(IAC, BREAK); 240346808Sdab printoption("SENT", IAC, BREAK); 240432377Sminshall flushline = 1; 240532377Sminshall if (autoflush) { 240632377Sminshall doflush(); 240732377Sminshall } 240832377Sminshall if (autosynch) { 240932377Sminshall dosynch(); 241032377Sminshall } 241127186Sminshall } 241238689Sborman 241346808Sdab void 241438689Sborman sendabort() 241538689Sborman { 241638689Sborman NET2ADD(IAC, ABORT); 241746808Sdab printoption("SENT", IAC, ABORT); 241838689Sborman flushline = 1; 241938689Sborman if (autoflush) { 242038689Sborman doflush(); 242138689Sborman } 242238689Sborman if (autosynch) { 242338689Sborman dosynch(); 242438689Sborman } 242538689Sborman } 242638689Sborman 242746808Sdab void 242838689Sborman sendsusp() 242938689Sborman { 243038689Sborman NET2ADD(IAC, SUSP); 243146808Sdab printoption("SENT", IAC, SUSP); 243238689Sborman flushline = 1; 243338689Sborman if (autoflush) { 243438689Sborman doflush(); 243538689Sborman } 243638689Sborman if (autosynch) { 243738689Sborman dosynch(); 243838689Sborman } 243938689Sborman } 244038689Sborman 244146808Sdab void 244238689Sborman sendeof() 244338689Sborman { 244438908Sborman NET2ADD(IAC, xEOF); 244546808Sdab printoption("SENT", IAC, xEOF); 244638689Sborman } 244738689Sborman 244846808Sdab void 244945232Sborman sendayt() 245045232Sborman { 245145232Sborman NET2ADD(IAC, AYT); 245246808Sdab printoption("SENT", IAC, AYT); 245345232Sborman } 245445232Sborman 245537219Sminshall /* 245637219Sminshall * Send a window size update to the remote system. 245737219Sminshall */ 245837219Sminshall 245946808Sdab void 246037219Sminshall sendnaws() 246137219Sminshall { 246237219Sminshall long rows, cols; 246338689Sborman unsigned char tmp[16]; 246438689Sborman register unsigned char *cp; 246537219Sminshall 246638689Sborman if (my_state_is_wont(TELOPT_NAWS)) 246738689Sborman return; 246837219Sminshall 246938689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 247038689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 247138689Sborman 247237219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 247337219Sminshall return; 247437219Sminshall } 247537219Sminshall 247638689Sborman cp = tmp; 247738689Sborman 247838689Sborman *cp++ = IAC; 247938689Sborman *cp++ = SB; 248038689Sborman *cp++ = TELOPT_NAWS; 248138689Sborman PUTSHORT(cp, cols); 248238689Sborman PUTSHORT(cp, rows); 248338689Sborman *cp++ = IAC; 248438689Sborman *cp++ = SE; 248538689Sborman if (NETROOM() >= cp - tmp) { 248638689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 248738689Sborman printsub('>', tmp+2, cp - tmp - 2); 248837219Sminshall } 248937219Sminshall } 249037226Sminshall 249146808Sdab void 249238908Sborman tel_enter_binary(rw) 249346808Sdab int rw; 249437226Sminshall { 249538908Sborman if (rw&1) 249638908Sborman send_do(TELOPT_BINARY, 1); 249738908Sborman if (rw&2) 249838908Sborman send_will(TELOPT_BINARY, 1); 249937226Sminshall } 250037226Sminshall 250146808Sdab void 250238908Sborman tel_leave_binary(rw) 250346808Sdab int rw; 250437226Sminshall { 250538908Sborman if (rw&1) 250638908Sborman send_dont(TELOPT_BINARY, 1); 250738908Sborman if (rw&2) 250838908Sborman send_wont(TELOPT_BINARY, 1); 250937226Sminshall } 2510