133685Sbostic /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 533685Sbostic * Redistribution and use in source and binary forms are permitted 634898Sbostic * provided that the above copyright notice and this paragraph are 734898Sbostic * duplicated in all such forms and that any documentation, 834898Sbostic * advertising materials, and other materials related to such 934898Sbostic * distribution and use acknowledge that the software was developed 1034898Sbostic * by the University of California, Berkeley. The name of the 1134898Sbostic * University may not be used to endorse or promote products derived 1234898Sbostic * from this software without specific prior written permission. 1334898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633685Sbostic */ 1711758Ssam 1821580Sdist #ifndef lint 19*38811Sborman static char sccsid[] = "@(#)telnet.c 5.42 (Berkeley) 08/28/89"; 2033685Sbostic #endif /* not lint */ 2121580Sdist 229217Ssam #include <sys/types.h> 239217Ssam 2432377Sminshall #if defined(unix) 2533804Sminshall #include <signal.h> 2632377Sminshall /* By the way, we need to include curses.h before telnet.h since, 2732377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 2832377Sminshall * declared in curses.h. 2932377Sminshall */ 3032377Sminshall #include <curses.h> 3132377Sminshall #endif /* defined(unix) */ 3232377Sminshall 3312212Ssam #include <arpa/telnet.h> 3432377Sminshall 3532377Sminshall #if defined(unix) 3627186Sminshall #include <strings.h> 3732377Sminshall #else /* defined(unix) */ 3832377Sminshall #include <string.h> 3932377Sminshall #endif /* defined(unix) */ 409217Ssam 4132381Sminshall #include "ring.h" 4232381Sminshall 4332377Sminshall #include "defines.h" 4432377Sminshall #include "externs.h" 4532377Sminshall #include "types.h" 4632377Sminshall #include "general.h" 4727178Sminshall 4827178Sminshall 4927228Sminshall #define strip(x) ((x)&0x7f) 506000Sroot 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 */ 6932377Sminshall debug = 0, 7032377Sminshall crmod, 7132377Sminshall netdata, /* Print out network data flow */ 7232377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 7334848Sminshall #if defined(TN3270) 7436241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 7536241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 7632377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 7734848Sminshall #endif /* defined(TN3270) */ 7833286Sminshall telnetport, 7932531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 8032531Sminshall flushout, /* flush output */ 8132531Sminshall autoflush = 0, /* flush output when interrupting? */ 8232531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 8337219Sminshall localflow, /* we handle flow control locally */ 8432531Sminshall localchars, /* we recognize interrupt/quit */ 8532531Sminshall donelclchars, /* the user has set "localchars" */ 8632531Sminshall donebinarytoggle, /* the user has put us in binary */ 8732531Sminshall dontlecho, /* do we suppress local echoing right now? */ 8832531Sminshall globalmode; 8927088Sminshall 9032377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 916000Sroot 9232377Sminshall char 9332377Sminshall *prompt = 0, 9432377Sminshall escape, 9532377Sminshall echoc; 9627186Sminshall 9727186Sminshall /* 986000Sroot * Telnet receiver states for fsm 996000Sroot */ 1006000Sroot #define TS_DATA 0 1016000Sroot #define TS_IAC 1 1026000Sroot #define TS_WILL 2 1036000Sroot #define TS_WONT 3 1046000Sroot #define TS_DO 4 1056000Sroot #define TS_DONT 5 10627021Sminshall #define TS_CR 6 10727676Sminshall #define TS_SB 7 /* sub-option collection */ 10827676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1096000Sroot 11032377Sminshall static int telrcv_state; 1116000Sroot 11232377Sminshall jmp_buf toplevel = { 0 }; 11332377Sminshall jmp_buf peerdied; 1146000Sroot 11532377Sminshall int flushline; 116*38811Sborman int linemode; 11727021Sminshall 11838689Sborman #ifdef KLUDGELINEMODE 11938689Sborman int kludgelinemode = 1; 12038689Sborman #endif 12138689Sborman 12232377Sminshall /* 12332377Sminshall * The following are some clocks used to decide how to interpret 12432377Sminshall * the relationship between various variables. 12532377Sminshall */ 1266000Sroot 12732377Sminshall Clocks clocks; 12832377Sminshall 12938689Sborman #ifdef notdef 13032377Sminshall Modelist modelist[] = { 13132377Sminshall { "telnet command mode", COMMAND_LINE }, 13232377Sminshall { "character-at-a-time mode", 0 }, 13332377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 13432377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 13532377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 13632377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 13732377Sminshall { "3270 mode", 0 }, 13832377Sminshall }; 13938689Sborman #endif 1406000Sroot 14132377Sminshall 14232377Sminshall /* 14332377Sminshall * Initialize telnet environment. 14432377Sminshall */ 1456000Sroot 14632377Sminshall init_telnet() 14732377Sminshall { 14832377Sminshall SB_CLEAR(); 14937226Sminshall ClearArray(options); 1506000Sroot 15137219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 1526000Sroot 15332377Sminshall SYNCHing = 0; 1546000Sroot 15532377Sminshall /* Don't change NetTrace */ 1566000Sroot 15732377Sminshall escape = CONTROL(']'); 15832377Sminshall echoc = CONTROL('E'); 1596000Sroot 16032377Sminshall flushline = 1; 16132377Sminshall telrcv_state = TS_DATA; 16232377Sminshall } 16332554Sminshall 1646000Sroot 16532554Sminshall #include <varargs.h> 1666000Sroot 16734848Sminshall /*VARARGS*/ 16832554Sminshall static void 16932554Sminshall printring(va_alist) 17032554Sminshall va_dcl 17132554Sminshall { 17232554Sminshall va_list ap; 17332554Sminshall char buffer[100]; /* where things go */ 17432554Sminshall char *ptr; 17532554Sminshall char *format; 17632554Sminshall char *string; 17732554Sminshall Ring *ring; 17832554Sminshall int i; 17932554Sminshall 18032554Sminshall va_start(ap); 18132554Sminshall 18232554Sminshall ring = va_arg(ap, Ring *); 18332554Sminshall format = va_arg(ap, char *); 18432554Sminshall ptr = buffer; 18532554Sminshall 18632554Sminshall while ((i = *format++) != 0) { 18732554Sminshall if (i == '%') { 18832554Sminshall i = *format++; 18932554Sminshall switch (i) { 19032554Sminshall case 'c': 19132554Sminshall *ptr++ = va_arg(ap, int); 19232554Sminshall break; 19332554Sminshall case 's': 19432554Sminshall string = va_arg(ap, char *); 19532554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19632554Sminshall ring_supply_data(ring, string, strlen(string)); 19732554Sminshall ptr = buffer; 19832554Sminshall break; 19932554Sminshall case 0: 20032554Sminshall ExitString("printring: trailing %%.\n", 1); 20132554Sminshall /*NOTREACHED*/ 20232554Sminshall default: 20332554Sminshall ExitString("printring: unknown format character.\n", 1); 20432554Sminshall /*NOTREACHED*/ 20532554Sminshall } 20632554Sminshall } else { 20732554Sminshall *ptr++ = i; 20832554Sminshall } 20932554Sminshall } 21032554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21132554Sminshall } 21232554Sminshall 21337226Sminshall /* 21437226Sminshall * These routines are in charge of sending option negotiations 21537226Sminshall * to the other side. 21637226Sminshall * 21737226Sminshall * The basic idea is that we send the negotiation if either side 21837226Sminshall * is in disagreement as to what the current state should be. 21937226Sminshall */ 22032554Sminshall 22138689Sborman send_do(c, init) 22238689Sborman register int c, init; 2236000Sroot { 22438689Sborman if (init) { 22538689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 22638689Sborman my_want_state_is_do(c)) 22738689Sborman return; 22838689Sborman set_my_want_state_do(c); 22938689Sborman do_dont_resp[c]++; 23037226Sminshall } 23138689Sborman NET2ADD(IAC, DO); 23238689Sborman NETADD(c); 23338689Sborman printoption("SENT", "do", c); 23437226Sminshall } 23537226Sminshall 23637226Sminshall void 23738689Sborman send_dont(c, init) 23838689Sborman register int c, init; 23937226Sminshall { 24038689Sborman if (init) { 24138689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 24238689Sborman my_want_state_is_dont(c)) 24338689Sborman return; 24438689Sborman set_my_want_state_dont(c); 24538689Sborman do_dont_resp[c]++; 24637226Sminshall } 24738689Sborman NET2ADD(IAC, DONT); 24838689Sborman NETADD(c); 24938689Sborman printoption("SENT", "dont", c); 25037226Sminshall } 25137226Sminshall 25237226Sminshall void 25338689Sborman send_will(c, init) 25438689Sborman register int c, init; 25537226Sminshall { 25638689Sborman if (init) { 25738689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 25838689Sborman my_want_state_is_will(c)) 25938689Sborman return; 26038689Sborman set_my_want_state_will(c); 26138689Sborman will_wont_resp[c]++; 26237226Sminshall } 26338689Sborman NET2ADD(IAC, WILL); 26438689Sborman NETADD(c); 26538689Sborman printoption("SENT", "will", c); 26637226Sminshall } 26737226Sminshall 26837226Sminshall void 26938689Sborman send_wont(c, init) 27038689Sborman register int c, init; 27137226Sminshall { 27238689Sborman if (init) { 27338689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 27438689Sborman my_want_state_is_wont(c)) 27538689Sborman return; 27638689Sborman set_my_want_state_wont(c); 27738689Sborman will_wont_resp[c]++; 27837226Sminshall } 27938689Sborman NET2ADD(IAC, WONT); 28038689Sborman NETADD(c); 28138689Sborman printoption("SENT", "wont", c); 28237226Sminshall } 28337226Sminshall 28437226Sminshall 28537226Sminshall void 28637226Sminshall willoption(option) 28737226Sminshall int option; 28837226Sminshall { 2896000Sroot char *fmt; 29038689Sborman int new_state_ok = 0; 2916000Sroot 29238689Sborman if (do_dont_resp[option]) { 29338689Sborman --do_dont_resp[option]; 29438689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 29538689Sborman --do_dont_resp[option]; 29638689Sborman } 29737226Sminshall 29838689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 2996000Sroot 30038689Sborman switch (option) { 30138689Sborman 30238689Sborman case TELOPT_ECHO: 30338689Sborman # if defined(TN3270) 30438689Sborman /* 30538689Sborman * The following is a pain in the rear-end. 30638689Sborman * Various IBM servers (some versions of Wiscnet, 30738689Sborman * possibly Fibronics/Spartacus, and who knows who 30838689Sborman * else) will NOT allow us to send "DO SGA" too early 30938689Sborman * in the setup proceedings. On the other hand, 31038689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31138689Sborman * So, we are stuck. Empirically (but, based on 31238689Sborman * a VERY small sample), the IBM servers don't send 31338689Sborman * out anything about ECHO, so we postpone our sending 31438689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 31538689Sborman * DO send). 31638689Sborman */ 31738689Sborman { 31838689Sborman if (askedSGA == 0) { 31938689Sborman askedSGA = 1; 32038689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32138689Sborman send_do(TELOPT_SGA, 1); 32232377Sminshall } 32332377Sminshall } 32438689Sborman /* Fall through */ 32538689Sborman case TELOPT_EOR: 32638689Sborman case TELOPT_BINARY: 32738689Sborman #endif /* defined(TN3270) */ 32838689Sborman case TELOPT_SGA: 32927110Sminshall settimer(modenegotiated); 33038689Sborman new_state_ok = 1; 3316000Sroot break; 3326000Sroot 33338689Sborman case TELOPT_TM: 33438689Sborman if (flushout) 33538689Sborman flushout = 0; 33638689Sborman /* 33738689Sborman * Special case for TM. If we get back a WILL, 33838689Sborman * pretend we got back a WONT. 33938689Sborman */ 34038689Sborman set_my_want_state_dont(option); 34138689Sborman set_my_state_dont(option); 34227110Sminshall return; /* Never reply to TM will's/wont's */ 3436000Sroot 34438689Sborman case TELOPT_LINEMODE: 34538689Sborman default: 3466000Sroot break; 34738689Sborman } 34838689Sborman 34938689Sborman if (new_state_ok) { 35038689Sborman set_my_want_state_do(option); 35138689Sborman send_do(option, 0); 35238689Sborman setconnmode(0); /* possibly set new tty mode */ 35338689Sborman } else { 35438689Sborman do_dont_resp[option]++; 35538689Sborman send_dont(option, 0); 35638689Sborman } 3576000Sroot } 35838689Sborman set_my_state_do(option); 3596000Sroot } 3606000Sroot 36132377Sminshall void 36237226Sminshall wontoption(option) 36337226Sminshall int option; 3646000Sroot { 3656000Sroot char *fmt; 3666000Sroot 36738689Sborman if (do_dont_resp[option]) { 36838689Sborman --do_dont_resp[option]; 36938689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 37038689Sborman --do_dont_resp[option]; 37138689Sborman } 37237226Sminshall 37338689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3746000Sroot 37538689Sborman switch (option) { 37638689Sborman 37738689Sborman #ifdef KLUDGELINEMODE 37838689Sborman case TELOPT_SGA: 37938689Sborman if (!kludgelinemode) 38038689Sborman break; 38138689Sborman /* FALL THROUGH */ 38238689Sborman #endif 38338689Sborman case TELOPT_ECHO: 38427110Sminshall settimer(modenegotiated); 3856000Sroot break; 3866000Sroot 38738689Sborman case TELOPT_TM: 38838689Sborman if (flushout) 38938689Sborman flushout = 0; 39038689Sborman set_my_want_state_dont(option); 39138689Sborman set_my_state_dont(option); 39227110Sminshall return; /* Never reply to TM will's/wont's */ 39327110Sminshall 39438689Sborman default: 39538689Sborman break; 39638689Sborman } 39738689Sborman set_my_want_state_dont(option); 39838689Sborman send_dont(option, 0); 39938689Sborman setconnmode(0); /* Set new tty mode */ 40038689Sborman } else if (option == TELOPT_TM) { 40138689Sborman /* 40238689Sborman * Special case for TM. 40338689Sborman */ 40438689Sborman if (flushout) 40538689Sborman flushout = 0; 40638689Sborman set_my_want_state_dont(option); 4076000Sroot } 40838689Sborman set_my_state_dont(option); 4096000Sroot } 4106000Sroot 41132377Sminshall static void 4126000Sroot dooption(option) 4136000Sroot int option; 4146000Sroot { 4156000Sroot char *fmt; 41638689Sborman int new_state_ok = 0; 4176000Sroot 41838689Sborman if (will_wont_resp[option]) { 41938689Sborman --will_wont_resp[option]; 42038689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 42138689Sborman --will_wont_resp[option]; 42238689Sborman } 42337226Sminshall 42438689Sborman if (will_wont_resp[option] == 0) { 42538689Sborman if (my_want_state_is_wont(option)) { 4266000Sroot 42738689Sborman switch (option) { 42838689Sborman 42938689Sborman case TELOPT_TM: 43038689Sborman /* 43138689Sborman * Special case for TM. We send a WILL, but pretend 43238689Sborman * we sent WONT. 43338689Sborman */ 43438689Sborman send_will(option, 0); 43538689Sborman set_my_want_state_wont(TELOPT_TM); 43638689Sborman set_my_state_wont(TELOPT_TM); 43738689Sborman return; 43838689Sborman 43932377Sminshall # if defined(TN3270) 44038689Sborman case TELOPT_EOR: /* end of record */ 44138689Sborman case TELOPT_BINARY: /* binary mode */ 44232377Sminshall # endif /* defined(TN3270) */ 44338689Sborman case TELOPT_NAWS: /* window size */ 44438689Sborman case TELOPT_TSPEED: /* terminal speed */ 44538689Sborman case TELOPT_LFLOW: /* local flow control */ 44638689Sborman case TELOPT_TTYPE: /* terminal type option */ 44738689Sborman case TELOPT_SGA: /* no big deal */ 44838689Sborman new_state_ok = 1; 4496000Sroot break; 4506000Sroot 45138689Sborman case TELOPT_LINEMODE: 45238689Sborman #ifdef KLUDGELINEMODE 45338689Sborman kludgelinemode = 0; 45438689Sborman #endif 45538689Sborman set_my_want_state_will(TELOPT_LINEMODE); 45638689Sborman send_will(option, 0); 45738689Sborman set_my_state_will(TELOPT_LINEMODE); 45838689Sborman slc_init(); 45938689Sborman return; 46038689Sborman 46138689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 46238689Sborman default: 4636000Sroot break; 46438689Sborman } 46538689Sborman 46638689Sborman if (new_state_ok) { 46738689Sborman set_my_want_state_will(option); 46838689Sborman send_will(option, 0); 46938689Sborman } else { 47038689Sborman will_wont_resp[option]++; 47138689Sborman send_wont(option, 0); 47238689Sborman } 47338689Sborman } else { 47438689Sborman /* 47538689Sborman * Handle options that need more things done after the 47638689Sborman * other side has acknowledged the option. 47738689Sborman */ 47838689Sborman switch (option) { 47938689Sborman case TELOPT_LINEMODE: 48038689Sborman #ifdef KLUDGELINEMODE 48138689Sborman kludgelinemode = 0; 48238689Sborman #endif 48338689Sborman set_my_state_will(option); 48438689Sborman slc_init(); 48538689Sborman return; 48638689Sborman } 48738689Sborman } 4886000Sroot } 48938689Sborman set_my_state_will(option); 4906000Sroot } 49127676Sminshall 49238689Sborman static void 49338689Sborman dontoption(option) 49438689Sborman int option; 49538689Sborman { 49638689Sborman 49738689Sborman if (will_wont_resp[option]) { 49838689Sborman --will_wont_resp[option]; 49938689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 50038689Sborman --will_wont_resp[option]; 50138689Sborman } 50238689Sborman 50338689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 504*38811Sborman switch (option) { 505*38811Sborman case TELOPT_LINEMODE: 506*38811Sborman linemode = 0; /* put us back to the default state */ 507*38811Sborman break; 508*38811Sborman } 50938689Sborman /* we always accept a DONT */ 51038689Sborman set_my_want_state_wont(option); 51138689Sborman send_wont(option, 0); 51238689Sborman } 51338689Sborman set_my_state_wont(option); 51438689Sborman } 51538689Sborman 51627676Sminshall /* 51727676Sminshall * suboption() 51827676Sminshall * 51927676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 52027676Sminshall * side. 52127676Sminshall * 52227676Sminshall * Currently we recognize: 52327676Sminshall * 52427676Sminshall * Terminal type, send request. 52537219Sminshall * Terminal speed (send request). 52637219Sminshall * Local flow control (is request). 52738689Sborman * Linemode 52827676Sminshall */ 52927676Sminshall 53038689Sborman static char tty1[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 0 }; 53138689Sborman static char tty2[] = { IAC, SE, 0 }; 53238689Sborman 53332377Sminshall static void 53427676Sminshall suboption() 53527676Sminshall { 53638689Sborman printsub('<', subbuffer, subend-subbuffer+2); 53727676Sminshall switch (subbuffer[0]&0xff) { 53827676Sminshall case TELOPT_TTYPE: 53938689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 54038689Sborman return; 54127676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 54227676Sminshall ; 54327676Sminshall } else { 54427676Sminshall char *name; 54532377Sminshall extern char *getenv(); 54627676Sminshall int len; 54727676Sminshall 54832377Sminshall #if defined(TN3270) 54932531Sminshall if (tn3270_ttype()) { 55032377Sminshall return; 55132377Sminshall } 55232377Sminshall #endif /* defined(TN3270) */ 55327676Sminshall name = getenv("TERM"); 55427676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 55527676Sminshall name = "UNKNOWN"; 55633492Sminshall len = strlen(name); 55727676Sminshall } 55827676Sminshall if ((len + 4+2) < NETROOM()) { 55937226Sminshall char temp[50]; 56037226Sminshall 56138689Sborman strcpy(temp, tty1); 56238689Sborman strcpy(&temp[4], name); 56338689Sborman upcase(&temp[4]); 56438689Sborman strcpy(&temp[4+len], tty2); 56538689Sborman len += 6; 56638689Sborman ring_supply_data(&netoring, temp, len); 56738689Sborman printsub('>', temp+2, len-2); 56832377Sminshall } else { 56937226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 57032377Sminshall /*NOTREACHED*/ 57127676Sminshall } 57227676Sminshall } 57337219Sminshall break; 57437219Sminshall case TELOPT_TSPEED: 57538689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 57638689Sborman return; 57737219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 57838689Sborman long ospeed,ispeed; 57938689Sborman char temp[50]; 58037219Sminshall int len; 58127676Sminshall 58237219Sminshall TerminalSpeeds(&ispeed, &ospeed); 58337219Sminshall 58438689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 58538689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 58638689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 58737219Sminshall 58838689Sborman if (len < NETROOM()) { 58938689Sborman ring_supply_data(&netoring, temp, len); 59038689Sborman printsub('>', temp+2, len - 2); 59137219Sminshall } 59237219Sminshall } 59337219Sminshall break; 59437219Sminshall case TELOPT_LFLOW: 59538689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 59638689Sborman return; 59737219Sminshall if ((subbuffer[1]&0xff) == 1) { 59837219Sminshall localflow = 1; 59937219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 60037219Sminshall localflow = 0; 60137219Sminshall } 60237219Sminshall setcommandmode(); 60338689Sborman setconnmode(0); 60437219Sminshall break; 60538689Sborman 60638689Sborman case TELOPT_LINEMODE: 60738689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 60838689Sborman return; 60938689Sborman switch (subbuffer[1]&0xff) { 61038689Sborman case WILL: 61138689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 61238689Sborman break; 61338689Sborman case WONT: 61438689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 61538689Sborman break; 61638689Sborman case DO: 61738689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 61838689Sborman break; 61938689Sborman case DONT: 62038689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 62138689Sborman break; 62238689Sborman case LM_SLC: 62338689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 62438689Sborman break; 62538689Sborman case LM_MODE: 62638689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 62738689Sborman break; 62838689Sborman default: 62938689Sborman break; 63038689Sborman } 63138689Sborman break; 63227676Sminshall default: 63327676Sminshall break; 63427676Sminshall } 63527676Sminshall } 63638689Sborman 63738689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 63838689Sborman 63938689Sborman lm_will(cmd, len) 64038689Sborman char *cmd; 64138689Sborman { 64238689Sborman switch(cmd[0]) { 64338689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 64438689Sborman default: 64538689Sborman str_lm[3] = DONT; 64638689Sborman str_lm[4] = cmd[0]; 64738689Sborman if (NETROOM() > sizeof(str_lm)) { 64838689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 64938689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 65038689Sborman } 65138689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 65238689Sborman break; 65338689Sborman } 65438689Sborman } 65538689Sborman 65638689Sborman lm_wont(cmd, len) 65738689Sborman char *cmd; 65838689Sborman { 65938689Sborman switch(cmd[0]) { 66038689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 66138689Sborman default: 66238689Sborman /* We are always DONT, so don't respond */ 66338689Sborman return; 66438689Sborman } 66538689Sborman } 66638689Sborman 66738689Sborman lm_do(cmd, len) 66838689Sborman char *cmd; 66938689Sborman { 67038689Sborman switch(cmd[0]) { 67138689Sborman case LM_FORWARDMASK: 67238689Sborman default: 67338689Sborman str_lm[3] = WONT; 67438689Sborman str_lm[4] = cmd[0]; 67538689Sborman if (NETROOM() > sizeof(str_lm)) { 67638689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 67738689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 67838689Sborman } 67938689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 68038689Sborman break; 68138689Sborman } 68238689Sborman } 68338689Sborman 68438689Sborman lm_dont(cmd, len) 68538689Sborman char *cmd; 68638689Sborman { 68738689Sborman switch(cmd[0]) { 68838689Sborman case LM_FORWARDMASK: 68938689Sborman default: 69038689Sborman /* we are always WONT, so don't respond */ 69138689Sborman break; 69238689Sborman } 69338689Sborman } 69438689Sborman 69538689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 69638689Sborman 69738689Sborman lm_mode(cmd, len, init) 69838689Sborman char *cmd; 69938689Sborman int len, init; 70038689Sborman { 70138689Sborman if (len != 1) 70238689Sborman return; 70338689Sborman if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd) 70438689Sborman return; 70538689Sborman if (*cmd&MODE_ACK) 70638689Sborman return; 70738689Sborman linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG)); 70838689Sborman str_lm_mode[4] = linemode; 70938689Sborman if (!init) 71038689Sborman str_lm_mode[4] |= MODE_ACK; 71138689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 71238689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 71338689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 71438689Sborman } 71538689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 71638689Sborman setconnmode(0); /* set changed mode */ 71738689Sborman } 71838689Sborman 71932377Sminshall 72027088Sminshall 72138689Sborman /* 72238689Sborman * slc() 72338689Sborman * Handle special character suboption of LINEMODE. 72438689Sborman */ 72538689Sborman 72638689Sborman struct spc { 72738689Sborman char val; 72838689Sborman char *valp; 72938689Sborman char flags; /* Current flags & level */ 73038689Sborman char mylevel; /* Maximum level & flags */ 73138689Sborman } spc_data[NSLC+1]; 73238689Sborman 73338689Sborman #define SLC_IMPORT 0 73438689Sborman #define SLC_EXPORT 1 73538689Sborman #define SLC_RVALUE 2 73638689Sborman static int slc_mode = SLC_EXPORT; 73738689Sborman 73838689Sborman slc_init() 73938689Sborman { 74038689Sborman register struct spc *spcp; 74138689Sborman extern char *tcval(); 74238689Sborman 74338689Sborman localchars = 1; 74438689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 74538689Sborman spcp->val = 0; 74638689Sborman spcp->valp = 0; 74738689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 74838689Sborman } 74938689Sborman 75038689Sborman #define initfunc(func, flags) { \ 75138689Sborman spcp = &spc_data[func]; \ 75238689Sborman if (spcp->valp = tcval(func)) { \ 75338689Sborman spcp->val = *spcp->valp; \ 75438689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 75538689Sborman } else { \ 75638689Sborman spcp->val = 0; \ 75738689Sborman spcp->mylevel = SLC_DEFAULT; \ 75838689Sborman } \ 75938689Sborman } 76038689Sborman 76138689Sborman initfunc(SLC_SYNCH, 0); 76238689Sborman /* No BRK */ 76338689Sborman initfunc(SLC_AO, 0); 76438689Sborman initfunc(SLC_AYT, 0); 76538689Sborman /* No EOR */ 76638689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 76738689Sborman initfunc(SLC_EOF, 0); 76838689Sborman #ifndef CRAY 76938689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 77038689Sborman #endif 77138689Sborman initfunc(SLC_EC, 0); 77238689Sborman initfunc(SLC_EL, 0); 77338689Sborman #ifndef CRAY 77438689Sborman initfunc(SLC_EW, 0); 77538689Sborman initfunc(SLC_RP, 0); 77638689Sborman initfunc(SLC_LNEXT, 0); 77738689Sborman #endif 77838689Sborman initfunc(SLC_XON, 0); 77938689Sborman initfunc(SLC_XOFF, 0); 78038689Sborman #ifdef CRAY 78138689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 78238689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 78338689Sborman #endif 78438689Sborman /* No FORW1 */ 78538689Sborman /* No FORW2 */ 78638689Sborman 78738689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 78838689Sborman #undef initfunc 78938689Sborman 79038689Sborman if (slc_mode == SLC_EXPORT) 79138689Sborman slc_export(); 79238689Sborman else 79338689Sborman slc_import(1); 79438689Sborman 79538689Sborman } 79638689Sborman 79738689Sborman slcstate() 79838689Sborman { 79938689Sborman printf("Special characters are %s values\n", 80038689Sborman slc_mode == SLC_IMPORT ? "remote default" : 80138689Sborman slc_mode == SLC_EXPORT ? "local" : 80238689Sborman "remote"); 80338689Sborman } 80438689Sborman 80538689Sborman slc_mode_export() 80638689Sborman { 80738689Sborman slc_mode = SLC_EXPORT; 80838689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 80938689Sborman slc_export(); 81038689Sborman } 81138689Sborman 81238689Sborman slc_mode_import(def) 81338689Sborman { 81438689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 81538689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 81638689Sborman slc_import(def); 81738689Sborman } 81838689Sborman 81938689Sborman char slc_import_val[] = { 82038689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 82138689Sborman }; 82238689Sborman char slc_import_def[] = { 82338689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 82438689Sborman }; 82538689Sborman 82638689Sborman slc_import(def) 82738689Sborman int def; 82838689Sborman { 82938689Sborman if (NETROOM() > sizeof(slc_import_val)) { 83038689Sborman if (def) { 83138689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 83238689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 83338689Sborman } else { 83438689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 83538689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 83638689Sborman } 83738689Sborman } 83838689Sborman /*@*/ else printf("slc_import: not enough room\n"); 83938689Sborman } 84038689Sborman 84138689Sborman slc_export() 84238689Sborman { 84338689Sborman register struct spc *spcp; 84438689Sborman 84538689Sborman TerminalDefaultChars(); 84638689Sborman 84738689Sborman slc_start_reply(); 84838689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 84938689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 85038689Sborman spcp->flags = spcp->mylevel; 85138689Sborman if (spcp->valp) 85238689Sborman spcp->val = *spcp->valp; 85338689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 85438689Sborman } 85538689Sborman } 85638689Sborman slc_end_reply(); 85738689Sborman if (slc_update()) 85838689Sborman setconnmode(1); /* set the new character values */ 85938689Sborman } 86038689Sborman 86138689Sborman slc(cp, len) 86238689Sborman register char *cp; 86338689Sborman int len; 86438689Sborman { 86538689Sborman register struct spc *spcp; 86638689Sborman register int func,level; 86738689Sborman 86838689Sborman slc_start_reply(); 86938689Sborman 87038689Sborman for (; len >= 3; len -=3, cp +=3) { 87138689Sborman 87238689Sborman func = cp[SLC_FUNC]; 87338689Sborman 87438689Sborman if (func == 0) { 87538689Sborman /* 87638689Sborman * Client side: always ignore 0 function. 87738689Sborman */ 87838689Sborman continue; 87938689Sborman } 88038689Sborman if (func > NSLC) { 88138689Sborman if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) 88238689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 88338689Sborman continue; 88438689Sborman } 88538689Sborman 88638689Sborman spcp = &spc_data[func]; 88738689Sborman 88838689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 88938689Sborman 89038689Sborman if ((cp[SLC_VALUE] == spcp->val) && 89138689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 89238689Sborman continue; 89338689Sborman } 89438689Sborman 89538689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 89638689Sborman /* 89738689Sborman * This is an error condition, the SLC_ACK 89838689Sborman * bit should never be set for the SLC_DEFAULT 89938689Sborman * level. Our best guess to recover is to 90038689Sborman * ignore the SLC_ACK bit. 90138689Sborman */ 90238689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 90338689Sborman } 90438689Sborman 90538689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 90638689Sborman spcp->val = cp[SLC_VALUE]; 90738689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 90838689Sborman continue; 90938689Sborman } 91038689Sborman 91138689Sborman level &= ~SLC_ACK; 91238689Sborman 91338689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 91438689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 91538689Sborman spcp->val = cp[SLC_VALUE]; 91638689Sborman } 91738689Sborman if (level == SLC_DEFAULT) { 91838689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 91938689Sborman spcp->flags = spcp->mylevel; 92038689Sborman else 92138689Sborman spcp->flags = SLC_NOSUPPORT; 92238689Sborman } 92338689Sborman slc_add_reply(func, spcp->flags, spcp->val); 92438689Sborman } 92538689Sborman slc_end_reply(); 92638689Sborman if (slc_update()) 92738689Sborman setconnmode(1); /* set the new character values */ 92838689Sborman } 92938689Sborman 93038689Sborman slc_check() 93138689Sborman { 93238689Sborman register struct spc *spcp; 93338689Sborman 93438689Sborman slc_start_reply(); 93538689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 93638689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 93738689Sborman spcp->val = *spcp->valp; 93838689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 93938689Sborman } 94038689Sborman } 94138689Sborman slc_end_reply(); 94238689Sborman setconnmode(1); 94338689Sborman } 94438689Sborman 94538689Sborman 94638689Sborman unsigned char slc_reply[128]; 94738689Sborman unsigned char *slc_replyp; 94838689Sborman slc_start_reply() 94938689Sborman { 95038689Sborman slc_replyp = slc_reply; 95138689Sborman *slc_replyp++ = IAC; 95238689Sborman *slc_replyp++ = SB; 95338689Sborman *slc_replyp++ = TELOPT_LINEMODE; 95438689Sborman *slc_replyp++ = LM_SLC; 95538689Sborman } 95638689Sborman 95738689Sborman slc_add_reply(func, flags, value) 95838689Sborman char func; 95938689Sborman char flags; 96038689Sborman char value; 96138689Sborman { 96238689Sborman if ((*slc_replyp++ = func) == IAC) 96338689Sborman *slc_replyp++ = IAC; 96438689Sborman if ((*slc_replyp++ = flags) == IAC) 96538689Sborman *slc_replyp++ = IAC; 96638689Sborman if ((*slc_replyp++ = value) == IAC) 96738689Sborman *slc_replyp++ = IAC; 96838689Sborman } 96938689Sborman 97038689Sborman slc_end_reply() 97138689Sborman { 97238689Sborman register char *cp; 97338689Sborman register int len; 97438689Sborman 97538689Sborman *slc_replyp++ = IAC; 97638689Sborman *slc_replyp++ = SE; 97738689Sborman len = slc_replyp - slc_reply; 97838689Sborman if (len <= 6) 97938689Sborman return; 98038689Sborman if (NETROOM() > len) { 98138689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 98238689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 98338689Sborman } 98438689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 98538689Sborman } 98638689Sborman 98738689Sborman slc_update() 98838689Sborman { 98938689Sborman register struct spc *spcp; 99038689Sborman int need_update = 0; 99138689Sborman 99238689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 99338689Sborman if (!(spcp->flags&SLC_ACK)) 99438689Sborman continue; 99538689Sborman spcp->flags &= ~SLC_ACK; 99638689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 99738689Sborman *spcp->valp = spcp->val; 99838689Sborman need_update = 1; 99938689Sborman } 100038689Sborman } 100138689Sborman return(need_update); 100238689Sborman } 100338689Sborman 100438689Sborman 100538689Sborman 100633804Sminshall int 100732377Sminshall telrcv() 100827110Sminshall { 100932377Sminshall register int c; 101032385Sminshall register int scc; 101132385Sminshall register char *sbp; 101232385Sminshall int count; 101332385Sminshall int returnValue = 0; 101427088Sminshall 101532385Sminshall scc = 0; 101632385Sminshall count = 0; 101732385Sminshall while (TTYROOM() > 2) { 101832385Sminshall if (scc == 0) { 101932385Sminshall if (count) { 102032528Sminshall ring_consumed(&netiring, count); 102132385Sminshall returnValue = 1; 102232385Sminshall count = 0; 102332385Sminshall } 102432528Sminshall sbp = netiring.consume; 102532528Sminshall scc = ring_full_consecutive(&netiring); 102632385Sminshall if (scc == 0) { 102732385Sminshall /* No more data coming in */ 102832385Sminshall break; 102932385Sminshall } 103032385Sminshall } 103132385Sminshall 103232385Sminshall c = *sbp++ & 0xff, scc--; count++; 103332385Sminshall 103432377Sminshall switch (telrcv_state) { 103527110Sminshall 103632377Sminshall case TS_CR: 103732377Sminshall telrcv_state = TS_DATA; 103835518Sminshall if (c == '\0') { 103935518Sminshall break; /* Ignore \0 after CR */ 104038689Sborman } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 104135518Sminshall TTYADD(c); 104235518Sminshall break; 104332377Sminshall } 104435518Sminshall /* Else, fall through */ 104527088Sminshall 104632377Sminshall case TS_DATA: 104732377Sminshall if (c == IAC) { 104832377Sminshall telrcv_state = TS_IAC; 104933804Sminshall break; 105032377Sminshall } 105132377Sminshall # if defined(TN3270) 105232377Sminshall if (In3270) { 105332377Sminshall *Ifrontp++ = c; 105432385Sminshall while (scc > 0) { 105532385Sminshall c = *sbp++ & 0377, scc--; count++; 105632377Sminshall if (c == IAC) { 105732377Sminshall telrcv_state = TS_IAC; 105834304Sminshall break; 105932377Sminshall } 106032377Sminshall *Ifrontp++ = c; 106132377Sminshall } 106232377Sminshall } else 106332377Sminshall # endif /* defined(TN3270) */ 106435518Sminshall /* 106535518Sminshall * The 'crmod' hack (see following) is needed 106635518Sminshall * since we can't * set CRMOD on output only. 106735518Sminshall * Machines like MULTICS like to send \r without 106835518Sminshall * \n; since we must turn off CRMOD to get proper 106935518Sminshall * input, the mapping is done here (sigh). 107035518Sminshall */ 107138689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 107235518Sminshall if (scc > 0) { 107335518Sminshall c = *sbp&0xff; 107435518Sminshall if (c == 0) { 107535518Sminshall sbp++, scc--; count++; 107635518Sminshall /* a "true" CR */ 107732377Sminshall TTYADD('\r'); 107838689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 107935518Sminshall (c == '\n')) { 108035518Sminshall sbp++, scc--; count++; 108132377Sminshall TTYADD('\n'); 108235518Sminshall } else { 108335518Sminshall TTYADD('\r'); 108435518Sminshall if (crmod) { 108535518Sminshall TTYADD('\n'); 108632377Sminshall } 108732377Sminshall } 108835518Sminshall } else { 108935518Sminshall telrcv_state = TS_CR; 109035518Sminshall TTYADD('\r'); 109135518Sminshall if (crmod) { 109235518Sminshall TTYADD('\n'); 109335518Sminshall } 109432377Sminshall } 109532377Sminshall } else { 109632377Sminshall TTYADD(c); 109732377Sminshall } 109832377Sminshall continue; 109927088Sminshall 110032377Sminshall case TS_IAC: 110138689Sborman process_iac: 110232377Sminshall switch (c) { 110332377Sminshall 110432377Sminshall case WILL: 110532377Sminshall telrcv_state = TS_WILL; 110632377Sminshall continue; 110727261Sminshall 110832377Sminshall case WONT: 110932377Sminshall telrcv_state = TS_WONT; 111032377Sminshall continue; 111127261Sminshall 111232377Sminshall case DO: 111332377Sminshall telrcv_state = TS_DO; 111432377Sminshall continue; 111527261Sminshall 111632377Sminshall case DONT: 111732377Sminshall telrcv_state = TS_DONT; 111832377Sminshall continue; 111927261Sminshall 112032377Sminshall case DM: 112132377Sminshall /* 112232377Sminshall * We may have missed an urgent notification, 112332377Sminshall * so make sure we flush whatever is in the 112432377Sminshall * buffer currently. 112532377Sminshall */ 112632377Sminshall SYNCHing = 1; 112732377Sminshall ttyflush(1); 112832554Sminshall SYNCHing = stilloob(); 112932377Sminshall settimer(gotDM); 113032377Sminshall break; 113127088Sminshall 113232377Sminshall case NOP: 113332377Sminshall case GA: 113432377Sminshall break; 113527088Sminshall 113632377Sminshall case SB: 113732377Sminshall SB_CLEAR(); 113832377Sminshall telrcv_state = TS_SB; 113938689Sborman printoption("RCVD", "IAC", SB); 114032377Sminshall continue; 114127261Sminshall 114232377Sminshall # if defined(TN3270) 114332377Sminshall case EOR: 114432377Sminshall if (In3270) { 114532377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 114632377Sminshall if (Ibackp == Ifrontp) { 114732377Sminshall Ibackp = Ifrontp = Ibuf; 114832377Sminshall ISend = 0; /* should have been! */ 114932377Sminshall } else { 115032377Sminshall ISend = 1; 115127088Sminshall } 115227088Sminshall } 115327088Sminshall break; 115432377Sminshall # endif /* defined(TN3270) */ 115532377Sminshall 115632377Sminshall case IAC: 115732377Sminshall # if !defined(TN3270) 115832377Sminshall TTYADD(IAC); 115932377Sminshall # else /* !defined(TN3270) */ 116032377Sminshall if (In3270) { 116132377Sminshall *Ifrontp++ = IAC; 116232377Sminshall } else { 116332377Sminshall TTYADD(IAC); 116432377Sminshall } 116532377Sminshall # endif /* !defined(TN3270) */ 116627088Sminshall break; 116732377Sminshall 116827088Sminshall default: 116927088Sminshall break; 117027088Sminshall } 117132377Sminshall telrcv_state = TS_DATA; 117232377Sminshall continue; 117327088Sminshall 117432377Sminshall case TS_WILL: 117537226Sminshall printoption("RCVD", "will", c); 117638689Sborman willoption(c); 117732377Sminshall SetIn3270(); 117832377Sminshall telrcv_state = TS_DATA; 117932377Sminshall continue; 118027110Sminshall 118132377Sminshall case TS_WONT: 118237226Sminshall printoption("RCVD", "wont", c); 118338689Sborman wontoption(c); 118432377Sminshall SetIn3270(); 118532377Sminshall telrcv_state = TS_DATA; 118632377Sminshall continue; 118727088Sminshall 118832377Sminshall case TS_DO: 118937226Sminshall printoption("RCVD", "do", c); 119037226Sminshall dooption(c); 119132377Sminshall SetIn3270(); 119237219Sminshall if (c == TELOPT_NAWS) { 119337219Sminshall sendnaws(); 119437219Sminshall } else if (c == TELOPT_LFLOW) { 119537219Sminshall localflow = 1; 119637219Sminshall setcommandmode(); 119738689Sborman setconnmode(0); 119837219Sminshall } 119932377Sminshall telrcv_state = TS_DATA; 120032377Sminshall continue; 120127088Sminshall 120232377Sminshall case TS_DONT: 120337226Sminshall printoption("RCVD", "dont", c); 120438689Sborman dontoption(c); 120537226Sminshall flushline = 1; 120638689Sborman setconnmode(0); /* set new tty mode (maybe) */ 120732377Sminshall SetIn3270(); 120832377Sminshall telrcv_state = TS_DATA; 120932377Sminshall continue; 121027088Sminshall 121132377Sminshall case TS_SB: 121232377Sminshall if (c == IAC) { 121332377Sminshall telrcv_state = TS_SE; 121432377Sminshall } else { 121532377Sminshall SB_ACCUM(c); 121632377Sminshall } 121732377Sminshall continue; 121827088Sminshall 121932377Sminshall case TS_SE: 122032377Sminshall if (c != SE) { 122132377Sminshall if (c != IAC) { 122238689Sborman /* 122338689Sborman * This is an error. We only expect to get 122438689Sborman * "IAC IAC" or "IAC SE". Several things may 122538689Sborman * have happend. An IAC was not doubled, the 122638689Sborman * IAC SE was left off, or another option got 122738689Sborman * inserted into the suboption are all possibilities. 122838689Sborman * If we assume that the IAC was not doubled, 122938689Sborman * and really the IAC SE was left off, we could 123038689Sborman * get into an infinate loop here. So, instead, 123138689Sborman * we terminate the suboption, and process the 123238689Sborman * partial suboption if we can. 123338689Sborman */ 123438689Sborman SB_TERM(); 123532377Sminshall SB_ACCUM(IAC); 123638689Sborman SB_ACCUM(c); 123738689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 123838689Sborman suboption(); /* handle sub-option */ 123938689Sborman SetIn3270(); 124038689Sborman telrcv_state = TS_IAC; 124138689Sborman goto process_iac; 124232377Sminshall } 124332377Sminshall SB_ACCUM(c); 124432377Sminshall telrcv_state = TS_SB; 124532377Sminshall } else { 124632377Sminshall SB_TERM(); 124738689Sborman SB_ACCUM(IAC); 124838689Sborman SB_ACCUM(SE); 124932377Sminshall suboption(); /* handle sub-option */ 125032377Sminshall SetIn3270(); 125132377Sminshall telrcv_state = TS_DATA; 125232377Sminshall } 125327088Sminshall } 125427088Sminshall } 125532667Sminshall if (count) 125632667Sminshall ring_consumed(&netiring, count); 125732385Sminshall return returnValue||count; 125827088Sminshall } 125932385Sminshall 126032385Sminshall static int 126132554Sminshall telsnd() 126232385Sminshall { 126332385Sminshall int tcc; 126432385Sminshall int count; 126532385Sminshall int returnValue = 0; 126632385Sminshall char *tbp; 126732385Sminshall 126832385Sminshall tcc = 0; 126932385Sminshall count = 0; 127032385Sminshall while (NETROOM() > 2) { 127132385Sminshall register int sc; 127232385Sminshall register int c; 127332385Sminshall 127432385Sminshall if (tcc == 0) { 127532385Sminshall if (count) { 127632528Sminshall ring_consumed(&ttyiring, count); 127732385Sminshall returnValue = 1; 127832385Sminshall count = 0; 127932385Sminshall } 128032528Sminshall tbp = ttyiring.consume; 128132528Sminshall tcc = ring_full_consecutive(&ttyiring); 128232385Sminshall if (tcc == 0) { 128332385Sminshall break; 128432385Sminshall } 128532385Sminshall } 128632385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 128732385Sminshall if (sc == escape) { 128838689Sborman /* 128938689Sborman * Double escape is a pass through of a single escape character. 129038689Sborman */ 129138689Sborman if (tcc && strip(*tbp) == escape) { 129238689Sborman tbp++; 129338689Sborman tcc--; 129438689Sborman count++; 129538689Sborman } else { 129638689Sborman command(0, tbp, tcc); 129738689Sborman count += tcc; 129838689Sborman tcc = 0; 129938689Sborman flushline = 1; 130038689Sborman break; 130138689Sborman } 130238689Sborman } 130338689Sborman #ifdef KLUDGELINEMODE 130438689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 130532385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 130632385Sminshall tcc--; tbp++; count++; 130732385Sminshall } else { 130832385Sminshall dontlecho = !dontlecho; 130932385Sminshall settimer(echotoggle); 131038689Sborman setconnmode(0); 131132385Sminshall flushline = 1; 131232385Sminshall break; 131332385Sminshall } 131432385Sminshall } 131538689Sborman #endif 131638689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 131732385Sminshall if (TerminalSpecialChars(sc) == 0) { 131832385Sminshall break; 131932385Sminshall } 132032385Sminshall } 132138689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 132232385Sminshall switch (c) { 132332385Sminshall case '\n': 132432385Sminshall /* 132532385Sminshall * If we are in CRMOD mode (\r ==> \n) 132632385Sminshall * on our local machine, then probably 132732385Sminshall * a newline (unix) is CRLF (TELNET). 132832385Sminshall */ 132932385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 133032385Sminshall NETADD('\r'); 133132385Sminshall } 133232385Sminshall NETADD('\n'); 133332385Sminshall flushline = 1; 133432385Sminshall break; 133532385Sminshall case '\r': 133632385Sminshall if (!crlf) { 133732385Sminshall NET2ADD('\r', '\0'); 133832385Sminshall } else { 133932385Sminshall NET2ADD('\r', '\n'); 134032385Sminshall } 134132385Sminshall flushline = 1; 134232385Sminshall break; 134332385Sminshall case IAC: 134432385Sminshall NET2ADD(IAC, IAC); 134532385Sminshall break; 134632385Sminshall default: 134732385Sminshall NETADD(c); 134832385Sminshall break; 134932385Sminshall } 135032385Sminshall } else if (c == IAC) { 135132385Sminshall NET2ADD(IAC, IAC); 135232385Sminshall } else { 135332385Sminshall NETADD(c); 135432385Sminshall } 135532385Sminshall } 135632667Sminshall if (count) 135732667Sminshall ring_consumed(&ttyiring, count); 135832385Sminshall return returnValue||count; /* Non-zero if we did anything */ 135932385Sminshall } 136032377Sminshall 136127088Sminshall /* 136232377Sminshall * Scheduler() 136332377Sminshall * 136432377Sminshall * Try to do something. 136532377Sminshall * 136632377Sminshall * If we do something useful, return 1; else return 0. 136732377Sminshall * 136827110Sminshall */ 136927110Sminshall 137027110Sminshall 137132377Sminshall int 137232377Sminshall Scheduler(block) 137332377Sminshall int block; /* should we block in the select ? */ 137427110Sminshall { 137532377Sminshall /* One wants to be a bit careful about setting returnValue 137632377Sminshall * to one, since a one implies we did some useful work, 137732377Sminshall * and therefore probably won't be called to block next 137832377Sminshall * time (TN3270 mode only). 137932377Sminshall */ 138032531Sminshall int returnValue; 138132531Sminshall int netin, netout, netex, ttyin, ttyout; 138227110Sminshall 138332531Sminshall /* Decide which rings should be processed */ 138432531Sminshall 138532531Sminshall netout = ring_full_count(&netoring) && 138638689Sborman (flushline || 138738689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 138838689Sborman #ifdef KLUDGELINEMODE 138938689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 139038689Sborman #endif 139138689Sborman ) || 139238689Sborman my_want_state_is_will(TELOPT_BINARY)); 139332531Sminshall ttyout = ring_full_count(&ttyoring); 139432531Sminshall 139532377Sminshall #if defined(TN3270) 139632531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 139732377Sminshall #else /* defined(TN3270) */ 139832531Sminshall ttyin = ring_empty_count(&ttyiring); 139932377Sminshall #endif /* defined(TN3270) */ 140032531Sminshall 140132531Sminshall #if defined(TN3270) 140232531Sminshall netin = ring_empty_count(&netiring); 140332377Sminshall # else /* !defined(TN3270) */ 140432531Sminshall netin = !ISend && ring_empty_count(&netiring); 140532377Sminshall # endif /* !defined(TN3270) */ 140632531Sminshall 140732531Sminshall netex = !SYNCHing; 140832531Sminshall 140932531Sminshall /* If we have seen a signal recently, reset things */ 141032377Sminshall # if defined(TN3270) && defined(unix) 141132377Sminshall if (HaveInput) { 141232377Sminshall HaveInput = 0; 141332377Sminshall signal(SIGIO, inputAvailable); 141432377Sminshall } 141532377Sminshall #endif /* defined(TN3270) && defined(unix) */ 141632377Sminshall 141732531Sminshall /* Call to system code to process rings */ 141827178Sminshall 141932531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 142027178Sminshall 142132531Sminshall /* Now, look at the input rings, looking for work to do. */ 142232377Sminshall 142332531Sminshall if (ring_full_count(&ttyiring)) { 142432377Sminshall # if defined(TN3270) 142532377Sminshall if (In3270) { 142634848Sminshall int c; 142734848Sminshall 142833804Sminshall c = DataFromTerminal(ttyiring.consume, 142932528Sminshall ring_full_consecutive(&ttyiring)); 143032377Sminshall if (c) { 143132377Sminshall returnValue = 1; 143232667Sminshall ring_consumed(&ttyiring, c); 143332377Sminshall } 143432377Sminshall } else { 143532377Sminshall # endif /* defined(TN3270) */ 143632554Sminshall returnValue |= telsnd(); 143732377Sminshall # if defined(TN3270) 143827178Sminshall } 143932531Sminshall # endif /* defined(TN3270) */ 144027178Sminshall } 144132377Sminshall 144232528Sminshall if (ring_full_count(&netiring)) { 144332377Sminshall # if !defined(TN3270) 144432385Sminshall returnValue |= telrcv(); 144532377Sminshall # else /* !defined(TN3270) */ 144632377Sminshall returnValue = Push3270(); 144732377Sminshall # endif /* !defined(TN3270) */ 144832377Sminshall } 144932377Sminshall return returnValue; 145027178Sminshall } 145127178Sminshall 145227178Sminshall /* 145332377Sminshall * Select from tty and network... 145427088Sminshall */ 145532377Sminshall void 145632377Sminshall telnet() 145727088Sminshall { 145832531Sminshall sys_telnet_init(); 145927088Sminshall 146032377Sminshall # if !defined(TN3270) 146132377Sminshall if (telnetport) { 146238689Sborman send_do(TELOPT_SGA, 1); 146338689Sborman send_will(TELOPT_TTYPE, 1); 146438689Sborman send_will(TELOPT_NAWS, 1); 146538689Sborman send_will(TELOPT_TSPEED, 1); 146638689Sborman send_will(TELOPT_LFLOW, 1); 146738689Sborman send_will(TELOPT_LINEMODE, 1); 146827178Sminshall } 146932377Sminshall # endif /* !defined(TN3270) */ 147027088Sminshall 147132377Sminshall # if !defined(TN3270) 147232377Sminshall for (;;) { 147332385Sminshall int schedValue; 147432385Sminshall 147532385Sminshall while ((schedValue = Scheduler(0)) != 0) { 147632385Sminshall if (schedValue == -1) { 147732385Sminshall setcommandmode(); 147832385Sminshall return; 147932385Sminshall } 148032385Sminshall } 148132385Sminshall 148232531Sminshall if (Scheduler(1) == -1) { 148332377Sminshall setcommandmode(); 148432377Sminshall return; 148532377Sminshall } 148632377Sminshall } 148732377Sminshall # else /* !defined(TN3270) */ 148832377Sminshall for (;;) { 148932377Sminshall int schedValue; 149027088Sminshall 149132377Sminshall while (!In3270 && !shell_active) { 149232531Sminshall if (Scheduler(1) == -1) { 149332377Sminshall setcommandmode(); 149432377Sminshall return; 149532377Sminshall } 149627088Sminshall } 149732377Sminshall 149832377Sminshall while ((schedValue = Scheduler(0)) != 0) { 149932377Sminshall if (schedValue == -1) { 150032377Sminshall setcommandmode(); 150132377Sminshall return; 150232377Sminshall } 150327088Sminshall } 150432377Sminshall /* If there is data waiting to go out to terminal, don't 150532377Sminshall * schedule any more data for the terminal. 150632377Sminshall */ 150734304Sminshall if (ring_full_count(&ttyoring)) { 150832377Sminshall schedValue = 1; 150927088Sminshall } else { 151032377Sminshall if (shell_active) { 151132377Sminshall if (shell_continue() == 0) { 151232377Sminshall ConnectScreen(); 151327088Sminshall } 151432377Sminshall } else if (In3270) { 151532377Sminshall schedValue = DoTerminalOutput(); 151632377Sminshall } 151727088Sminshall } 151832377Sminshall if (schedValue && (shell_active == 0)) { 151932531Sminshall if (Scheduler(1) == -1) { 152032377Sminshall setcommandmode(); 152132377Sminshall return; 152232377Sminshall } 152327088Sminshall } 152432377Sminshall } 152532377Sminshall # endif /* !defined(TN3270) */ 152627088Sminshall } 152732377Sminshall 152834848Sminshall #if 0 /* XXX - this not being in is a bug */ 152927088Sminshall /* 153032554Sminshall * nextitem() 153132554Sminshall * 153232554Sminshall * Return the address of the next "item" in the TELNET data 153332554Sminshall * stream. This will be the address of the next character if 153432554Sminshall * the current address is a user data character, or it will 153532554Sminshall * be the address of the character following the TELNET command 153632554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 153732554Sminshall * character. 153832554Sminshall */ 153932554Sminshall 154032554Sminshall static char * 154132554Sminshall nextitem(current) 154232554Sminshall char *current; 154332554Sminshall { 154432554Sminshall if ((*current&0xff) != IAC) { 154532554Sminshall return current+1; 154632554Sminshall } 154732554Sminshall switch (*(current+1)&0xff) { 154832554Sminshall case DO: 154932554Sminshall case DONT: 155032554Sminshall case WILL: 155132554Sminshall case WONT: 155232554Sminshall return current+3; 155332554Sminshall case SB: /* loop forever looking for the SE */ 155432554Sminshall { 155532554Sminshall register char *look = current+2; 155632554Sminshall 155732554Sminshall for (;;) { 155832554Sminshall if ((*look++&0xff) == IAC) { 155932554Sminshall if ((*look++&0xff) == SE) { 156032554Sminshall return look; 156132554Sminshall } 156232554Sminshall } 156332554Sminshall } 156432554Sminshall } 156532554Sminshall default: 156632554Sminshall return current+2; 156732554Sminshall } 156832554Sminshall } 156934848Sminshall #endif /* 0 */ 157032554Sminshall 157132554Sminshall /* 157232554Sminshall * netclear() 157332554Sminshall * 157432554Sminshall * We are about to do a TELNET SYNCH operation. Clear 157532554Sminshall * the path to the network. 157632554Sminshall * 157732554Sminshall * Things are a bit tricky since we may have sent the first 157832554Sminshall * byte or so of a previous TELNET command into the network. 157932554Sminshall * So, we have to scan the network buffer from the beginning 158032554Sminshall * until we are up to where we want to be. 158132554Sminshall * 158232554Sminshall * A side effect of what we do, just to keep things 158332554Sminshall * simple, is to clear the urgent data pointer. The principal 158432554Sminshall * caller should be setting the urgent data pointer AFTER calling 158532554Sminshall * us in any case. 158632554Sminshall */ 158732554Sminshall 158832554Sminshall static void 158932554Sminshall netclear() 159032554Sminshall { 159132554Sminshall #if 0 /* XXX */ 159232554Sminshall register char *thisitem, *next; 159332554Sminshall char *good; 159432554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 159532554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 159632554Sminshall 159732554Sminshall thisitem = netobuf; 159832554Sminshall 159932554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 160032554Sminshall thisitem = next; 160132554Sminshall } 160232554Sminshall 160332554Sminshall /* Now, thisitem is first before/at boundary. */ 160432554Sminshall 160532554Sminshall good = netobuf; /* where the good bytes go */ 160632554Sminshall 160732554Sminshall while (netoring.add > thisitem) { 160832554Sminshall if (wewant(thisitem)) { 160932554Sminshall int length; 161032554Sminshall 161132554Sminshall next = thisitem; 161232554Sminshall do { 161332554Sminshall next = nextitem(next); 161432554Sminshall } while (wewant(next) && (nfrontp > next)); 161532554Sminshall length = next-thisitem; 161632554Sminshall memcpy(good, thisitem, length); 161732554Sminshall good += length; 161832554Sminshall thisitem = next; 161932554Sminshall } else { 162032554Sminshall thisitem = nextitem(thisitem); 162132554Sminshall } 162232554Sminshall } 162332554Sminshall 162432554Sminshall #endif /* 0 */ 162532554Sminshall } 162632554Sminshall 162732554Sminshall /* 162832377Sminshall * These routines add various telnet commands to the data stream. 162927088Sminshall */ 163032377Sminshall 163132554Sminshall static void 163232554Sminshall doflush() 163332554Sminshall { 163432554Sminshall NET2ADD(IAC, DO); 163532554Sminshall NETADD(TELOPT_TM); 163632554Sminshall flushline = 1; 163732554Sminshall flushout = 1; 163832554Sminshall ttyflush(1); /* Flush/drop output */ 163932554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 164037226Sminshall printoption("SENT", "do", TELOPT_TM); 164132554Sminshall } 164232554Sminshall 164332377Sminshall void 164432377Sminshall xmitAO() 164527088Sminshall { 164632377Sminshall NET2ADD(IAC, AO); 164732377Sminshall if (autoflush) { 164832377Sminshall doflush(); 164932377Sminshall } 165032377Sminshall } 165127088Sminshall 165232377Sminshall 165332377Sminshall void 165432377Sminshall xmitEL() 165527088Sminshall { 165632377Sminshall NET2ADD(IAC, EL); 165727088Sminshall } 165827088Sminshall 165932377Sminshall void 166032377Sminshall xmitEC() 166127088Sminshall { 166232377Sminshall NET2ADD(IAC, EC); 166327088Sminshall } 166427088Sminshall 166532377Sminshall 166632377Sminshall #if defined(NOT43) 166732377Sminshall int 166832377Sminshall #else /* defined(NOT43) */ 166932377Sminshall void 167032377Sminshall #endif /* defined(NOT43) */ 167132377Sminshall dosynch() 167227088Sminshall { 167332377Sminshall netclear(); /* clear the path to the network */ 167433294Sminshall NETADD(IAC); 167533294Sminshall setneturg(); 167633294Sminshall NETADD(DM); 167727088Sminshall 167832377Sminshall #if defined(NOT43) 167932377Sminshall return 0; 168032377Sminshall #endif /* defined(NOT43) */ 168127088Sminshall } 168227088Sminshall 168332377Sminshall void 168432377Sminshall intp() 168527088Sminshall { 168632377Sminshall NET2ADD(IAC, IP); 168732377Sminshall flushline = 1; 168832377Sminshall if (autoflush) { 168932377Sminshall doflush(); 169032377Sminshall } 169132377Sminshall if (autosynch) { 169232377Sminshall dosynch(); 169332377Sminshall } 169427088Sminshall } 169527186Sminshall 169632377Sminshall void 169732377Sminshall sendbrk() 169827186Sminshall { 169932377Sminshall NET2ADD(IAC, BREAK); 170032377Sminshall flushline = 1; 170132377Sminshall if (autoflush) { 170232377Sminshall doflush(); 170332377Sminshall } 170432377Sminshall if (autosynch) { 170532377Sminshall dosynch(); 170632377Sminshall } 170727186Sminshall } 170838689Sborman 170938689Sborman void 171038689Sborman sendabort() 171138689Sborman { 171238689Sborman NET2ADD(IAC, ABORT); 171338689Sborman flushline = 1; 171438689Sborman if (autoflush) { 171538689Sborman doflush(); 171638689Sborman } 171738689Sborman if (autosynch) { 171838689Sborman dosynch(); 171938689Sborman } 172038689Sborman } 172138689Sborman 172238689Sborman void 172338689Sborman sendsusp() 172438689Sborman { 172538689Sborman NET2ADD(IAC, SUSP); 172638689Sborman flushline = 1; 172738689Sborman if (autoflush) { 172838689Sborman doflush(); 172938689Sborman } 173038689Sborman if (autosynch) { 173138689Sborman dosynch(); 173238689Sborman } 173338689Sborman } 173438689Sborman 173538689Sborman void 173638689Sborman sendeof() 173738689Sborman { 173838689Sborman NET2ADD(IAC, xEOF); 173938689Sborman } 174038689Sborman 174137219Sminshall /* 174237219Sminshall * Send a window size update to the remote system. 174337219Sminshall */ 174437219Sminshall 174537219Sminshall void 174637219Sminshall sendnaws() 174737219Sminshall { 174837219Sminshall long rows, cols; 174938689Sborman unsigned char tmp[16]; 175038689Sborman register unsigned char *cp; 175137219Sminshall 175238689Sborman if (my_state_is_wont(TELOPT_NAWS)) 175338689Sborman return; 175437219Sminshall 175538689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 175638689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 175738689Sborman 175837219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 175937219Sminshall return; 176037219Sminshall } 176137219Sminshall 176238689Sborman cp = tmp; 176338689Sborman 176438689Sborman *cp++ = IAC; 176538689Sborman *cp++ = SB; 176638689Sborman *cp++ = TELOPT_NAWS; 176738689Sborman PUTSHORT(cp, cols); 176838689Sborman PUTSHORT(cp, rows); 176938689Sborman *cp++ = IAC; 177038689Sborman *cp++ = SE; 177138689Sborman if (NETROOM() >= cp - tmp) { 177238689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 177338689Sborman printsub('>', tmp+2, cp - tmp - 2); 177437219Sminshall } 177537219Sminshall } 177637226Sminshall 177737226Sminshall tel_enter_binary() 177837226Sminshall { 177938689Sborman send_do(TELOPT_BINARY, 1); 178038689Sborman send_will(TELOPT_BINARY, 1); 178137226Sminshall } 178237226Sminshall 178337226Sminshall tel_leave_binary() 178437226Sminshall { 178538689Sborman send_dont(TELOPT_BINARY, 1); 178638689Sborman send_wont(TELOPT_BINARY, 1); 178737226Sminshall } 1788