133685Sbostic /* 2*45232Sborman * 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*45232Sborman static char sccsid[] = "@(#)telnet.c 5.51 (Berkeley) 09/14/90"; 1033685Sbostic #endif /* not lint */ 1121580Sdist 129217Ssam #include <sys/types.h> 139217Ssam 1443319Skfall #ifdef KERBEROS 1543319Skfall #include <sys/socket.h> 1643319Skfall #include <netinet/in.h> 1743319Skfall #include <kerberosIV/des.h> 1843319Skfall #include <kerberosIV/krb.h> 1943319Skfall #include "krb4-proto.h" 2043319Skfall #endif 2143319Skfall 2232377Sminshall #if defined(unix) 2333804Sminshall #include <signal.h> 2432377Sminshall /* By the way, we need to include curses.h before telnet.h since, 2532377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 2632377Sminshall * declared in curses.h. 2732377Sminshall */ 2832377Sminshall #endif /* defined(unix) */ 2932377Sminshall 3012212Ssam #include <arpa/telnet.h> 3132377Sminshall 3244360Sborman #if defined(unix) 3344360Sborman #include <strings.h> 3444360Sborman #else /* defined(unix) */ 3532377Sminshall #include <string.h> 3644360Sborman #endif /* defined(unix) */ 379217Ssam 3838908Sborman #include <ctype.h> 3938908Sborman 4032381Sminshall #include "ring.h" 4132381Sminshall 4232377Sminshall #include "defines.h" 4332377Sminshall #include "externs.h" 4432377Sminshall #include "types.h" 4532377Sminshall #include "general.h" 4627178Sminshall 4727178Sminshall 4827228Sminshall #define strip(x) ((x)&0x7f) 496000Sroot 5044360Sborman extern char *env_getvalue(); 5127088Sminshall 5232377Sminshall static char subbuffer[SUBBUFSIZE], 5332377Sminshall *subpointer, *subend; /* buffer for sub-options */ 5427676Sminshall #define SB_CLEAR() subpointer = subbuffer; 5527676Sminshall #define SB_TERM() subend = subpointer; 5627676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 5727676Sminshall *subpointer++ = (c); \ 5827676Sminshall } 5927676Sminshall 6037226Sminshall char options[256]; /* The combined options */ 6138689Sborman char do_dont_resp[256]; 6238689Sborman char will_wont_resp[256]; 636000Sroot 6432377Sminshall int 6532377Sminshall connected, 6632377Sminshall showoptions, 6732377Sminshall In3270, /* Are we in 3270 mode? */ 6832377Sminshall ISend, /* trying to send network data in */ 6943319Skfall #ifdef KERBEROS 7043319Skfall kerberized = 0, /* Are we using Kerberos authentication ? */ 7143319Skfall #endif 7232377Sminshall debug = 0, 7332377Sminshall crmod, 7432377Sminshall netdata, /* Print out network data flow */ 7532377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 7634848Sminshall #if defined(TN3270) 7736241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 7836241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 7932377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 8034848Sminshall #endif /* defined(TN3270) */ 8133286Sminshall telnetport, 8232531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 8332531Sminshall flushout, /* flush output */ 8432531Sminshall autoflush = 0, /* flush output when interrupting? */ 8532531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 8637219Sminshall localflow, /* we handle flow control locally */ 8732531Sminshall localchars, /* we recognize interrupt/quit */ 8832531Sminshall donelclchars, /* the user has set "localchars" */ 8932531Sminshall donebinarytoggle, /* the user has put us in binary */ 9032531Sminshall dontlecho, /* do we suppress local echoing right now? */ 9132531Sminshall globalmode; 9227088Sminshall 9344360Sborman char *prompt = 0; 946000Sroot 9544360Sborman cc_t escape; 9644360Sborman #ifdef KLUDGELINEMODE 9744360Sborman cc_t echoc; 9844360Sborman #endif 9927186Sminshall 10027186Sminshall /* 1016000Sroot * Telnet receiver states for fsm 1026000Sroot */ 1036000Sroot #define TS_DATA 0 1046000Sroot #define TS_IAC 1 1056000Sroot #define TS_WILL 2 1066000Sroot #define TS_WONT 3 1076000Sroot #define TS_DO 4 1086000Sroot #define TS_DONT 5 10927021Sminshall #define TS_CR 6 11027676Sminshall #define TS_SB 7 /* sub-option collection */ 11127676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1126000Sroot 11332377Sminshall static int telrcv_state; 1146000Sroot 11532377Sminshall jmp_buf toplevel = { 0 }; 11632377Sminshall jmp_buf peerdied; 1176000Sroot 11832377Sminshall int flushline; 11938811Sborman int linemode; 12027021Sminshall 12138689Sborman #ifdef KLUDGELINEMODE 12238689Sborman int kludgelinemode = 1; 12338689Sborman #endif 12438689Sborman 12532377Sminshall /* 12632377Sminshall * The following are some clocks used to decide how to interpret 12732377Sminshall * the relationship between various variables. 12832377Sminshall */ 1296000Sroot 13032377Sminshall Clocks clocks; 13132377Sminshall 13238689Sborman #ifdef notdef 13332377Sminshall Modelist modelist[] = { 13432377Sminshall { "telnet command mode", COMMAND_LINE }, 13532377Sminshall { "character-at-a-time mode", 0 }, 13632377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 13732377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 13832377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 13932377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 14032377Sminshall { "3270 mode", 0 }, 14132377Sminshall }; 14238689Sborman #endif 1436000Sroot 14432377Sminshall 14532377Sminshall /* 14632377Sminshall * Initialize telnet environment. 14732377Sminshall */ 1486000Sroot 14932377Sminshall init_telnet() 15032377Sminshall { 15144360Sborman env_init(); 15244360Sborman 15332377Sminshall SB_CLEAR(); 15437226Sminshall ClearArray(options); 1556000Sroot 15637219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 1576000Sroot 15832377Sminshall SYNCHing = 0; 1596000Sroot 16032377Sminshall /* Don't change NetTrace */ 1616000Sroot 16232377Sminshall escape = CONTROL(']'); 16344360Sborman #ifdef KLUDGELINEMODE 16432377Sminshall echoc = CONTROL('E'); 16544360Sborman #endif 1666000Sroot 16732377Sminshall flushline = 1; 16832377Sminshall telrcv_state = TS_DATA; 16932377Sminshall } 17032554Sminshall 1716000Sroot 17244360Sborman #ifdef notdef 17332554Sminshall #include <varargs.h> 1746000Sroot 17534848Sminshall /*VARARGS*/ 17632554Sminshall static void 17732554Sminshall printring(va_alist) 17832554Sminshall va_dcl 17932554Sminshall { 18032554Sminshall va_list ap; 18132554Sminshall char buffer[100]; /* where things go */ 18232554Sminshall char *ptr; 18332554Sminshall char *format; 18432554Sminshall char *string; 18532554Sminshall Ring *ring; 18632554Sminshall int i; 18732554Sminshall 18832554Sminshall va_start(ap); 18932554Sminshall 19032554Sminshall ring = va_arg(ap, Ring *); 19132554Sminshall format = va_arg(ap, char *); 19232554Sminshall ptr = buffer; 19332554Sminshall 19432554Sminshall while ((i = *format++) != 0) { 19532554Sminshall if (i == '%') { 19632554Sminshall i = *format++; 19732554Sminshall switch (i) { 19832554Sminshall case 'c': 19932554Sminshall *ptr++ = va_arg(ap, int); 20032554Sminshall break; 20132554Sminshall case 's': 20232554Sminshall string = va_arg(ap, char *); 20332554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 20432554Sminshall ring_supply_data(ring, string, strlen(string)); 20532554Sminshall ptr = buffer; 20632554Sminshall break; 20732554Sminshall case 0: 20832554Sminshall ExitString("printring: trailing %%.\n", 1); 20932554Sminshall /*NOTREACHED*/ 21032554Sminshall default: 21132554Sminshall ExitString("printring: unknown format character.\n", 1); 21232554Sminshall /*NOTREACHED*/ 21332554Sminshall } 21432554Sminshall } else { 21532554Sminshall *ptr++ = i; 21632554Sminshall } 21732554Sminshall } 21832554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21932554Sminshall } 22044360Sborman #endif 22132554Sminshall 22237226Sminshall /* 22337226Sminshall * These routines are in charge of sending option negotiations 22437226Sminshall * to the other side. 22537226Sminshall * 22637226Sminshall * The basic idea is that we send the negotiation if either side 22737226Sminshall * is in disagreement as to what the current state should be. 22837226Sminshall */ 22932554Sminshall 23038689Sborman send_do(c, init) 23138689Sborman register int c, init; 2326000Sroot { 23338689Sborman if (init) { 23438689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 23538689Sborman my_want_state_is_do(c)) 23638689Sborman return; 23738689Sborman set_my_want_state_do(c); 23838689Sborman do_dont_resp[c]++; 23937226Sminshall } 24038689Sborman NET2ADD(IAC, DO); 24138689Sborman NETADD(c); 24238689Sborman printoption("SENT", "do", c); 24337226Sminshall } 24437226Sminshall 24537226Sminshall void 24638689Sborman send_dont(c, init) 24738689Sborman register int c, init; 24837226Sminshall { 24938689Sborman if (init) { 25038689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 25138689Sborman my_want_state_is_dont(c)) 25238689Sborman return; 25338689Sborman set_my_want_state_dont(c); 25438689Sborman do_dont_resp[c]++; 25537226Sminshall } 25638689Sborman NET2ADD(IAC, DONT); 25738689Sborman NETADD(c); 25838689Sborman printoption("SENT", "dont", c); 25937226Sminshall } 26037226Sminshall 26137226Sminshall void 26238689Sborman send_will(c, init) 26338689Sborman register int c, init; 26437226Sminshall { 26538689Sborman if (init) { 26638689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 26738689Sborman my_want_state_is_will(c)) 26838689Sborman return; 26938689Sborman set_my_want_state_will(c); 27038689Sborman will_wont_resp[c]++; 27137226Sminshall } 27238689Sborman NET2ADD(IAC, WILL); 27338689Sborman NETADD(c); 27438689Sborman printoption("SENT", "will", c); 27537226Sminshall } 27637226Sminshall 27737226Sminshall void 27838689Sborman send_wont(c, init) 27938689Sborman register int c, init; 28037226Sminshall { 28138689Sborman if (init) { 28238689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 28338689Sborman my_want_state_is_wont(c)) 28438689Sborman return; 28538689Sborman set_my_want_state_wont(c); 28638689Sborman will_wont_resp[c]++; 28737226Sminshall } 28838689Sborman NET2ADD(IAC, WONT); 28938689Sborman NETADD(c); 29038689Sborman printoption("SENT", "wont", c); 29137226Sminshall } 29237226Sminshall 29337226Sminshall 29437226Sminshall void 29537226Sminshall willoption(option) 29637226Sminshall int option; 29737226Sminshall { 29838689Sborman int new_state_ok = 0; 2996000Sroot 30038689Sborman if (do_dont_resp[option]) { 30138689Sborman --do_dont_resp[option]; 30238689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 30338689Sborman --do_dont_resp[option]; 30438689Sborman } 30537226Sminshall 30638689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 3076000Sroot 30838689Sborman switch (option) { 30938689Sborman 31038689Sborman case TELOPT_ECHO: 31138689Sborman # if defined(TN3270) 31238689Sborman /* 31338689Sborman * The following is a pain in the rear-end. 31438689Sborman * Various IBM servers (some versions of Wiscnet, 31538689Sborman * possibly Fibronics/Spartacus, and who knows who 31638689Sborman * else) will NOT allow us to send "DO SGA" too early 31738689Sborman * in the setup proceedings. On the other hand, 31838689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31938689Sborman * So, we are stuck. Empirically (but, based on 32038689Sborman * a VERY small sample), the IBM servers don't send 32138689Sborman * out anything about ECHO, so we postpone our sending 32238689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 32338689Sborman * DO send). 32438689Sborman */ 32538689Sborman { 32638689Sborman if (askedSGA == 0) { 32738689Sborman askedSGA = 1; 32838689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32938689Sborman send_do(TELOPT_SGA, 1); 33032377Sminshall } 33132377Sminshall } 33238689Sborman /* Fall through */ 33338689Sborman case TELOPT_EOR: 33438908Sborman #endif /* defined(TN3270) */ 33538689Sborman case TELOPT_BINARY: 33638689Sborman case TELOPT_SGA: 33727110Sminshall settimer(modenegotiated); 33838908Sborman /* FALL THROUGH */ 33938908Sborman case TELOPT_STATUS: 34038689Sborman new_state_ok = 1; 3416000Sroot break; 3426000Sroot 34338689Sborman case TELOPT_TM: 34438689Sborman if (flushout) 34538689Sborman flushout = 0; 34638689Sborman /* 34738689Sborman * Special case for TM. If we get back a WILL, 34838689Sborman * pretend we got back a WONT. 34938689Sborman */ 35038689Sborman set_my_want_state_dont(option); 35138689Sborman set_my_state_dont(option); 35227110Sminshall return; /* Never reply to TM will's/wont's */ 3536000Sroot 35438689Sborman case TELOPT_LINEMODE: 35538689Sborman default: 3566000Sroot break; 35738689Sborman } 35838689Sborman 35938689Sborman if (new_state_ok) { 36038689Sborman set_my_want_state_do(option); 36138689Sborman send_do(option, 0); 36238689Sborman setconnmode(0); /* possibly set new tty mode */ 36338689Sborman } else { 36438689Sborman do_dont_resp[option]++; 36538689Sborman send_dont(option, 0); 36638689Sborman } 3676000Sroot } 36838689Sborman set_my_state_do(option); 3696000Sroot } 3706000Sroot 37132377Sminshall void 37237226Sminshall wontoption(option) 37337226Sminshall int option; 3746000Sroot { 37538689Sborman if (do_dont_resp[option]) { 37638689Sborman --do_dont_resp[option]; 37738689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 37838689Sborman --do_dont_resp[option]; 37938689Sborman } 38037226Sminshall 38138689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3826000Sroot 38338689Sborman switch (option) { 38438689Sborman 38538689Sborman #ifdef KLUDGELINEMODE 38638689Sborman case TELOPT_SGA: 38738689Sborman if (!kludgelinemode) 38838689Sborman break; 38938689Sborman /* FALL THROUGH */ 39038689Sborman #endif 39138689Sborman case TELOPT_ECHO: 39227110Sminshall settimer(modenegotiated); 3936000Sroot break; 3946000Sroot 39538689Sborman case TELOPT_TM: 39638689Sborman if (flushout) 39738689Sborman flushout = 0; 39838689Sborman set_my_want_state_dont(option); 39938689Sborman set_my_state_dont(option); 40027110Sminshall return; /* Never reply to TM will's/wont's */ 40127110Sminshall 40238689Sborman default: 40338689Sborman break; 40438689Sborman } 40538689Sborman set_my_want_state_dont(option); 40644360Sborman if (my_state_is_do(option)) 40744360Sborman send_dont(option, 0); 40838689Sborman setconnmode(0); /* Set new tty mode */ 40938689Sborman } else if (option == TELOPT_TM) { 41038689Sborman /* 41138689Sborman * Special case for TM. 41238689Sborman */ 41338689Sborman if (flushout) 41438689Sborman flushout = 0; 41538689Sborman set_my_want_state_dont(option); 4166000Sroot } 41738689Sborman set_my_state_dont(option); 4186000Sroot } 4196000Sroot 42032377Sminshall static void 4216000Sroot dooption(option) 4226000Sroot int option; 4236000Sroot { 42438689Sborman int new_state_ok = 0; 4256000Sroot 42638689Sborman if (will_wont_resp[option]) { 42738689Sborman --will_wont_resp[option]; 42838689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 42938689Sborman --will_wont_resp[option]; 43038689Sborman } 43137226Sminshall 43238689Sborman if (will_wont_resp[option] == 0) { 43338689Sborman if (my_want_state_is_wont(option)) { 4346000Sroot 43538689Sborman switch (option) { 43638689Sborman 43738689Sborman case TELOPT_TM: 43838689Sborman /* 43938689Sborman * Special case for TM. We send a WILL, but pretend 44038689Sborman * we sent WONT. 44138689Sborman */ 44238689Sborman send_will(option, 0); 44338689Sborman set_my_want_state_wont(TELOPT_TM); 44438689Sborman set_my_state_wont(TELOPT_TM); 44538689Sborman return; 44638689Sborman 44743319Skfall #ifdef KERBEROS 44843319Skfall case TELOPT_AUTHENTICATION: 44943319Skfall if (kerberized) 45043319Skfall new_state_ok = 1; 45143319Skfall break; 45243319Skfall #endif 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 */ 46338689Sborman new_state_ok = 1; 4646000Sroot break; 4656000Sroot 46644360Sborman case TELOPT_XDISPLOC: /* X Display location */ 46744360Sborman if (env_getvalue("DISPLAY")) 46844360Sborman new_state_ok = 1; 46944360Sborman break; 47044360Sborman 47138689Sborman case TELOPT_LINEMODE: 47238689Sborman #ifdef KLUDGELINEMODE 47338689Sborman kludgelinemode = 0; 47444360Sborman send_do(TELOPT_SGA, 1); 47538689Sborman #endif 47638689Sborman set_my_want_state_will(TELOPT_LINEMODE); 47738689Sborman send_will(option, 0); 47838689Sborman set_my_state_will(TELOPT_LINEMODE); 47938689Sborman slc_init(); 48038689Sborman return; 48138689Sborman 48238689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 48338689Sborman default: 4846000Sroot break; 48538689Sborman } 48638689Sborman 48738689Sborman if (new_state_ok) { 48838689Sborman set_my_want_state_will(option); 48938689Sborman send_will(option, 0); 490*45232Sborman setconnmode(0); /* Set new tty mode */ 49138689Sborman } else { 49238689Sborman will_wont_resp[option]++; 49338689Sborman send_wont(option, 0); 49438689Sborman } 49538689Sborman } else { 49638689Sborman /* 49738689Sborman * Handle options that need more things done after the 49838689Sborman * other side has acknowledged the option. 49938689Sborman */ 50038689Sborman switch (option) { 50138689Sborman case TELOPT_LINEMODE: 50238689Sborman #ifdef KLUDGELINEMODE 50338689Sborman kludgelinemode = 0; 50444360Sborman send_do(TELOPT_SGA, 1); 50538689Sborman #endif 50638689Sborman set_my_state_will(option); 50738689Sborman slc_init(); 50844360Sborman send_do(TELOPT_SGA, 0); 50938689Sborman return; 51038689Sborman } 51138689Sborman } 5126000Sroot } 51338689Sborman set_my_state_will(option); 5146000Sroot } 51527676Sminshall 51638689Sborman static void 51738689Sborman dontoption(option) 51838689Sborman int option; 51938689Sborman { 52038689Sborman 52138689Sborman if (will_wont_resp[option]) { 52238689Sborman --will_wont_resp[option]; 52338689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 52438689Sborman --will_wont_resp[option]; 52538689Sborman } 52638689Sborman 52738689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 52838811Sborman switch (option) { 52938811Sborman case TELOPT_LINEMODE: 53038811Sborman linemode = 0; /* put us back to the default state */ 53138811Sborman break; 53238811Sborman } 53338689Sborman /* we always accept a DONT */ 53438689Sborman set_my_want_state_wont(option); 53544360Sborman if (my_state_is_will(option)) 53644360Sborman send_wont(option, 0); 53739529Sborman setconnmode(0); /* Set new tty mode */ 53838689Sborman } 53938689Sborman set_my_state_wont(option); 54038689Sborman } 54138689Sborman 54227676Sminshall /* 54338908Sborman * Given a buffer returned by tgetent(), this routine will turn 54438908Sborman * the pipe seperated list of names in the buffer into an array 54538908Sborman * of pointers to null terminated names. We toss out any bad, 54638908Sborman * duplicate, or verbose names (names with spaces). 54738908Sborman */ 54838908Sborman 54938908Sborman static char *unknown[] = { "UNKNOWN", 0 }; 55038908Sborman 55138908Sborman char ** 55238908Sborman mklist(buf, name) 55338908Sborman char *buf, *name; 55438908Sborman { 55538908Sborman register int n; 55638908Sborman register char c, *cp, **argvp, *cp2, **argv; 55738908Sborman char *malloc(); 55838908Sborman 55938908Sborman if (name) { 56038908Sborman if (strlen(name) > 40) 56138908Sborman name = 0; 56238908Sborman else { 56338908Sborman unknown[0] = name; 56438908Sborman upcase(name); 56538908Sborman } 56638908Sborman } 56738908Sborman /* 56838908Sborman * Count up the number of names. 56938908Sborman */ 57038908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 57138908Sborman if (*cp == '|') 57238908Sborman n++; 57338908Sborman } 57438908Sborman /* 57538908Sborman * Allocate an array to put the name pointers into 57638908Sborman */ 57738908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 57838908Sborman if (argv == 0) 57938908Sborman return(unknown); 58038908Sborman 58138908Sborman /* 58238908Sborman * Fill up the array of pointers to names. 58338908Sborman */ 58438908Sborman *argv = 0; 58538908Sborman argvp = argv+1; 58638908Sborman n = 0; 58738908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 58838908Sborman if (c == '|' || c == ':') { 58938908Sborman *cp++ = '\0'; 59038908Sborman /* 59138908Sborman * Skip entries that have spaces or are over 40 59238908Sborman * characters long. If this is our environment 59338908Sborman * name, then put it up front. Otherwise, as 59438908Sborman * long as this is not a duplicate name (case 59538908Sborman * insensitive) add it to the list. 59638908Sborman */ 59738908Sborman if (n || (cp - cp2 > 41)) 59838908Sborman ; 59938908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 60038908Sborman *argv = cp2; 60138908Sborman else if (is_unique(cp2, argv+1, argvp)) 60238908Sborman *argvp++ = cp2; 60338908Sborman if (c == ':') 60438908Sborman break; 60538908Sborman /* 60638908Sborman * Skip multiple delimiters. Reset cp2 to 60738908Sborman * the beginning of the next name. Reset n, 60838908Sborman * the flag for names with spaces. 60938908Sborman */ 61038908Sborman while ((c = *cp) == '|') 61138908Sborman cp++; 61238908Sborman cp2 = cp; 61338908Sborman n = 0; 61438908Sborman } 61538908Sborman /* 61638908Sborman * Skip entries with spaces or non-ascii values. 61738908Sborman * Convert lower case letters to upper case. 61838908Sborman */ 61938908Sborman if ((c == ' ') || !isascii(c)) 62038908Sborman n = 1; 62138908Sborman else if (islower(c)) 62238908Sborman *cp = toupper(c); 62338908Sborman } 62438908Sborman 62538908Sborman /* 62638908Sborman * Check for an old V6 2 character name. If the second 62738908Sborman * name points to the beginning of the buffer, and is 62838908Sborman * only 2 characters long, move it to the end of the array. 62938908Sborman */ 63038908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 63138908Sborman *argvp++ = buf; 63238908Sborman cp = *argv++; 63338908Sborman *argv = cp; 63438908Sborman } 63538908Sborman 63638908Sborman /* 63738908Sborman * Duplicate last name, for TTYPE option, and null 63838908Sborman * terminate the array. If we didn't find a match on 63938908Sborman * our terminal name, put that name at the beginning. 64038908Sborman */ 64138908Sborman cp = *(argvp-1); 64238908Sborman *argvp++ = cp; 64338908Sborman *argvp = 0; 64438908Sborman 64538908Sborman if (*argv == 0) { 64638908Sborman if (name) 64738908Sborman *argv = name; 64838908Sborman else 64938908Sborman argv++; 65038908Sborman } 65138908Sborman if (*argv) 65238908Sborman return(argv); 65338908Sborman else 65438908Sborman return(unknown); 65538908Sborman } 65638908Sborman 65738908Sborman is_unique(name, as, ae) 65838908Sborman register char *name, **as, **ae; 65938908Sborman { 66038908Sborman register char **ap; 66138908Sborman register int n; 66238908Sborman 66338908Sborman n = strlen(name) + 1; 66438908Sborman for (ap = as; ap < ae; ap++) 66538908Sborman if (strncasecmp(*ap, name, n) == 0) 66638908Sborman return(0); 66738908Sborman return (1); 66838908Sborman } 66938908Sborman 67038908Sborman #ifdef TERMCAP 67139529Sborman char termbuf[1024]; 67244360Sborman /*ARGSUSED*/ 67338908Sborman setupterm(tname, fd, errp) 67438908Sborman char *tname; 67538908Sborman int fd, *errp; 67638908Sborman { 67739529Sborman if (tgetent(termbuf, tname) == 1) { 67839529Sborman termbuf[1023] = '\0'; 67938908Sborman if (errp) 68038908Sborman *errp = 1; 68138908Sborman return(0); 68238908Sborman } 68338908Sborman if (errp) 68438908Sborman *errp = 0; 68538908Sborman return(-1); 68638908Sborman } 68739529Sborman #else 68839529Sborman #define termbuf ttytype 68939529Sborman extern char ttytype[]; 69038908Sborman #endif 69138908Sborman 69238908Sborman char * 69338908Sborman gettermname() 69438908Sborman { 69538908Sborman char *tname; 69638908Sborman static int first = 1; 69738908Sborman static char **tnamep; 69838908Sborman static char **next; 69938908Sborman int err; 70038908Sborman 70138908Sborman if (first) { 70238908Sborman first = 0; 70344360Sborman if ((tname = env_getvalue("TERM")) && 70438908Sborman (setupterm(tname, 1, &err) == 0)) { 70539529Sborman tnamep = mklist(termbuf, tname); 70638908Sborman } else { 70738908Sborman if (tname && (strlen(tname) <= 40)) { 70838908Sborman unknown[0] = tname; 70938908Sborman upcase(tname); 71038908Sborman } 71138908Sborman tnamep = unknown; 71238908Sborman } 71338908Sborman next = tnamep; 71438908Sborman } 71538908Sborman if (*next == 0) 71638908Sborman next = tnamep; 71738908Sborman return(*next++); 71838908Sborman } 71938908Sborman /* 72027676Sminshall * suboption() 72127676Sminshall * 72227676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 72327676Sminshall * side. 72427676Sminshall * 72527676Sminshall * Currently we recognize: 72627676Sminshall * 72727676Sminshall * Terminal type, send request. 72837219Sminshall * Terminal speed (send request). 72937219Sminshall * Local flow control (is request). 73038689Sborman * Linemode 73127676Sminshall */ 73227676Sminshall 73332377Sminshall static void 73427676Sminshall suboption() 73527676Sminshall { 73638689Sborman printsub('<', subbuffer, subend-subbuffer+2); 73727676Sminshall switch (subbuffer[0]&0xff) { 73827676Sminshall case TELOPT_TTYPE: 73938689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 74038689Sborman return; 74127676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 74227676Sminshall ; 74327676Sminshall } else { 74427676Sminshall char *name; 74538908Sborman char temp[50]; 74627676Sminshall int len; 74727676Sminshall 74832377Sminshall #if defined(TN3270) 74932531Sminshall if (tn3270_ttype()) { 75032377Sminshall return; 75132377Sminshall } 75232377Sminshall #endif /* defined(TN3270) */ 75338908Sborman name = gettermname(); 75438908Sborman len = strlen(name) + 4 + 2; 75538908Sborman if (len < NETROOM()) { 75638908Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 75738908Sborman TELQUAL_IS, name, IAC, SE); 75838689Sborman ring_supply_data(&netoring, temp, len); 75938908Sborman printsub('>', &temp[2], len-2); 76032377Sminshall } else { 76137226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 76232377Sminshall /*NOTREACHED*/ 76327676Sminshall } 76427676Sminshall } 76537219Sminshall break; 76637219Sminshall case TELOPT_TSPEED: 76738689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 76838689Sborman return; 76937219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 770*45232Sborman long ospeed, ispeed; 77138689Sborman char temp[50]; 77237219Sminshall int len; 77327676Sminshall 77437219Sminshall TerminalSpeeds(&ispeed, &ospeed); 77537219Sminshall 77638689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 77738689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 77838689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 77937219Sminshall 78038689Sborman if (len < NETROOM()) { 78138689Sborman ring_supply_data(&netoring, temp, len); 78238689Sborman printsub('>', temp+2, len - 2); 78337219Sminshall } 78444360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 78537219Sminshall } 78637219Sminshall break; 78737219Sminshall case TELOPT_LFLOW: 78838689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 78938689Sborman return; 79037219Sminshall if ((subbuffer[1]&0xff) == 1) { 79137219Sminshall localflow = 1; 79237219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 79337219Sminshall localflow = 0; 79437219Sminshall } 79537219Sminshall setcommandmode(); 79638689Sborman setconnmode(0); 79737219Sminshall break; 79838689Sborman 79938689Sborman case TELOPT_LINEMODE: 80038689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 80138689Sborman return; 80238689Sborman switch (subbuffer[1]&0xff) { 80338689Sborman case WILL: 80438689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 80538689Sborman break; 80638689Sborman case WONT: 80738689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 80838689Sborman break; 80938689Sborman case DO: 81038689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 81138689Sborman break; 81238689Sborman case DONT: 81338689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 81438689Sborman break; 81538689Sborman case LM_SLC: 81638689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 81738689Sborman break; 81838689Sborman case LM_MODE: 81938689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 82038689Sborman break; 82138689Sborman default: 82244360Sborman break; 82344360Sborman } 82444360Sborman break; 82544360Sborman 82644360Sborman case TELOPT_ENVIRON: 82744360Sborman switch(subbuffer[1]&0xff) { 82844360Sborman case TELQUAL_IS: 82944360Sborman case TELQUAL_INFO: 83044360Sborman if (my_want_state_is_dont(TELOPT_ENVIRON)) 83144360Sborman return; 83244360Sborman break; 83344360Sborman case TELQUAL_SEND: 83444360Sborman if (my_want_state_is_wont(TELOPT_ENVIRON)) { 83544360Sborman return; 83644360Sborman } 83744360Sborman break; 83844360Sborman default: 83944360Sborman return; 84044360Sborman } 84144360Sborman env_opt(&subbuffer[1], subend - &subbuffer[1]); 84244360Sborman break; 84344360Sborman 84444360Sborman case TELOPT_XDISPLOC: 84544360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC)) 84644360Sborman return; 84744360Sborman if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 84844360Sborman char temp[50], *dp; 84944360Sborman int len; 85044360Sborman 85144360Sborman if ((dp = env_getvalue("DISPLAY")) == NULL) { 85244360Sborman /* 85344360Sborman * Something happened, we no longer have a DISPLAY 85444360Sborman * variable. So, turn off the option. 85544360Sborman */ 85644360Sborman send_wont(TELOPT_XDISPLOC, 1); 85738689Sborman break; 85844360Sborman } 85944360Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 86044360Sborman TELQUAL_IS, dp, IAC, SE); 86144360Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 86244360Sborman 86344360Sborman if (len < NETROOM()) { 86444360Sborman ring_supply_data(&netoring, temp, len); 86544360Sborman printsub('>', temp+2, len - 2); 86644360Sborman } 86744360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 86838689Sborman } 86944360Sborman break; 87043319Skfall 87143319Skfall #ifdef KERBEROS 87243319Skfall case TELOPT_AUTHENTICATION: 87343319Skfall if ((subbuffer[1] & 0xff) == TELQUAL_SEND) { 87443319Skfall register char *cp = &subbuffer[2]; 87543320Skfall char tmp[256]; 87643319Skfall int dokrb4 = 0, unknowntypes = 0, noresponse = 1; 87743319Skfall 87843319Skfall while (cp < subend) { 879*45232Sborman switch (*cp&0xff) { 88043319Skfall case TELQUAL_AUTHTYPE_KERBEROS_V4: 88143319Skfall dokrb4 = 1; 88243319Skfall break; 88343319Skfall default: 88443319Skfall unknowntypes++; 88543319Skfall } 88643319Skfall cp++; 88743319Skfall } 88843319Skfall 88943319Skfall if (noresponse && dokrb4) { 89043319Skfall register unsigned char *ucp = (unsigned char *)cp; 89143319Skfall char *krb_realm; 89243319Skfall char hst_inst[INST_SZ]; 89343319Skfall KTEXT_ST authent_st; 89443319Skfall int space = 0; 89543319Skfall int retval; 89643319Skfall extern char *krb_realmofhost(), *krb_get_phost(); 89743319Skfall 89843319Skfall fprintf(stderr, 89943319Skfall "[Trying Kerberos V4 authentication]\n"); 90043319Skfall 90143319Skfall krb_realm = krb_get_phost(hostname); 90243319Skfall bzero(hst_inst, sizeof(hst_inst)); 90343319Skfall if (krb_realm) 90443319Skfall strncpy(hst_inst, krb_realm, sizeof(hst_inst)); 90543319Skfall hst_inst[sizeof(hst_inst)-1] = '\0'; 90643319Skfall if (!(krb_realm = krb_realmofhost(hst_inst))) { 90743319Skfall fprintf(stderr, "no realm for %s\n", hostname); 90843319Skfall goto cantsend4; 90943319Skfall } 91043319Skfall if (retval = krb_mk_req(&authent_st, "rcmd", hst_inst, 91143319Skfall krb_realm, 0L)) { 91243319Skfall fprintf(stderr, "mk_req failed: %s\n", 91343319Skfall krb_err_txt[retval]); 91443319Skfall goto cantsend4; 91543319Skfall } 91643319Skfall space = authent_st.length; 91743319Skfall for (ucp = authent_st.dat; ucp < authent_st.dat + 91843319Skfall authent_st.length; ucp++) { 91943319Skfall if (*ucp == IAC) 92043319Skfall space++; 92143319Skfall } 92243320Skfall if (NETROOM() < 6 + 1 + 2 + 92343319Skfall space + 2) { 92443319Skfall fprintf(stderr, 92543319Skfall "no room to send V4 ticket/authenticator\n"); 92643319Skfall cantsend4: 92743319Skfall if (7 < NETROOM()) { 92843319Skfall printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, 92943319Skfall TELOPT_AUTHENTICATION, 93043319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 93143319Skfall sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, 93243319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 93343319Skfall printsub(">", tmp, 4+2-2-2); 93443319Skfall } else 93543319Skfall exit(1); 93643319Skfall } else { 93743319Skfall #ifdef notdef 93843320Skfall printring(&netoring, "%c%c%c%c%c%c", IAC, SB, 93943319Skfall TELOPT_AUTHENTICATION, 94043319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, 94143320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4); 94243320Skfall sprintf(tmp, "%c%c%c%c%c%c", TELOPT_AUTHENTICATION, 94343319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, 94443320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); 94543319Skfall #else 94643320Skfall printring(&netoring, "%c%c%c%c%c", IAC, SB, 94743319Skfall TELOPT_AUTHENTICATION, 94843319Skfall TELQUAL_IS, 94943320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4); 95043320Skfall sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, 95143319Skfall TELQUAL_IS, 95243320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); 95343319Skfall #endif 95443320Skfall printsub(">", tmp, 4+2-2-2); 95543319Skfall ring_supply_bindata(&netoring, 95643319Skfall (char *)authent_st.dat, authent_st.length, IAC); 95743319Skfall printring(&netoring, "%c%c", IAC, SE); 95843319Skfall } 95943319Skfall noresponse = 0; 96043319Skfall } 96143319Skfall if (noresponse) { 96243319Skfall if (NETROOM() < 7) { 96343319Skfall ExitString("not enough room to reject unhandled authtype\n", 1); 96443319Skfall } else { 96543319Skfall fprintf(stderr,"[Sending empty auth info in response to request for %d unknown type(s):\n\t", unknowntypes); 96643319Skfall #ifdef notdef 96743319Skfall cp = &subbuffer[3]; 96843319Skfall #else 96943319Skfall cp = &subbuffer[2]; 97043319Skfall #endif 97143319Skfall while (cp < subend) { 972*45232Sborman switch (*cp&0xff) { 97343319Skfall case TELQUAL_AUTHTYPE_KERBEROS_V4: 97443319Skfall break; 97543319Skfall default: 97643319Skfall fprintf(stderr, "%d,", *cp); 97743319Skfall break; 97843319Skfall } 97943319Skfall cp++; 98043319Skfall } 98143319Skfall fputs("]\n", stderr); 98243319Skfall printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, 98343319Skfall TELOPT_AUTHENTICATION, 98443319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 98543319Skfall } 98643319Skfall } 98743319Skfall } 98838689Sborman break; 98943319Skfall #endif /* KERBEROS */ 99044360Sborman 99127676Sminshall default: 99227676Sminshall break; 99327676Sminshall } 99427676Sminshall } 99538689Sborman 99638689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 99738689Sborman 99838689Sborman lm_will(cmd, len) 999*45232Sborman unsigned char *cmd; 100038689Sborman { 100144360Sborman if (len < 1) { 100244360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 100344360Sborman return; 100444360Sborman } 100538689Sborman switch(cmd[0]) { 100638689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 100738689Sborman default: 100838689Sborman str_lm[3] = DONT; 100938689Sborman str_lm[4] = cmd[0]; 101038689Sborman if (NETROOM() > sizeof(str_lm)) { 101138689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 101238689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 101338689Sborman } 101438689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 101538689Sborman break; 101638689Sborman } 101738689Sborman } 101838689Sborman 101938689Sborman lm_wont(cmd, len) 1020*45232Sborman unsigned char *cmd; 102138689Sborman { 102244360Sborman if (len < 1) { 102344360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 102444360Sborman return; 102544360Sborman } 102638689Sborman switch(cmd[0]) { 102738689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 102838689Sborman default: 102938689Sborman /* We are always DONT, so don't respond */ 103038689Sborman return; 103138689Sborman } 103238689Sborman } 103338689Sborman 103438689Sborman lm_do(cmd, len) 1035*45232Sborman unsigned char *cmd; 103638689Sborman { 103744360Sborman if (len < 1) { 103844360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 103944360Sborman return; 104044360Sborman } 104138689Sborman switch(cmd[0]) { 104238689Sborman case LM_FORWARDMASK: 104338689Sborman default: 104438689Sborman str_lm[3] = WONT; 104538689Sborman str_lm[4] = cmd[0]; 104638689Sborman if (NETROOM() > sizeof(str_lm)) { 104738689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 104838689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 104938689Sborman } 105038689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 105138689Sborman break; 105238689Sborman } 105338689Sborman } 105438689Sborman 105538689Sborman lm_dont(cmd, len) 1056*45232Sborman unsigned char *cmd; 105738689Sborman { 105844360Sborman if (len < 1) { 105944360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 106044360Sborman return; 106144360Sborman } 106238689Sborman switch(cmd[0]) { 106338689Sborman case LM_FORWARDMASK: 106438689Sborman default: 106538689Sborman /* we are always WONT, so don't respond */ 106638689Sborman break; 106738689Sborman } 106838689Sborman } 106938689Sborman 107038689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 107138689Sborman 107238689Sborman lm_mode(cmd, len, init) 107338689Sborman char *cmd; 107438689Sborman int len, init; 107538689Sborman { 107638689Sborman if (len != 1) 107738689Sborman return; 107844360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 107938689Sborman return; 108038689Sborman if (*cmd&MODE_ACK) 108138689Sborman return; 108244360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK); 108338689Sborman str_lm_mode[4] = linemode; 108438689Sborman if (!init) 108538689Sborman str_lm_mode[4] |= MODE_ACK; 108638689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 108738689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 108838689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 108938689Sborman } 109038689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 109138689Sborman setconnmode(0); /* set changed mode */ 109238689Sborman } 109338689Sborman 109432377Sminshall 109527088Sminshall 109638689Sborman /* 109738689Sborman * slc() 109838689Sborman * Handle special character suboption of LINEMODE. 109938689Sborman */ 110038689Sborman 110138689Sborman struct spc { 110240245Sborman cc_t val; 110340245Sborman cc_t *valp; 110438689Sborman char flags; /* Current flags & level */ 110538689Sborman char mylevel; /* Maximum level & flags */ 110638689Sborman } spc_data[NSLC+1]; 110738689Sborman 110838689Sborman #define SLC_IMPORT 0 110938689Sborman #define SLC_EXPORT 1 111038689Sborman #define SLC_RVALUE 2 111138689Sborman static int slc_mode = SLC_EXPORT; 111238689Sborman 111338689Sborman slc_init() 111438689Sborman { 111538689Sborman register struct spc *spcp; 111640245Sborman extern cc_t *tcval(); 111738689Sborman 111838689Sborman localchars = 1; 111938689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 112038689Sborman spcp->val = 0; 112138689Sborman spcp->valp = 0; 112238689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 112338689Sborman } 112438689Sborman 112538689Sborman #define initfunc(func, flags) { \ 112638689Sborman spcp = &spc_data[func]; \ 112738689Sborman if (spcp->valp = tcval(func)) { \ 112838689Sborman spcp->val = *spcp->valp; \ 112938689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 113038689Sborman } else { \ 113138689Sborman spcp->val = 0; \ 113238689Sborman spcp->mylevel = SLC_DEFAULT; \ 113338689Sborman } \ 113438689Sborman } 113538689Sborman 113638689Sborman initfunc(SLC_SYNCH, 0); 113738689Sborman /* No BRK */ 113838689Sborman initfunc(SLC_AO, 0); 113938689Sborman initfunc(SLC_AYT, 0); 114038689Sborman /* No EOR */ 114138689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 114238689Sborman initfunc(SLC_EOF, 0); 114339529Sborman #ifndef SYSV_TERMIO 114438689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 114538689Sborman #endif 114638689Sborman initfunc(SLC_EC, 0); 114738689Sborman initfunc(SLC_EL, 0); 114839529Sborman #ifndef SYSV_TERMIO 114938689Sborman initfunc(SLC_EW, 0); 115038689Sborman initfunc(SLC_RP, 0); 115138689Sborman initfunc(SLC_LNEXT, 0); 115238689Sborman #endif 115338689Sborman initfunc(SLC_XON, 0); 115438689Sborman initfunc(SLC_XOFF, 0); 115539529Sborman #ifdef SYSV_TERMIO 115638689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 115738689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 115838689Sborman #endif 115944360Sborman initfunc(SLC_FORW1, 0); 116044360Sborman #ifdef USE_TERMIO 116144360Sborman initfunc(SLC_FORW2, 0); 116238689Sborman /* No FORW2 */ 116344360Sborman #endif 116438689Sborman 116538689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 116638689Sborman #undef initfunc 116738689Sborman 116838689Sborman if (slc_mode == SLC_EXPORT) 116938689Sborman slc_export(); 117038689Sborman else 117138689Sborman slc_import(1); 117238689Sborman 117338689Sborman } 117438689Sborman 117538689Sborman slcstate() 117638689Sborman { 117738689Sborman printf("Special characters are %s values\n", 117838689Sborman slc_mode == SLC_IMPORT ? "remote default" : 117938689Sborman slc_mode == SLC_EXPORT ? "local" : 118038689Sborman "remote"); 118138689Sborman } 118238689Sborman 118338689Sborman slc_mode_export() 118438689Sborman { 118538689Sborman slc_mode = SLC_EXPORT; 118638689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 118738689Sborman slc_export(); 118838689Sborman } 118938689Sborman 119038689Sborman slc_mode_import(def) 119138689Sborman { 119238689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 119338689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 119438689Sborman slc_import(def); 119538689Sborman } 119638689Sborman 119738689Sborman char slc_import_val[] = { 119838689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 119938689Sborman }; 120038689Sborman char slc_import_def[] = { 120138689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 120238689Sborman }; 120338689Sborman 120438689Sborman slc_import(def) 120538689Sborman int def; 120638689Sborman { 120738689Sborman if (NETROOM() > sizeof(slc_import_val)) { 120838689Sborman if (def) { 120938689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 121038689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 121138689Sborman } else { 121238689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 121338689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 121438689Sborman } 121538689Sborman } 121638689Sborman /*@*/ else printf("slc_import: not enough room\n"); 121738689Sborman } 121838689Sborman 121938689Sborman slc_export() 122038689Sborman { 122138689Sborman register struct spc *spcp; 122238689Sborman 122338689Sborman TerminalDefaultChars(); 122438689Sborman 122538689Sborman slc_start_reply(); 122638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 122738689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 1228*45232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 1229*45232Sborman spcp->flags = SLC_NOSUPPORT; 1230*45232Sborman else 1231*45232Sborman spcp->flags = spcp->mylevel; 123238689Sborman if (spcp->valp) 123338689Sborman spcp->val = *spcp->valp; 1234*45232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 123538689Sborman } 123638689Sborman } 123738689Sborman slc_end_reply(); 123838689Sborman if (slc_update()) 123938689Sborman setconnmode(1); /* set the new character values */ 124038689Sborman } 124138689Sborman 124238689Sborman slc(cp, len) 124338689Sborman register char *cp; 124438689Sborman int len; 124538689Sborman { 124638689Sborman register struct spc *spcp; 124738689Sborman register int func,level; 124838689Sborman 124938689Sborman slc_start_reply(); 125038689Sborman 125138689Sborman for (; len >= 3; len -=3, cp +=3) { 125238689Sborman 125338689Sborman func = cp[SLC_FUNC]; 125438689Sborman 125538689Sborman if (func == 0) { 125638689Sborman /* 125738689Sborman * Client side: always ignore 0 function. 125838689Sborman */ 125938689Sborman continue; 126038689Sborman } 126138689Sborman if (func > NSLC) { 1262*45232Sborman if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 126338689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 126438689Sborman continue; 126538689Sborman } 126638689Sborman 126738689Sborman spcp = &spc_data[func]; 126838689Sborman 126938689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 127038689Sborman 127140245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 127238689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 127338689Sborman continue; 127438689Sborman } 127538689Sborman 127638689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 127738689Sborman /* 127838689Sborman * This is an error condition, the SLC_ACK 127938689Sborman * bit should never be set for the SLC_DEFAULT 128038689Sborman * level. Our best guess to recover is to 128138689Sborman * ignore the SLC_ACK bit. 128238689Sborman */ 128338689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 128438689Sborman } 128538689Sborman 128638689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 128740245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 128838689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 128938689Sborman continue; 129038689Sborman } 129138689Sborman 129238689Sborman level &= ~SLC_ACK; 129338689Sborman 129438689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 129538689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 129640245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 129738689Sborman } 129838689Sborman if (level == SLC_DEFAULT) { 129938689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 130038689Sborman spcp->flags = spcp->mylevel; 130138689Sborman else 130238689Sborman spcp->flags = SLC_NOSUPPORT; 130338689Sborman } 130438689Sborman slc_add_reply(func, spcp->flags, spcp->val); 130538689Sborman } 130638689Sborman slc_end_reply(); 130738689Sborman if (slc_update()) 130838689Sborman setconnmode(1); /* set the new character values */ 130938689Sborman } 131038689Sborman 131138689Sborman slc_check() 131238689Sborman { 131338689Sborman register struct spc *spcp; 131438689Sborman 131538689Sborman slc_start_reply(); 131638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 131738689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 131838689Sborman spcp->val = *spcp->valp; 1319*45232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 1320*45232Sborman spcp->flags = SLC_NOSUPPORT; 1321*45232Sborman else 1322*45232Sborman spcp->flags = spcp->mylevel; 1323*45232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 132438689Sborman } 132538689Sborman } 132638689Sborman slc_end_reply(); 132738689Sborman setconnmode(1); 132838689Sborman } 132938689Sborman 133038689Sborman 133138689Sborman unsigned char slc_reply[128]; 133238689Sborman unsigned char *slc_replyp; 133338689Sborman slc_start_reply() 133438689Sborman { 133538689Sborman slc_replyp = slc_reply; 133638689Sborman *slc_replyp++ = IAC; 133738689Sborman *slc_replyp++ = SB; 133838689Sborman *slc_replyp++ = TELOPT_LINEMODE; 133938689Sborman *slc_replyp++ = LM_SLC; 134038689Sborman } 134138689Sborman 134238689Sborman slc_add_reply(func, flags, value) 134338689Sborman char func; 134438689Sborman char flags; 134540245Sborman cc_t value; 134638689Sborman { 134738689Sborman if ((*slc_replyp++ = func) == IAC) 134838689Sborman *slc_replyp++ = IAC; 134938689Sborman if ((*slc_replyp++ = flags) == IAC) 135038689Sborman *slc_replyp++ = IAC; 135140245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 135238689Sborman *slc_replyp++ = IAC; 135338689Sborman } 135438689Sborman 135538689Sborman slc_end_reply() 135638689Sborman { 135738689Sborman register int len; 135838689Sborman 135938689Sborman *slc_replyp++ = IAC; 136038689Sborman *slc_replyp++ = SE; 136138689Sborman len = slc_replyp - slc_reply; 136238689Sborman if (len <= 6) 136338689Sborman return; 136438689Sborman if (NETROOM() > len) { 136538689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 136638689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 136738689Sborman } 136838689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 136938689Sborman } 137038689Sborman 137138689Sborman slc_update() 137238689Sborman { 137338689Sborman register struct spc *spcp; 137438689Sborman int need_update = 0; 137538689Sborman 137638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 137738689Sborman if (!(spcp->flags&SLC_ACK)) 137838689Sborman continue; 137938689Sborman spcp->flags &= ~SLC_ACK; 138038689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 138138689Sborman *spcp->valp = spcp->val; 138238689Sborman need_update = 1; 138338689Sborman } 138438689Sborman } 138538689Sborman return(need_update); 138638689Sborman } 138738689Sborman 138844360Sborman env_opt(buf, len) 138944360Sborman register char *buf; 139044360Sborman register int len; 139144360Sborman { 139244360Sborman register char *ep = 0, *epc = 0; 139344360Sborman register int i; 139444360Sborman 1395*45232Sborman switch(buf[0]&0xff) { 139644360Sborman case TELQUAL_SEND: 139744360Sborman env_opt_start(); 139844360Sborman if (len == 1) { 139944360Sborman env_opt_add(NULL); 140044360Sborman } else for (i = 1; i < len; i++) { 1401*45232Sborman switch (buf[i]&0xff) { 140244360Sborman case ENV_VALUE: 140344360Sborman if (ep) { 140444360Sborman *epc = 0; 140544360Sborman env_opt_add(ep); 140644360Sborman } 140744360Sborman ep = epc = &buf[i+1]; 140844360Sborman break; 140944360Sborman case ENV_ESC: 141044360Sborman i++; 141144360Sborman /*FALL THROUGH*/ 141244360Sborman default: 141344360Sborman if (epc) 141444360Sborman *epc++ = buf[i]; 141544360Sborman break; 141644360Sborman } 141744360Sborman if (ep) { 141844360Sborman *epc = 0; 141944360Sborman env_opt_add(ep); 142044360Sborman } 142144360Sborman } 142244360Sborman env_opt_end(1); 142344360Sborman break; 142444360Sborman 142544360Sborman case TELQUAL_IS: 142644360Sborman case TELQUAL_INFO: 142744360Sborman /* Ignore for now. We shouldn't get it anyway. */ 142844360Sborman break; 142944360Sborman 143044360Sborman default: 143144360Sborman break; 143244360Sborman } 143344360Sborman } 143444360Sborman 143544360Sborman #define OPT_REPLY_SIZE 256 143644360Sborman unsigned char *opt_reply; 143744360Sborman unsigned char *opt_replyp; 143844360Sborman unsigned char *opt_replyend; 143944360Sborman 144044360Sborman env_opt_start() 144144360Sborman { 144244360Sborman extern char *realloc(); 144344360Sborman extern char *malloc(); 144444360Sborman 144544360Sborman if (opt_reply) 144644360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 144744360Sborman else 144844360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 144944360Sborman if (opt_reply == NULL) { 145044360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 145144360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 145244360Sborman return; 145344360Sborman } 145444360Sborman opt_replyp = opt_reply; 145544360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 145644360Sborman *opt_replyp++ = IAC; 145744360Sborman *opt_replyp++ = SB; 145844360Sborman *opt_replyp++ = TELOPT_ENVIRON; 145944360Sborman *opt_replyp++ = TELQUAL_IS; 146044360Sborman } 146144360Sborman 146244360Sborman env_opt_start_info() 146344360Sborman { 146444360Sborman env_opt_start(); 146544360Sborman if (opt_replyp) 146644360Sborman opt_replyp[-1] = TELQUAL_INFO; 146744360Sborman } 146844360Sborman 146944360Sborman env_opt_add(ep) 147044360Sborman register char *ep; 147144360Sborman { 147244360Sborman register char *vp, c; 147344360Sborman extern char *realloc(); 147444360Sborman extern char *env_default(); 147544360Sborman 147644360Sborman if (opt_reply == NULL) /*XXX*/ 147744360Sborman return; /*XXX*/ 147844360Sborman 147944360Sborman if (ep == NULL || *ep == '\0') { 148044360Sborman env_default(1); 148144360Sborman while (ep = env_default(0)) 148244360Sborman env_opt_add(ep); 148344360Sborman return; 148444360Sborman } 148544360Sborman vp = env_getvalue(ep); 148644360Sborman if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) { 148744360Sborman register int len; 148844360Sborman opt_replyend += OPT_REPLY_SIZE; 148944360Sborman len = opt_replyend - opt_reply; 149044360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 149144360Sborman if (opt_reply == NULL) { 149244360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 149344360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 149444360Sborman return; 149544360Sborman } 149644360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 149744360Sborman opt_replyend = opt_reply + len; 149844360Sborman } 149944360Sborman *opt_replyp++ = ENV_VAR; 150044360Sborman for (;;) { 150144360Sborman while (c = *ep++) { 1502*45232Sborman switch(c&0xff) { 150344360Sborman case IAC: 150444360Sborman *opt_replyp++ = IAC; 150544360Sborman break; 150644360Sborman case ENV_VALUE: 150744360Sborman case ENV_VAR: 150844360Sborman case ENV_ESC: 150944360Sborman *opt_replyp++ = ENV_ESC; 151044360Sborman break; 151144360Sborman } 151244360Sborman *opt_replyp++ = c; 151344360Sborman } 151444360Sborman if (ep = vp) { 151544360Sborman *opt_replyp++ = ENV_VALUE; 151644360Sborman vp = NULL; 151744360Sborman } else 151844360Sborman break; 151944360Sborman } 152044360Sborman } 152144360Sborman 152244360Sborman env_opt_end(emptyok) 152344360Sborman register int emptyok; 152444360Sborman { 152544360Sborman register int len; 152644360Sborman 152744360Sborman len = opt_replyp - opt_reply + 2; 152844360Sborman if (emptyok || len > 6) { 152944360Sborman *opt_replyp++ = IAC; 153044360Sborman *opt_replyp++ = SE; 153144360Sborman if (NETROOM() > len) { 153244360Sborman ring_supply_data(&netoring, opt_reply, len); 153344360Sborman printsub('>', &opt_reply[2], len - 2); 153444360Sborman } 153544360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 153644360Sborman } 153744360Sborman if (opt_reply) { 153844360Sborman free(opt_reply); 153944360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 154044360Sborman } 154144360Sborman } 154244360Sborman 154338689Sborman 154438689Sborman 154533804Sminshall int 154632377Sminshall telrcv() 154727110Sminshall { 154832377Sminshall register int c; 154932385Sminshall register int scc; 155032385Sminshall register char *sbp; 155132385Sminshall int count; 155232385Sminshall int returnValue = 0; 155327088Sminshall 155432385Sminshall scc = 0; 155532385Sminshall count = 0; 155632385Sminshall while (TTYROOM() > 2) { 155732385Sminshall if (scc == 0) { 155832385Sminshall if (count) { 155932528Sminshall ring_consumed(&netiring, count); 156032385Sminshall returnValue = 1; 156132385Sminshall count = 0; 156232385Sminshall } 156332528Sminshall sbp = netiring.consume; 156432528Sminshall scc = ring_full_consecutive(&netiring); 156532385Sminshall if (scc == 0) { 156632385Sminshall /* No more data coming in */ 156732385Sminshall break; 156832385Sminshall } 156932385Sminshall } 157032385Sminshall 157132385Sminshall c = *sbp++ & 0xff, scc--; count++; 157232385Sminshall 157332377Sminshall switch (telrcv_state) { 157427110Sminshall 157532377Sminshall case TS_CR: 157632377Sminshall telrcv_state = TS_DATA; 157735518Sminshall if (c == '\0') { 157835518Sminshall break; /* Ignore \0 after CR */ 157939529Sborman } 158039529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 158135518Sminshall TTYADD(c); 158235518Sminshall break; 158332377Sminshall } 158435518Sminshall /* Else, fall through */ 158527088Sminshall 158632377Sminshall case TS_DATA: 158732377Sminshall if (c == IAC) { 158832377Sminshall telrcv_state = TS_IAC; 158933804Sminshall break; 159032377Sminshall } 159132377Sminshall # if defined(TN3270) 159232377Sminshall if (In3270) { 159332377Sminshall *Ifrontp++ = c; 159432385Sminshall while (scc > 0) { 159532385Sminshall c = *sbp++ & 0377, scc--; count++; 159632377Sminshall if (c == IAC) { 159732377Sminshall telrcv_state = TS_IAC; 159834304Sminshall break; 159932377Sminshall } 160032377Sminshall *Ifrontp++ = c; 160132377Sminshall } 160232377Sminshall } else 160332377Sminshall # endif /* defined(TN3270) */ 160435518Sminshall /* 160535518Sminshall * The 'crmod' hack (see following) is needed 160635518Sminshall * since we can't * set CRMOD on output only. 160735518Sminshall * Machines like MULTICS like to send \r without 160835518Sminshall * \n; since we must turn off CRMOD to get proper 160935518Sminshall * input, the mapping is done here (sigh). 161035518Sminshall */ 161138689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 161235518Sminshall if (scc > 0) { 161335518Sminshall c = *sbp&0xff; 161435518Sminshall if (c == 0) { 161535518Sminshall sbp++, scc--; count++; 161635518Sminshall /* a "true" CR */ 161732377Sminshall TTYADD('\r'); 161838689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 161935518Sminshall (c == '\n')) { 162035518Sminshall sbp++, scc--; count++; 162132377Sminshall TTYADD('\n'); 162235518Sminshall } else { 162335518Sminshall TTYADD('\r'); 162435518Sminshall if (crmod) { 162535518Sminshall TTYADD('\n'); 162632377Sminshall } 162732377Sminshall } 162835518Sminshall } else { 162935518Sminshall telrcv_state = TS_CR; 163035518Sminshall TTYADD('\r'); 163135518Sminshall if (crmod) { 163235518Sminshall TTYADD('\n'); 163335518Sminshall } 163432377Sminshall } 163532377Sminshall } else { 163632377Sminshall TTYADD(c); 163732377Sminshall } 163832377Sminshall continue; 163927088Sminshall 164032377Sminshall case TS_IAC: 164138689Sborman process_iac: 164232377Sminshall switch (c) { 164332377Sminshall 164432377Sminshall case WILL: 164532377Sminshall telrcv_state = TS_WILL; 164632377Sminshall continue; 164727261Sminshall 164832377Sminshall case WONT: 164932377Sminshall telrcv_state = TS_WONT; 165032377Sminshall continue; 165127261Sminshall 165232377Sminshall case DO: 165332377Sminshall telrcv_state = TS_DO; 165432377Sminshall continue; 165527261Sminshall 165632377Sminshall case DONT: 165732377Sminshall telrcv_state = TS_DONT; 165832377Sminshall continue; 165927261Sminshall 166032377Sminshall case DM: 166132377Sminshall /* 166232377Sminshall * We may have missed an urgent notification, 166332377Sminshall * so make sure we flush whatever is in the 166432377Sminshall * buffer currently. 166532377Sminshall */ 1666*45232Sborman printoption("RCVD", "IAC", DM); 166732377Sminshall SYNCHing = 1; 166844360Sborman (void) ttyflush(1); 166932554Sminshall SYNCHing = stilloob(); 167032377Sminshall settimer(gotDM); 167132377Sminshall break; 167227088Sminshall 167332377Sminshall case SB: 167432377Sminshall SB_CLEAR(); 167532377Sminshall telrcv_state = TS_SB; 167638689Sborman printoption("RCVD", "IAC", SB); 167732377Sminshall continue; 167827261Sminshall 167932377Sminshall # if defined(TN3270) 168032377Sminshall case EOR: 168132377Sminshall if (In3270) { 168232377Sminshall if (Ibackp == Ifrontp) { 168332377Sminshall Ibackp = Ifrontp = Ibuf; 168432377Sminshall ISend = 0; /* should have been! */ 168532377Sminshall } else { 168644360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 168732377Sminshall ISend = 1; 168827088Sminshall } 168927088Sminshall } 1690*45232Sborman printoption("RCVD", "IAC", EOR); 169127088Sminshall break; 169232377Sminshall # endif /* defined(TN3270) */ 169332377Sminshall 169432377Sminshall case IAC: 169532377Sminshall # if !defined(TN3270) 169632377Sminshall TTYADD(IAC); 169732377Sminshall # else /* !defined(TN3270) */ 169832377Sminshall if (In3270) { 169932377Sminshall *Ifrontp++ = IAC; 170032377Sminshall } else { 170132377Sminshall TTYADD(IAC); 170232377Sminshall } 170332377Sminshall # endif /* !defined(TN3270) */ 170427088Sminshall break; 170532377Sminshall 170644360Sborman case NOP: 170744360Sborman case GA: 170827088Sminshall default: 170944360Sborman printoption("RCVD", "IAC", c); 171027088Sminshall break; 171127088Sminshall } 171232377Sminshall telrcv_state = TS_DATA; 171332377Sminshall continue; 171427088Sminshall 171532377Sminshall case TS_WILL: 171637226Sminshall printoption("RCVD", "will", c); 171738689Sborman willoption(c); 171832377Sminshall SetIn3270(); 171932377Sminshall telrcv_state = TS_DATA; 172032377Sminshall continue; 172127110Sminshall 172232377Sminshall case TS_WONT: 172337226Sminshall printoption("RCVD", "wont", c); 172438689Sborman wontoption(c); 172532377Sminshall SetIn3270(); 172632377Sminshall telrcv_state = TS_DATA; 172732377Sminshall continue; 172827088Sminshall 172932377Sminshall case TS_DO: 173037226Sminshall printoption("RCVD", "do", c); 173137226Sminshall dooption(c); 173232377Sminshall SetIn3270(); 173337219Sminshall if (c == TELOPT_NAWS) { 173437219Sminshall sendnaws(); 173537219Sminshall } else if (c == TELOPT_LFLOW) { 173637219Sminshall localflow = 1; 173737219Sminshall setcommandmode(); 173838689Sborman setconnmode(0); 173937219Sminshall } 174032377Sminshall telrcv_state = TS_DATA; 174132377Sminshall continue; 174227088Sminshall 174332377Sminshall case TS_DONT: 174437226Sminshall printoption("RCVD", "dont", c); 174538689Sborman dontoption(c); 174637226Sminshall flushline = 1; 174738689Sborman setconnmode(0); /* set new tty mode (maybe) */ 174832377Sminshall SetIn3270(); 174932377Sminshall telrcv_state = TS_DATA; 175032377Sminshall continue; 175127088Sminshall 175232377Sminshall case TS_SB: 175332377Sminshall if (c == IAC) { 175432377Sminshall telrcv_state = TS_SE; 175532377Sminshall } else { 175632377Sminshall SB_ACCUM(c); 175732377Sminshall } 175832377Sminshall continue; 175927088Sminshall 176032377Sminshall case TS_SE: 176132377Sminshall if (c != SE) { 176232377Sminshall if (c != IAC) { 176338689Sborman /* 176438689Sborman * This is an error. We only expect to get 176538689Sborman * "IAC IAC" or "IAC SE". Several things may 176638689Sborman * have happend. An IAC was not doubled, the 176738689Sborman * IAC SE was left off, or another option got 176838689Sborman * inserted into the suboption are all possibilities. 176938689Sborman * If we assume that the IAC was not doubled, 177038689Sborman * and really the IAC SE was left off, we could 177138689Sborman * get into an infinate loop here. So, instead, 177238689Sborman * we terminate the suboption, and process the 177338689Sborman * partial suboption if we can. 177438689Sborman */ 177538689Sborman SB_TERM(); 177632377Sminshall SB_ACCUM(IAC); 177738689Sborman SB_ACCUM(c); 177838689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 177938689Sborman suboption(); /* handle sub-option */ 178038689Sborman SetIn3270(); 178138689Sborman telrcv_state = TS_IAC; 178238689Sborman goto process_iac; 178332377Sminshall } 178432377Sminshall SB_ACCUM(c); 178532377Sminshall telrcv_state = TS_SB; 178632377Sminshall } else { 178732377Sminshall SB_TERM(); 178838689Sborman SB_ACCUM(IAC); 178938689Sborman SB_ACCUM(SE); 179032377Sminshall suboption(); /* handle sub-option */ 179132377Sminshall SetIn3270(); 179232377Sminshall telrcv_state = TS_DATA; 179332377Sminshall } 179427088Sminshall } 179527088Sminshall } 179632667Sminshall if (count) 179732667Sminshall ring_consumed(&netiring, count); 179832385Sminshall return returnValue||count; 179927088Sminshall } 180032385Sminshall 180132385Sminshall static int 180232554Sminshall telsnd() 180332385Sminshall { 180432385Sminshall int tcc; 180532385Sminshall int count; 180632385Sminshall int returnValue = 0; 180732385Sminshall char *tbp; 180832385Sminshall 180932385Sminshall tcc = 0; 181032385Sminshall count = 0; 181132385Sminshall while (NETROOM() > 2) { 181232385Sminshall register int sc; 181332385Sminshall register int c; 181432385Sminshall 181532385Sminshall if (tcc == 0) { 181632385Sminshall if (count) { 181732528Sminshall ring_consumed(&ttyiring, count); 181832385Sminshall returnValue = 1; 181932385Sminshall count = 0; 182032385Sminshall } 182132528Sminshall tbp = ttyiring.consume; 182232528Sminshall tcc = ring_full_consecutive(&ttyiring); 182332385Sminshall if (tcc == 0) { 182432385Sminshall break; 182532385Sminshall } 182632385Sminshall } 182732385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 182832385Sminshall if (sc == escape) { 182938689Sborman /* 183038689Sborman * Double escape is a pass through of a single escape character. 183138689Sborman */ 183238689Sborman if (tcc && strip(*tbp) == escape) { 183338689Sborman tbp++; 183438689Sborman tcc--; 183538689Sborman count++; 183638689Sborman } else { 183738689Sborman command(0, tbp, tcc); 183838689Sborman count += tcc; 183938689Sborman tcc = 0; 184038689Sborman flushline = 1; 184138689Sborman break; 184238689Sborman } 184338689Sborman } 184438689Sborman #ifdef KLUDGELINEMODE 184538689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 184632385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 184732385Sminshall tcc--; tbp++; count++; 184832385Sminshall } else { 184932385Sminshall dontlecho = !dontlecho; 185032385Sminshall settimer(echotoggle); 185138689Sborman setconnmode(0); 185232385Sminshall flushline = 1; 185332385Sminshall break; 185432385Sminshall } 185532385Sminshall } 185638689Sborman #endif 185738689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 185832385Sminshall if (TerminalSpecialChars(sc) == 0) { 185932385Sminshall break; 186032385Sminshall } 186132385Sminshall } 186238689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 186332385Sminshall switch (c) { 186432385Sminshall case '\n': 186532385Sminshall /* 186632385Sminshall * If we are in CRMOD mode (\r ==> \n) 186732385Sminshall * on our local machine, then probably 186832385Sminshall * a newline (unix) is CRLF (TELNET). 186932385Sminshall */ 187032385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 187132385Sminshall NETADD('\r'); 187232385Sminshall } 187332385Sminshall NETADD('\n'); 187432385Sminshall flushline = 1; 187532385Sminshall break; 187632385Sminshall case '\r': 187732385Sminshall if (!crlf) { 187832385Sminshall NET2ADD('\r', '\0'); 187932385Sminshall } else { 188032385Sminshall NET2ADD('\r', '\n'); 188132385Sminshall } 188232385Sminshall flushline = 1; 188332385Sminshall break; 188432385Sminshall case IAC: 188532385Sminshall NET2ADD(IAC, IAC); 188632385Sminshall break; 188732385Sminshall default: 188832385Sminshall NETADD(c); 188932385Sminshall break; 189032385Sminshall } 189132385Sminshall } else if (c == IAC) { 189232385Sminshall NET2ADD(IAC, IAC); 189332385Sminshall } else { 189432385Sminshall NETADD(c); 189532385Sminshall } 189632385Sminshall } 189732667Sminshall if (count) 189832667Sminshall ring_consumed(&ttyiring, count); 189932385Sminshall return returnValue||count; /* Non-zero if we did anything */ 190032385Sminshall } 190132377Sminshall 190227088Sminshall /* 190332377Sminshall * Scheduler() 190432377Sminshall * 190532377Sminshall * Try to do something. 190632377Sminshall * 190732377Sminshall * If we do something useful, return 1; else return 0. 190832377Sminshall * 190927110Sminshall */ 191027110Sminshall 191127110Sminshall 191232377Sminshall int 191332377Sminshall Scheduler(block) 191432377Sminshall int block; /* should we block in the select ? */ 191527110Sminshall { 191632377Sminshall /* One wants to be a bit careful about setting returnValue 191732377Sminshall * to one, since a one implies we did some useful work, 191832377Sminshall * and therefore probably won't be called to block next 191932377Sminshall * time (TN3270 mode only). 192032377Sminshall */ 192132531Sminshall int returnValue; 192232531Sminshall int netin, netout, netex, ttyin, ttyout; 192327110Sminshall 192432531Sminshall /* Decide which rings should be processed */ 192532531Sminshall 192632531Sminshall netout = ring_full_count(&netoring) && 192738689Sborman (flushline || 192838689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 192938689Sborman #ifdef KLUDGELINEMODE 193038689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 193138689Sborman #endif 193238689Sborman ) || 193338689Sborman my_want_state_is_will(TELOPT_BINARY)); 193432531Sminshall ttyout = ring_full_count(&ttyoring); 193532531Sminshall 193632377Sminshall #if defined(TN3270) 193732531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 193832377Sminshall #else /* defined(TN3270) */ 193932531Sminshall ttyin = ring_empty_count(&ttyiring); 194032377Sminshall #endif /* defined(TN3270) */ 194132531Sminshall 194232531Sminshall #if defined(TN3270) 194332531Sminshall netin = ring_empty_count(&netiring); 194432377Sminshall # else /* !defined(TN3270) */ 194532531Sminshall netin = !ISend && ring_empty_count(&netiring); 194632377Sminshall # endif /* !defined(TN3270) */ 194732531Sminshall 194832531Sminshall netex = !SYNCHing; 194932531Sminshall 195032531Sminshall /* If we have seen a signal recently, reset things */ 195132377Sminshall # if defined(TN3270) && defined(unix) 195232377Sminshall if (HaveInput) { 195332377Sminshall HaveInput = 0; 195444360Sborman (void) signal(SIGIO, inputAvailable); 195532377Sminshall } 195632377Sminshall #endif /* defined(TN3270) && defined(unix) */ 195732377Sminshall 195832531Sminshall /* Call to system code to process rings */ 195927178Sminshall 196032531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 196127178Sminshall 196232531Sminshall /* Now, look at the input rings, looking for work to do. */ 196332377Sminshall 196432531Sminshall if (ring_full_count(&ttyiring)) { 196532377Sminshall # if defined(TN3270) 196632377Sminshall if (In3270) { 196734848Sminshall int c; 196834848Sminshall 196933804Sminshall c = DataFromTerminal(ttyiring.consume, 197032528Sminshall ring_full_consecutive(&ttyiring)); 197132377Sminshall if (c) { 197232377Sminshall returnValue = 1; 197332667Sminshall ring_consumed(&ttyiring, c); 197432377Sminshall } 197532377Sminshall } else { 197632377Sminshall # endif /* defined(TN3270) */ 197732554Sminshall returnValue |= telsnd(); 197832377Sminshall # if defined(TN3270) 197927178Sminshall } 198032531Sminshall # endif /* defined(TN3270) */ 198127178Sminshall } 198232377Sminshall 198332528Sminshall if (ring_full_count(&netiring)) { 198432377Sminshall # if !defined(TN3270) 198532385Sminshall returnValue |= telrcv(); 198632377Sminshall # else /* !defined(TN3270) */ 198732377Sminshall returnValue = Push3270(); 198832377Sminshall # endif /* !defined(TN3270) */ 198932377Sminshall } 199032377Sminshall return returnValue; 199127178Sminshall } 199227178Sminshall 199327178Sminshall /* 199432377Sminshall * Select from tty and network... 199527088Sminshall */ 199632377Sminshall void 199732377Sminshall telnet() 199827088Sminshall { 199932531Sminshall sys_telnet_init(); 200027088Sminshall 200132377Sminshall # if !defined(TN3270) 200232377Sminshall if (telnetport) { 200338689Sborman send_do(TELOPT_SGA, 1); 200438689Sborman send_will(TELOPT_TTYPE, 1); 200538689Sborman send_will(TELOPT_NAWS, 1); 200638689Sborman send_will(TELOPT_TSPEED, 1); 200738689Sborman send_will(TELOPT_LFLOW, 1); 200838689Sborman send_will(TELOPT_LINEMODE, 1); 200943319Skfall #ifdef KERBEROS 201043319Skfall if (kerberized) 201143319Skfall send_will(TELOPT_AUTHENTICATION, 1); 201243319Skfall #endif 201338908Sborman send_do(TELOPT_STATUS, 1); 201444360Sborman if (env_getvalue("DISPLAY")) 201544360Sborman send_will(TELOPT_XDISPLOC, 1); 201644360Sborman send_will(TELOPT_ENVIRON, 1); 201727178Sminshall } 201832377Sminshall # endif /* !defined(TN3270) */ 201927088Sminshall 202032377Sminshall # if !defined(TN3270) 202132377Sminshall for (;;) { 202232385Sminshall int schedValue; 202332385Sminshall 202432385Sminshall while ((schedValue = Scheduler(0)) != 0) { 202532385Sminshall if (schedValue == -1) { 202632385Sminshall setcommandmode(); 202732385Sminshall return; 202832385Sminshall } 202932385Sminshall } 203032385Sminshall 203132531Sminshall if (Scheduler(1) == -1) { 203232377Sminshall setcommandmode(); 203332377Sminshall return; 203432377Sminshall } 203532377Sminshall } 203632377Sminshall # else /* !defined(TN3270) */ 203732377Sminshall for (;;) { 203832377Sminshall int schedValue; 203927088Sminshall 204032377Sminshall while (!In3270 && !shell_active) { 204132531Sminshall if (Scheduler(1) == -1) { 204232377Sminshall setcommandmode(); 204332377Sminshall return; 204432377Sminshall } 204527088Sminshall } 204632377Sminshall 204732377Sminshall while ((schedValue = Scheduler(0)) != 0) { 204832377Sminshall if (schedValue == -1) { 204932377Sminshall setcommandmode(); 205032377Sminshall return; 205132377Sminshall } 205227088Sminshall } 205332377Sminshall /* If there is data waiting to go out to terminal, don't 205432377Sminshall * schedule any more data for the terminal. 205532377Sminshall */ 205634304Sminshall if (ring_full_count(&ttyoring)) { 205732377Sminshall schedValue = 1; 205827088Sminshall } else { 205932377Sminshall if (shell_active) { 206032377Sminshall if (shell_continue() == 0) { 206132377Sminshall ConnectScreen(); 206227088Sminshall } 206332377Sminshall } else if (In3270) { 206432377Sminshall schedValue = DoTerminalOutput(); 206532377Sminshall } 206627088Sminshall } 206732377Sminshall if (schedValue && (shell_active == 0)) { 206832531Sminshall if (Scheduler(1) == -1) { 206932377Sminshall setcommandmode(); 207032377Sminshall return; 207132377Sminshall } 207227088Sminshall } 207332377Sminshall } 207432377Sminshall # endif /* !defined(TN3270) */ 207527088Sminshall } 207632377Sminshall 207734848Sminshall #if 0 /* XXX - this not being in is a bug */ 207827088Sminshall /* 207932554Sminshall * nextitem() 208032554Sminshall * 208132554Sminshall * Return the address of the next "item" in the TELNET data 208232554Sminshall * stream. This will be the address of the next character if 208332554Sminshall * the current address is a user data character, or it will 208432554Sminshall * be the address of the character following the TELNET command 208532554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 208632554Sminshall * character. 208732554Sminshall */ 208832554Sminshall 208932554Sminshall static char * 209032554Sminshall nextitem(current) 209132554Sminshall char *current; 209232554Sminshall { 209332554Sminshall if ((*current&0xff) != IAC) { 209432554Sminshall return current+1; 209532554Sminshall } 209632554Sminshall switch (*(current+1)&0xff) { 209732554Sminshall case DO: 209832554Sminshall case DONT: 209932554Sminshall case WILL: 210032554Sminshall case WONT: 210132554Sminshall return current+3; 210232554Sminshall case SB: /* loop forever looking for the SE */ 210332554Sminshall { 210432554Sminshall register char *look = current+2; 210532554Sminshall 210632554Sminshall for (;;) { 210732554Sminshall if ((*look++&0xff) == IAC) { 210832554Sminshall if ((*look++&0xff) == SE) { 210932554Sminshall return look; 211032554Sminshall } 211132554Sminshall } 211232554Sminshall } 211332554Sminshall } 211432554Sminshall default: 211532554Sminshall return current+2; 211632554Sminshall } 211732554Sminshall } 211834848Sminshall #endif /* 0 */ 211932554Sminshall 212032554Sminshall /* 212132554Sminshall * netclear() 212232554Sminshall * 212332554Sminshall * We are about to do a TELNET SYNCH operation. Clear 212432554Sminshall * the path to the network. 212532554Sminshall * 212632554Sminshall * Things are a bit tricky since we may have sent the first 212732554Sminshall * byte or so of a previous TELNET command into the network. 212832554Sminshall * So, we have to scan the network buffer from the beginning 212932554Sminshall * until we are up to where we want to be. 213032554Sminshall * 213132554Sminshall * A side effect of what we do, just to keep things 213232554Sminshall * simple, is to clear the urgent data pointer. The principal 213332554Sminshall * caller should be setting the urgent data pointer AFTER calling 213432554Sminshall * us in any case. 213532554Sminshall */ 213632554Sminshall 213732554Sminshall static void 213832554Sminshall netclear() 213932554Sminshall { 214032554Sminshall #if 0 /* XXX */ 214132554Sminshall register char *thisitem, *next; 214232554Sminshall char *good; 214332554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 214432554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 214532554Sminshall 214632554Sminshall thisitem = netobuf; 214732554Sminshall 214832554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 214932554Sminshall thisitem = next; 215032554Sminshall } 215132554Sminshall 215232554Sminshall /* Now, thisitem is first before/at boundary. */ 215332554Sminshall 215432554Sminshall good = netobuf; /* where the good bytes go */ 215532554Sminshall 215632554Sminshall while (netoring.add > thisitem) { 215732554Sminshall if (wewant(thisitem)) { 215832554Sminshall int length; 215932554Sminshall 216032554Sminshall next = thisitem; 216132554Sminshall do { 216232554Sminshall next = nextitem(next); 216332554Sminshall } while (wewant(next) && (nfrontp > next)); 216432554Sminshall length = next-thisitem; 216532554Sminshall memcpy(good, thisitem, length); 216632554Sminshall good += length; 216732554Sminshall thisitem = next; 216832554Sminshall } else { 216932554Sminshall thisitem = nextitem(thisitem); 217032554Sminshall } 217132554Sminshall } 217232554Sminshall 217332554Sminshall #endif /* 0 */ 217432554Sminshall } 217532554Sminshall 217632554Sminshall /* 217732377Sminshall * These routines add various telnet commands to the data stream. 217827088Sminshall */ 217932377Sminshall 218032554Sminshall static void 218132554Sminshall doflush() 218232554Sminshall { 218332554Sminshall NET2ADD(IAC, DO); 218432554Sminshall NETADD(TELOPT_TM); 218532554Sminshall flushline = 1; 218632554Sminshall flushout = 1; 218744360Sborman (void) ttyflush(1); /* Flush/drop output */ 218832554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 218937226Sminshall printoption("SENT", "do", TELOPT_TM); 219032554Sminshall } 219132554Sminshall 219232377Sminshall void 219332377Sminshall xmitAO() 219427088Sminshall { 219532377Sminshall NET2ADD(IAC, AO); 219638908Sborman printoption("SENT", "IAC", AO); 219732377Sminshall if (autoflush) { 219832377Sminshall doflush(); 219932377Sminshall } 220032377Sminshall } 220127088Sminshall 220232377Sminshall 220332377Sminshall void 220432377Sminshall xmitEL() 220527088Sminshall { 220632377Sminshall NET2ADD(IAC, EL); 220738908Sborman printoption("SENT", "IAC", EL); 220827088Sminshall } 220927088Sminshall 221032377Sminshall void 221132377Sminshall xmitEC() 221227088Sminshall { 221332377Sminshall NET2ADD(IAC, EC); 221438908Sborman printoption("SENT", "IAC", EC); 221527088Sminshall } 221627088Sminshall 221732377Sminshall 221832377Sminshall #if defined(NOT43) 221932377Sminshall int 222032377Sminshall #else /* defined(NOT43) */ 222132377Sminshall void 222232377Sminshall #endif /* defined(NOT43) */ 222332377Sminshall dosynch() 222427088Sminshall { 222532377Sminshall netclear(); /* clear the path to the network */ 222633294Sminshall NETADD(IAC); 222733294Sminshall setneturg(); 222833294Sminshall NETADD(DM); 222938908Sborman printoption("SENT", "IAC", DM); 223027088Sminshall 223132377Sminshall #if defined(NOT43) 223232377Sminshall return 0; 223332377Sminshall #endif /* defined(NOT43) */ 223427088Sminshall } 223527088Sminshall 223632377Sminshall void 223738908Sborman get_status() 223838908Sborman { 223938908Sborman char tmp[16]; 224038908Sborman register char *cp; 224138908Sborman 224238908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 224338908Sborman printf("Remote side does not support STATUS option\n"); 224438908Sborman return; 224538908Sborman } 224638908Sborman if (!showoptions) 224738908Sborman printf("You will not see the response unless you set \"options\"\n"); 224838908Sborman 224938908Sborman cp = tmp; 225038908Sborman 225138908Sborman *cp++ = IAC; 225238908Sborman *cp++ = SB; 225338908Sborman *cp++ = TELOPT_STATUS; 225438908Sborman *cp++ = TELQUAL_SEND; 225538908Sborman *cp++ = IAC; 225638908Sborman *cp++ = SE; 225738908Sborman if (NETROOM() >= cp - tmp) { 225838908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 225938908Sborman printsub('>', tmp+2, cp - tmp - 2); 226038908Sborman } 226138908Sborman } 226238908Sborman 226338908Sborman void 226432377Sminshall intp() 226527088Sminshall { 226632377Sminshall NET2ADD(IAC, IP); 226738908Sborman printoption("SENT", "IAC", IP); 226832377Sminshall flushline = 1; 226932377Sminshall if (autoflush) { 227032377Sminshall doflush(); 227132377Sminshall } 227232377Sminshall if (autosynch) { 227332377Sminshall dosynch(); 227432377Sminshall } 227527088Sminshall } 227627186Sminshall 227732377Sminshall void 227832377Sminshall sendbrk() 227927186Sminshall { 228032377Sminshall NET2ADD(IAC, BREAK); 228138908Sborman printoption("SENT", "IAC", BREAK); 228232377Sminshall flushline = 1; 228332377Sminshall if (autoflush) { 228432377Sminshall doflush(); 228532377Sminshall } 228632377Sminshall if (autosynch) { 228732377Sminshall dosynch(); 228832377Sminshall } 228927186Sminshall } 229038689Sborman 229138689Sborman void 229238689Sborman sendabort() 229338689Sborman { 229438689Sborman NET2ADD(IAC, ABORT); 229538908Sborman printoption("SENT", "IAC", ABORT); 229638689Sborman flushline = 1; 229738689Sborman if (autoflush) { 229838689Sborman doflush(); 229938689Sborman } 230038689Sborman if (autosynch) { 230138689Sborman dosynch(); 230238689Sborman } 230338689Sborman } 230438689Sborman 230538689Sborman void 230638689Sborman sendsusp() 230738689Sborman { 230838689Sborman NET2ADD(IAC, SUSP); 230938908Sborman printoption("SENT", "IAC", SUSP); 231038689Sborman flushline = 1; 231138689Sborman if (autoflush) { 231238689Sborman doflush(); 231338689Sborman } 231438689Sborman if (autosynch) { 231538689Sborman dosynch(); 231638689Sborman } 231738689Sborman } 231838689Sborman 231938689Sborman void 232038689Sborman sendeof() 232138689Sborman { 232238908Sborman NET2ADD(IAC, xEOF); 232338908Sborman printoption("SENT", "IAC", xEOF); 232438689Sborman } 232538689Sborman 2326*45232Sborman void 2327*45232Sborman sendayt() 2328*45232Sborman { 2329*45232Sborman NET2ADD(IAC, AYT); 2330*45232Sborman printoption("SENT", "IAC", AYT); 2331*45232Sborman } 2332*45232Sborman 233337219Sminshall /* 233437219Sminshall * Send a window size update to the remote system. 233537219Sminshall */ 233637219Sminshall 233737219Sminshall void 233837219Sminshall sendnaws() 233937219Sminshall { 234037219Sminshall long rows, cols; 234138689Sborman unsigned char tmp[16]; 234238689Sborman register unsigned char *cp; 234337219Sminshall 234438689Sborman if (my_state_is_wont(TELOPT_NAWS)) 234538689Sborman return; 234637219Sminshall 234738689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 234838689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 234938689Sborman 235037219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 235137219Sminshall return; 235237219Sminshall } 235337219Sminshall 235438689Sborman cp = tmp; 235538689Sborman 235638689Sborman *cp++ = IAC; 235738689Sborman *cp++ = SB; 235838689Sborman *cp++ = TELOPT_NAWS; 235938689Sborman PUTSHORT(cp, cols); 236038689Sborman PUTSHORT(cp, rows); 236138689Sborman *cp++ = IAC; 236238689Sborman *cp++ = SE; 236338689Sborman if (NETROOM() >= cp - tmp) { 236438689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 236538689Sborman printsub('>', tmp+2, cp - tmp - 2); 236637219Sminshall } 236737219Sminshall } 236837226Sminshall 236938908Sborman tel_enter_binary(rw) 237038908Sborman int rw; 237137226Sminshall { 237238908Sborman if (rw&1) 237338908Sborman send_do(TELOPT_BINARY, 1); 237438908Sborman if (rw&2) 237538908Sborman send_will(TELOPT_BINARY, 1); 237637226Sminshall } 237737226Sminshall 237838908Sborman tel_leave_binary(rw) 237938908Sborman int rw; 238037226Sminshall { 238138908Sborman if (rw&1) 238238908Sborman send_dont(TELOPT_BINARY, 1); 238338908Sborman if (rw&2) 238438908Sborman send_wont(TELOPT_BINARY, 1); 238537226Sminshall } 2386