133685Sbostic /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 542770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 711758Ssam 821580Sdist #ifndef lint 9*44360Sborman static char sccsid[] = "@(#)telnet.c 5.50 (Berkeley) 06/28/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 32*44360Sborman #if defined(unix) 33*44360Sborman #include <strings.h> 34*44360Sborman #else /* defined(unix) */ 3532377Sminshall #include <string.h> 36*44360Sborman #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 50*44360Sborman 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 93*44360Sborman char *prompt = 0; 946000Sroot 95*44360Sborman cc_t escape; 96*44360Sborman #ifdef KLUDGELINEMODE 97*44360Sborman cc_t echoc; 98*44360Sborman #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 { 151*44360Sborman env_init(); 152*44360Sborman 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(']'); 163*44360Sborman #ifdef KLUDGELINEMODE 16432377Sminshall echoc = CONTROL('E'); 165*44360Sborman #endif 1666000Sroot 16732377Sminshall flushline = 1; 16832377Sminshall telrcv_state = TS_DATA; 16932377Sminshall } 17032554Sminshall 1716000Sroot 172*44360Sborman #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 } 220*44360Sborman #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); 406*44360Sborman if (my_state_is_do(option)) 407*44360Sborman 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 */ 462*44360Sborman case TELOPT_ENVIRON: /* environment variable option */ 46338689Sborman new_state_ok = 1; 4646000Sroot break; 4656000Sroot 466*44360Sborman case TELOPT_XDISPLOC: /* X Display location */ 467*44360Sborman if (env_getvalue("DISPLAY")) 468*44360Sborman new_state_ok = 1; 469*44360Sborman break; 470*44360Sborman 47138689Sborman case TELOPT_LINEMODE: 47238689Sborman #ifdef KLUDGELINEMODE 47338689Sborman kludgelinemode = 0; 474*44360Sborman 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); 49038689Sborman } else { 49138689Sborman will_wont_resp[option]++; 49238689Sborman send_wont(option, 0); 49338689Sborman } 49438689Sborman } else { 49538689Sborman /* 49638689Sborman * Handle options that need more things done after the 49738689Sborman * other side has acknowledged the option. 49838689Sborman */ 49938689Sborman switch (option) { 50038689Sborman case TELOPT_LINEMODE: 50138689Sborman #ifdef KLUDGELINEMODE 50238689Sborman kludgelinemode = 0; 503*44360Sborman send_do(TELOPT_SGA, 1); 50438689Sborman #endif 50538689Sborman set_my_state_will(option); 50638689Sborman slc_init(); 507*44360Sborman send_do(TELOPT_SGA, 0); 50838689Sborman return; 50938689Sborman } 51038689Sborman } 5116000Sroot } 51238689Sborman set_my_state_will(option); 5136000Sroot } 51427676Sminshall 51538689Sborman static void 51638689Sborman dontoption(option) 51738689Sborman int option; 51838689Sborman { 51938689Sborman 52038689Sborman if (will_wont_resp[option]) { 52138689Sborman --will_wont_resp[option]; 52238689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 52338689Sborman --will_wont_resp[option]; 52438689Sborman } 52538689Sborman 52638689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 52738811Sborman switch (option) { 52838811Sborman case TELOPT_LINEMODE: 52938811Sborman linemode = 0; /* put us back to the default state */ 53038811Sborman break; 53138811Sborman } 53238689Sborman /* we always accept a DONT */ 53338689Sborman set_my_want_state_wont(option); 534*44360Sborman if (my_state_is_will(option)) 535*44360Sborman send_wont(option, 0); 53639529Sborman setconnmode(0); /* Set new tty mode */ 53738689Sborman } 53838689Sborman set_my_state_wont(option); 53938689Sborman } 54038689Sborman 54127676Sminshall /* 54238908Sborman * Given a buffer returned by tgetent(), this routine will turn 54338908Sborman * the pipe seperated list of names in the buffer into an array 54438908Sborman * of pointers to null terminated names. We toss out any bad, 54538908Sborman * duplicate, or verbose names (names with spaces). 54638908Sborman */ 54738908Sborman 54838908Sborman static char *unknown[] = { "UNKNOWN", 0 }; 54938908Sborman 55038908Sborman char ** 55138908Sborman mklist(buf, name) 55238908Sborman char *buf, *name; 55338908Sborman { 55438908Sborman register int n; 55538908Sborman register char c, *cp, **argvp, *cp2, **argv; 55638908Sborman char *malloc(); 55738908Sborman 55838908Sborman if (name) { 55938908Sborman if (strlen(name) > 40) 56038908Sborman name = 0; 56138908Sborman else { 56238908Sborman unknown[0] = name; 56338908Sborman upcase(name); 56438908Sborman } 56538908Sborman } 56638908Sborman /* 56738908Sborman * Count up the number of names. 56838908Sborman */ 56938908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 57038908Sborman if (*cp == '|') 57138908Sborman n++; 57238908Sborman } 57338908Sborman /* 57438908Sborman * Allocate an array to put the name pointers into 57538908Sborman */ 57638908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 57738908Sborman if (argv == 0) 57838908Sborman return(unknown); 57938908Sborman 58038908Sborman /* 58138908Sborman * Fill up the array of pointers to names. 58238908Sborman */ 58338908Sborman *argv = 0; 58438908Sborman argvp = argv+1; 58538908Sborman n = 0; 58638908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 58738908Sborman if (c == '|' || c == ':') { 58838908Sborman *cp++ = '\0'; 58938908Sborman /* 59038908Sborman * Skip entries that have spaces or are over 40 59138908Sborman * characters long. If this is our environment 59238908Sborman * name, then put it up front. Otherwise, as 59338908Sborman * long as this is not a duplicate name (case 59438908Sborman * insensitive) add it to the list. 59538908Sborman */ 59638908Sborman if (n || (cp - cp2 > 41)) 59738908Sborman ; 59838908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 59938908Sborman *argv = cp2; 60038908Sborman else if (is_unique(cp2, argv+1, argvp)) 60138908Sborman *argvp++ = cp2; 60238908Sborman if (c == ':') 60338908Sborman break; 60438908Sborman /* 60538908Sborman * Skip multiple delimiters. Reset cp2 to 60638908Sborman * the beginning of the next name. Reset n, 60738908Sborman * the flag for names with spaces. 60838908Sborman */ 60938908Sborman while ((c = *cp) == '|') 61038908Sborman cp++; 61138908Sborman cp2 = cp; 61238908Sborman n = 0; 61338908Sborman } 61438908Sborman /* 61538908Sborman * Skip entries with spaces or non-ascii values. 61638908Sborman * Convert lower case letters to upper case. 61738908Sborman */ 61838908Sborman if ((c == ' ') || !isascii(c)) 61938908Sborman n = 1; 62038908Sborman else if (islower(c)) 62138908Sborman *cp = toupper(c); 62238908Sborman } 62338908Sborman 62438908Sborman /* 62538908Sborman * Check for an old V6 2 character name. If the second 62638908Sborman * name points to the beginning of the buffer, and is 62738908Sborman * only 2 characters long, move it to the end of the array. 62838908Sborman */ 62938908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 63038908Sborman *argvp++ = buf; 63138908Sborman cp = *argv++; 63238908Sborman *argv = cp; 63338908Sborman } 63438908Sborman 63538908Sborman /* 63638908Sborman * Duplicate last name, for TTYPE option, and null 63738908Sborman * terminate the array. If we didn't find a match on 63838908Sborman * our terminal name, put that name at the beginning. 63938908Sborman */ 64038908Sborman cp = *(argvp-1); 64138908Sborman *argvp++ = cp; 64238908Sborman *argvp = 0; 64338908Sborman 64438908Sborman if (*argv == 0) { 64538908Sborman if (name) 64638908Sborman *argv = name; 64738908Sborman else 64838908Sborman argv++; 64938908Sborman } 65038908Sborman if (*argv) 65138908Sborman return(argv); 65238908Sborman else 65338908Sborman return(unknown); 65438908Sborman } 65538908Sborman 65638908Sborman is_unique(name, as, ae) 65738908Sborman register char *name, **as, **ae; 65838908Sborman { 65938908Sborman register char **ap; 66038908Sborman register int n; 66138908Sborman 66238908Sborman n = strlen(name) + 1; 66338908Sborman for (ap = as; ap < ae; ap++) 66438908Sborman if (strncasecmp(*ap, name, n) == 0) 66538908Sborman return(0); 66638908Sborman return (1); 66738908Sborman } 66838908Sborman 66938908Sborman #ifdef TERMCAP 67039529Sborman char termbuf[1024]; 671*44360Sborman /*ARGSUSED*/ 67238908Sborman setupterm(tname, fd, errp) 67338908Sborman char *tname; 67438908Sborman int fd, *errp; 67538908Sborman { 67639529Sborman if (tgetent(termbuf, tname) == 1) { 67739529Sborman termbuf[1023] = '\0'; 67838908Sborman if (errp) 67938908Sborman *errp = 1; 68038908Sborman return(0); 68138908Sborman } 68238908Sborman if (errp) 68338908Sborman *errp = 0; 68438908Sborman return(-1); 68538908Sborman } 68639529Sborman #else 68739529Sborman #define termbuf ttytype 68839529Sborman extern char ttytype[]; 68938908Sborman #endif 69038908Sborman 69138908Sborman char * 69238908Sborman gettermname() 69338908Sborman { 69438908Sborman char *tname; 69538908Sborman static int first = 1; 69638908Sborman static char **tnamep; 69738908Sborman static char **next; 69838908Sborman int err; 69938908Sborman 70038908Sborman if (first) { 70138908Sborman first = 0; 702*44360Sborman if ((tname = env_getvalue("TERM")) && 70338908Sborman (setupterm(tname, 1, &err) == 0)) { 70439529Sborman tnamep = mklist(termbuf, tname); 70538908Sborman } else { 70638908Sborman if (tname && (strlen(tname) <= 40)) { 70738908Sborman unknown[0] = tname; 70838908Sborman upcase(tname); 70938908Sborman } 71038908Sborman tnamep = unknown; 71138908Sborman } 71238908Sborman next = tnamep; 71338908Sborman } 71438908Sborman if (*next == 0) 71538908Sborman next = tnamep; 71638908Sborman return(*next++); 71738908Sborman } 71838908Sborman /* 71927676Sminshall * suboption() 72027676Sminshall * 72127676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 72227676Sminshall * side. 72327676Sminshall * 72427676Sminshall * Currently we recognize: 72527676Sminshall * 72627676Sminshall * Terminal type, send request. 72737219Sminshall * Terminal speed (send request). 72837219Sminshall * Local flow control (is request). 72938689Sborman * Linemode 73027676Sminshall */ 73127676Sminshall 73232377Sminshall static void 73327676Sminshall suboption() 73427676Sminshall { 73538689Sborman printsub('<', subbuffer, subend-subbuffer+2); 73627676Sminshall switch (subbuffer[0]&0xff) { 73727676Sminshall case TELOPT_TTYPE: 73838689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 73938689Sborman return; 74027676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 74127676Sminshall ; 74227676Sminshall } else { 74327676Sminshall char *name; 74438908Sborman char temp[50]; 74527676Sminshall int len; 74627676Sminshall 74732377Sminshall #if defined(TN3270) 74832531Sminshall if (tn3270_ttype()) { 74932377Sminshall return; 75032377Sminshall } 75132377Sminshall #endif /* defined(TN3270) */ 75238908Sborman name = gettermname(); 75338908Sborman len = strlen(name) + 4 + 2; 75438908Sborman if (len < NETROOM()) { 75538908Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 75638908Sborman TELQUAL_IS, name, IAC, SE); 75738689Sborman ring_supply_data(&netoring, temp, len); 75838908Sborman printsub('>', &temp[2], len-2); 75932377Sminshall } else { 76037226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 76132377Sminshall /*NOTREACHED*/ 76227676Sminshall } 76327676Sminshall } 76437219Sminshall break; 76537219Sminshall case TELOPT_TSPEED: 76638689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 76738689Sborman return; 76837219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 769*44360Sborman int ospeed, ispeed; 77038689Sborman char temp[50]; 77137219Sminshall int len; 77227676Sminshall 77337219Sminshall TerminalSpeeds(&ispeed, &ospeed); 77437219Sminshall 77538689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 77638689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 77738689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 77837219Sminshall 77938689Sborman if (len < NETROOM()) { 78038689Sborman ring_supply_data(&netoring, temp, len); 78138689Sborman printsub('>', temp+2, len - 2); 78237219Sminshall } 783*44360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 78437219Sminshall } 78537219Sminshall break; 78637219Sminshall case TELOPT_LFLOW: 78738689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 78838689Sborman return; 78937219Sminshall if ((subbuffer[1]&0xff) == 1) { 79037219Sminshall localflow = 1; 79137219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 79237219Sminshall localflow = 0; 79337219Sminshall } 79437219Sminshall setcommandmode(); 79538689Sborman setconnmode(0); 79637219Sminshall break; 79738689Sborman 79838689Sborman case TELOPT_LINEMODE: 79938689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 80038689Sborman return; 80138689Sborman switch (subbuffer[1]&0xff) { 80238689Sborman case WILL: 80338689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 80438689Sborman break; 80538689Sborman case WONT: 80638689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 80738689Sborman break; 80838689Sborman case DO: 80938689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 81038689Sborman break; 81138689Sborman case DONT: 81238689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 81338689Sborman break; 81438689Sborman case LM_SLC: 81538689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 81638689Sborman break; 81738689Sborman case LM_MODE: 81838689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 81938689Sborman break; 82038689Sborman default: 821*44360Sborman break; 822*44360Sborman } 823*44360Sborman break; 824*44360Sborman 825*44360Sborman case TELOPT_ENVIRON: 826*44360Sborman switch(subbuffer[1]&0xff) { 827*44360Sborman case TELQUAL_IS: 828*44360Sborman case TELQUAL_INFO: 829*44360Sborman if (my_want_state_is_dont(TELOPT_ENVIRON)) 830*44360Sborman return; 831*44360Sborman break; 832*44360Sborman case TELQUAL_SEND: 833*44360Sborman if (my_want_state_is_wont(TELOPT_ENVIRON)) { 834*44360Sborman return; 835*44360Sborman } 836*44360Sborman break; 837*44360Sborman default: 838*44360Sborman return; 839*44360Sborman } 840*44360Sborman env_opt(&subbuffer[1], subend - &subbuffer[1]); 841*44360Sborman break; 842*44360Sborman 843*44360Sborman case TELOPT_XDISPLOC: 844*44360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC)) 845*44360Sborman return; 846*44360Sborman if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 847*44360Sborman char temp[50], *dp; 848*44360Sborman int len; 849*44360Sborman 850*44360Sborman if ((dp = env_getvalue("DISPLAY")) == NULL) { 851*44360Sborman /* 852*44360Sborman * Something happened, we no longer have a DISPLAY 853*44360Sborman * variable. So, turn off the option. 854*44360Sborman */ 855*44360Sborman send_wont(TELOPT_XDISPLOC, 1); 85638689Sborman break; 857*44360Sborman } 858*44360Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 859*44360Sborman TELQUAL_IS, dp, IAC, SE); 860*44360Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 861*44360Sborman 862*44360Sborman if (len < NETROOM()) { 863*44360Sborman ring_supply_data(&netoring, temp, len); 864*44360Sborman printsub('>', temp+2, len - 2); 865*44360Sborman } 866*44360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 86738689Sborman } 868*44360Sborman break; 86943319Skfall 87043319Skfall #ifdef KERBEROS 87143319Skfall case TELOPT_AUTHENTICATION: 87243319Skfall if ((subbuffer[1] & 0xff) == TELQUAL_SEND) { 87343319Skfall register char *cp = &subbuffer[2]; 87443320Skfall char tmp[256]; 87543319Skfall int dokrb4 = 0, unknowntypes = 0, noresponse = 1; 87643319Skfall 87743319Skfall while (cp < subend) { 87843319Skfall switch (*cp) { 87943319Skfall case TELQUAL_AUTHTYPE_KERBEROS_V4: 88043319Skfall dokrb4 = 1; 88143319Skfall break; 88243319Skfall default: 88343319Skfall unknowntypes++; 88443319Skfall } 88543319Skfall cp++; 88643319Skfall } 88743319Skfall 88843319Skfall if (noresponse && dokrb4) { 88943319Skfall register unsigned char *ucp = (unsigned char *)cp; 89043319Skfall char *krb_realm; 89143319Skfall char hst_inst[INST_SZ]; 89243319Skfall KTEXT_ST authent_st; 89343319Skfall int space = 0; 89443319Skfall int retval; 89543319Skfall extern char *krb_realmofhost(), *krb_get_phost(); 89643319Skfall 89743319Skfall fprintf(stderr, 89843319Skfall "[Trying Kerberos V4 authentication]\n"); 89943319Skfall 90043319Skfall krb_realm = krb_get_phost(hostname); 90143319Skfall bzero(hst_inst, sizeof(hst_inst)); 90243319Skfall if (krb_realm) 90343319Skfall strncpy(hst_inst, krb_realm, sizeof(hst_inst)); 90443319Skfall hst_inst[sizeof(hst_inst)-1] = '\0'; 90543319Skfall if (!(krb_realm = krb_realmofhost(hst_inst))) { 90643319Skfall fprintf(stderr, "no realm for %s\n", hostname); 90743319Skfall goto cantsend4; 90843319Skfall } 90943319Skfall if (retval = krb_mk_req(&authent_st, "rcmd", hst_inst, 91043319Skfall krb_realm, 0L)) { 91143319Skfall fprintf(stderr, "mk_req failed: %s\n", 91243319Skfall krb_err_txt[retval]); 91343319Skfall goto cantsend4; 91443319Skfall } 91543319Skfall space = authent_st.length; 91643319Skfall for (ucp = authent_st.dat; ucp < authent_st.dat + 91743319Skfall authent_st.length; ucp++) { 91843319Skfall if (*ucp == IAC) 91943319Skfall space++; 92043319Skfall } 92143320Skfall if (NETROOM() < 6 + 1 + 2 + 92243319Skfall space + 2) { 92343319Skfall fprintf(stderr, 92443319Skfall "no room to send V4 ticket/authenticator\n"); 92543319Skfall cantsend4: 92643319Skfall if (7 < NETROOM()) { 92743319Skfall printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, 92843319Skfall TELOPT_AUTHENTICATION, 92943319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 93043319Skfall sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, 93143319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 93243319Skfall printsub(">", tmp, 4+2-2-2); 93343319Skfall } else 93443319Skfall exit(1); 93543319Skfall } else { 93643319Skfall #ifdef notdef 93743320Skfall printring(&netoring, "%c%c%c%c%c%c", IAC, SB, 93843319Skfall TELOPT_AUTHENTICATION, 93943319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, 94043320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4); 94143320Skfall sprintf(tmp, "%c%c%c%c%c%c", TELOPT_AUTHENTICATION, 94243319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, 94343320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); 94443319Skfall #else 94543320Skfall printring(&netoring, "%c%c%c%c%c", IAC, SB, 94643319Skfall TELOPT_AUTHENTICATION, 94743319Skfall TELQUAL_IS, 94843320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4); 94943320Skfall sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, 95043319Skfall TELQUAL_IS, 95143320Skfall TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); 95243319Skfall #endif 95343320Skfall printsub(">", tmp, 4+2-2-2); 95443319Skfall ring_supply_bindata(&netoring, 95543319Skfall (char *)authent_st.dat, authent_st.length, IAC); 95643319Skfall printring(&netoring, "%c%c", IAC, SE); 95743319Skfall } 95843319Skfall noresponse = 0; 95943319Skfall } 96043319Skfall if (noresponse) { 96143319Skfall if (NETROOM() < 7) { 96243319Skfall ExitString("not enough room to reject unhandled authtype\n", 1); 96343319Skfall } else { 96443319Skfall fprintf(stderr,"[Sending empty auth info in response to request for %d unknown type(s):\n\t", unknowntypes); 96543319Skfall #ifdef notdef 96643319Skfall cp = &subbuffer[3]; 96743319Skfall #else 96843319Skfall cp = &subbuffer[2]; 96943319Skfall #endif 97043319Skfall while (cp < subend) { 97143319Skfall switch (*cp) { 97243319Skfall case TELQUAL_AUTHTYPE_KERBEROS_V4: 97343319Skfall break; 97443319Skfall default: 97543319Skfall fprintf(stderr, "%d,", *cp); 97643319Skfall break; 97743319Skfall } 97843319Skfall cp++; 97943319Skfall } 98043319Skfall fputs("]\n", stderr); 98143319Skfall printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, 98243319Skfall TELOPT_AUTHENTICATION, 98343319Skfall TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); 98443319Skfall } 98543319Skfall } 98643319Skfall } 98738689Sborman break; 98843319Skfall #endif /* KERBEROS */ 989*44360Sborman 99027676Sminshall default: 99127676Sminshall break; 99227676Sminshall } 99327676Sminshall } 99438689Sborman 99538689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 99638689Sborman 99738689Sborman lm_will(cmd, len) 99838689Sborman char *cmd; 99938689Sborman { 1000*44360Sborman if (len < 1) { 1001*44360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 1002*44360Sborman return; 1003*44360Sborman } 100438689Sborman switch(cmd[0]) { 100538689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 100638689Sborman default: 100738689Sborman str_lm[3] = DONT; 100838689Sborman str_lm[4] = cmd[0]; 100938689Sborman if (NETROOM() > sizeof(str_lm)) { 101038689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 101138689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 101238689Sborman } 101338689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 101438689Sborman break; 101538689Sborman } 101638689Sborman } 101738689Sborman 101838689Sborman lm_wont(cmd, len) 101938689Sborman char *cmd; 102038689Sborman { 1021*44360Sborman if (len < 1) { 1022*44360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 1023*44360Sborman return; 1024*44360Sborman } 102538689Sborman switch(cmd[0]) { 102638689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 102738689Sborman default: 102838689Sborman /* We are always DONT, so don't respond */ 102938689Sborman return; 103038689Sborman } 103138689Sborman } 103238689Sborman 103338689Sborman lm_do(cmd, len) 103438689Sborman char *cmd; 103538689Sborman { 1036*44360Sborman if (len < 1) { 1037*44360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 1038*44360Sborman return; 1039*44360Sborman } 104038689Sborman switch(cmd[0]) { 104138689Sborman case LM_FORWARDMASK: 104238689Sborman default: 104338689Sborman str_lm[3] = WONT; 104438689Sborman str_lm[4] = cmd[0]; 104538689Sborman if (NETROOM() > sizeof(str_lm)) { 104638689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 104738689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 104838689Sborman } 104938689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 105038689Sborman break; 105138689Sborman } 105238689Sborman } 105338689Sborman 105438689Sborman lm_dont(cmd, len) 105538689Sborman char *cmd; 105638689Sborman { 1057*44360Sborman if (len < 1) { 1058*44360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 1059*44360Sborman return; 1060*44360Sborman } 106138689Sborman switch(cmd[0]) { 106238689Sborman case LM_FORWARDMASK: 106338689Sborman default: 106438689Sborman /* we are always WONT, so don't respond */ 106538689Sborman break; 106638689Sborman } 106738689Sborman } 106838689Sborman 106938689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 107038689Sborman 107138689Sborman lm_mode(cmd, len, init) 107238689Sborman char *cmd; 107338689Sborman int len, init; 107438689Sborman { 107538689Sborman if (len != 1) 107638689Sborman return; 1077*44360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 107838689Sborman return; 107938689Sborman if (*cmd&MODE_ACK) 108038689Sborman return; 1081*44360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK); 108238689Sborman str_lm_mode[4] = linemode; 108338689Sborman if (!init) 108438689Sborman str_lm_mode[4] |= MODE_ACK; 108538689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 108638689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 108738689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 108838689Sborman } 108938689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 109038689Sborman setconnmode(0); /* set changed mode */ 109138689Sborman } 109238689Sborman 109332377Sminshall 109427088Sminshall 109538689Sborman /* 109638689Sborman * slc() 109738689Sborman * Handle special character suboption of LINEMODE. 109838689Sborman */ 109938689Sborman 110038689Sborman struct spc { 110140245Sborman cc_t val; 110240245Sborman cc_t *valp; 110338689Sborman char flags; /* Current flags & level */ 110438689Sborman char mylevel; /* Maximum level & flags */ 110538689Sborman } spc_data[NSLC+1]; 110638689Sborman 110738689Sborman #define SLC_IMPORT 0 110838689Sborman #define SLC_EXPORT 1 110938689Sborman #define SLC_RVALUE 2 111038689Sborman static int slc_mode = SLC_EXPORT; 111138689Sborman 111238689Sborman slc_init() 111338689Sborman { 111438689Sborman register struct spc *spcp; 111540245Sborman extern cc_t *tcval(); 111638689Sborman 111738689Sborman localchars = 1; 111838689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 111938689Sborman spcp->val = 0; 112038689Sborman spcp->valp = 0; 112138689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 112238689Sborman } 112338689Sborman 112438689Sborman #define initfunc(func, flags) { \ 112538689Sborman spcp = &spc_data[func]; \ 112638689Sborman if (spcp->valp = tcval(func)) { \ 112738689Sborman spcp->val = *spcp->valp; \ 112838689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 112938689Sborman } else { \ 113038689Sborman spcp->val = 0; \ 113138689Sborman spcp->mylevel = SLC_DEFAULT; \ 113238689Sborman } \ 113338689Sborman } 113438689Sborman 113538689Sborman initfunc(SLC_SYNCH, 0); 113638689Sborman /* No BRK */ 113738689Sborman initfunc(SLC_AO, 0); 113838689Sborman initfunc(SLC_AYT, 0); 113938689Sborman /* No EOR */ 114038689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 114138689Sborman initfunc(SLC_EOF, 0); 114239529Sborman #ifndef SYSV_TERMIO 114338689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 114438689Sborman #endif 114538689Sborman initfunc(SLC_EC, 0); 114638689Sborman initfunc(SLC_EL, 0); 114739529Sborman #ifndef SYSV_TERMIO 114838689Sborman initfunc(SLC_EW, 0); 114938689Sborman initfunc(SLC_RP, 0); 115038689Sborman initfunc(SLC_LNEXT, 0); 115138689Sborman #endif 115238689Sborman initfunc(SLC_XON, 0); 115338689Sborman initfunc(SLC_XOFF, 0); 115439529Sborman #ifdef SYSV_TERMIO 115538689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 115638689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 115738689Sborman #endif 1158*44360Sborman initfunc(SLC_FORW1, 0); 1159*44360Sborman #ifdef USE_TERMIO 1160*44360Sborman initfunc(SLC_FORW2, 0); 116138689Sborman /* No FORW2 */ 1162*44360Sborman #endif 116338689Sborman 116438689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 116538689Sborman #undef initfunc 116638689Sborman 116738689Sborman if (slc_mode == SLC_EXPORT) 116838689Sborman slc_export(); 116938689Sborman else 117038689Sborman slc_import(1); 117138689Sborman 117238689Sborman } 117338689Sborman 117438689Sborman slcstate() 117538689Sborman { 117638689Sborman printf("Special characters are %s values\n", 117738689Sborman slc_mode == SLC_IMPORT ? "remote default" : 117838689Sborman slc_mode == SLC_EXPORT ? "local" : 117938689Sborman "remote"); 118038689Sborman } 118138689Sborman 118238689Sborman slc_mode_export() 118338689Sborman { 118438689Sborman slc_mode = SLC_EXPORT; 118538689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 118638689Sborman slc_export(); 118738689Sborman } 118838689Sborman 118938689Sborman slc_mode_import(def) 119038689Sborman { 119138689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 119238689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 119338689Sborman slc_import(def); 119438689Sborman } 119538689Sborman 119638689Sborman char slc_import_val[] = { 119738689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 119838689Sborman }; 119938689Sborman char slc_import_def[] = { 120038689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 120138689Sborman }; 120238689Sborman 120338689Sborman slc_import(def) 120438689Sborman int def; 120538689Sborman { 120638689Sborman if (NETROOM() > sizeof(slc_import_val)) { 120738689Sborman if (def) { 120838689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 120938689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 121038689Sborman } else { 121138689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 121238689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 121338689Sborman } 121438689Sborman } 121538689Sborman /*@*/ else printf("slc_import: not enough room\n"); 121638689Sborman } 121738689Sborman 121838689Sborman slc_export() 121938689Sborman { 122038689Sborman register struct spc *spcp; 122138689Sborman 122238689Sborman TerminalDefaultChars(); 122338689Sborman 122438689Sborman slc_start_reply(); 122538689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 122638689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 122738689Sborman spcp->flags = spcp->mylevel; 122838689Sborman if (spcp->valp) 122938689Sborman spcp->val = *spcp->valp; 123038689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 123138689Sborman } 123238689Sborman } 123338689Sborman slc_end_reply(); 123438689Sborman if (slc_update()) 123538689Sborman setconnmode(1); /* set the new character values */ 123638689Sborman } 123738689Sborman 123838689Sborman slc(cp, len) 123938689Sborman register char *cp; 124038689Sborman int len; 124138689Sborman { 124238689Sborman register struct spc *spcp; 124338689Sborman register int func,level; 124438689Sborman 124538689Sborman slc_start_reply(); 124638689Sborman 124738689Sborman for (; len >= 3; len -=3, cp +=3) { 124838689Sborman 124938689Sborman func = cp[SLC_FUNC]; 125038689Sborman 125138689Sborman if (func == 0) { 125238689Sborman /* 125338689Sborman * Client side: always ignore 0 function. 125438689Sborman */ 125538689Sborman continue; 125638689Sborman } 125738689Sborman if (func > NSLC) { 125838689Sborman if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) 125938689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 126038689Sborman continue; 126138689Sborman } 126238689Sborman 126338689Sborman spcp = &spc_data[func]; 126438689Sborman 126538689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 126638689Sborman 126740245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 126838689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 126938689Sborman continue; 127038689Sborman } 127138689Sborman 127238689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 127338689Sborman /* 127438689Sborman * This is an error condition, the SLC_ACK 127538689Sborman * bit should never be set for the SLC_DEFAULT 127638689Sborman * level. Our best guess to recover is to 127738689Sborman * ignore the SLC_ACK bit. 127838689Sborman */ 127938689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 128038689Sborman } 128138689Sborman 128238689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 128340245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 128438689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 128538689Sborman continue; 128638689Sborman } 128738689Sborman 128838689Sborman level &= ~SLC_ACK; 128938689Sborman 129038689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 129138689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 129240245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 129338689Sborman } 129438689Sborman if (level == SLC_DEFAULT) { 129538689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 129638689Sborman spcp->flags = spcp->mylevel; 129738689Sborman else 129838689Sborman spcp->flags = SLC_NOSUPPORT; 129938689Sborman } 130038689Sborman slc_add_reply(func, spcp->flags, spcp->val); 130138689Sborman } 130238689Sborman slc_end_reply(); 130338689Sborman if (slc_update()) 130438689Sborman setconnmode(1); /* set the new character values */ 130538689Sborman } 130638689Sborman 130738689Sborman slc_check() 130838689Sborman { 130938689Sborman register struct spc *spcp; 131038689Sborman 131138689Sborman slc_start_reply(); 131238689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 131338689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 131438689Sborman spcp->val = *spcp->valp; 131538689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 131638689Sborman } 131738689Sborman } 131838689Sborman slc_end_reply(); 131938689Sborman setconnmode(1); 132038689Sborman } 132138689Sborman 132238689Sborman 132338689Sborman unsigned char slc_reply[128]; 132438689Sborman unsigned char *slc_replyp; 132538689Sborman slc_start_reply() 132638689Sborman { 132738689Sborman slc_replyp = slc_reply; 132838689Sborman *slc_replyp++ = IAC; 132938689Sborman *slc_replyp++ = SB; 133038689Sborman *slc_replyp++ = TELOPT_LINEMODE; 133138689Sborman *slc_replyp++ = LM_SLC; 133238689Sborman } 133338689Sborman 133438689Sborman slc_add_reply(func, flags, value) 133538689Sborman char func; 133638689Sborman char flags; 133740245Sborman cc_t value; 133838689Sborman { 133938689Sborman if ((*slc_replyp++ = func) == IAC) 134038689Sborman *slc_replyp++ = IAC; 134138689Sborman if ((*slc_replyp++ = flags) == IAC) 134238689Sborman *slc_replyp++ = IAC; 134340245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 134438689Sborman *slc_replyp++ = IAC; 134538689Sborman } 134638689Sborman 134738689Sborman slc_end_reply() 134838689Sborman { 134938689Sborman register int len; 135038689Sborman 135138689Sborman *slc_replyp++ = IAC; 135238689Sborman *slc_replyp++ = SE; 135338689Sborman len = slc_replyp - slc_reply; 135438689Sborman if (len <= 6) 135538689Sborman return; 135638689Sborman if (NETROOM() > len) { 135738689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 135838689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 135938689Sborman } 136038689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 136138689Sborman } 136238689Sborman 136338689Sborman slc_update() 136438689Sborman { 136538689Sborman register struct spc *spcp; 136638689Sborman int need_update = 0; 136738689Sborman 136838689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 136938689Sborman if (!(spcp->flags&SLC_ACK)) 137038689Sborman continue; 137138689Sborman spcp->flags &= ~SLC_ACK; 137238689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 137338689Sborman *spcp->valp = spcp->val; 137438689Sborman need_update = 1; 137538689Sborman } 137638689Sborman } 137738689Sborman return(need_update); 137838689Sborman } 137938689Sborman 1380*44360Sborman env_opt(buf, len) 1381*44360Sborman register char *buf; 1382*44360Sborman register int len; 1383*44360Sborman { 1384*44360Sborman register char *ep = 0, *epc = 0; 1385*44360Sborman register int i; 1386*44360Sborman 1387*44360Sborman switch(buf[0]) { 1388*44360Sborman case TELQUAL_SEND: 1389*44360Sborman env_opt_start(); 1390*44360Sborman if (len == 1) { 1391*44360Sborman env_opt_add(NULL); 1392*44360Sborman } else for (i = 1; i < len; i++) { 1393*44360Sborman switch (buf[i]) { 1394*44360Sborman case ENV_VALUE: 1395*44360Sborman if (ep) { 1396*44360Sborman *epc = 0; 1397*44360Sborman env_opt_add(ep); 1398*44360Sborman } 1399*44360Sborman ep = epc = &buf[i+1]; 1400*44360Sborman break; 1401*44360Sborman case ENV_ESC: 1402*44360Sborman i++; 1403*44360Sborman /*FALL THROUGH*/ 1404*44360Sborman default: 1405*44360Sborman if (epc) 1406*44360Sborman *epc++ = buf[i]; 1407*44360Sborman break; 1408*44360Sborman } 1409*44360Sborman if (ep) { 1410*44360Sborman *epc = 0; 1411*44360Sborman env_opt_add(ep); 1412*44360Sborman } 1413*44360Sborman } 1414*44360Sborman env_opt_end(1); 1415*44360Sborman break; 1416*44360Sborman 1417*44360Sborman case TELQUAL_IS: 1418*44360Sborman case TELQUAL_INFO: 1419*44360Sborman /* Ignore for now. We shouldn't get it anyway. */ 1420*44360Sborman break; 1421*44360Sborman 1422*44360Sborman default: 1423*44360Sborman break; 1424*44360Sborman } 1425*44360Sborman } 1426*44360Sborman 1427*44360Sborman #define OPT_REPLY_SIZE 256 1428*44360Sborman unsigned char *opt_reply; 1429*44360Sborman unsigned char *opt_replyp; 1430*44360Sborman unsigned char *opt_replyend; 1431*44360Sborman 1432*44360Sborman env_opt_start() 1433*44360Sborman { 1434*44360Sborman extern char *realloc(); 1435*44360Sborman extern char *malloc(); 1436*44360Sborman 1437*44360Sborman if (opt_reply) 1438*44360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 1439*44360Sborman else 1440*44360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 1441*44360Sborman if (opt_reply == NULL) { 1442*44360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 1443*44360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 1444*44360Sborman return; 1445*44360Sborman } 1446*44360Sborman opt_replyp = opt_reply; 1447*44360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 1448*44360Sborman *opt_replyp++ = IAC; 1449*44360Sborman *opt_replyp++ = SB; 1450*44360Sborman *opt_replyp++ = TELOPT_ENVIRON; 1451*44360Sborman *opt_replyp++ = TELQUAL_IS; 1452*44360Sborman } 1453*44360Sborman 1454*44360Sborman env_opt_start_info() 1455*44360Sborman { 1456*44360Sborman env_opt_start(); 1457*44360Sborman if (opt_replyp) 1458*44360Sborman opt_replyp[-1] = TELQUAL_INFO; 1459*44360Sborman } 1460*44360Sborman 1461*44360Sborman env_opt_add(ep) 1462*44360Sborman register char *ep; 1463*44360Sborman { 1464*44360Sborman register char *vp, c; 1465*44360Sborman extern char *realloc(); 1466*44360Sborman extern char *env_default(); 1467*44360Sborman 1468*44360Sborman if (opt_reply == NULL) /*XXX*/ 1469*44360Sborman return; /*XXX*/ 1470*44360Sborman 1471*44360Sborman if (ep == NULL || *ep == '\0') { 1472*44360Sborman env_default(1); 1473*44360Sborman while (ep = env_default(0)) 1474*44360Sborman env_opt_add(ep); 1475*44360Sborman return; 1476*44360Sborman } 1477*44360Sborman vp = env_getvalue(ep); 1478*44360Sborman if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) { 1479*44360Sborman register int len; 1480*44360Sborman opt_replyend += OPT_REPLY_SIZE; 1481*44360Sborman len = opt_replyend - opt_reply; 1482*44360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 1483*44360Sborman if (opt_reply == NULL) { 1484*44360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 1485*44360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 1486*44360Sborman return; 1487*44360Sborman } 1488*44360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 1489*44360Sborman opt_replyend = opt_reply + len; 1490*44360Sborman } 1491*44360Sborman *opt_replyp++ = ENV_VAR; 1492*44360Sborman for (;;) { 1493*44360Sborman while (c = *ep++) { 1494*44360Sborman switch(c) { 1495*44360Sborman case IAC: 1496*44360Sborman *opt_replyp++ = IAC; 1497*44360Sborman break; 1498*44360Sborman case ENV_VALUE: 1499*44360Sborman case ENV_VAR: 1500*44360Sborman case ENV_ESC: 1501*44360Sborman *opt_replyp++ = ENV_ESC; 1502*44360Sborman break; 1503*44360Sborman } 1504*44360Sborman *opt_replyp++ = c; 1505*44360Sborman } 1506*44360Sborman if (ep = vp) { 1507*44360Sborman *opt_replyp++ = ENV_VALUE; 1508*44360Sborman vp = NULL; 1509*44360Sborman } else 1510*44360Sborman break; 1511*44360Sborman } 1512*44360Sborman } 1513*44360Sborman 1514*44360Sborman env_opt_end(emptyok) 1515*44360Sborman register int emptyok; 1516*44360Sborman { 1517*44360Sborman register int len; 1518*44360Sborman 1519*44360Sborman len = opt_replyp - opt_reply + 2; 1520*44360Sborman if (emptyok || len > 6) { 1521*44360Sborman *opt_replyp++ = IAC; 1522*44360Sborman *opt_replyp++ = SE; 1523*44360Sborman if (NETROOM() > len) { 1524*44360Sborman ring_supply_data(&netoring, opt_reply, len); 1525*44360Sborman printsub('>', &opt_reply[2], len - 2); 1526*44360Sborman } 1527*44360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 1528*44360Sborman } 1529*44360Sborman if (opt_reply) { 1530*44360Sborman free(opt_reply); 1531*44360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 1532*44360Sborman } 1533*44360Sborman } 1534*44360Sborman 153538689Sborman 153638689Sborman 153733804Sminshall int 153832377Sminshall telrcv() 153927110Sminshall { 154032377Sminshall register int c; 154132385Sminshall register int scc; 154232385Sminshall register char *sbp; 154332385Sminshall int count; 154432385Sminshall int returnValue = 0; 154527088Sminshall 154632385Sminshall scc = 0; 154732385Sminshall count = 0; 154832385Sminshall while (TTYROOM() > 2) { 154932385Sminshall if (scc == 0) { 155032385Sminshall if (count) { 155132528Sminshall ring_consumed(&netiring, count); 155232385Sminshall returnValue = 1; 155332385Sminshall count = 0; 155432385Sminshall } 155532528Sminshall sbp = netiring.consume; 155632528Sminshall scc = ring_full_consecutive(&netiring); 155732385Sminshall if (scc == 0) { 155832385Sminshall /* No more data coming in */ 155932385Sminshall break; 156032385Sminshall } 156132385Sminshall } 156232385Sminshall 156332385Sminshall c = *sbp++ & 0xff, scc--; count++; 156432385Sminshall 156532377Sminshall switch (telrcv_state) { 156627110Sminshall 156732377Sminshall case TS_CR: 156832377Sminshall telrcv_state = TS_DATA; 156935518Sminshall if (c == '\0') { 157035518Sminshall break; /* Ignore \0 after CR */ 157139529Sborman } 157239529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 157335518Sminshall TTYADD(c); 157435518Sminshall break; 157532377Sminshall } 157635518Sminshall /* Else, fall through */ 157727088Sminshall 157832377Sminshall case TS_DATA: 157932377Sminshall if (c == IAC) { 158032377Sminshall telrcv_state = TS_IAC; 158133804Sminshall break; 158232377Sminshall } 158332377Sminshall # if defined(TN3270) 158432377Sminshall if (In3270) { 158532377Sminshall *Ifrontp++ = c; 158632385Sminshall while (scc > 0) { 158732385Sminshall c = *sbp++ & 0377, scc--; count++; 158832377Sminshall if (c == IAC) { 158932377Sminshall telrcv_state = TS_IAC; 159034304Sminshall break; 159132377Sminshall } 159232377Sminshall *Ifrontp++ = c; 159332377Sminshall } 159432377Sminshall } else 159532377Sminshall # endif /* defined(TN3270) */ 159635518Sminshall /* 159735518Sminshall * The 'crmod' hack (see following) is needed 159835518Sminshall * since we can't * set CRMOD on output only. 159935518Sminshall * Machines like MULTICS like to send \r without 160035518Sminshall * \n; since we must turn off CRMOD to get proper 160135518Sminshall * input, the mapping is done here (sigh). 160235518Sminshall */ 160338689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 160435518Sminshall if (scc > 0) { 160535518Sminshall c = *sbp&0xff; 160635518Sminshall if (c == 0) { 160735518Sminshall sbp++, scc--; count++; 160835518Sminshall /* a "true" CR */ 160932377Sminshall TTYADD('\r'); 161038689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 161135518Sminshall (c == '\n')) { 161235518Sminshall sbp++, scc--; count++; 161332377Sminshall TTYADD('\n'); 161435518Sminshall } else { 161535518Sminshall TTYADD('\r'); 161635518Sminshall if (crmod) { 161735518Sminshall TTYADD('\n'); 161832377Sminshall } 161932377Sminshall } 162035518Sminshall } else { 162135518Sminshall telrcv_state = TS_CR; 162235518Sminshall TTYADD('\r'); 162335518Sminshall if (crmod) { 162435518Sminshall TTYADD('\n'); 162535518Sminshall } 162632377Sminshall } 162732377Sminshall } else { 162832377Sminshall TTYADD(c); 162932377Sminshall } 163032377Sminshall continue; 163127088Sminshall 163232377Sminshall case TS_IAC: 163338689Sborman process_iac: 163432377Sminshall switch (c) { 163532377Sminshall 163632377Sminshall case WILL: 163732377Sminshall telrcv_state = TS_WILL; 163832377Sminshall continue; 163927261Sminshall 164032377Sminshall case WONT: 164132377Sminshall telrcv_state = TS_WONT; 164232377Sminshall continue; 164327261Sminshall 164432377Sminshall case DO: 164532377Sminshall telrcv_state = TS_DO; 164632377Sminshall continue; 164727261Sminshall 164832377Sminshall case DONT: 164932377Sminshall telrcv_state = TS_DONT; 165032377Sminshall continue; 165127261Sminshall 165232377Sminshall case DM: 165332377Sminshall /* 165432377Sminshall * We may have missed an urgent notification, 165532377Sminshall * so make sure we flush whatever is in the 165632377Sminshall * buffer currently. 165732377Sminshall */ 165832377Sminshall SYNCHing = 1; 1659*44360Sborman (void) ttyflush(1); 166032554Sminshall SYNCHing = stilloob(); 166132377Sminshall settimer(gotDM); 166232377Sminshall break; 166327088Sminshall 166432377Sminshall case SB: 166532377Sminshall SB_CLEAR(); 166632377Sminshall telrcv_state = TS_SB; 166738689Sborman printoption("RCVD", "IAC", SB); 166832377Sminshall continue; 166927261Sminshall 167032377Sminshall # if defined(TN3270) 167132377Sminshall case EOR: 167232377Sminshall if (In3270) { 167332377Sminshall if (Ibackp == Ifrontp) { 167432377Sminshall Ibackp = Ifrontp = Ibuf; 167532377Sminshall ISend = 0; /* should have been! */ 167632377Sminshall } else { 1677*44360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 167832377Sminshall ISend = 1; 167927088Sminshall } 168027088Sminshall } 168127088Sminshall break; 168232377Sminshall # endif /* defined(TN3270) */ 168332377Sminshall 168432377Sminshall case IAC: 168532377Sminshall # if !defined(TN3270) 168632377Sminshall TTYADD(IAC); 168732377Sminshall # else /* !defined(TN3270) */ 168832377Sminshall if (In3270) { 168932377Sminshall *Ifrontp++ = IAC; 169032377Sminshall } else { 169132377Sminshall TTYADD(IAC); 169232377Sminshall } 169332377Sminshall # endif /* !defined(TN3270) */ 169427088Sminshall break; 169532377Sminshall 1696*44360Sborman case NOP: 1697*44360Sborman case GA: 169827088Sminshall default: 1699*44360Sborman printoption("RCVD", "IAC", c); 170027088Sminshall break; 170127088Sminshall } 170232377Sminshall telrcv_state = TS_DATA; 170332377Sminshall continue; 170427088Sminshall 170532377Sminshall case TS_WILL: 170637226Sminshall printoption("RCVD", "will", c); 170738689Sborman willoption(c); 170832377Sminshall SetIn3270(); 170932377Sminshall telrcv_state = TS_DATA; 171032377Sminshall continue; 171127110Sminshall 171232377Sminshall case TS_WONT: 171337226Sminshall printoption("RCVD", "wont", c); 171438689Sborman wontoption(c); 171532377Sminshall SetIn3270(); 171632377Sminshall telrcv_state = TS_DATA; 171732377Sminshall continue; 171827088Sminshall 171932377Sminshall case TS_DO: 172037226Sminshall printoption("RCVD", "do", c); 172137226Sminshall dooption(c); 172232377Sminshall SetIn3270(); 172337219Sminshall if (c == TELOPT_NAWS) { 172437219Sminshall sendnaws(); 172537219Sminshall } else if (c == TELOPT_LFLOW) { 172637219Sminshall localflow = 1; 172737219Sminshall setcommandmode(); 172838689Sborman setconnmode(0); 172937219Sminshall } 173032377Sminshall telrcv_state = TS_DATA; 173132377Sminshall continue; 173227088Sminshall 173332377Sminshall case TS_DONT: 173437226Sminshall printoption("RCVD", "dont", c); 173538689Sborman dontoption(c); 173637226Sminshall flushline = 1; 173738689Sborman setconnmode(0); /* set new tty mode (maybe) */ 173832377Sminshall SetIn3270(); 173932377Sminshall telrcv_state = TS_DATA; 174032377Sminshall continue; 174127088Sminshall 174232377Sminshall case TS_SB: 174332377Sminshall if (c == IAC) { 174432377Sminshall telrcv_state = TS_SE; 174532377Sminshall } else { 174632377Sminshall SB_ACCUM(c); 174732377Sminshall } 174832377Sminshall continue; 174927088Sminshall 175032377Sminshall case TS_SE: 175132377Sminshall if (c != SE) { 175232377Sminshall if (c != IAC) { 175338689Sborman /* 175438689Sborman * This is an error. We only expect to get 175538689Sborman * "IAC IAC" or "IAC SE". Several things may 175638689Sborman * have happend. An IAC was not doubled, the 175738689Sborman * IAC SE was left off, or another option got 175838689Sborman * inserted into the suboption are all possibilities. 175938689Sborman * If we assume that the IAC was not doubled, 176038689Sborman * and really the IAC SE was left off, we could 176138689Sborman * get into an infinate loop here. So, instead, 176238689Sborman * we terminate the suboption, and process the 176338689Sborman * partial suboption if we can. 176438689Sborman */ 176538689Sborman SB_TERM(); 176632377Sminshall SB_ACCUM(IAC); 176738689Sborman SB_ACCUM(c); 176838689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 176938689Sborman suboption(); /* handle sub-option */ 177038689Sborman SetIn3270(); 177138689Sborman telrcv_state = TS_IAC; 177238689Sborman goto process_iac; 177332377Sminshall } 177432377Sminshall SB_ACCUM(c); 177532377Sminshall telrcv_state = TS_SB; 177632377Sminshall } else { 177732377Sminshall SB_TERM(); 177838689Sborman SB_ACCUM(IAC); 177938689Sborman SB_ACCUM(SE); 178032377Sminshall suboption(); /* handle sub-option */ 178132377Sminshall SetIn3270(); 178232377Sminshall telrcv_state = TS_DATA; 178332377Sminshall } 178427088Sminshall } 178527088Sminshall } 178632667Sminshall if (count) 178732667Sminshall ring_consumed(&netiring, count); 178832385Sminshall return returnValue||count; 178927088Sminshall } 179032385Sminshall 179132385Sminshall static int 179232554Sminshall telsnd() 179332385Sminshall { 179432385Sminshall int tcc; 179532385Sminshall int count; 179632385Sminshall int returnValue = 0; 179732385Sminshall char *tbp; 179832385Sminshall 179932385Sminshall tcc = 0; 180032385Sminshall count = 0; 180132385Sminshall while (NETROOM() > 2) { 180232385Sminshall register int sc; 180332385Sminshall register int c; 180432385Sminshall 180532385Sminshall if (tcc == 0) { 180632385Sminshall if (count) { 180732528Sminshall ring_consumed(&ttyiring, count); 180832385Sminshall returnValue = 1; 180932385Sminshall count = 0; 181032385Sminshall } 181132528Sminshall tbp = ttyiring.consume; 181232528Sminshall tcc = ring_full_consecutive(&ttyiring); 181332385Sminshall if (tcc == 0) { 181432385Sminshall break; 181532385Sminshall } 181632385Sminshall } 181732385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 181832385Sminshall if (sc == escape) { 181938689Sborman /* 182038689Sborman * Double escape is a pass through of a single escape character. 182138689Sborman */ 182238689Sborman if (tcc && strip(*tbp) == escape) { 182338689Sborman tbp++; 182438689Sborman tcc--; 182538689Sborman count++; 182638689Sborman } else { 182738689Sborman command(0, tbp, tcc); 182838689Sborman count += tcc; 182938689Sborman tcc = 0; 183038689Sborman flushline = 1; 183138689Sborman break; 183238689Sborman } 183338689Sborman } 183438689Sborman #ifdef KLUDGELINEMODE 183538689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 183632385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 183732385Sminshall tcc--; tbp++; count++; 183832385Sminshall } else { 183932385Sminshall dontlecho = !dontlecho; 184032385Sminshall settimer(echotoggle); 184138689Sborman setconnmode(0); 184232385Sminshall flushline = 1; 184332385Sminshall break; 184432385Sminshall } 184532385Sminshall } 184638689Sborman #endif 184738689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 184832385Sminshall if (TerminalSpecialChars(sc) == 0) { 184932385Sminshall break; 185032385Sminshall } 185132385Sminshall } 185238689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 185332385Sminshall switch (c) { 185432385Sminshall case '\n': 185532385Sminshall /* 185632385Sminshall * If we are in CRMOD mode (\r ==> \n) 185732385Sminshall * on our local machine, then probably 185832385Sminshall * a newline (unix) is CRLF (TELNET). 185932385Sminshall */ 186032385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 186132385Sminshall NETADD('\r'); 186232385Sminshall } 186332385Sminshall NETADD('\n'); 186432385Sminshall flushline = 1; 186532385Sminshall break; 186632385Sminshall case '\r': 186732385Sminshall if (!crlf) { 186832385Sminshall NET2ADD('\r', '\0'); 186932385Sminshall } else { 187032385Sminshall NET2ADD('\r', '\n'); 187132385Sminshall } 187232385Sminshall flushline = 1; 187332385Sminshall break; 187432385Sminshall case IAC: 187532385Sminshall NET2ADD(IAC, IAC); 187632385Sminshall break; 187732385Sminshall default: 187832385Sminshall NETADD(c); 187932385Sminshall break; 188032385Sminshall } 188132385Sminshall } else if (c == IAC) { 188232385Sminshall NET2ADD(IAC, IAC); 188332385Sminshall } else { 188432385Sminshall NETADD(c); 188532385Sminshall } 188632385Sminshall } 188732667Sminshall if (count) 188832667Sminshall ring_consumed(&ttyiring, count); 188932385Sminshall return returnValue||count; /* Non-zero if we did anything */ 189032385Sminshall } 189132377Sminshall 189227088Sminshall /* 189332377Sminshall * Scheduler() 189432377Sminshall * 189532377Sminshall * Try to do something. 189632377Sminshall * 189732377Sminshall * If we do something useful, return 1; else return 0. 189832377Sminshall * 189927110Sminshall */ 190027110Sminshall 190127110Sminshall 190232377Sminshall int 190332377Sminshall Scheduler(block) 190432377Sminshall int block; /* should we block in the select ? */ 190527110Sminshall { 190632377Sminshall /* One wants to be a bit careful about setting returnValue 190732377Sminshall * to one, since a one implies we did some useful work, 190832377Sminshall * and therefore probably won't be called to block next 190932377Sminshall * time (TN3270 mode only). 191032377Sminshall */ 191132531Sminshall int returnValue; 191232531Sminshall int netin, netout, netex, ttyin, ttyout; 191327110Sminshall 191432531Sminshall /* Decide which rings should be processed */ 191532531Sminshall 191632531Sminshall netout = ring_full_count(&netoring) && 191738689Sborman (flushline || 191838689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 191938689Sborman #ifdef KLUDGELINEMODE 192038689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 192138689Sborman #endif 192238689Sborman ) || 192338689Sborman my_want_state_is_will(TELOPT_BINARY)); 192432531Sminshall ttyout = ring_full_count(&ttyoring); 192532531Sminshall 192632377Sminshall #if defined(TN3270) 192732531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 192832377Sminshall #else /* defined(TN3270) */ 192932531Sminshall ttyin = ring_empty_count(&ttyiring); 193032377Sminshall #endif /* defined(TN3270) */ 193132531Sminshall 193232531Sminshall #if defined(TN3270) 193332531Sminshall netin = ring_empty_count(&netiring); 193432377Sminshall # else /* !defined(TN3270) */ 193532531Sminshall netin = !ISend && ring_empty_count(&netiring); 193632377Sminshall # endif /* !defined(TN3270) */ 193732531Sminshall 193832531Sminshall netex = !SYNCHing; 193932531Sminshall 194032531Sminshall /* If we have seen a signal recently, reset things */ 194132377Sminshall # if defined(TN3270) && defined(unix) 194232377Sminshall if (HaveInput) { 194332377Sminshall HaveInput = 0; 1944*44360Sborman (void) signal(SIGIO, inputAvailable); 194532377Sminshall } 194632377Sminshall #endif /* defined(TN3270) && defined(unix) */ 194732377Sminshall 194832531Sminshall /* Call to system code to process rings */ 194927178Sminshall 195032531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 195127178Sminshall 195232531Sminshall /* Now, look at the input rings, looking for work to do. */ 195332377Sminshall 195432531Sminshall if (ring_full_count(&ttyiring)) { 195532377Sminshall # if defined(TN3270) 195632377Sminshall if (In3270) { 195734848Sminshall int c; 195834848Sminshall 195933804Sminshall c = DataFromTerminal(ttyiring.consume, 196032528Sminshall ring_full_consecutive(&ttyiring)); 196132377Sminshall if (c) { 196232377Sminshall returnValue = 1; 196332667Sminshall ring_consumed(&ttyiring, c); 196432377Sminshall } 196532377Sminshall } else { 196632377Sminshall # endif /* defined(TN3270) */ 196732554Sminshall returnValue |= telsnd(); 196832377Sminshall # if defined(TN3270) 196927178Sminshall } 197032531Sminshall # endif /* defined(TN3270) */ 197127178Sminshall } 197232377Sminshall 197332528Sminshall if (ring_full_count(&netiring)) { 197432377Sminshall # if !defined(TN3270) 197532385Sminshall returnValue |= telrcv(); 197632377Sminshall # else /* !defined(TN3270) */ 197732377Sminshall returnValue = Push3270(); 197832377Sminshall # endif /* !defined(TN3270) */ 197932377Sminshall } 198032377Sminshall return returnValue; 198127178Sminshall } 198227178Sminshall 198327178Sminshall /* 198432377Sminshall * Select from tty and network... 198527088Sminshall */ 198632377Sminshall void 198732377Sminshall telnet() 198827088Sminshall { 198932531Sminshall sys_telnet_init(); 199027088Sminshall 199132377Sminshall # if !defined(TN3270) 199232377Sminshall if (telnetport) { 199338689Sborman send_do(TELOPT_SGA, 1); 199438689Sborman send_will(TELOPT_TTYPE, 1); 199538689Sborman send_will(TELOPT_NAWS, 1); 199638689Sborman send_will(TELOPT_TSPEED, 1); 199738689Sborman send_will(TELOPT_LFLOW, 1); 199838689Sborman send_will(TELOPT_LINEMODE, 1); 199943319Skfall #ifdef KERBEROS 200043319Skfall if (kerberized) 200143319Skfall send_will(TELOPT_AUTHENTICATION, 1); 200243319Skfall #endif 200338908Sborman send_do(TELOPT_STATUS, 1); 2004*44360Sborman if (env_getvalue("DISPLAY")) 2005*44360Sborman send_will(TELOPT_XDISPLOC, 1); 2006*44360Sborman send_will(TELOPT_ENVIRON, 1); 200727178Sminshall } 200832377Sminshall # endif /* !defined(TN3270) */ 200927088Sminshall 201032377Sminshall # if !defined(TN3270) 201132377Sminshall for (;;) { 201232385Sminshall int schedValue; 201332385Sminshall 201432385Sminshall while ((schedValue = Scheduler(0)) != 0) { 201532385Sminshall if (schedValue == -1) { 201632385Sminshall setcommandmode(); 201732385Sminshall return; 201832385Sminshall } 201932385Sminshall } 202032385Sminshall 202132531Sminshall if (Scheduler(1) == -1) { 202232377Sminshall setcommandmode(); 202332377Sminshall return; 202432377Sminshall } 202532377Sminshall } 202632377Sminshall # else /* !defined(TN3270) */ 202732377Sminshall for (;;) { 202832377Sminshall int schedValue; 202927088Sminshall 203032377Sminshall while (!In3270 && !shell_active) { 203132531Sminshall if (Scheduler(1) == -1) { 203232377Sminshall setcommandmode(); 203332377Sminshall return; 203432377Sminshall } 203527088Sminshall } 203632377Sminshall 203732377Sminshall while ((schedValue = Scheduler(0)) != 0) { 203832377Sminshall if (schedValue == -1) { 203932377Sminshall setcommandmode(); 204032377Sminshall return; 204132377Sminshall } 204227088Sminshall } 204332377Sminshall /* If there is data waiting to go out to terminal, don't 204432377Sminshall * schedule any more data for the terminal. 204532377Sminshall */ 204634304Sminshall if (ring_full_count(&ttyoring)) { 204732377Sminshall schedValue = 1; 204827088Sminshall } else { 204932377Sminshall if (shell_active) { 205032377Sminshall if (shell_continue() == 0) { 205132377Sminshall ConnectScreen(); 205227088Sminshall } 205332377Sminshall } else if (In3270) { 205432377Sminshall schedValue = DoTerminalOutput(); 205532377Sminshall } 205627088Sminshall } 205732377Sminshall if (schedValue && (shell_active == 0)) { 205832531Sminshall if (Scheduler(1) == -1) { 205932377Sminshall setcommandmode(); 206032377Sminshall return; 206132377Sminshall } 206227088Sminshall } 206332377Sminshall } 206432377Sminshall # endif /* !defined(TN3270) */ 206527088Sminshall } 206632377Sminshall 206734848Sminshall #if 0 /* XXX - this not being in is a bug */ 206827088Sminshall /* 206932554Sminshall * nextitem() 207032554Sminshall * 207132554Sminshall * Return the address of the next "item" in the TELNET data 207232554Sminshall * stream. This will be the address of the next character if 207332554Sminshall * the current address is a user data character, or it will 207432554Sminshall * be the address of the character following the TELNET command 207532554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 207632554Sminshall * character. 207732554Sminshall */ 207832554Sminshall 207932554Sminshall static char * 208032554Sminshall nextitem(current) 208132554Sminshall char *current; 208232554Sminshall { 208332554Sminshall if ((*current&0xff) != IAC) { 208432554Sminshall return current+1; 208532554Sminshall } 208632554Sminshall switch (*(current+1)&0xff) { 208732554Sminshall case DO: 208832554Sminshall case DONT: 208932554Sminshall case WILL: 209032554Sminshall case WONT: 209132554Sminshall return current+3; 209232554Sminshall case SB: /* loop forever looking for the SE */ 209332554Sminshall { 209432554Sminshall register char *look = current+2; 209532554Sminshall 209632554Sminshall for (;;) { 209732554Sminshall if ((*look++&0xff) == IAC) { 209832554Sminshall if ((*look++&0xff) == SE) { 209932554Sminshall return look; 210032554Sminshall } 210132554Sminshall } 210232554Sminshall } 210332554Sminshall } 210432554Sminshall default: 210532554Sminshall return current+2; 210632554Sminshall } 210732554Sminshall } 210834848Sminshall #endif /* 0 */ 210932554Sminshall 211032554Sminshall /* 211132554Sminshall * netclear() 211232554Sminshall * 211332554Sminshall * We are about to do a TELNET SYNCH operation. Clear 211432554Sminshall * the path to the network. 211532554Sminshall * 211632554Sminshall * Things are a bit tricky since we may have sent the first 211732554Sminshall * byte or so of a previous TELNET command into the network. 211832554Sminshall * So, we have to scan the network buffer from the beginning 211932554Sminshall * until we are up to where we want to be. 212032554Sminshall * 212132554Sminshall * A side effect of what we do, just to keep things 212232554Sminshall * simple, is to clear the urgent data pointer. The principal 212332554Sminshall * caller should be setting the urgent data pointer AFTER calling 212432554Sminshall * us in any case. 212532554Sminshall */ 212632554Sminshall 212732554Sminshall static void 212832554Sminshall netclear() 212932554Sminshall { 213032554Sminshall #if 0 /* XXX */ 213132554Sminshall register char *thisitem, *next; 213232554Sminshall char *good; 213332554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 213432554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 213532554Sminshall 213632554Sminshall thisitem = netobuf; 213732554Sminshall 213832554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 213932554Sminshall thisitem = next; 214032554Sminshall } 214132554Sminshall 214232554Sminshall /* Now, thisitem is first before/at boundary. */ 214332554Sminshall 214432554Sminshall good = netobuf; /* where the good bytes go */ 214532554Sminshall 214632554Sminshall while (netoring.add > thisitem) { 214732554Sminshall if (wewant(thisitem)) { 214832554Sminshall int length; 214932554Sminshall 215032554Sminshall next = thisitem; 215132554Sminshall do { 215232554Sminshall next = nextitem(next); 215332554Sminshall } while (wewant(next) && (nfrontp > next)); 215432554Sminshall length = next-thisitem; 215532554Sminshall memcpy(good, thisitem, length); 215632554Sminshall good += length; 215732554Sminshall thisitem = next; 215832554Sminshall } else { 215932554Sminshall thisitem = nextitem(thisitem); 216032554Sminshall } 216132554Sminshall } 216232554Sminshall 216332554Sminshall #endif /* 0 */ 216432554Sminshall } 216532554Sminshall 216632554Sminshall /* 216732377Sminshall * These routines add various telnet commands to the data stream. 216827088Sminshall */ 216932377Sminshall 217032554Sminshall static void 217132554Sminshall doflush() 217232554Sminshall { 217332554Sminshall NET2ADD(IAC, DO); 217432554Sminshall NETADD(TELOPT_TM); 217532554Sminshall flushline = 1; 217632554Sminshall flushout = 1; 2177*44360Sborman (void) ttyflush(1); /* Flush/drop output */ 217832554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 217937226Sminshall printoption("SENT", "do", TELOPT_TM); 218032554Sminshall } 218132554Sminshall 218232377Sminshall void 218332377Sminshall xmitAO() 218427088Sminshall { 218532377Sminshall NET2ADD(IAC, AO); 218638908Sborman printoption("SENT", "IAC", AO); 218732377Sminshall if (autoflush) { 218832377Sminshall doflush(); 218932377Sminshall } 219032377Sminshall } 219127088Sminshall 219232377Sminshall 219332377Sminshall void 219432377Sminshall xmitEL() 219527088Sminshall { 219632377Sminshall NET2ADD(IAC, EL); 219738908Sborman printoption("SENT", "IAC", EL); 219827088Sminshall } 219927088Sminshall 220032377Sminshall void 220132377Sminshall xmitEC() 220227088Sminshall { 220332377Sminshall NET2ADD(IAC, EC); 220438908Sborman printoption("SENT", "IAC", EC); 220527088Sminshall } 220627088Sminshall 220732377Sminshall 220832377Sminshall #if defined(NOT43) 220932377Sminshall int 221032377Sminshall #else /* defined(NOT43) */ 221132377Sminshall void 221232377Sminshall #endif /* defined(NOT43) */ 221332377Sminshall dosynch() 221427088Sminshall { 221532377Sminshall netclear(); /* clear the path to the network */ 221633294Sminshall NETADD(IAC); 221733294Sminshall setneturg(); 221833294Sminshall NETADD(DM); 221938908Sborman printoption("SENT", "IAC", DM); 222027088Sminshall 222132377Sminshall #if defined(NOT43) 222232377Sminshall return 0; 222332377Sminshall #endif /* defined(NOT43) */ 222427088Sminshall } 222527088Sminshall 222632377Sminshall void 222738908Sborman get_status() 222838908Sborman { 222938908Sborman char tmp[16]; 223038908Sborman register char *cp; 223138908Sborman 223238908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 223338908Sborman printf("Remote side does not support STATUS option\n"); 223438908Sborman return; 223538908Sborman } 223638908Sborman if (!showoptions) 223738908Sborman printf("You will not see the response unless you set \"options\"\n"); 223838908Sborman 223938908Sborman cp = tmp; 224038908Sborman 224138908Sborman *cp++ = IAC; 224238908Sborman *cp++ = SB; 224338908Sborman *cp++ = TELOPT_STATUS; 224438908Sborman *cp++ = TELQUAL_SEND; 224538908Sborman *cp++ = IAC; 224638908Sborman *cp++ = SE; 224738908Sborman if (NETROOM() >= cp - tmp) { 224838908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 224938908Sborman printsub('>', tmp+2, cp - tmp - 2); 225038908Sborman } 225138908Sborman } 225238908Sborman 225338908Sborman void 225432377Sminshall intp() 225527088Sminshall { 225632377Sminshall NET2ADD(IAC, IP); 225738908Sborman printoption("SENT", "IAC", IP); 225832377Sminshall flushline = 1; 225932377Sminshall if (autoflush) { 226032377Sminshall doflush(); 226132377Sminshall } 226232377Sminshall if (autosynch) { 226332377Sminshall dosynch(); 226432377Sminshall } 226527088Sminshall } 226627186Sminshall 226732377Sminshall void 226832377Sminshall sendbrk() 226927186Sminshall { 227032377Sminshall NET2ADD(IAC, BREAK); 227138908Sborman printoption("SENT", "IAC", BREAK); 227232377Sminshall flushline = 1; 227332377Sminshall if (autoflush) { 227432377Sminshall doflush(); 227532377Sminshall } 227632377Sminshall if (autosynch) { 227732377Sminshall dosynch(); 227832377Sminshall } 227927186Sminshall } 228038689Sborman 228138689Sborman void 228238689Sborman sendabort() 228338689Sborman { 228438689Sborman NET2ADD(IAC, ABORT); 228538908Sborman printoption("SENT", "IAC", ABORT); 228638689Sborman flushline = 1; 228738689Sborman if (autoflush) { 228838689Sborman doflush(); 228938689Sborman } 229038689Sborman if (autosynch) { 229138689Sborman dosynch(); 229238689Sborman } 229338689Sborman } 229438689Sborman 229538689Sborman void 229638689Sborman sendsusp() 229738689Sborman { 229838689Sborman NET2ADD(IAC, SUSP); 229938908Sborman printoption("SENT", "IAC", SUSP); 230038689Sborman flushline = 1; 230138689Sborman if (autoflush) { 230238689Sborman doflush(); 230338689Sborman } 230438689Sborman if (autosynch) { 230538689Sborman dosynch(); 230638689Sborman } 230738689Sborman } 230838689Sborman 230938689Sborman void 231038689Sborman sendeof() 231138689Sborman { 231238908Sborman NET2ADD(IAC, xEOF); 231338908Sborman printoption("SENT", "IAC", xEOF); 231438689Sborman } 231538689Sborman 231637219Sminshall /* 231737219Sminshall * Send a window size update to the remote system. 231837219Sminshall */ 231937219Sminshall 232037219Sminshall void 232137219Sminshall sendnaws() 232237219Sminshall { 232337219Sminshall long rows, cols; 232438689Sborman unsigned char tmp[16]; 232538689Sborman register unsigned char *cp; 232637219Sminshall 232738689Sborman if (my_state_is_wont(TELOPT_NAWS)) 232838689Sborman return; 232937219Sminshall 233038689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 233138689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 233238689Sborman 233337219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 233437219Sminshall return; 233537219Sminshall } 233637219Sminshall 233738689Sborman cp = tmp; 233838689Sborman 233938689Sborman *cp++ = IAC; 234038689Sborman *cp++ = SB; 234138689Sborman *cp++ = TELOPT_NAWS; 234238689Sborman PUTSHORT(cp, cols); 234338689Sborman PUTSHORT(cp, rows); 234438689Sborman *cp++ = IAC; 234538689Sborman *cp++ = SE; 234638689Sborman if (NETROOM() >= cp - tmp) { 234738689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 234838689Sborman printsub('>', tmp+2, cp - tmp - 2); 234937219Sminshall } 235037219Sminshall } 235137226Sminshall 235238908Sborman tel_enter_binary(rw) 235338908Sborman int rw; 235437226Sminshall { 235538908Sborman if (rw&1) 235638908Sborman send_do(TELOPT_BINARY, 1); 235738908Sborman if (rw&2) 235838908Sborman send_will(TELOPT_BINARY, 1); 235937226Sminshall } 236037226Sminshall 236138908Sborman tel_leave_binary(rw) 236238908Sborman int rw; 236337226Sminshall { 236438908Sborman if (rw&1) 236538908Sborman send_dont(TELOPT_BINARY, 1); 236638908Sborman if (rw&2) 236738908Sborman send_wont(TELOPT_BINARY, 1); 236837226Sminshall } 2369