133685Sbostic /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 5*42770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 711758Ssam 821580Sdist #ifndef lint 9*42770Sbostic static char sccsid[] = "@(#)telnet.c 5.47 (Berkeley) 06/01/90"; 1033685Sbostic #endif /* not lint */ 1121580Sdist 129217Ssam #include <sys/types.h> 139217Ssam 1432377Sminshall #if defined(unix) 1533804Sminshall #include <signal.h> 1632377Sminshall /* By the way, we need to include curses.h before telnet.h since, 1732377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 1832377Sminshall * declared in curses.h. 1932377Sminshall */ 2032377Sminshall #endif /* defined(unix) */ 2132377Sminshall 2212212Ssam #include <arpa/telnet.h> 2332377Sminshall 2432377Sminshall #include <string.h> 259217Ssam 2638908Sborman #include <ctype.h> 2738908Sborman 2832381Sminshall #include "ring.h" 2932381Sminshall 3032377Sminshall #include "defines.h" 3132377Sminshall #include "externs.h" 3232377Sminshall #include "types.h" 3332377Sminshall #include "general.h" 3427178Sminshall 3527178Sminshall 3627228Sminshall #define strip(x) ((x)&0x7f) 376000Sroot 3827088Sminshall 3932377Sminshall static char subbuffer[SUBBUFSIZE], 4032377Sminshall *subpointer, *subend; /* buffer for sub-options */ 4127676Sminshall #define SB_CLEAR() subpointer = subbuffer; 4227676Sminshall #define SB_TERM() subend = subpointer; 4327676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4427676Sminshall *subpointer++ = (c); \ 4527676Sminshall } 4627676Sminshall 4737226Sminshall char options[256]; /* The combined options */ 4838689Sborman char do_dont_resp[256]; 4938689Sborman char will_wont_resp[256]; 506000Sroot 5132377Sminshall int 5232377Sminshall connected, 5332377Sminshall showoptions, 5432377Sminshall In3270, /* Are we in 3270 mode? */ 5532377Sminshall ISend, /* trying to send network data in */ 5632377Sminshall debug = 0, 5732377Sminshall crmod, 5832377Sminshall netdata, /* Print out network data flow */ 5932377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 6034848Sminshall #if defined(TN3270) 6136241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 6236241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 6332377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 6434848Sminshall #endif /* defined(TN3270) */ 6533286Sminshall telnetport, 6632531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 6732531Sminshall flushout, /* flush output */ 6832531Sminshall autoflush = 0, /* flush output when interrupting? */ 6932531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 7037219Sminshall localflow, /* we handle flow control locally */ 7132531Sminshall localchars, /* we recognize interrupt/quit */ 7232531Sminshall donelclchars, /* the user has set "localchars" */ 7332531Sminshall donebinarytoggle, /* the user has put us in binary */ 7432531Sminshall dontlecho, /* do we suppress local echoing right now? */ 7532531Sminshall globalmode; 7627088Sminshall 7732377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 786000Sroot 7940245Sborman unsigned char *prompt = 0; 8027186Sminshall 8140245Sborman cc_t escape, echoc; 8240245Sborman 8327186Sminshall /* 846000Sroot * Telnet receiver states for fsm 856000Sroot */ 866000Sroot #define TS_DATA 0 876000Sroot #define TS_IAC 1 886000Sroot #define TS_WILL 2 896000Sroot #define TS_WONT 3 906000Sroot #define TS_DO 4 916000Sroot #define TS_DONT 5 9227021Sminshall #define TS_CR 6 9327676Sminshall #define TS_SB 7 /* sub-option collection */ 9427676Sminshall #define TS_SE 8 /* looking for sub-option end */ 956000Sroot 9632377Sminshall static int telrcv_state; 976000Sroot 9832377Sminshall jmp_buf toplevel = { 0 }; 9932377Sminshall jmp_buf peerdied; 1006000Sroot 10132377Sminshall int flushline; 10238811Sborman int linemode; 10327021Sminshall 10438689Sborman #ifdef KLUDGELINEMODE 10538689Sborman int kludgelinemode = 1; 10638689Sborman #endif 10738689Sborman 10832377Sminshall /* 10932377Sminshall * The following are some clocks used to decide how to interpret 11032377Sminshall * the relationship between various variables. 11132377Sminshall */ 1126000Sroot 11332377Sminshall Clocks clocks; 11432377Sminshall 11538689Sborman #ifdef notdef 11632377Sminshall Modelist modelist[] = { 11732377Sminshall { "telnet command mode", COMMAND_LINE }, 11832377Sminshall { "character-at-a-time mode", 0 }, 11932377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 12032377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 12132377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 12232377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 12332377Sminshall { "3270 mode", 0 }, 12432377Sminshall }; 12538689Sborman #endif 1266000Sroot 12732377Sminshall 12832377Sminshall /* 12932377Sminshall * Initialize telnet environment. 13032377Sminshall */ 1316000Sroot 13232377Sminshall init_telnet() 13332377Sminshall { 13432377Sminshall SB_CLEAR(); 13537226Sminshall ClearArray(options); 1366000Sroot 13737219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 1386000Sroot 13932377Sminshall SYNCHing = 0; 1406000Sroot 14132377Sminshall /* Don't change NetTrace */ 1426000Sroot 14332377Sminshall escape = CONTROL(']'); 14432377Sminshall echoc = CONTROL('E'); 1456000Sroot 14632377Sminshall flushline = 1; 14732377Sminshall telrcv_state = TS_DATA; 14832377Sminshall } 14932554Sminshall 1506000Sroot 15132554Sminshall #include <varargs.h> 1526000Sroot 15334848Sminshall /*VARARGS*/ 15432554Sminshall static void 15532554Sminshall printring(va_alist) 15632554Sminshall va_dcl 15732554Sminshall { 15832554Sminshall va_list ap; 15932554Sminshall char buffer[100]; /* where things go */ 16032554Sminshall char *ptr; 16132554Sminshall char *format; 16232554Sminshall char *string; 16332554Sminshall Ring *ring; 16432554Sminshall int i; 16532554Sminshall 16632554Sminshall va_start(ap); 16732554Sminshall 16832554Sminshall ring = va_arg(ap, Ring *); 16932554Sminshall format = va_arg(ap, char *); 17032554Sminshall ptr = buffer; 17132554Sminshall 17232554Sminshall while ((i = *format++) != 0) { 17332554Sminshall if (i == '%') { 17432554Sminshall i = *format++; 17532554Sminshall switch (i) { 17632554Sminshall case 'c': 17732554Sminshall *ptr++ = va_arg(ap, int); 17832554Sminshall break; 17932554Sminshall case 's': 18032554Sminshall string = va_arg(ap, char *); 18132554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 18232554Sminshall ring_supply_data(ring, string, strlen(string)); 18332554Sminshall ptr = buffer; 18432554Sminshall break; 18532554Sminshall case 0: 18632554Sminshall ExitString("printring: trailing %%.\n", 1); 18732554Sminshall /*NOTREACHED*/ 18832554Sminshall default: 18932554Sminshall ExitString("printring: unknown format character.\n", 1); 19032554Sminshall /*NOTREACHED*/ 19132554Sminshall } 19232554Sminshall } else { 19332554Sminshall *ptr++ = i; 19432554Sminshall } 19532554Sminshall } 19632554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19732554Sminshall } 19832554Sminshall 19937226Sminshall /* 20037226Sminshall * These routines are in charge of sending option negotiations 20137226Sminshall * to the other side. 20237226Sminshall * 20337226Sminshall * The basic idea is that we send the negotiation if either side 20437226Sminshall * is in disagreement as to what the current state should be. 20537226Sminshall */ 20632554Sminshall 20738689Sborman send_do(c, init) 20838689Sborman register int c, init; 2096000Sroot { 21038689Sborman if (init) { 21138689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 21238689Sborman my_want_state_is_do(c)) 21338689Sborman return; 21438689Sborman set_my_want_state_do(c); 21538689Sborman do_dont_resp[c]++; 21637226Sminshall } 21738689Sborman NET2ADD(IAC, DO); 21838689Sborman NETADD(c); 21938689Sborman printoption("SENT", "do", c); 22037226Sminshall } 22137226Sminshall 22237226Sminshall void 22338689Sborman send_dont(c, init) 22438689Sborman register int c, init; 22537226Sminshall { 22638689Sborman if (init) { 22738689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 22838689Sborman my_want_state_is_dont(c)) 22938689Sborman return; 23038689Sborman set_my_want_state_dont(c); 23138689Sborman do_dont_resp[c]++; 23237226Sminshall } 23338689Sborman NET2ADD(IAC, DONT); 23438689Sborman NETADD(c); 23538689Sborman printoption("SENT", "dont", c); 23637226Sminshall } 23737226Sminshall 23837226Sminshall void 23938689Sborman send_will(c, init) 24038689Sborman register int c, init; 24137226Sminshall { 24238689Sborman if (init) { 24338689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 24438689Sborman my_want_state_is_will(c)) 24538689Sborman return; 24638689Sborman set_my_want_state_will(c); 24738689Sborman will_wont_resp[c]++; 24837226Sminshall } 24938689Sborman NET2ADD(IAC, WILL); 25038689Sborman NETADD(c); 25138689Sborman printoption("SENT", "will", c); 25237226Sminshall } 25337226Sminshall 25437226Sminshall void 25538689Sborman send_wont(c, init) 25638689Sborman register int c, init; 25737226Sminshall { 25838689Sborman if (init) { 25938689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 26038689Sborman my_want_state_is_wont(c)) 26138689Sborman return; 26238689Sborman set_my_want_state_wont(c); 26338689Sborman will_wont_resp[c]++; 26437226Sminshall } 26538689Sborman NET2ADD(IAC, WONT); 26638689Sborman NETADD(c); 26738689Sborman printoption("SENT", "wont", c); 26837226Sminshall } 26937226Sminshall 27037226Sminshall 27137226Sminshall void 27237226Sminshall willoption(option) 27337226Sminshall int option; 27437226Sminshall { 2756000Sroot char *fmt; 27638689Sborman int new_state_ok = 0; 2776000Sroot 27838689Sborman if (do_dont_resp[option]) { 27938689Sborman --do_dont_resp[option]; 28038689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 28138689Sborman --do_dont_resp[option]; 28238689Sborman } 28337226Sminshall 28438689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 2856000Sroot 28638689Sborman switch (option) { 28738689Sborman 28838689Sborman case TELOPT_ECHO: 28938689Sborman # if defined(TN3270) 29038689Sborman /* 29138689Sborman * The following is a pain in the rear-end. 29238689Sborman * Various IBM servers (some versions of Wiscnet, 29338689Sborman * possibly Fibronics/Spartacus, and who knows who 29438689Sborman * else) will NOT allow us to send "DO SGA" too early 29538689Sborman * in the setup proceedings. On the other hand, 29638689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 29738689Sborman * So, we are stuck. Empirically (but, based on 29838689Sborman * a VERY small sample), the IBM servers don't send 29938689Sborman * out anything about ECHO, so we postpone our sending 30038689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 30138689Sborman * DO send). 30238689Sborman */ 30338689Sborman { 30438689Sborman if (askedSGA == 0) { 30538689Sborman askedSGA = 1; 30638689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 30738689Sborman send_do(TELOPT_SGA, 1); 30832377Sminshall } 30932377Sminshall } 31038689Sborman /* Fall through */ 31138689Sborman case TELOPT_EOR: 31238908Sborman #endif /* defined(TN3270) */ 31338689Sborman case TELOPT_BINARY: 31438689Sborman case TELOPT_SGA: 31527110Sminshall settimer(modenegotiated); 31638908Sborman /* FALL THROUGH */ 31738908Sborman case TELOPT_STATUS: 31838689Sborman new_state_ok = 1; 3196000Sroot break; 3206000Sroot 32138689Sborman case TELOPT_TM: 32238689Sborman if (flushout) 32338689Sborman flushout = 0; 32438689Sborman /* 32538689Sborman * Special case for TM. If we get back a WILL, 32638689Sborman * pretend we got back a WONT. 32738689Sborman */ 32838689Sborman set_my_want_state_dont(option); 32938689Sborman set_my_state_dont(option); 33027110Sminshall return; /* Never reply to TM will's/wont's */ 3316000Sroot 33238689Sborman case TELOPT_LINEMODE: 33338689Sborman default: 3346000Sroot break; 33538689Sborman } 33638689Sborman 33738689Sborman if (new_state_ok) { 33838689Sborman set_my_want_state_do(option); 33938689Sborman send_do(option, 0); 34038689Sborman setconnmode(0); /* possibly set new tty mode */ 34138689Sborman } else { 34238689Sborman do_dont_resp[option]++; 34338689Sborman send_dont(option, 0); 34438689Sborman } 3456000Sroot } 34638689Sborman set_my_state_do(option); 3476000Sroot } 3486000Sroot 34932377Sminshall void 35037226Sminshall wontoption(option) 35137226Sminshall int option; 3526000Sroot { 3536000Sroot char *fmt; 3546000Sroot 35538689Sborman if (do_dont_resp[option]) { 35638689Sborman --do_dont_resp[option]; 35738689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 35838689Sborman --do_dont_resp[option]; 35938689Sborman } 36037226Sminshall 36138689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3626000Sroot 36338689Sborman switch (option) { 36438689Sborman 36538689Sborman #ifdef KLUDGELINEMODE 36638689Sborman case TELOPT_SGA: 36738689Sborman if (!kludgelinemode) 36838689Sborman break; 36938689Sborman /* FALL THROUGH */ 37038689Sborman #endif 37138689Sborman case TELOPT_ECHO: 37227110Sminshall settimer(modenegotiated); 3736000Sroot break; 3746000Sroot 37538689Sborman case TELOPT_TM: 37638689Sborman if (flushout) 37738689Sborman flushout = 0; 37838689Sborman set_my_want_state_dont(option); 37938689Sborman set_my_state_dont(option); 38027110Sminshall return; /* Never reply to TM will's/wont's */ 38127110Sminshall 38238689Sborman default: 38338689Sborman break; 38438689Sborman } 38538689Sborman set_my_want_state_dont(option); 38638689Sborman send_dont(option, 0); 38738689Sborman setconnmode(0); /* Set new tty mode */ 38838689Sborman } else if (option == TELOPT_TM) { 38938689Sborman /* 39038689Sborman * Special case for TM. 39138689Sborman */ 39238689Sborman if (flushout) 39338689Sborman flushout = 0; 39438689Sborman set_my_want_state_dont(option); 3956000Sroot } 39638689Sborman set_my_state_dont(option); 3976000Sroot } 3986000Sroot 39932377Sminshall static void 4006000Sroot dooption(option) 4016000Sroot int option; 4026000Sroot { 4036000Sroot char *fmt; 40438689Sborman int new_state_ok = 0; 4056000Sroot 40638689Sborman if (will_wont_resp[option]) { 40738689Sborman --will_wont_resp[option]; 40838689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 40938689Sborman --will_wont_resp[option]; 41038689Sborman } 41137226Sminshall 41238689Sborman if (will_wont_resp[option] == 0) { 41338689Sborman if (my_want_state_is_wont(option)) { 4146000Sroot 41538689Sborman switch (option) { 41638689Sborman 41738689Sborman case TELOPT_TM: 41838689Sborman /* 41938689Sborman * Special case for TM. We send a WILL, but pretend 42038689Sborman * we sent WONT. 42138689Sborman */ 42238689Sborman send_will(option, 0); 42338689Sborman set_my_want_state_wont(TELOPT_TM); 42438689Sborman set_my_state_wont(TELOPT_TM); 42538689Sborman return; 42638689Sborman 42732377Sminshall # if defined(TN3270) 42838689Sborman case TELOPT_EOR: /* end of record */ 42938908Sborman # endif /* defined(TN3270) */ 43038689Sborman case TELOPT_BINARY: /* binary mode */ 43138689Sborman case TELOPT_NAWS: /* window size */ 43238689Sborman case TELOPT_TSPEED: /* terminal speed */ 43338689Sborman case TELOPT_LFLOW: /* local flow control */ 43438689Sborman case TELOPT_TTYPE: /* terminal type option */ 43538689Sborman case TELOPT_SGA: /* no big deal */ 43638689Sborman new_state_ok = 1; 4376000Sroot break; 4386000Sroot 43938689Sborman case TELOPT_LINEMODE: 44038689Sborman #ifdef KLUDGELINEMODE 44138689Sborman kludgelinemode = 0; 44238689Sborman #endif 44338689Sborman set_my_want_state_will(TELOPT_LINEMODE); 44438689Sborman send_will(option, 0); 44538689Sborman set_my_state_will(TELOPT_LINEMODE); 44638689Sborman slc_init(); 44738689Sborman return; 44838689Sborman 44938689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 45038689Sborman default: 4516000Sroot break; 45238689Sborman } 45338689Sborman 45438689Sborman if (new_state_ok) { 45538689Sborman set_my_want_state_will(option); 45638689Sborman send_will(option, 0); 45738689Sborman } else { 45838689Sborman will_wont_resp[option]++; 45938689Sborman send_wont(option, 0); 46038689Sborman } 46138689Sborman } else { 46238689Sborman /* 46338689Sborman * Handle options that need more things done after the 46438689Sborman * other side has acknowledged the option. 46538689Sborman */ 46638689Sborman switch (option) { 46738689Sborman case TELOPT_LINEMODE: 46838689Sborman #ifdef KLUDGELINEMODE 46938689Sborman kludgelinemode = 0; 47038689Sborman #endif 47138689Sborman set_my_state_will(option); 47238689Sborman slc_init(); 47338689Sborman return; 47438689Sborman } 47538689Sborman } 4766000Sroot } 47738689Sborman set_my_state_will(option); 4786000Sroot } 47927676Sminshall 48038689Sborman static void 48138689Sborman dontoption(option) 48238689Sborman int option; 48338689Sborman { 48438689Sborman 48538689Sborman if (will_wont_resp[option]) { 48638689Sborman --will_wont_resp[option]; 48738689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 48838689Sborman --will_wont_resp[option]; 48938689Sborman } 49038689Sborman 49138689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 49238811Sborman switch (option) { 49338811Sborman case TELOPT_LINEMODE: 49438811Sborman linemode = 0; /* put us back to the default state */ 49538811Sborman break; 49638811Sborman } 49738689Sborman /* we always accept a DONT */ 49838689Sborman set_my_want_state_wont(option); 49938689Sborman send_wont(option, 0); 50039529Sborman setconnmode(0); /* Set new tty mode */ 50138689Sborman } 50238689Sborman set_my_state_wont(option); 50338689Sborman } 50438689Sborman 50527676Sminshall /* 50638908Sborman * Given a buffer returned by tgetent(), this routine will turn 50738908Sborman * the pipe seperated list of names in the buffer into an array 50838908Sborman * of pointers to null terminated names. We toss out any bad, 50938908Sborman * duplicate, or verbose names (names with spaces). 51038908Sborman */ 51138908Sborman 51238908Sborman static char *unknown[] = { "UNKNOWN", 0 }; 51338908Sborman 51438908Sborman char ** 51538908Sborman mklist(buf, name) 51638908Sborman char *buf, *name; 51738908Sborman { 51838908Sborman register int n; 51938908Sborman register char c, *cp, **argvp, *cp2, **argv; 52038908Sborman char *malloc(); 52138908Sborman 52238908Sborman if (name) { 52338908Sborman if (strlen(name) > 40) 52438908Sborman name = 0; 52538908Sborman else { 52638908Sborman unknown[0] = name; 52738908Sborman upcase(name); 52838908Sborman } 52938908Sborman } 53038908Sborman /* 53138908Sborman * Count up the number of names. 53238908Sborman */ 53338908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 53438908Sborman if (*cp == '|') 53538908Sborman n++; 53638908Sborman } 53738908Sborman /* 53838908Sborman * Allocate an array to put the name pointers into 53938908Sborman */ 54038908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 54138908Sborman if (argv == 0) 54238908Sborman return(unknown); 54338908Sborman 54438908Sborman /* 54538908Sborman * Fill up the array of pointers to names. 54638908Sborman */ 54738908Sborman *argv = 0; 54838908Sborman argvp = argv+1; 54938908Sborman n = 0; 55038908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 55138908Sborman if (c == '|' || c == ':') { 55238908Sborman *cp++ = '\0'; 55338908Sborman /* 55438908Sborman * Skip entries that have spaces or are over 40 55538908Sborman * characters long. If this is our environment 55638908Sborman * name, then put it up front. Otherwise, as 55738908Sborman * long as this is not a duplicate name (case 55838908Sborman * insensitive) add it to the list. 55938908Sborman */ 56038908Sborman if (n || (cp - cp2 > 41)) 56138908Sborman ; 56238908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 56338908Sborman *argv = cp2; 56438908Sborman else if (is_unique(cp2, argv+1, argvp)) 56538908Sborman *argvp++ = cp2; 56638908Sborman if (c == ':') 56738908Sborman break; 56838908Sborman /* 56938908Sborman * Skip multiple delimiters. Reset cp2 to 57038908Sborman * the beginning of the next name. Reset n, 57138908Sborman * the flag for names with spaces. 57238908Sborman */ 57338908Sborman while ((c = *cp) == '|') 57438908Sborman cp++; 57538908Sborman cp2 = cp; 57638908Sborman n = 0; 57738908Sborman } 57838908Sborman /* 57938908Sborman * Skip entries with spaces or non-ascii values. 58038908Sborman * Convert lower case letters to upper case. 58138908Sborman */ 58238908Sborman if ((c == ' ') || !isascii(c)) 58338908Sborman n = 1; 58438908Sborman else if (islower(c)) 58538908Sborman *cp = toupper(c); 58638908Sborman } 58738908Sborman 58838908Sborman /* 58938908Sborman * Check for an old V6 2 character name. If the second 59038908Sborman * name points to the beginning of the buffer, and is 59138908Sborman * only 2 characters long, move it to the end of the array. 59238908Sborman */ 59338908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 59438908Sborman *argvp++ = buf; 59538908Sborman cp = *argv++; 59638908Sborman *argv = cp; 59738908Sborman } 59838908Sborman 59938908Sborman /* 60038908Sborman * Duplicate last name, for TTYPE option, and null 60138908Sborman * terminate the array. If we didn't find a match on 60238908Sborman * our terminal name, put that name at the beginning. 60338908Sborman */ 60438908Sborman cp = *(argvp-1); 60538908Sborman *argvp++ = cp; 60638908Sborman *argvp = 0; 60738908Sborman 60838908Sborman if (*argv == 0) { 60938908Sborman if (name) 61038908Sborman *argv = name; 61138908Sborman else 61238908Sborman argv++; 61338908Sborman } 61438908Sborman if (*argv) 61538908Sborman return(argv); 61638908Sborman else 61738908Sborman return(unknown); 61838908Sborman } 61938908Sborman 62038908Sborman is_unique(name, as, ae) 62138908Sborman register char *name, **as, **ae; 62238908Sborman { 62338908Sborman register char **ap; 62438908Sborman register int n; 62538908Sborman 62638908Sborman n = strlen(name) + 1; 62738908Sborman for (ap = as; ap < ae; ap++) 62838908Sborman if (strncasecmp(*ap, name, n) == 0) 62938908Sborman return(0); 63038908Sborman return (1); 63138908Sborman } 63238908Sborman 63338908Sborman #ifdef TERMCAP 63439529Sborman char termbuf[1024]; 63538908Sborman setupterm(tname, fd, errp) 63638908Sborman char *tname; 63738908Sborman int fd, *errp; 63838908Sborman { 63939529Sborman if (tgetent(termbuf, tname) == 1) { 64039529Sborman termbuf[1023] = '\0'; 64138908Sborman if (errp) 64238908Sborman *errp = 1; 64338908Sborman return(0); 64438908Sborman } 64538908Sborman if (errp) 64638908Sborman *errp = 0; 64738908Sborman return(-1); 64838908Sborman } 64939529Sborman #else 65039529Sborman #define termbuf ttytype 65139529Sborman extern char ttytype[]; 65238908Sborman #endif 65338908Sborman 65438908Sborman char * 65538908Sborman gettermname() 65638908Sborman { 65738908Sborman char *tname; 65838908Sborman static int first = 1; 65938908Sborman static char **tnamep; 66038908Sborman static char **next; 66138908Sborman char *getenv(); 66238908Sborman int err; 66338908Sborman 66438908Sborman if (first) { 66538908Sborman first = 0; 66638908Sborman if ((tname = getenv("TERM")) && 66738908Sborman (setupterm(tname, 1, &err) == 0)) { 66839529Sborman tnamep = mklist(termbuf, tname); 66938908Sborman } else { 67038908Sborman if (tname && (strlen(tname) <= 40)) { 67138908Sborman unknown[0] = tname; 67238908Sborman upcase(tname); 67338908Sborman } 67438908Sborman tnamep = unknown; 67538908Sborman } 67638908Sborman next = tnamep; 67738908Sborman } 67838908Sborman if (*next == 0) 67938908Sborman next = tnamep; 68038908Sborman return(*next++); 68138908Sborman } 68238908Sborman /* 68327676Sminshall * suboption() 68427676Sminshall * 68527676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 68627676Sminshall * side. 68727676Sminshall * 68827676Sminshall * Currently we recognize: 68927676Sminshall * 69027676Sminshall * Terminal type, send request. 69137219Sminshall * Terminal speed (send request). 69237219Sminshall * Local flow control (is request). 69338689Sborman * Linemode 69427676Sminshall */ 69527676Sminshall 69632377Sminshall static void 69727676Sminshall suboption() 69827676Sminshall { 69938689Sborman printsub('<', subbuffer, subend-subbuffer+2); 70027676Sminshall switch (subbuffer[0]&0xff) { 70127676Sminshall case TELOPT_TTYPE: 70238689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 70338689Sborman return; 70427676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 70527676Sminshall ; 70627676Sminshall } else { 70727676Sminshall char *name; 70832377Sminshall extern char *getenv(); 70938908Sborman char temp[50]; 71027676Sminshall int len; 71127676Sminshall 71232377Sminshall #if defined(TN3270) 71332531Sminshall if (tn3270_ttype()) { 71432377Sminshall return; 71532377Sminshall } 71632377Sminshall #endif /* defined(TN3270) */ 71738908Sborman name = gettermname(); 71838908Sborman len = strlen(name) + 4 + 2; 71938908Sborman if (len < NETROOM()) { 72038908Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 72138908Sborman TELQUAL_IS, name, IAC, SE); 72238689Sborman ring_supply_data(&netoring, temp, len); 72338908Sborman printsub('>', &temp[2], len-2); 72432377Sminshall } else { 72537226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 72632377Sminshall /*NOTREACHED*/ 72727676Sminshall } 72827676Sminshall } 72937219Sminshall break; 73037219Sminshall case TELOPT_TSPEED: 73138689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 73238689Sborman return; 73337219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 73438689Sborman long ospeed,ispeed; 73538689Sborman char temp[50]; 73637219Sminshall int len; 73727676Sminshall 73837219Sminshall TerminalSpeeds(&ispeed, &ospeed); 73937219Sminshall 74038689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 74138689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 74238689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 74337219Sminshall 74438689Sborman if (len < NETROOM()) { 74538689Sborman ring_supply_data(&netoring, temp, len); 74638689Sborman printsub('>', temp+2, len - 2); 74737219Sminshall } 74837219Sminshall } 74937219Sminshall break; 75037219Sminshall case TELOPT_LFLOW: 75138689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 75238689Sborman return; 75337219Sminshall if ((subbuffer[1]&0xff) == 1) { 75437219Sminshall localflow = 1; 75537219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 75637219Sminshall localflow = 0; 75737219Sminshall } 75837219Sminshall setcommandmode(); 75938689Sborman setconnmode(0); 76037219Sminshall break; 76138689Sborman 76238689Sborman case TELOPT_LINEMODE: 76338689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 76438689Sborman return; 76538689Sborman switch (subbuffer[1]&0xff) { 76638689Sborman case WILL: 76738689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 76838689Sborman break; 76938689Sborman case WONT: 77038689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 77138689Sborman break; 77238689Sborman case DO: 77338689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 77438689Sborman break; 77538689Sborman case DONT: 77638689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 77738689Sborman break; 77838689Sborman case LM_SLC: 77938689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 78038689Sborman break; 78138689Sborman case LM_MODE: 78238689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 78338689Sborman break; 78438689Sborman default: 78538689Sborman break; 78638689Sborman } 78738689Sborman break; 78827676Sminshall default: 78927676Sminshall break; 79027676Sminshall } 79127676Sminshall } 79238689Sborman 79338689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 79438689Sborman 79538689Sborman lm_will(cmd, len) 79638689Sborman char *cmd; 79738689Sborman { 79838689Sborman switch(cmd[0]) { 79938689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 80038689Sborman default: 80138689Sborman str_lm[3] = DONT; 80238689Sborman str_lm[4] = cmd[0]; 80338689Sborman if (NETROOM() > sizeof(str_lm)) { 80438689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 80538689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 80638689Sborman } 80738689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 80838689Sborman break; 80938689Sborman } 81038689Sborman } 81138689Sborman 81238689Sborman lm_wont(cmd, len) 81338689Sborman char *cmd; 81438689Sborman { 81538689Sborman switch(cmd[0]) { 81638689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 81738689Sborman default: 81838689Sborman /* We are always DONT, so don't respond */ 81938689Sborman return; 82038689Sborman } 82138689Sborman } 82238689Sborman 82338689Sborman lm_do(cmd, len) 82438689Sborman char *cmd; 82538689Sborman { 82638689Sborman switch(cmd[0]) { 82738689Sborman case LM_FORWARDMASK: 82838689Sborman default: 82938689Sborman str_lm[3] = WONT; 83038689Sborman str_lm[4] = cmd[0]; 83138689Sborman if (NETROOM() > sizeof(str_lm)) { 83238689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 83338689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 83438689Sborman } 83538689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 83638689Sborman break; 83738689Sborman } 83838689Sborman } 83938689Sborman 84038689Sborman lm_dont(cmd, len) 84138689Sborman char *cmd; 84238689Sborman { 84338689Sborman switch(cmd[0]) { 84438689Sborman case LM_FORWARDMASK: 84538689Sborman default: 84638689Sborman /* we are always WONT, so don't respond */ 84738689Sborman break; 84838689Sborman } 84938689Sborman } 85038689Sborman 85138689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 85238689Sborman 85338689Sborman lm_mode(cmd, len, init) 85438689Sborman char *cmd; 85538689Sborman int len, init; 85638689Sborman { 85738689Sborman if (len != 1) 85838689Sborman return; 85938689Sborman if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd) 86038689Sborman return; 86138689Sborman if (*cmd&MODE_ACK) 86238689Sborman return; 86338689Sborman linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG)); 86438689Sborman str_lm_mode[4] = linemode; 86538689Sborman if (!init) 86638689Sborman str_lm_mode[4] |= MODE_ACK; 86738689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 86838689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 86938689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 87038689Sborman } 87138689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 87238689Sborman setconnmode(0); /* set changed mode */ 87338689Sborman } 87438689Sborman 87532377Sminshall 87627088Sminshall 87738689Sborman /* 87838689Sborman * slc() 87938689Sborman * Handle special character suboption of LINEMODE. 88038689Sborman */ 88138689Sborman 88238689Sborman struct spc { 88340245Sborman cc_t val; 88440245Sborman cc_t *valp; 88538689Sborman char flags; /* Current flags & level */ 88638689Sborman char mylevel; /* Maximum level & flags */ 88738689Sborman } spc_data[NSLC+1]; 88838689Sborman 88938689Sborman #define SLC_IMPORT 0 89038689Sborman #define SLC_EXPORT 1 89138689Sborman #define SLC_RVALUE 2 89238689Sborman static int slc_mode = SLC_EXPORT; 89338689Sborman 89438689Sborman slc_init() 89538689Sborman { 89638689Sborman register struct spc *spcp; 89740245Sborman extern cc_t *tcval(); 89838689Sborman 89938689Sborman localchars = 1; 90038689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 90138689Sborman spcp->val = 0; 90238689Sborman spcp->valp = 0; 90338689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 90438689Sborman } 90538689Sborman 90638689Sborman #define initfunc(func, flags) { \ 90738689Sborman spcp = &spc_data[func]; \ 90838689Sborman if (spcp->valp = tcval(func)) { \ 90938689Sborman spcp->val = *spcp->valp; \ 91038689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 91138689Sborman } else { \ 91238689Sborman spcp->val = 0; \ 91338689Sborman spcp->mylevel = SLC_DEFAULT; \ 91438689Sborman } \ 91538689Sborman } 91638689Sborman 91738689Sborman initfunc(SLC_SYNCH, 0); 91838689Sborman /* No BRK */ 91938689Sborman initfunc(SLC_AO, 0); 92038689Sborman initfunc(SLC_AYT, 0); 92138689Sborman /* No EOR */ 92238689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 92338689Sborman initfunc(SLC_EOF, 0); 92439529Sborman #ifndef SYSV_TERMIO 92538689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 92638689Sborman #endif 92738689Sborman initfunc(SLC_EC, 0); 92838689Sborman initfunc(SLC_EL, 0); 92939529Sborman #ifndef SYSV_TERMIO 93038689Sborman initfunc(SLC_EW, 0); 93138689Sborman initfunc(SLC_RP, 0); 93238689Sborman initfunc(SLC_LNEXT, 0); 93338689Sborman #endif 93438689Sborman initfunc(SLC_XON, 0); 93538689Sborman initfunc(SLC_XOFF, 0); 93639529Sborman #ifdef SYSV_TERMIO 93738689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 93838689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 93938689Sborman #endif 94038689Sborman /* No FORW1 */ 94138689Sborman /* No FORW2 */ 94238689Sborman 94338689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 94438689Sborman #undef initfunc 94538689Sborman 94638689Sborman if (slc_mode == SLC_EXPORT) 94738689Sborman slc_export(); 94838689Sborman else 94938689Sborman slc_import(1); 95038689Sborman 95138689Sborman } 95238689Sborman 95338689Sborman slcstate() 95438689Sborman { 95538689Sborman printf("Special characters are %s values\n", 95638689Sborman slc_mode == SLC_IMPORT ? "remote default" : 95738689Sborman slc_mode == SLC_EXPORT ? "local" : 95838689Sborman "remote"); 95938689Sborman } 96038689Sborman 96138689Sborman slc_mode_export() 96238689Sborman { 96338689Sborman slc_mode = SLC_EXPORT; 96438689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 96538689Sborman slc_export(); 96638689Sborman } 96738689Sborman 96838689Sborman slc_mode_import(def) 96938689Sborman { 97038689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 97138689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 97238689Sborman slc_import(def); 97338689Sborman } 97438689Sborman 97538689Sborman char slc_import_val[] = { 97638689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 97738689Sborman }; 97838689Sborman char slc_import_def[] = { 97938689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 98038689Sborman }; 98138689Sborman 98238689Sborman slc_import(def) 98338689Sborman int def; 98438689Sborman { 98538689Sborman if (NETROOM() > sizeof(slc_import_val)) { 98638689Sborman if (def) { 98738689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 98838689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 98938689Sborman } else { 99038689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 99138689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 99238689Sborman } 99338689Sborman } 99438689Sborman /*@*/ else printf("slc_import: not enough room\n"); 99538689Sborman } 99638689Sborman 99738689Sborman slc_export() 99838689Sborman { 99938689Sborman register struct spc *spcp; 100038689Sborman 100138689Sborman TerminalDefaultChars(); 100238689Sborman 100338689Sborman slc_start_reply(); 100438689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 100538689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 100638689Sborman spcp->flags = spcp->mylevel; 100738689Sborman if (spcp->valp) 100838689Sborman spcp->val = *spcp->valp; 100938689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 101038689Sborman } 101138689Sborman } 101238689Sborman slc_end_reply(); 101338689Sborman if (slc_update()) 101438689Sborman setconnmode(1); /* set the new character values */ 101538689Sborman } 101638689Sborman 101738689Sborman slc(cp, len) 101838689Sborman register char *cp; 101938689Sborman int len; 102038689Sborman { 102138689Sborman register struct spc *spcp; 102238689Sborman register int func,level; 102338689Sborman 102438689Sborman slc_start_reply(); 102538689Sborman 102638689Sborman for (; len >= 3; len -=3, cp +=3) { 102738689Sborman 102838689Sborman func = cp[SLC_FUNC]; 102938689Sborman 103038689Sborman if (func == 0) { 103138689Sborman /* 103238689Sborman * Client side: always ignore 0 function. 103338689Sborman */ 103438689Sborman continue; 103538689Sborman } 103638689Sborman if (func > NSLC) { 103738689Sborman if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) 103838689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 103938689Sborman continue; 104038689Sborman } 104138689Sborman 104238689Sborman spcp = &spc_data[func]; 104338689Sborman 104438689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 104538689Sborman 104640245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 104738689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 104838689Sborman continue; 104938689Sborman } 105038689Sborman 105138689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 105238689Sborman /* 105338689Sborman * This is an error condition, the SLC_ACK 105438689Sborman * bit should never be set for the SLC_DEFAULT 105538689Sborman * level. Our best guess to recover is to 105638689Sborman * ignore the SLC_ACK bit. 105738689Sborman */ 105838689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 105938689Sborman } 106038689Sborman 106138689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 106240245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 106338689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 106438689Sborman continue; 106538689Sborman } 106638689Sborman 106738689Sborman level &= ~SLC_ACK; 106838689Sborman 106938689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 107038689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 107140245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 107238689Sborman } 107338689Sborman if (level == SLC_DEFAULT) { 107438689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 107538689Sborman spcp->flags = spcp->mylevel; 107638689Sborman else 107738689Sborman spcp->flags = SLC_NOSUPPORT; 107838689Sborman } 107938689Sborman slc_add_reply(func, spcp->flags, spcp->val); 108038689Sborman } 108138689Sborman slc_end_reply(); 108238689Sborman if (slc_update()) 108338689Sborman setconnmode(1); /* set the new character values */ 108438689Sborman } 108538689Sborman 108638689Sborman slc_check() 108738689Sborman { 108838689Sborman register struct spc *spcp; 108938689Sborman 109038689Sborman slc_start_reply(); 109138689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 109238689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 109338689Sborman spcp->val = *spcp->valp; 109438689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 109538689Sborman } 109638689Sborman } 109738689Sborman slc_end_reply(); 109838689Sborman setconnmode(1); 109938689Sborman } 110038689Sborman 110138689Sborman 110238689Sborman unsigned char slc_reply[128]; 110338689Sborman unsigned char *slc_replyp; 110438689Sborman slc_start_reply() 110538689Sborman { 110638689Sborman slc_replyp = slc_reply; 110738689Sborman *slc_replyp++ = IAC; 110838689Sborman *slc_replyp++ = SB; 110938689Sborman *slc_replyp++ = TELOPT_LINEMODE; 111038689Sborman *slc_replyp++ = LM_SLC; 111138689Sborman } 111238689Sborman 111338689Sborman slc_add_reply(func, flags, value) 111438689Sborman char func; 111538689Sborman char flags; 111640245Sborman cc_t value; 111738689Sborman { 111838689Sborman if ((*slc_replyp++ = func) == IAC) 111938689Sborman *slc_replyp++ = IAC; 112038689Sborman if ((*slc_replyp++ = flags) == IAC) 112138689Sborman *slc_replyp++ = IAC; 112240245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 112338689Sborman *slc_replyp++ = IAC; 112438689Sborman } 112538689Sborman 112638689Sborman slc_end_reply() 112738689Sborman { 112838689Sborman register char *cp; 112938689Sborman register int len; 113038689Sborman 113138689Sborman *slc_replyp++ = IAC; 113238689Sborman *slc_replyp++ = SE; 113338689Sborman len = slc_replyp - slc_reply; 113438689Sborman if (len <= 6) 113538689Sborman return; 113638689Sborman if (NETROOM() > len) { 113738689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 113838689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 113938689Sborman } 114038689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 114138689Sborman } 114238689Sborman 114338689Sborman slc_update() 114438689Sborman { 114538689Sborman register struct spc *spcp; 114638689Sborman int need_update = 0; 114738689Sborman 114838689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 114938689Sborman if (!(spcp->flags&SLC_ACK)) 115038689Sborman continue; 115138689Sborman spcp->flags &= ~SLC_ACK; 115238689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 115338689Sborman *spcp->valp = spcp->val; 115438689Sborman need_update = 1; 115538689Sborman } 115638689Sborman } 115738689Sborman return(need_update); 115838689Sborman } 115938689Sborman 116038689Sborman 116138689Sborman 116233804Sminshall int 116332377Sminshall telrcv() 116427110Sminshall { 116532377Sminshall register int c; 116632385Sminshall register int scc; 116732385Sminshall register char *sbp; 116832385Sminshall int count; 116932385Sminshall int returnValue = 0; 117027088Sminshall 117132385Sminshall scc = 0; 117232385Sminshall count = 0; 117332385Sminshall while (TTYROOM() > 2) { 117432385Sminshall if (scc == 0) { 117532385Sminshall if (count) { 117632528Sminshall ring_consumed(&netiring, count); 117732385Sminshall returnValue = 1; 117832385Sminshall count = 0; 117932385Sminshall } 118032528Sminshall sbp = netiring.consume; 118132528Sminshall scc = ring_full_consecutive(&netiring); 118232385Sminshall if (scc == 0) { 118332385Sminshall /* No more data coming in */ 118432385Sminshall break; 118532385Sminshall } 118632385Sminshall } 118732385Sminshall 118832385Sminshall c = *sbp++ & 0xff, scc--; count++; 118932385Sminshall 119032377Sminshall switch (telrcv_state) { 119127110Sminshall 119232377Sminshall case TS_CR: 119332377Sminshall telrcv_state = TS_DATA; 119435518Sminshall if (c == '\0') { 119535518Sminshall break; /* Ignore \0 after CR */ 119639529Sborman } 119739529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 119835518Sminshall TTYADD(c); 119935518Sminshall break; 120032377Sminshall } 120135518Sminshall /* Else, fall through */ 120227088Sminshall 120332377Sminshall case TS_DATA: 120432377Sminshall if (c == IAC) { 120532377Sminshall telrcv_state = TS_IAC; 120633804Sminshall break; 120732377Sminshall } 120832377Sminshall # if defined(TN3270) 120932377Sminshall if (In3270) { 121032377Sminshall *Ifrontp++ = c; 121132385Sminshall while (scc > 0) { 121232385Sminshall c = *sbp++ & 0377, scc--; count++; 121332377Sminshall if (c == IAC) { 121432377Sminshall telrcv_state = TS_IAC; 121534304Sminshall break; 121632377Sminshall } 121732377Sminshall *Ifrontp++ = c; 121832377Sminshall } 121932377Sminshall } else 122032377Sminshall # endif /* defined(TN3270) */ 122135518Sminshall /* 122235518Sminshall * The 'crmod' hack (see following) is needed 122335518Sminshall * since we can't * set CRMOD on output only. 122435518Sminshall * Machines like MULTICS like to send \r without 122535518Sminshall * \n; since we must turn off CRMOD to get proper 122635518Sminshall * input, the mapping is done here (sigh). 122735518Sminshall */ 122838689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 122935518Sminshall if (scc > 0) { 123035518Sminshall c = *sbp&0xff; 123135518Sminshall if (c == 0) { 123235518Sminshall sbp++, scc--; count++; 123335518Sminshall /* a "true" CR */ 123432377Sminshall TTYADD('\r'); 123538689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 123635518Sminshall (c == '\n')) { 123735518Sminshall sbp++, scc--; count++; 123832377Sminshall TTYADD('\n'); 123935518Sminshall } else { 124035518Sminshall TTYADD('\r'); 124135518Sminshall if (crmod) { 124235518Sminshall TTYADD('\n'); 124332377Sminshall } 124432377Sminshall } 124535518Sminshall } else { 124635518Sminshall telrcv_state = TS_CR; 124735518Sminshall TTYADD('\r'); 124835518Sminshall if (crmod) { 124935518Sminshall TTYADD('\n'); 125035518Sminshall } 125132377Sminshall } 125232377Sminshall } else { 125332377Sminshall TTYADD(c); 125432377Sminshall } 125532377Sminshall continue; 125627088Sminshall 125732377Sminshall case TS_IAC: 125838689Sborman process_iac: 125932377Sminshall switch (c) { 126032377Sminshall 126132377Sminshall case WILL: 126232377Sminshall telrcv_state = TS_WILL; 126332377Sminshall continue; 126427261Sminshall 126532377Sminshall case WONT: 126632377Sminshall telrcv_state = TS_WONT; 126732377Sminshall continue; 126827261Sminshall 126932377Sminshall case DO: 127032377Sminshall telrcv_state = TS_DO; 127132377Sminshall continue; 127227261Sminshall 127332377Sminshall case DONT: 127432377Sminshall telrcv_state = TS_DONT; 127532377Sminshall continue; 127627261Sminshall 127732377Sminshall case DM: 127832377Sminshall /* 127932377Sminshall * We may have missed an urgent notification, 128032377Sminshall * so make sure we flush whatever is in the 128132377Sminshall * buffer currently. 128232377Sminshall */ 128332377Sminshall SYNCHing = 1; 128432377Sminshall ttyflush(1); 128532554Sminshall SYNCHing = stilloob(); 128632377Sminshall settimer(gotDM); 128732377Sminshall break; 128827088Sminshall 128932377Sminshall case NOP: 129032377Sminshall case GA: 129132377Sminshall break; 129227088Sminshall 129332377Sminshall case SB: 129432377Sminshall SB_CLEAR(); 129532377Sminshall telrcv_state = TS_SB; 129638689Sborman printoption("RCVD", "IAC", SB); 129732377Sminshall continue; 129827261Sminshall 129932377Sminshall # if defined(TN3270) 130032377Sminshall case EOR: 130132377Sminshall if (In3270) { 130232377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 130332377Sminshall if (Ibackp == Ifrontp) { 130432377Sminshall Ibackp = Ifrontp = Ibuf; 130532377Sminshall ISend = 0; /* should have been! */ 130632377Sminshall } else { 130732377Sminshall ISend = 1; 130827088Sminshall } 130927088Sminshall } 131027088Sminshall break; 131132377Sminshall # endif /* defined(TN3270) */ 131232377Sminshall 131332377Sminshall case IAC: 131432377Sminshall # if !defined(TN3270) 131532377Sminshall TTYADD(IAC); 131632377Sminshall # else /* !defined(TN3270) */ 131732377Sminshall if (In3270) { 131832377Sminshall *Ifrontp++ = IAC; 131932377Sminshall } else { 132032377Sminshall TTYADD(IAC); 132132377Sminshall } 132232377Sminshall # endif /* !defined(TN3270) */ 132327088Sminshall break; 132432377Sminshall 132527088Sminshall default: 132627088Sminshall break; 132727088Sminshall } 132832377Sminshall telrcv_state = TS_DATA; 132932377Sminshall continue; 133027088Sminshall 133132377Sminshall case TS_WILL: 133237226Sminshall printoption("RCVD", "will", c); 133338689Sborman willoption(c); 133432377Sminshall SetIn3270(); 133532377Sminshall telrcv_state = TS_DATA; 133632377Sminshall continue; 133727110Sminshall 133832377Sminshall case TS_WONT: 133937226Sminshall printoption("RCVD", "wont", c); 134038689Sborman wontoption(c); 134132377Sminshall SetIn3270(); 134232377Sminshall telrcv_state = TS_DATA; 134332377Sminshall continue; 134427088Sminshall 134532377Sminshall case TS_DO: 134637226Sminshall printoption("RCVD", "do", c); 134737226Sminshall dooption(c); 134832377Sminshall SetIn3270(); 134937219Sminshall if (c == TELOPT_NAWS) { 135037219Sminshall sendnaws(); 135137219Sminshall } else if (c == TELOPT_LFLOW) { 135237219Sminshall localflow = 1; 135337219Sminshall setcommandmode(); 135438689Sborman setconnmode(0); 135537219Sminshall } 135632377Sminshall telrcv_state = TS_DATA; 135732377Sminshall continue; 135827088Sminshall 135932377Sminshall case TS_DONT: 136037226Sminshall printoption("RCVD", "dont", c); 136138689Sborman dontoption(c); 136237226Sminshall flushline = 1; 136338689Sborman setconnmode(0); /* set new tty mode (maybe) */ 136432377Sminshall SetIn3270(); 136532377Sminshall telrcv_state = TS_DATA; 136632377Sminshall continue; 136727088Sminshall 136832377Sminshall case TS_SB: 136932377Sminshall if (c == IAC) { 137032377Sminshall telrcv_state = TS_SE; 137132377Sminshall } else { 137232377Sminshall SB_ACCUM(c); 137332377Sminshall } 137432377Sminshall continue; 137527088Sminshall 137632377Sminshall case TS_SE: 137732377Sminshall if (c != SE) { 137832377Sminshall if (c != IAC) { 137938689Sborman /* 138038689Sborman * This is an error. We only expect to get 138138689Sborman * "IAC IAC" or "IAC SE". Several things may 138238689Sborman * have happend. An IAC was not doubled, the 138338689Sborman * IAC SE was left off, or another option got 138438689Sborman * inserted into the suboption are all possibilities. 138538689Sborman * If we assume that the IAC was not doubled, 138638689Sborman * and really the IAC SE was left off, we could 138738689Sborman * get into an infinate loop here. So, instead, 138838689Sborman * we terminate the suboption, and process the 138938689Sborman * partial suboption if we can. 139038689Sborman */ 139138689Sborman SB_TERM(); 139232377Sminshall SB_ACCUM(IAC); 139338689Sborman SB_ACCUM(c); 139438689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 139538689Sborman suboption(); /* handle sub-option */ 139638689Sborman SetIn3270(); 139738689Sborman telrcv_state = TS_IAC; 139838689Sborman goto process_iac; 139932377Sminshall } 140032377Sminshall SB_ACCUM(c); 140132377Sminshall telrcv_state = TS_SB; 140232377Sminshall } else { 140332377Sminshall SB_TERM(); 140438689Sborman SB_ACCUM(IAC); 140538689Sborman SB_ACCUM(SE); 140632377Sminshall suboption(); /* handle sub-option */ 140732377Sminshall SetIn3270(); 140832377Sminshall telrcv_state = TS_DATA; 140932377Sminshall } 141027088Sminshall } 141127088Sminshall } 141232667Sminshall if (count) 141332667Sminshall ring_consumed(&netiring, count); 141432385Sminshall return returnValue||count; 141527088Sminshall } 141632385Sminshall 141732385Sminshall static int 141832554Sminshall telsnd() 141932385Sminshall { 142032385Sminshall int tcc; 142132385Sminshall int count; 142232385Sminshall int returnValue = 0; 142332385Sminshall char *tbp; 142432385Sminshall 142532385Sminshall tcc = 0; 142632385Sminshall count = 0; 142732385Sminshall while (NETROOM() > 2) { 142832385Sminshall register int sc; 142932385Sminshall register int c; 143032385Sminshall 143132385Sminshall if (tcc == 0) { 143232385Sminshall if (count) { 143332528Sminshall ring_consumed(&ttyiring, count); 143432385Sminshall returnValue = 1; 143532385Sminshall count = 0; 143632385Sminshall } 143732528Sminshall tbp = ttyiring.consume; 143832528Sminshall tcc = ring_full_consecutive(&ttyiring); 143932385Sminshall if (tcc == 0) { 144032385Sminshall break; 144132385Sminshall } 144232385Sminshall } 144332385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 144432385Sminshall if (sc == escape) { 144538689Sborman /* 144638689Sborman * Double escape is a pass through of a single escape character. 144738689Sborman */ 144838689Sborman if (tcc && strip(*tbp) == escape) { 144938689Sborman tbp++; 145038689Sborman tcc--; 145138689Sborman count++; 145238689Sborman } else { 145338689Sborman command(0, tbp, tcc); 145438689Sborman count += tcc; 145538689Sborman tcc = 0; 145638689Sborman flushline = 1; 145738689Sborman break; 145838689Sborman } 145938689Sborman } 146038689Sborman #ifdef KLUDGELINEMODE 146138689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 146232385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 146332385Sminshall tcc--; tbp++; count++; 146432385Sminshall } else { 146532385Sminshall dontlecho = !dontlecho; 146632385Sminshall settimer(echotoggle); 146738689Sborman setconnmode(0); 146832385Sminshall flushline = 1; 146932385Sminshall break; 147032385Sminshall } 147132385Sminshall } 147238689Sborman #endif 147338689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 147432385Sminshall if (TerminalSpecialChars(sc) == 0) { 147532385Sminshall break; 147632385Sminshall } 147732385Sminshall } 147838689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 147932385Sminshall switch (c) { 148032385Sminshall case '\n': 148132385Sminshall /* 148232385Sminshall * If we are in CRMOD mode (\r ==> \n) 148332385Sminshall * on our local machine, then probably 148432385Sminshall * a newline (unix) is CRLF (TELNET). 148532385Sminshall */ 148632385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 148732385Sminshall NETADD('\r'); 148832385Sminshall } 148932385Sminshall NETADD('\n'); 149032385Sminshall flushline = 1; 149132385Sminshall break; 149232385Sminshall case '\r': 149332385Sminshall if (!crlf) { 149432385Sminshall NET2ADD('\r', '\0'); 149532385Sminshall } else { 149632385Sminshall NET2ADD('\r', '\n'); 149732385Sminshall } 149832385Sminshall flushline = 1; 149932385Sminshall break; 150032385Sminshall case IAC: 150132385Sminshall NET2ADD(IAC, IAC); 150232385Sminshall break; 150332385Sminshall default: 150432385Sminshall NETADD(c); 150532385Sminshall break; 150632385Sminshall } 150732385Sminshall } else if (c == IAC) { 150832385Sminshall NET2ADD(IAC, IAC); 150932385Sminshall } else { 151032385Sminshall NETADD(c); 151132385Sminshall } 151232385Sminshall } 151332667Sminshall if (count) 151432667Sminshall ring_consumed(&ttyiring, count); 151532385Sminshall return returnValue||count; /* Non-zero if we did anything */ 151632385Sminshall } 151732377Sminshall 151827088Sminshall /* 151932377Sminshall * Scheduler() 152032377Sminshall * 152132377Sminshall * Try to do something. 152232377Sminshall * 152332377Sminshall * If we do something useful, return 1; else return 0. 152432377Sminshall * 152527110Sminshall */ 152627110Sminshall 152727110Sminshall 152832377Sminshall int 152932377Sminshall Scheduler(block) 153032377Sminshall int block; /* should we block in the select ? */ 153127110Sminshall { 153232377Sminshall /* One wants to be a bit careful about setting returnValue 153332377Sminshall * to one, since a one implies we did some useful work, 153432377Sminshall * and therefore probably won't be called to block next 153532377Sminshall * time (TN3270 mode only). 153632377Sminshall */ 153732531Sminshall int returnValue; 153832531Sminshall int netin, netout, netex, ttyin, ttyout; 153927110Sminshall 154032531Sminshall /* Decide which rings should be processed */ 154132531Sminshall 154232531Sminshall netout = ring_full_count(&netoring) && 154338689Sborman (flushline || 154438689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 154538689Sborman #ifdef KLUDGELINEMODE 154638689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 154738689Sborman #endif 154838689Sborman ) || 154938689Sborman my_want_state_is_will(TELOPT_BINARY)); 155032531Sminshall ttyout = ring_full_count(&ttyoring); 155132531Sminshall 155232377Sminshall #if defined(TN3270) 155332531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 155432377Sminshall #else /* defined(TN3270) */ 155532531Sminshall ttyin = ring_empty_count(&ttyiring); 155632377Sminshall #endif /* defined(TN3270) */ 155732531Sminshall 155832531Sminshall #if defined(TN3270) 155932531Sminshall netin = ring_empty_count(&netiring); 156032377Sminshall # else /* !defined(TN3270) */ 156132531Sminshall netin = !ISend && ring_empty_count(&netiring); 156232377Sminshall # endif /* !defined(TN3270) */ 156332531Sminshall 156432531Sminshall netex = !SYNCHing; 156532531Sminshall 156632531Sminshall /* If we have seen a signal recently, reset things */ 156732377Sminshall # if defined(TN3270) && defined(unix) 156832377Sminshall if (HaveInput) { 156932377Sminshall HaveInput = 0; 157032377Sminshall signal(SIGIO, inputAvailable); 157132377Sminshall } 157232377Sminshall #endif /* defined(TN3270) && defined(unix) */ 157332377Sminshall 157432531Sminshall /* Call to system code to process rings */ 157527178Sminshall 157632531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 157727178Sminshall 157832531Sminshall /* Now, look at the input rings, looking for work to do. */ 157932377Sminshall 158032531Sminshall if (ring_full_count(&ttyiring)) { 158132377Sminshall # if defined(TN3270) 158232377Sminshall if (In3270) { 158334848Sminshall int c; 158434848Sminshall 158533804Sminshall c = DataFromTerminal(ttyiring.consume, 158632528Sminshall ring_full_consecutive(&ttyiring)); 158732377Sminshall if (c) { 158832377Sminshall returnValue = 1; 158932667Sminshall ring_consumed(&ttyiring, c); 159032377Sminshall } 159132377Sminshall } else { 159232377Sminshall # endif /* defined(TN3270) */ 159332554Sminshall returnValue |= telsnd(); 159432377Sminshall # if defined(TN3270) 159527178Sminshall } 159632531Sminshall # endif /* defined(TN3270) */ 159727178Sminshall } 159832377Sminshall 159932528Sminshall if (ring_full_count(&netiring)) { 160032377Sminshall # if !defined(TN3270) 160132385Sminshall returnValue |= telrcv(); 160232377Sminshall # else /* !defined(TN3270) */ 160332377Sminshall returnValue = Push3270(); 160432377Sminshall # endif /* !defined(TN3270) */ 160532377Sminshall } 160632377Sminshall return returnValue; 160727178Sminshall } 160827178Sminshall 160927178Sminshall /* 161032377Sminshall * Select from tty and network... 161127088Sminshall */ 161232377Sminshall void 161332377Sminshall telnet() 161427088Sminshall { 161532531Sminshall sys_telnet_init(); 161627088Sminshall 161732377Sminshall # if !defined(TN3270) 161832377Sminshall if (telnetport) { 161938689Sborman send_do(TELOPT_SGA, 1); 162038689Sborman send_will(TELOPT_TTYPE, 1); 162138689Sborman send_will(TELOPT_NAWS, 1); 162238689Sborman send_will(TELOPT_TSPEED, 1); 162338689Sborman send_will(TELOPT_LFLOW, 1); 162438689Sborman send_will(TELOPT_LINEMODE, 1); 162538908Sborman send_do(TELOPT_STATUS, 1); 162627178Sminshall } 162732377Sminshall # endif /* !defined(TN3270) */ 162827088Sminshall 162932377Sminshall # if !defined(TN3270) 163032377Sminshall for (;;) { 163132385Sminshall int schedValue; 163232385Sminshall 163332385Sminshall while ((schedValue = Scheduler(0)) != 0) { 163432385Sminshall if (schedValue == -1) { 163532385Sminshall setcommandmode(); 163632385Sminshall return; 163732385Sminshall } 163832385Sminshall } 163932385Sminshall 164032531Sminshall if (Scheduler(1) == -1) { 164132377Sminshall setcommandmode(); 164232377Sminshall return; 164332377Sminshall } 164432377Sminshall } 164532377Sminshall # else /* !defined(TN3270) */ 164632377Sminshall for (;;) { 164732377Sminshall int schedValue; 164827088Sminshall 164932377Sminshall while (!In3270 && !shell_active) { 165032531Sminshall if (Scheduler(1) == -1) { 165132377Sminshall setcommandmode(); 165232377Sminshall return; 165332377Sminshall } 165427088Sminshall } 165532377Sminshall 165632377Sminshall while ((schedValue = Scheduler(0)) != 0) { 165732377Sminshall if (schedValue == -1) { 165832377Sminshall setcommandmode(); 165932377Sminshall return; 166032377Sminshall } 166127088Sminshall } 166232377Sminshall /* If there is data waiting to go out to terminal, don't 166332377Sminshall * schedule any more data for the terminal. 166432377Sminshall */ 166534304Sminshall if (ring_full_count(&ttyoring)) { 166632377Sminshall schedValue = 1; 166727088Sminshall } else { 166832377Sminshall if (shell_active) { 166932377Sminshall if (shell_continue() == 0) { 167032377Sminshall ConnectScreen(); 167127088Sminshall } 167232377Sminshall } else if (In3270) { 167332377Sminshall schedValue = DoTerminalOutput(); 167432377Sminshall } 167527088Sminshall } 167632377Sminshall if (schedValue && (shell_active == 0)) { 167732531Sminshall if (Scheduler(1) == -1) { 167832377Sminshall setcommandmode(); 167932377Sminshall return; 168032377Sminshall } 168127088Sminshall } 168232377Sminshall } 168332377Sminshall # endif /* !defined(TN3270) */ 168427088Sminshall } 168532377Sminshall 168634848Sminshall #if 0 /* XXX - this not being in is a bug */ 168727088Sminshall /* 168832554Sminshall * nextitem() 168932554Sminshall * 169032554Sminshall * Return the address of the next "item" in the TELNET data 169132554Sminshall * stream. This will be the address of the next character if 169232554Sminshall * the current address is a user data character, or it will 169332554Sminshall * be the address of the character following the TELNET command 169432554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 169532554Sminshall * character. 169632554Sminshall */ 169732554Sminshall 169832554Sminshall static char * 169932554Sminshall nextitem(current) 170032554Sminshall char *current; 170132554Sminshall { 170232554Sminshall if ((*current&0xff) != IAC) { 170332554Sminshall return current+1; 170432554Sminshall } 170532554Sminshall switch (*(current+1)&0xff) { 170632554Sminshall case DO: 170732554Sminshall case DONT: 170832554Sminshall case WILL: 170932554Sminshall case WONT: 171032554Sminshall return current+3; 171132554Sminshall case SB: /* loop forever looking for the SE */ 171232554Sminshall { 171332554Sminshall register char *look = current+2; 171432554Sminshall 171532554Sminshall for (;;) { 171632554Sminshall if ((*look++&0xff) == IAC) { 171732554Sminshall if ((*look++&0xff) == SE) { 171832554Sminshall return look; 171932554Sminshall } 172032554Sminshall } 172132554Sminshall } 172232554Sminshall } 172332554Sminshall default: 172432554Sminshall return current+2; 172532554Sminshall } 172632554Sminshall } 172734848Sminshall #endif /* 0 */ 172832554Sminshall 172932554Sminshall /* 173032554Sminshall * netclear() 173132554Sminshall * 173232554Sminshall * We are about to do a TELNET SYNCH operation. Clear 173332554Sminshall * the path to the network. 173432554Sminshall * 173532554Sminshall * Things are a bit tricky since we may have sent the first 173632554Sminshall * byte or so of a previous TELNET command into the network. 173732554Sminshall * So, we have to scan the network buffer from the beginning 173832554Sminshall * until we are up to where we want to be. 173932554Sminshall * 174032554Sminshall * A side effect of what we do, just to keep things 174132554Sminshall * simple, is to clear the urgent data pointer. The principal 174232554Sminshall * caller should be setting the urgent data pointer AFTER calling 174332554Sminshall * us in any case. 174432554Sminshall */ 174532554Sminshall 174632554Sminshall static void 174732554Sminshall netclear() 174832554Sminshall { 174932554Sminshall #if 0 /* XXX */ 175032554Sminshall register char *thisitem, *next; 175132554Sminshall char *good; 175232554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 175332554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 175432554Sminshall 175532554Sminshall thisitem = netobuf; 175632554Sminshall 175732554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 175832554Sminshall thisitem = next; 175932554Sminshall } 176032554Sminshall 176132554Sminshall /* Now, thisitem is first before/at boundary. */ 176232554Sminshall 176332554Sminshall good = netobuf; /* where the good bytes go */ 176432554Sminshall 176532554Sminshall while (netoring.add > thisitem) { 176632554Sminshall if (wewant(thisitem)) { 176732554Sminshall int length; 176832554Sminshall 176932554Sminshall next = thisitem; 177032554Sminshall do { 177132554Sminshall next = nextitem(next); 177232554Sminshall } while (wewant(next) && (nfrontp > next)); 177332554Sminshall length = next-thisitem; 177432554Sminshall memcpy(good, thisitem, length); 177532554Sminshall good += length; 177632554Sminshall thisitem = next; 177732554Sminshall } else { 177832554Sminshall thisitem = nextitem(thisitem); 177932554Sminshall } 178032554Sminshall } 178132554Sminshall 178232554Sminshall #endif /* 0 */ 178332554Sminshall } 178432554Sminshall 178532554Sminshall /* 178632377Sminshall * These routines add various telnet commands to the data stream. 178727088Sminshall */ 178832377Sminshall 178932554Sminshall static void 179032554Sminshall doflush() 179132554Sminshall { 179232554Sminshall NET2ADD(IAC, DO); 179332554Sminshall NETADD(TELOPT_TM); 179432554Sminshall flushline = 1; 179532554Sminshall flushout = 1; 179632554Sminshall ttyflush(1); /* Flush/drop output */ 179732554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 179837226Sminshall printoption("SENT", "do", TELOPT_TM); 179932554Sminshall } 180032554Sminshall 180132377Sminshall void 180232377Sminshall xmitAO() 180327088Sminshall { 180432377Sminshall NET2ADD(IAC, AO); 180538908Sborman printoption("SENT", "IAC", AO); 180632377Sminshall if (autoflush) { 180732377Sminshall doflush(); 180832377Sminshall } 180932377Sminshall } 181027088Sminshall 181132377Sminshall 181232377Sminshall void 181332377Sminshall xmitEL() 181427088Sminshall { 181532377Sminshall NET2ADD(IAC, EL); 181638908Sborman printoption("SENT", "IAC", EL); 181727088Sminshall } 181827088Sminshall 181932377Sminshall void 182032377Sminshall xmitEC() 182127088Sminshall { 182232377Sminshall NET2ADD(IAC, EC); 182338908Sborman printoption("SENT", "IAC", EC); 182427088Sminshall } 182527088Sminshall 182632377Sminshall 182732377Sminshall #if defined(NOT43) 182832377Sminshall int 182932377Sminshall #else /* defined(NOT43) */ 183032377Sminshall void 183132377Sminshall #endif /* defined(NOT43) */ 183232377Sminshall dosynch() 183327088Sminshall { 183432377Sminshall netclear(); /* clear the path to the network */ 183533294Sminshall NETADD(IAC); 183633294Sminshall setneturg(); 183733294Sminshall NETADD(DM); 183838908Sborman printoption("SENT", "IAC", DM); 183927088Sminshall 184032377Sminshall #if defined(NOT43) 184132377Sminshall return 0; 184232377Sminshall #endif /* defined(NOT43) */ 184327088Sminshall } 184427088Sminshall 184532377Sminshall void 184638908Sborman get_status() 184738908Sborman { 184838908Sborman char tmp[16]; 184938908Sborman register char *cp; 185038908Sborman 185138908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 185238908Sborman printf("Remote side does not support STATUS option\n"); 185338908Sborman return; 185438908Sborman } 185538908Sborman if (!showoptions) 185638908Sborman printf("You will not see the response unless you set \"options\"\n"); 185738908Sborman 185838908Sborman cp = tmp; 185938908Sborman 186038908Sborman *cp++ = IAC; 186138908Sborman *cp++ = SB; 186238908Sborman *cp++ = TELOPT_STATUS; 186338908Sborman *cp++ = TELQUAL_SEND; 186438908Sborman *cp++ = IAC; 186538908Sborman *cp++ = SE; 186638908Sborman if (NETROOM() >= cp - tmp) { 186738908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 186838908Sborman printsub('>', tmp+2, cp - tmp - 2); 186938908Sborman } 187038908Sborman } 187138908Sborman 187238908Sborman void 187332377Sminshall intp() 187427088Sminshall { 187532377Sminshall NET2ADD(IAC, IP); 187638908Sborman printoption("SENT", "IAC", IP); 187732377Sminshall flushline = 1; 187832377Sminshall if (autoflush) { 187932377Sminshall doflush(); 188032377Sminshall } 188132377Sminshall if (autosynch) { 188232377Sminshall dosynch(); 188332377Sminshall } 188427088Sminshall } 188527186Sminshall 188632377Sminshall void 188732377Sminshall sendbrk() 188827186Sminshall { 188932377Sminshall NET2ADD(IAC, BREAK); 189038908Sborman printoption("SENT", "IAC", BREAK); 189132377Sminshall flushline = 1; 189232377Sminshall if (autoflush) { 189332377Sminshall doflush(); 189432377Sminshall } 189532377Sminshall if (autosynch) { 189632377Sminshall dosynch(); 189732377Sminshall } 189827186Sminshall } 189938689Sborman 190038689Sborman void 190138689Sborman sendabort() 190238689Sborman { 190338689Sborman NET2ADD(IAC, ABORT); 190438908Sborman printoption("SENT", "IAC", ABORT); 190538689Sborman flushline = 1; 190638689Sborman if (autoflush) { 190738689Sborman doflush(); 190838689Sborman } 190938689Sborman if (autosynch) { 191038689Sborman dosynch(); 191138689Sborman } 191238689Sborman } 191338689Sborman 191438689Sborman void 191538689Sborman sendsusp() 191638689Sborman { 191738689Sborman NET2ADD(IAC, SUSP); 191838908Sborman printoption("SENT", "IAC", SUSP); 191938689Sborman flushline = 1; 192038689Sborman if (autoflush) { 192138689Sborman doflush(); 192238689Sborman } 192338689Sborman if (autosynch) { 192438689Sborman dosynch(); 192538689Sborman } 192638689Sborman } 192738689Sborman 192838689Sborman void 192938689Sborman sendeof() 193038689Sborman { 193138908Sborman NET2ADD(IAC, xEOF); 193238908Sborman printoption("SENT", "IAC", xEOF); 193338689Sborman } 193438689Sborman 193537219Sminshall /* 193637219Sminshall * Send a window size update to the remote system. 193737219Sminshall */ 193837219Sminshall 193937219Sminshall void 194037219Sminshall sendnaws() 194137219Sminshall { 194237219Sminshall long rows, cols; 194338689Sborman unsigned char tmp[16]; 194438689Sborman register unsigned char *cp; 194537219Sminshall 194638689Sborman if (my_state_is_wont(TELOPT_NAWS)) 194738689Sborman return; 194837219Sminshall 194938689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 195038689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 195138689Sborman 195237219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 195337219Sminshall return; 195437219Sminshall } 195537219Sminshall 195638689Sborman cp = tmp; 195738689Sborman 195838689Sborman *cp++ = IAC; 195938689Sborman *cp++ = SB; 196038689Sborman *cp++ = TELOPT_NAWS; 196138689Sborman PUTSHORT(cp, cols); 196238689Sborman PUTSHORT(cp, rows); 196338689Sborman *cp++ = IAC; 196438689Sborman *cp++ = SE; 196538689Sborman if (NETROOM() >= cp - tmp) { 196638689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 196738689Sborman printsub('>', tmp+2, cp - tmp - 2); 196837219Sminshall } 196937219Sminshall } 197037226Sminshall 197138908Sborman tel_enter_binary(rw) 197238908Sborman int rw; 197337226Sminshall { 197438908Sborman if (rw&1) 197538908Sborman send_do(TELOPT_BINARY, 1); 197638908Sborman if (rw&2) 197738908Sborman send_will(TELOPT_BINARY, 1); 197837226Sminshall } 197937226Sminshall 198038908Sborman tel_leave_binary(rw) 198138908Sborman int rw; 198237226Sminshall { 198338908Sborman if (rw&1) 198438908Sborman send_dont(TELOPT_BINARY, 1); 198538908Sborman if (rw&2) 198638908Sborman send_wont(TELOPT_BINARY, 1); 198737226Sminshall } 1988