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*38689Sborman static char sccsid[] = "@(#)telnet.c 5.41 (Berkeley) 08/21/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 */ 61*38689Sborman char do_dont_resp[256]; 62*38689Sborman 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; 11627021Sminshall 117*38689Sborman #ifdef KLUDGELINEMODE 118*38689Sborman int kludgelinemode = 1; 119*38689Sborman #endif 120*38689Sborman 12132377Sminshall /* 12232377Sminshall * The following are some clocks used to decide how to interpret 12332377Sminshall * the relationship between various variables. 12432377Sminshall */ 1256000Sroot 12632377Sminshall Clocks clocks; 12732377Sminshall 128*38689Sborman #ifdef notdef 12932377Sminshall Modelist modelist[] = { 13032377Sminshall { "telnet command mode", COMMAND_LINE }, 13132377Sminshall { "character-at-a-time mode", 0 }, 13232377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 13332377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 13432377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 13532377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 13632377Sminshall { "3270 mode", 0 }, 13732377Sminshall }; 138*38689Sborman #endif 1396000Sroot 14032377Sminshall 14132377Sminshall /* 14232377Sminshall * Initialize telnet environment. 14332377Sminshall */ 1446000Sroot 14532377Sminshall init_telnet() 14632377Sminshall { 14732377Sminshall SB_CLEAR(); 14837226Sminshall ClearArray(options); 1496000Sroot 15037219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 1516000Sroot 15232377Sminshall SYNCHing = 0; 1536000Sroot 15432377Sminshall /* Don't change NetTrace */ 1556000Sroot 15632377Sminshall escape = CONTROL(']'); 15732377Sminshall echoc = CONTROL('E'); 1586000Sroot 15932377Sminshall flushline = 1; 16032377Sminshall telrcv_state = TS_DATA; 16132377Sminshall } 16232554Sminshall 1636000Sroot 16432554Sminshall #include <varargs.h> 1656000Sroot 16634848Sminshall /*VARARGS*/ 16732554Sminshall static void 16832554Sminshall printring(va_alist) 16932554Sminshall va_dcl 17032554Sminshall { 17132554Sminshall va_list ap; 17232554Sminshall char buffer[100]; /* where things go */ 17332554Sminshall char *ptr; 17432554Sminshall char *format; 17532554Sminshall char *string; 17632554Sminshall Ring *ring; 17732554Sminshall int i; 17832554Sminshall 17932554Sminshall va_start(ap); 18032554Sminshall 18132554Sminshall ring = va_arg(ap, Ring *); 18232554Sminshall format = va_arg(ap, char *); 18332554Sminshall ptr = buffer; 18432554Sminshall 18532554Sminshall while ((i = *format++) != 0) { 18632554Sminshall if (i == '%') { 18732554Sminshall i = *format++; 18832554Sminshall switch (i) { 18932554Sminshall case 'c': 19032554Sminshall *ptr++ = va_arg(ap, int); 19132554Sminshall break; 19232554Sminshall case 's': 19332554Sminshall string = va_arg(ap, char *); 19432554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19532554Sminshall ring_supply_data(ring, string, strlen(string)); 19632554Sminshall ptr = buffer; 19732554Sminshall break; 19832554Sminshall case 0: 19932554Sminshall ExitString("printring: trailing %%.\n", 1); 20032554Sminshall /*NOTREACHED*/ 20132554Sminshall default: 20232554Sminshall ExitString("printring: unknown format character.\n", 1); 20332554Sminshall /*NOTREACHED*/ 20432554Sminshall } 20532554Sminshall } else { 20632554Sminshall *ptr++ = i; 20732554Sminshall } 20832554Sminshall } 20932554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21032554Sminshall } 21132554Sminshall 21237226Sminshall /* 21337226Sminshall * These routines are in charge of sending option negotiations 21437226Sminshall * to the other side. 21537226Sminshall * 21637226Sminshall * The basic idea is that we send the negotiation if either side 21737226Sminshall * is in disagreement as to what the current state should be. 21837226Sminshall */ 21932554Sminshall 220*38689Sborman send_do(c, init) 221*38689Sborman register int c, init; 2226000Sroot { 223*38689Sborman if (init) { 224*38689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 225*38689Sborman my_want_state_is_do(c)) 226*38689Sborman return; 227*38689Sborman set_my_want_state_do(c); 228*38689Sborman do_dont_resp[c]++; 22937226Sminshall } 230*38689Sborman NET2ADD(IAC, DO); 231*38689Sborman NETADD(c); 232*38689Sborman printoption("SENT", "do", c); 23337226Sminshall } 23437226Sminshall 23537226Sminshall void 236*38689Sborman send_dont(c, init) 237*38689Sborman register int c, init; 23837226Sminshall { 239*38689Sborman if (init) { 240*38689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 241*38689Sborman my_want_state_is_dont(c)) 242*38689Sborman return; 243*38689Sborman set_my_want_state_dont(c); 244*38689Sborman do_dont_resp[c]++; 24537226Sminshall } 246*38689Sborman NET2ADD(IAC, DONT); 247*38689Sborman NETADD(c); 248*38689Sborman printoption("SENT", "dont", c); 24937226Sminshall } 25037226Sminshall 25137226Sminshall void 252*38689Sborman send_will(c, init) 253*38689Sborman register int c, init; 25437226Sminshall { 255*38689Sborman if (init) { 256*38689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 257*38689Sborman my_want_state_is_will(c)) 258*38689Sborman return; 259*38689Sborman set_my_want_state_will(c); 260*38689Sborman will_wont_resp[c]++; 26137226Sminshall } 262*38689Sborman NET2ADD(IAC, WILL); 263*38689Sborman NETADD(c); 264*38689Sborman printoption("SENT", "will", c); 26537226Sminshall } 26637226Sminshall 26737226Sminshall void 268*38689Sborman send_wont(c, init) 269*38689Sborman register int c, init; 27037226Sminshall { 271*38689Sborman if (init) { 272*38689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 273*38689Sborman my_want_state_is_wont(c)) 274*38689Sborman return; 275*38689Sborman set_my_want_state_wont(c); 276*38689Sborman will_wont_resp[c]++; 27737226Sminshall } 278*38689Sborman NET2ADD(IAC, WONT); 279*38689Sborman NETADD(c); 280*38689Sborman printoption("SENT", "wont", c); 28137226Sminshall } 28237226Sminshall 28337226Sminshall 28437226Sminshall void 28537226Sminshall willoption(option) 28637226Sminshall int option; 28737226Sminshall { 2886000Sroot char *fmt; 289*38689Sborman int new_state_ok = 0; 2906000Sroot 291*38689Sborman if (do_dont_resp[option]) { 292*38689Sborman --do_dont_resp[option]; 293*38689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 294*38689Sborman --do_dont_resp[option]; 295*38689Sborman } 29637226Sminshall 297*38689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 2986000Sroot 299*38689Sborman switch (option) { 300*38689Sborman 301*38689Sborman case TELOPT_ECHO: 302*38689Sborman # if defined(TN3270) 303*38689Sborman /* 304*38689Sborman * The following is a pain in the rear-end. 305*38689Sborman * Various IBM servers (some versions of Wiscnet, 306*38689Sborman * possibly Fibronics/Spartacus, and who knows who 307*38689Sborman * else) will NOT allow us to send "DO SGA" too early 308*38689Sborman * in the setup proceedings. On the other hand, 309*38689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 310*38689Sborman * So, we are stuck. Empirically (but, based on 311*38689Sborman * a VERY small sample), the IBM servers don't send 312*38689Sborman * out anything about ECHO, so we postpone our sending 313*38689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 314*38689Sborman * DO send). 315*38689Sborman */ 316*38689Sborman { 317*38689Sborman if (askedSGA == 0) { 318*38689Sborman askedSGA = 1; 319*38689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 320*38689Sborman send_do(TELOPT_SGA, 1); 32132377Sminshall } 32232377Sminshall } 323*38689Sborman /* Fall through */ 324*38689Sborman case TELOPT_EOR: 325*38689Sborman case TELOPT_BINARY: 326*38689Sborman #endif /* defined(TN3270) */ 327*38689Sborman case TELOPT_SGA: 32827110Sminshall settimer(modenegotiated); 329*38689Sborman new_state_ok = 1; 3306000Sroot break; 3316000Sroot 332*38689Sborman case TELOPT_TM: 333*38689Sborman if (flushout) 334*38689Sborman flushout = 0; 335*38689Sborman /* 336*38689Sborman * Special case for TM. If we get back a WILL, 337*38689Sborman * pretend we got back a WONT. 338*38689Sborman */ 339*38689Sborman set_my_want_state_dont(option); 340*38689Sborman set_my_state_dont(option); 34127110Sminshall return; /* Never reply to TM will's/wont's */ 3426000Sroot 343*38689Sborman case TELOPT_LINEMODE: 344*38689Sborman default: 3456000Sroot break; 346*38689Sborman } 347*38689Sborman 348*38689Sborman if (new_state_ok) { 349*38689Sborman set_my_want_state_do(option); 350*38689Sborman send_do(option, 0); 351*38689Sborman setconnmode(0); /* possibly set new tty mode */ 352*38689Sborman } else { 353*38689Sborman do_dont_resp[option]++; 354*38689Sborman send_dont(option, 0); 355*38689Sborman } 3566000Sroot } 357*38689Sborman set_my_state_do(option); 3586000Sroot } 3596000Sroot 36032377Sminshall void 36137226Sminshall wontoption(option) 36237226Sminshall int option; 3636000Sroot { 3646000Sroot char *fmt; 3656000Sroot 366*38689Sborman if (do_dont_resp[option]) { 367*38689Sborman --do_dont_resp[option]; 368*38689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 369*38689Sborman --do_dont_resp[option]; 370*38689Sborman } 37137226Sminshall 372*38689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3736000Sroot 374*38689Sborman switch (option) { 375*38689Sborman 376*38689Sborman #ifdef KLUDGELINEMODE 377*38689Sborman case TELOPT_SGA: 378*38689Sborman if (!kludgelinemode) 379*38689Sborman break; 380*38689Sborman /* FALL THROUGH */ 381*38689Sborman #endif 382*38689Sborman case TELOPT_ECHO: 38327110Sminshall settimer(modenegotiated); 3846000Sroot break; 3856000Sroot 386*38689Sborman case TELOPT_TM: 387*38689Sborman if (flushout) 388*38689Sborman flushout = 0; 389*38689Sborman set_my_want_state_dont(option); 390*38689Sborman set_my_state_dont(option); 39127110Sminshall return; /* Never reply to TM will's/wont's */ 39227110Sminshall 393*38689Sborman default: 394*38689Sborman break; 395*38689Sborman } 396*38689Sborman set_my_want_state_dont(option); 397*38689Sborman send_dont(option, 0); 398*38689Sborman setconnmode(0); /* Set new tty mode */ 399*38689Sborman } else if (option == TELOPT_TM) { 400*38689Sborman /* 401*38689Sborman * Special case for TM. 402*38689Sborman */ 403*38689Sborman if (flushout) 404*38689Sborman flushout = 0; 405*38689Sborman set_my_want_state_dont(option); 4066000Sroot } 407*38689Sborman set_my_state_dont(option); 4086000Sroot } 4096000Sroot 41032377Sminshall static void 4116000Sroot dooption(option) 4126000Sroot int option; 4136000Sroot { 4146000Sroot char *fmt; 415*38689Sborman int new_state_ok = 0; 4166000Sroot 417*38689Sborman if (will_wont_resp[option]) { 418*38689Sborman --will_wont_resp[option]; 419*38689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 420*38689Sborman --will_wont_resp[option]; 421*38689Sborman } 42237226Sminshall 423*38689Sborman if (will_wont_resp[option] == 0) { 424*38689Sborman if (my_want_state_is_wont(option)) { 4256000Sroot 426*38689Sborman switch (option) { 427*38689Sborman 428*38689Sborman case TELOPT_TM: 429*38689Sborman /* 430*38689Sborman * Special case for TM. We send a WILL, but pretend 431*38689Sborman * we sent WONT. 432*38689Sborman */ 433*38689Sborman send_will(option, 0); 434*38689Sborman set_my_want_state_wont(TELOPT_TM); 435*38689Sborman set_my_state_wont(TELOPT_TM); 436*38689Sborman return; 437*38689Sborman 43832377Sminshall # if defined(TN3270) 439*38689Sborman case TELOPT_EOR: /* end of record */ 440*38689Sborman case TELOPT_BINARY: /* binary mode */ 44132377Sminshall # endif /* defined(TN3270) */ 442*38689Sborman case TELOPT_NAWS: /* window size */ 443*38689Sborman case TELOPT_TSPEED: /* terminal speed */ 444*38689Sborman case TELOPT_LFLOW: /* local flow control */ 445*38689Sborman case TELOPT_TTYPE: /* terminal type option */ 446*38689Sborman case TELOPT_SGA: /* no big deal */ 447*38689Sborman new_state_ok = 1; 4486000Sroot break; 4496000Sroot 450*38689Sborman case TELOPT_LINEMODE: 451*38689Sborman #ifdef KLUDGELINEMODE 452*38689Sborman kludgelinemode = 0; 453*38689Sborman #endif 454*38689Sborman set_my_want_state_will(TELOPT_LINEMODE); 455*38689Sborman send_will(option, 0); 456*38689Sborman set_my_state_will(TELOPT_LINEMODE); 457*38689Sborman slc_init(); 458*38689Sborman return; 459*38689Sborman 460*38689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 461*38689Sborman default: 4626000Sroot break; 463*38689Sborman } 464*38689Sborman 465*38689Sborman if (new_state_ok) { 466*38689Sborman set_my_want_state_will(option); 467*38689Sborman send_will(option, 0); 468*38689Sborman } else { 469*38689Sborman will_wont_resp[option]++; 470*38689Sborman send_wont(option, 0); 471*38689Sborman } 472*38689Sborman } else { 473*38689Sborman /* 474*38689Sborman * Handle options that need more things done after the 475*38689Sborman * other side has acknowledged the option. 476*38689Sborman */ 477*38689Sborman switch (option) { 478*38689Sborman case TELOPT_LINEMODE: 479*38689Sborman #ifdef KLUDGELINEMODE 480*38689Sborman kludgelinemode = 0; 481*38689Sborman #endif 482*38689Sborman set_my_state_will(option); 483*38689Sborman slc_init(); 484*38689Sborman return; 485*38689Sborman } 486*38689Sborman } 4876000Sroot } 488*38689Sborman set_my_state_will(option); 4896000Sroot } 49027676Sminshall 491*38689Sborman static void 492*38689Sborman dontoption(option) 493*38689Sborman int option; 494*38689Sborman { 495*38689Sborman 496*38689Sborman if (will_wont_resp[option]) { 497*38689Sborman --will_wont_resp[option]; 498*38689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 499*38689Sborman --will_wont_resp[option]; 500*38689Sborman } 501*38689Sborman 502*38689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 503*38689Sborman /* we always accept a DONT */ 504*38689Sborman set_my_want_state_wont(option); 505*38689Sborman send_wont(option, 0); 506*38689Sborman } 507*38689Sborman set_my_state_wont(option); 508*38689Sborman } 509*38689Sborman 51027676Sminshall /* 51127676Sminshall * suboption() 51227676Sminshall * 51327676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 51427676Sminshall * side. 51527676Sminshall * 51627676Sminshall * Currently we recognize: 51727676Sminshall * 51827676Sminshall * Terminal type, send request. 51937219Sminshall * Terminal speed (send request). 52037219Sminshall * Local flow control (is request). 521*38689Sborman * Linemode 52227676Sminshall */ 52327676Sminshall 524*38689Sborman static char tty1[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 0 }; 525*38689Sborman static char tty2[] = { IAC, SE, 0 }; 526*38689Sborman 52732377Sminshall static void 52827676Sminshall suboption() 52927676Sminshall { 530*38689Sborman printsub('<', subbuffer, subend-subbuffer+2); 53127676Sminshall switch (subbuffer[0]&0xff) { 53227676Sminshall case TELOPT_TTYPE: 533*38689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 534*38689Sborman return; 53527676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 53627676Sminshall ; 53727676Sminshall } else { 53827676Sminshall char *name; 53932377Sminshall extern char *getenv(); 54027676Sminshall int len; 54127676Sminshall 54232377Sminshall #if defined(TN3270) 54332531Sminshall if (tn3270_ttype()) { 54432377Sminshall return; 54532377Sminshall } 54632377Sminshall #endif /* defined(TN3270) */ 54727676Sminshall name = getenv("TERM"); 54827676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 54927676Sminshall name = "UNKNOWN"; 55033492Sminshall len = strlen(name); 55127676Sminshall } 55227676Sminshall if ((len + 4+2) < NETROOM()) { 55337226Sminshall char temp[50]; 55437226Sminshall 555*38689Sborman strcpy(temp, tty1); 556*38689Sborman strcpy(&temp[4], name); 557*38689Sborman upcase(&temp[4]); 558*38689Sborman strcpy(&temp[4+len], tty2); 559*38689Sborman len += 6; 560*38689Sborman ring_supply_data(&netoring, temp, len); 561*38689Sborman printsub('>', temp+2, len-2); 56232377Sminshall } else { 56337226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 56432377Sminshall /*NOTREACHED*/ 56527676Sminshall } 56627676Sminshall } 56737219Sminshall break; 56837219Sminshall case TELOPT_TSPEED: 569*38689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 570*38689Sborman return; 57137219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 572*38689Sborman long ospeed,ispeed; 573*38689Sborman char temp[50]; 57437219Sminshall int len; 57527676Sminshall 57637219Sminshall TerminalSpeeds(&ispeed, &ospeed); 57737219Sminshall 578*38689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 579*38689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 580*38689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 58137219Sminshall 582*38689Sborman if (len < NETROOM()) { 583*38689Sborman ring_supply_data(&netoring, temp, len); 584*38689Sborman printsub('>', temp+2, len - 2); 58537219Sminshall } 58637219Sminshall } 58737219Sminshall break; 58837219Sminshall case TELOPT_LFLOW: 589*38689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 590*38689Sborman return; 59137219Sminshall if ((subbuffer[1]&0xff) == 1) { 59237219Sminshall localflow = 1; 59337219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 59437219Sminshall localflow = 0; 59537219Sminshall } 59637219Sminshall setcommandmode(); 597*38689Sborman setconnmode(0); 59837219Sminshall break; 599*38689Sborman 600*38689Sborman case TELOPT_LINEMODE: 601*38689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 602*38689Sborman return; 603*38689Sborman switch (subbuffer[1]&0xff) { 604*38689Sborman case WILL: 605*38689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 606*38689Sborman break; 607*38689Sborman case WONT: 608*38689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 609*38689Sborman break; 610*38689Sborman case DO: 611*38689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 612*38689Sborman break; 613*38689Sborman case DONT: 614*38689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 615*38689Sborman break; 616*38689Sborman case LM_SLC: 617*38689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 618*38689Sborman break; 619*38689Sborman case LM_MODE: 620*38689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 621*38689Sborman break; 622*38689Sborman default: 623*38689Sborman break; 624*38689Sborman } 625*38689Sborman break; 62627676Sminshall default: 62727676Sminshall break; 62827676Sminshall } 62927676Sminshall } 630*38689Sborman 631*38689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 632*38689Sborman 633*38689Sborman lm_will(cmd, len) 634*38689Sborman char *cmd; 635*38689Sborman { 636*38689Sborman switch(cmd[0]) { 637*38689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 638*38689Sborman default: 639*38689Sborman str_lm[3] = DONT; 640*38689Sborman str_lm[4] = cmd[0]; 641*38689Sborman if (NETROOM() > sizeof(str_lm)) { 642*38689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 643*38689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 644*38689Sborman } 645*38689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 646*38689Sborman break; 647*38689Sborman } 648*38689Sborman } 649*38689Sborman 650*38689Sborman lm_wont(cmd, len) 651*38689Sborman char *cmd; 652*38689Sborman { 653*38689Sborman switch(cmd[0]) { 654*38689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 655*38689Sborman default: 656*38689Sborman /* We are always DONT, so don't respond */ 657*38689Sborman return; 658*38689Sborman } 659*38689Sborman } 660*38689Sborman 661*38689Sborman int linemode; 662*38689Sborman 663*38689Sborman lm_do(cmd, len) 664*38689Sborman char *cmd; 665*38689Sborman { 666*38689Sborman switch(cmd[0]) { 667*38689Sborman case LM_FORWARDMASK: 668*38689Sborman default: 669*38689Sborman str_lm[3] = WONT; 670*38689Sborman str_lm[4] = cmd[0]; 671*38689Sborman if (NETROOM() > sizeof(str_lm)) { 672*38689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 673*38689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 674*38689Sborman } 675*38689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 676*38689Sborman break; 677*38689Sborman } 678*38689Sborman } 679*38689Sborman 680*38689Sborman lm_dont(cmd, len) 681*38689Sborman char *cmd; 682*38689Sborman { 683*38689Sborman switch(cmd[0]) { 684*38689Sborman case LM_FORWARDMASK: 685*38689Sborman default: 686*38689Sborman /* we are always WONT, so don't respond */ 687*38689Sborman break; 688*38689Sborman } 689*38689Sborman } 690*38689Sborman 691*38689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 692*38689Sborman 693*38689Sborman lm_mode(cmd, len, init) 694*38689Sborman char *cmd; 695*38689Sborman int len, init; 696*38689Sborman { 697*38689Sborman if (len != 1) 698*38689Sborman return; 699*38689Sborman if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd) 700*38689Sborman return; 701*38689Sborman if (*cmd&MODE_ACK) 702*38689Sborman return; 703*38689Sborman linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG)); 704*38689Sborman str_lm_mode[4] = linemode; 705*38689Sborman if (!init) 706*38689Sborman str_lm_mode[4] |= MODE_ACK; 707*38689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 708*38689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 709*38689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 710*38689Sborman } 711*38689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 712*38689Sborman setconnmode(0); /* set changed mode */ 713*38689Sborman } 714*38689Sborman 71532377Sminshall 71627088Sminshall 717*38689Sborman /* 718*38689Sborman * slc() 719*38689Sborman * Handle special character suboption of LINEMODE. 720*38689Sborman */ 721*38689Sborman 722*38689Sborman struct spc { 723*38689Sborman char val; 724*38689Sborman char *valp; 725*38689Sborman char flags; /* Current flags & level */ 726*38689Sborman char mylevel; /* Maximum level & flags */ 727*38689Sborman } spc_data[NSLC+1]; 728*38689Sborman 729*38689Sborman #define SLC_IMPORT 0 730*38689Sborman #define SLC_EXPORT 1 731*38689Sborman #define SLC_RVALUE 2 732*38689Sborman static int slc_mode = SLC_EXPORT; 733*38689Sborman 734*38689Sborman slc_init() 735*38689Sborman { 736*38689Sborman register struct spc *spcp; 737*38689Sborman extern char *tcval(); 738*38689Sborman 739*38689Sborman localchars = 1; 740*38689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 741*38689Sborman spcp->val = 0; 742*38689Sborman spcp->valp = 0; 743*38689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 744*38689Sborman } 745*38689Sborman 746*38689Sborman #define initfunc(func, flags) { \ 747*38689Sborman spcp = &spc_data[func]; \ 748*38689Sborman if (spcp->valp = tcval(func)) { \ 749*38689Sborman spcp->val = *spcp->valp; \ 750*38689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 751*38689Sborman } else { \ 752*38689Sborman spcp->val = 0; \ 753*38689Sborman spcp->mylevel = SLC_DEFAULT; \ 754*38689Sborman } \ 755*38689Sborman } 756*38689Sborman 757*38689Sborman initfunc(SLC_SYNCH, 0); 758*38689Sborman /* No BRK */ 759*38689Sborman initfunc(SLC_AO, 0); 760*38689Sborman initfunc(SLC_AYT, 0); 761*38689Sborman /* No EOR */ 762*38689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 763*38689Sborman initfunc(SLC_EOF, 0); 764*38689Sborman #ifndef CRAY 765*38689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 766*38689Sborman #endif 767*38689Sborman initfunc(SLC_EC, 0); 768*38689Sborman initfunc(SLC_EL, 0); 769*38689Sborman #ifndef CRAY 770*38689Sborman initfunc(SLC_EW, 0); 771*38689Sborman initfunc(SLC_RP, 0); 772*38689Sborman initfunc(SLC_LNEXT, 0); 773*38689Sborman #endif 774*38689Sborman initfunc(SLC_XON, 0); 775*38689Sborman initfunc(SLC_XOFF, 0); 776*38689Sborman #ifdef CRAY 777*38689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 778*38689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 779*38689Sborman #endif 780*38689Sborman /* No FORW1 */ 781*38689Sborman /* No FORW2 */ 782*38689Sborman 783*38689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 784*38689Sborman #undef initfunc 785*38689Sborman 786*38689Sborman if (slc_mode == SLC_EXPORT) 787*38689Sborman slc_export(); 788*38689Sborman else 789*38689Sborman slc_import(1); 790*38689Sborman 791*38689Sborman } 792*38689Sborman 793*38689Sborman slcstate() 794*38689Sborman { 795*38689Sborman printf("Special characters are %s values\n", 796*38689Sborman slc_mode == SLC_IMPORT ? "remote default" : 797*38689Sborman slc_mode == SLC_EXPORT ? "local" : 798*38689Sborman "remote"); 799*38689Sborman } 800*38689Sborman 801*38689Sborman slc_mode_export() 802*38689Sborman { 803*38689Sborman slc_mode = SLC_EXPORT; 804*38689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 805*38689Sborman slc_export(); 806*38689Sborman } 807*38689Sborman 808*38689Sborman slc_mode_import(def) 809*38689Sborman { 810*38689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 811*38689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 812*38689Sborman slc_import(def); 813*38689Sborman } 814*38689Sborman 815*38689Sborman char slc_import_val[] = { 816*38689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 817*38689Sborman }; 818*38689Sborman char slc_import_def[] = { 819*38689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 820*38689Sborman }; 821*38689Sborman 822*38689Sborman slc_import(def) 823*38689Sborman int def; 824*38689Sborman { 825*38689Sborman if (NETROOM() > sizeof(slc_import_val)) { 826*38689Sborman if (def) { 827*38689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 828*38689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 829*38689Sborman } else { 830*38689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 831*38689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 832*38689Sborman } 833*38689Sborman } 834*38689Sborman /*@*/ else printf("slc_import: not enough room\n"); 835*38689Sborman } 836*38689Sborman 837*38689Sborman slc_export() 838*38689Sborman { 839*38689Sborman register struct spc *spcp; 840*38689Sborman 841*38689Sborman TerminalDefaultChars(); 842*38689Sborman 843*38689Sborman slc_start_reply(); 844*38689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 845*38689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 846*38689Sborman spcp->flags = spcp->mylevel; 847*38689Sborman if (spcp->valp) 848*38689Sborman spcp->val = *spcp->valp; 849*38689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 850*38689Sborman } 851*38689Sborman } 852*38689Sborman slc_end_reply(); 853*38689Sborman if (slc_update()) 854*38689Sborman setconnmode(1); /* set the new character values */ 855*38689Sborman } 856*38689Sborman 857*38689Sborman slc(cp, len) 858*38689Sborman register char *cp; 859*38689Sborman int len; 860*38689Sborman { 861*38689Sborman register struct spc *spcp; 862*38689Sborman register int func,level; 863*38689Sborman 864*38689Sborman slc_start_reply(); 865*38689Sborman 866*38689Sborman for (; len >= 3; len -=3, cp +=3) { 867*38689Sborman 868*38689Sborman func = cp[SLC_FUNC]; 869*38689Sborman 870*38689Sborman if (func == 0) { 871*38689Sborman /* 872*38689Sborman * Client side: always ignore 0 function. 873*38689Sborman */ 874*38689Sborman continue; 875*38689Sborman } 876*38689Sborman if (func > NSLC) { 877*38689Sborman if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) 878*38689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 879*38689Sborman continue; 880*38689Sborman } 881*38689Sborman 882*38689Sborman spcp = &spc_data[func]; 883*38689Sborman 884*38689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 885*38689Sborman 886*38689Sborman if ((cp[SLC_VALUE] == spcp->val) && 887*38689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 888*38689Sborman continue; 889*38689Sborman } 890*38689Sborman 891*38689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 892*38689Sborman /* 893*38689Sborman * This is an error condition, the SLC_ACK 894*38689Sborman * bit should never be set for the SLC_DEFAULT 895*38689Sborman * level. Our best guess to recover is to 896*38689Sborman * ignore the SLC_ACK bit. 897*38689Sborman */ 898*38689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 899*38689Sborman } 900*38689Sborman 901*38689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 902*38689Sborman spcp->val = cp[SLC_VALUE]; 903*38689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 904*38689Sborman continue; 905*38689Sborman } 906*38689Sborman 907*38689Sborman level &= ~SLC_ACK; 908*38689Sborman 909*38689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 910*38689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 911*38689Sborman spcp->val = cp[SLC_VALUE]; 912*38689Sborman } 913*38689Sborman if (level == SLC_DEFAULT) { 914*38689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 915*38689Sborman spcp->flags = spcp->mylevel; 916*38689Sborman else 917*38689Sborman spcp->flags = SLC_NOSUPPORT; 918*38689Sborman } 919*38689Sborman slc_add_reply(func, spcp->flags, spcp->val); 920*38689Sborman } 921*38689Sborman slc_end_reply(); 922*38689Sborman if (slc_update()) 923*38689Sborman setconnmode(1); /* set the new character values */ 924*38689Sborman } 925*38689Sborman 926*38689Sborman slc_check() 927*38689Sborman { 928*38689Sborman register struct spc *spcp; 929*38689Sborman 930*38689Sborman slc_start_reply(); 931*38689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 932*38689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 933*38689Sborman spcp->val = *spcp->valp; 934*38689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 935*38689Sborman } 936*38689Sborman } 937*38689Sborman slc_end_reply(); 938*38689Sborman setconnmode(1); 939*38689Sborman } 940*38689Sborman 941*38689Sborman 942*38689Sborman unsigned char slc_reply[128]; 943*38689Sborman unsigned char *slc_replyp; 944*38689Sborman slc_start_reply() 945*38689Sborman { 946*38689Sborman slc_replyp = slc_reply; 947*38689Sborman *slc_replyp++ = IAC; 948*38689Sborman *slc_replyp++ = SB; 949*38689Sborman *slc_replyp++ = TELOPT_LINEMODE; 950*38689Sborman *slc_replyp++ = LM_SLC; 951*38689Sborman } 952*38689Sborman 953*38689Sborman slc_add_reply(func, flags, value) 954*38689Sborman char func; 955*38689Sborman char flags; 956*38689Sborman char value; 957*38689Sborman { 958*38689Sborman if ((*slc_replyp++ = func) == IAC) 959*38689Sborman *slc_replyp++ = IAC; 960*38689Sborman if ((*slc_replyp++ = flags) == IAC) 961*38689Sborman *slc_replyp++ = IAC; 962*38689Sborman if ((*slc_replyp++ = value) == IAC) 963*38689Sborman *slc_replyp++ = IAC; 964*38689Sborman } 965*38689Sborman 966*38689Sborman slc_end_reply() 967*38689Sborman { 968*38689Sborman register char *cp; 969*38689Sborman register int len; 970*38689Sborman 971*38689Sborman *slc_replyp++ = IAC; 972*38689Sborman *slc_replyp++ = SE; 973*38689Sborman len = slc_replyp - slc_reply; 974*38689Sborman if (len <= 6) 975*38689Sborman return; 976*38689Sborman if (NETROOM() > len) { 977*38689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 978*38689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 979*38689Sborman } 980*38689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 981*38689Sborman } 982*38689Sborman 983*38689Sborman slc_update() 984*38689Sborman { 985*38689Sborman register struct spc *spcp; 986*38689Sborman int need_update = 0; 987*38689Sborman 988*38689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 989*38689Sborman if (!(spcp->flags&SLC_ACK)) 990*38689Sborman continue; 991*38689Sborman spcp->flags &= ~SLC_ACK; 992*38689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 993*38689Sborman *spcp->valp = spcp->val; 994*38689Sborman need_update = 1; 995*38689Sborman } 996*38689Sborman } 997*38689Sborman return(need_update); 998*38689Sborman } 999*38689Sborman 1000*38689Sborman 1001*38689Sborman 100233804Sminshall int 100332377Sminshall telrcv() 100427110Sminshall { 100532377Sminshall register int c; 100632385Sminshall register int scc; 100732385Sminshall register char *sbp; 100832385Sminshall int count; 100932385Sminshall int returnValue = 0; 101027088Sminshall 101132385Sminshall scc = 0; 101232385Sminshall count = 0; 101332385Sminshall while (TTYROOM() > 2) { 101432385Sminshall if (scc == 0) { 101532385Sminshall if (count) { 101632528Sminshall ring_consumed(&netiring, count); 101732385Sminshall returnValue = 1; 101832385Sminshall count = 0; 101932385Sminshall } 102032528Sminshall sbp = netiring.consume; 102132528Sminshall scc = ring_full_consecutive(&netiring); 102232385Sminshall if (scc == 0) { 102332385Sminshall /* No more data coming in */ 102432385Sminshall break; 102532385Sminshall } 102632385Sminshall } 102732385Sminshall 102832385Sminshall c = *sbp++ & 0xff, scc--; count++; 102932385Sminshall 103032377Sminshall switch (telrcv_state) { 103127110Sminshall 103232377Sminshall case TS_CR: 103332377Sminshall telrcv_state = TS_DATA; 103435518Sminshall if (c == '\0') { 103535518Sminshall break; /* Ignore \0 after CR */ 1036*38689Sborman } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 103735518Sminshall TTYADD(c); 103835518Sminshall break; 103932377Sminshall } 104035518Sminshall /* Else, fall through */ 104127088Sminshall 104232377Sminshall case TS_DATA: 104332377Sminshall if (c == IAC) { 104432377Sminshall telrcv_state = TS_IAC; 104533804Sminshall break; 104632377Sminshall } 104732377Sminshall # if defined(TN3270) 104832377Sminshall if (In3270) { 104932377Sminshall *Ifrontp++ = c; 105032385Sminshall while (scc > 0) { 105132385Sminshall c = *sbp++ & 0377, scc--; count++; 105232377Sminshall if (c == IAC) { 105332377Sminshall telrcv_state = TS_IAC; 105434304Sminshall break; 105532377Sminshall } 105632377Sminshall *Ifrontp++ = c; 105732377Sminshall } 105832377Sminshall } else 105932377Sminshall # endif /* defined(TN3270) */ 106035518Sminshall /* 106135518Sminshall * The 'crmod' hack (see following) is needed 106235518Sminshall * since we can't * set CRMOD on output only. 106335518Sminshall * Machines like MULTICS like to send \r without 106435518Sminshall * \n; since we must turn off CRMOD to get proper 106535518Sminshall * input, the mapping is done here (sigh). 106635518Sminshall */ 1067*38689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 106835518Sminshall if (scc > 0) { 106935518Sminshall c = *sbp&0xff; 107035518Sminshall if (c == 0) { 107135518Sminshall sbp++, scc--; count++; 107235518Sminshall /* a "true" CR */ 107332377Sminshall TTYADD('\r'); 1074*38689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 107535518Sminshall (c == '\n')) { 107635518Sminshall sbp++, scc--; count++; 107732377Sminshall TTYADD('\n'); 107835518Sminshall } else { 107935518Sminshall TTYADD('\r'); 108035518Sminshall if (crmod) { 108135518Sminshall TTYADD('\n'); 108232377Sminshall } 108332377Sminshall } 108435518Sminshall } else { 108535518Sminshall telrcv_state = TS_CR; 108635518Sminshall TTYADD('\r'); 108735518Sminshall if (crmod) { 108835518Sminshall TTYADD('\n'); 108935518Sminshall } 109032377Sminshall } 109132377Sminshall } else { 109232377Sminshall TTYADD(c); 109332377Sminshall } 109432377Sminshall continue; 109527088Sminshall 109632377Sminshall case TS_IAC: 1097*38689Sborman process_iac: 109832377Sminshall switch (c) { 109932377Sminshall 110032377Sminshall case WILL: 110132377Sminshall telrcv_state = TS_WILL; 110232377Sminshall continue; 110327261Sminshall 110432377Sminshall case WONT: 110532377Sminshall telrcv_state = TS_WONT; 110632377Sminshall continue; 110727261Sminshall 110832377Sminshall case DO: 110932377Sminshall telrcv_state = TS_DO; 111032377Sminshall continue; 111127261Sminshall 111232377Sminshall case DONT: 111332377Sminshall telrcv_state = TS_DONT; 111432377Sminshall continue; 111527261Sminshall 111632377Sminshall case DM: 111732377Sminshall /* 111832377Sminshall * We may have missed an urgent notification, 111932377Sminshall * so make sure we flush whatever is in the 112032377Sminshall * buffer currently. 112132377Sminshall */ 112232377Sminshall SYNCHing = 1; 112332377Sminshall ttyflush(1); 112432554Sminshall SYNCHing = stilloob(); 112532377Sminshall settimer(gotDM); 112632377Sminshall break; 112727088Sminshall 112832377Sminshall case NOP: 112932377Sminshall case GA: 113032377Sminshall break; 113127088Sminshall 113232377Sminshall case SB: 113332377Sminshall SB_CLEAR(); 113432377Sminshall telrcv_state = TS_SB; 1135*38689Sborman printoption("RCVD", "IAC", SB); 113632377Sminshall continue; 113727261Sminshall 113832377Sminshall # if defined(TN3270) 113932377Sminshall case EOR: 114032377Sminshall if (In3270) { 114132377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 114232377Sminshall if (Ibackp == Ifrontp) { 114332377Sminshall Ibackp = Ifrontp = Ibuf; 114432377Sminshall ISend = 0; /* should have been! */ 114532377Sminshall } else { 114632377Sminshall ISend = 1; 114727088Sminshall } 114827088Sminshall } 114927088Sminshall break; 115032377Sminshall # endif /* defined(TN3270) */ 115132377Sminshall 115232377Sminshall case IAC: 115332377Sminshall # if !defined(TN3270) 115432377Sminshall TTYADD(IAC); 115532377Sminshall # else /* !defined(TN3270) */ 115632377Sminshall if (In3270) { 115732377Sminshall *Ifrontp++ = IAC; 115832377Sminshall } else { 115932377Sminshall TTYADD(IAC); 116032377Sminshall } 116132377Sminshall # endif /* !defined(TN3270) */ 116227088Sminshall break; 116332377Sminshall 116427088Sminshall default: 116527088Sminshall break; 116627088Sminshall } 116732377Sminshall telrcv_state = TS_DATA; 116832377Sminshall continue; 116927088Sminshall 117032377Sminshall case TS_WILL: 117137226Sminshall printoption("RCVD", "will", c); 1172*38689Sborman willoption(c); 117332377Sminshall SetIn3270(); 117432377Sminshall telrcv_state = TS_DATA; 117532377Sminshall continue; 117627110Sminshall 117732377Sminshall case TS_WONT: 117837226Sminshall printoption("RCVD", "wont", c); 1179*38689Sborman wontoption(c); 118032377Sminshall SetIn3270(); 118132377Sminshall telrcv_state = TS_DATA; 118232377Sminshall continue; 118327088Sminshall 118432377Sminshall case TS_DO: 118537226Sminshall printoption("RCVD", "do", c); 118637226Sminshall dooption(c); 118732377Sminshall SetIn3270(); 118837219Sminshall if (c == TELOPT_NAWS) { 118937219Sminshall sendnaws(); 119037219Sminshall } else if (c == TELOPT_LFLOW) { 119137219Sminshall localflow = 1; 119237219Sminshall setcommandmode(); 1193*38689Sborman setconnmode(0); 119437219Sminshall } 119532377Sminshall telrcv_state = TS_DATA; 119632377Sminshall continue; 119727088Sminshall 119832377Sminshall case TS_DONT: 119937226Sminshall printoption("RCVD", "dont", c); 1200*38689Sborman dontoption(c); 120137226Sminshall flushline = 1; 1202*38689Sborman setconnmode(0); /* set new tty mode (maybe) */ 120332377Sminshall SetIn3270(); 120432377Sminshall telrcv_state = TS_DATA; 120532377Sminshall continue; 120627088Sminshall 120732377Sminshall case TS_SB: 120832377Sminshall if (c == IAC) { 120932377Sminshall telrcv_state = TS_SE; 121032377Sminshall } else { 121132377Sminshall SB_ACCUM(c); 121232377Sminshall } 121332377Sminshall continue; 121427088Sminshall 121532377Sminshall case TS_SE: 121632377Sminshall if (c != SE) { 121732377Sminshall if (c != IAC) { 1218*38689Sborman /* 1219*38689Sborman * This is an error. We only expect to get 1220*38689Sborman * "IAC IAC" or "IAC SE". Several things may 1221*38689Sborman * have happend. An IAC was not doubled, the 1222*38689Sborman * IAC SE was left off, or another option got 1223*38689Sborman * inserted into the suboption are all possibilities. 1224*38689Sborman * If we assume that the IAC was not doubled, 1225*38689Sborman * and really the IAC SE was left off, we could 1226*38689Sborman * get into an infinate loop here. So, instead, 1227*38689Sborman * we terminate the suboption, and process the 1228*38689Sborman * partial suboption if we can. 1229*38689Sborman */ 1230*38689Sborman SB_TERM(); 123132377Sminshall SB_ACCUM(IAC); 1232*38689Sborman SB_ACCUM(c); 1233*38689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 1234*38689Sborman suboption(); /* handle sub-option */ 1235*38689Sborman SetIn3270(); 1236*38689Sborman telrcv_state = TS_IAC; 1237*38689Sborman goto process_iac; 123832377Sminshall } 123932377Sminshall SB_ACCUM(c); 124032377Sminshall telrcv_state = TS_SB; 124132377Sminshall } else { 124232377Sminshall SB_TERM(); 1243*38689Sborman SB_ACCUM(IAC); 1244*38689Sborman SB_ACCUM(SE); 124532377Sminshall suboption(); /* handle sub-option */ 124632377Sminshall SetIn3270(); 124732377Sminshall telrcv_state = TS_DATA; 124832377Sminshall } 124927088Sminshall } 125027088Sminshall } 125132667Sminshall if (count) 125232667Sminshall ring_consumed(&netiring, count); 125332385Sminshall return returnValue||count; 125427088Sminshall } 125532385Sminshall 125632385Sminshall static int 125732554Sminshall telsnd() 125832385Sminshall { 125932385Sminshall int tcc; 126032385Sminshall int count; 126132385Sminshall int returnValue = 0; 126232385Sminshall char *tbp; 126332385Sminshall 126432385Sminshall tcc = 0; 126532385Sminshall count = 0; 126632385Sminshall while (NETROOM() > 2) { 126732385Sminshall register int sc; 126832385Sminshall register int c; 126932385Sminshall 127032385Sminshall if (tcc == 0) { 127132385Sminshall if (count) { 127232528Sminshall ring_consumed(&ttyiring, count); 127332385Sminshall returnValue = 1; 127432385Sminshall count = 0; 127532385Sminshall } 127632528Sminshall tbp = ttyiring.consume; 127732528Sminshall tcc = ring_full_consecutive(&ttyiring); 127832385Sminshall if (tcc == 0) { 127932385Sminshall break; 128032385Sminshall } 128132385Sminshall } 128232385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 128332385Sminshall if (sc == escape) { 1284*38689Sborman /* 1285*38689Sborman * Double escape is a pass through of a single escape character. 1286*38689Sborman */ 1287*38689Sborman if (tcc && strip(*tbp) == escape) { 1288*38689Sborman tbp++; 1289*38689Sborman tcc--; 1290*38689Sborman count++; 1291*38689Sborman } else { 1292*38689Sborman command(0, tbp, tcc); 1293*38689Sborman count += tcc; 1294*38689Sborman tcc = 0; 1295*38689Sborman flushline = 1; 1296*38689Sborman break; 1297*38689Sborman } 1298*38689Sborman } 1299*38689Sborman #ifdef KLUDGELINEMODE 1300*38689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 130132385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 130232385Sminshall tcc--; tbp++; count++; 130332385Sminshall } else { 130432385Sminshall dontlecho = !dontlecho; 130532385Sminshall settimer(echotoggle); 1306*38689Sborman setconnmode(0); 130732385Sminshall flushline = 1; 130832385Sminshall break; 130932385Sminshall } 131032385Sminshall } 1311*38689Sborman #endif 1312*38689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 131332385Sminshall if (TerminalSpecialChars(sc) == 0) { 131432385Sminshall break; 131532385Sminshall } 131632385Sminshall } 1317*38689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 131832385Sminshall switch (c) { 131932385Sminshall case '\n': 132032385Sminshall /* 132132385Sminshall * If we are in CRMOD mode (\r ==> \n) 132232385Sminshall * on our local machine, then probably 132332385Sminshall * a newline (unix) is CRLF (TELNET). 132432385Sminshall */ 132532385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 132632385Sminshall NETADD('\r'); 132732385Sminshall } 132832385Sminshall NETADD('\n'); 132932385Sminshall flushline = 1; 133032385Sminshall break; 133132385Sminshall case '\r': 133232385Sminshall if (!crlf) { 133332385Sminshall NET2ADD('\r', '\0'); 133432385Sminshall } else { 133532385Sminshall NET2ADD('\r', '\n'); 133632385Sminshall } 133732385Sminshall flushline = 1; 133832385Sminshall break; 133932385Sminshall case IAC: 134032385Sminshall NET2ADD(IAC, IAC); 134132385Sminshall break; 134232385Sminshall default: 134332385Sminshall NETADD(c); 134432385Sminshall break; 134532385Sminshall } 134632385Sminshall } else if (c == IAC) { 134732385Sminshall NET2ADD(IAC, IAC); 134832385Sminshall } else { 134932385Sminshall NETADD(c); 135032385Sminshall } 135132385Sminshall } 135232667Sminshall if (count) 135332667Sminshall ring_consumed(&ttyiring, count); 135432385Sminshall return returnValue||count; /* Non-zero if we did anything */ 135532385Sminshall } 135632377Sminshall 135727088Sminshall /* 135832377Sminshall * Scheduler() 135932377Sminshall * 136032377Sminshall * Try to do something. 136132377Sminshall * 136232377Sminshall * If we do something useful, return 1; else return 0. 136332377Sminshall * 136427110Sminshall */ 136527110Sminshall 136627110Sminshall 136732377Sminshall int 136832377Sminshall Scheduler(block) 136932377Sminshall int block; /* should we block in the select ? */ 137027110Sminshall { 137132377Sminshall /* One wants to be a bit careful about setting returnValue 137232377Sminshall * to one, since a one implies we did some useful work, 137332377Sminshall * and therefore probably won't be called to block next 137432377Sminshall * time (TN3270 mode only). 137532377Sminshall */ 137632531Sminshall int returnValue; 137732531Sminshall int netin, netout, netex, ttyin, ttyout; 137827110Sminshall 137932531Sminshall /* Decide which rings should be processed */ 138032531Sminshall 138132531Sminshall netout = ring_full_count(&netoring) && 1382*38689Sborman (flushline || 1383*38689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 1384*38689Sborman #ifdef KLUDGELINEMODE 1385*38689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 1386*38689Sborman #endif 1387*38689Sborman ) || 1388*38689Sborman my_want_state_is_will(TELOPT_BINARY)); 138932531Sminshall ttyout = ring_full_count(&ttyoring); 139032531Sminshall 139132377Sminshall #if defined(TN3270) 139232531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 139332377Sminshall #else /* defined(TN3270) */ 139432531Sminshall ttyin = ring_empty_count(&ttyiring); 139532377Sminshall #endif /* defined(TN3270) */ 139632531Sminshall 139732531Sminshall #if defined(TN3270) 139832531Sminshall netin = ring_empty_count(&netiring); 139932377Sminshall # else /* !defined(TN3270) */ 140032531Sminshall netin = !ISend && ring_empty_count(&netiring); 140132377Sminshall # endif /* !defined(TN3270) */ 140232531Sminshall 140332531Sminshall netex = !SYNCHing; 140432531Sminshall 140532531Sminshall /* If we have seen a signal recently, reset things */ 140632377Sminshall # if defined(TN3270) && defined(unix) 140732377Sminshall if (HaveInput) { 140832377Sminshall HaveInput = 0; 140932377Sminshall signal(SIGIO, inputAvailable); 141032377Sminshall } 141132377Sminshall #endif /* defined(TN3270) && defined(unix) */ 141232377Sminshall 141332531Sminshall /* Call to system code to process rings */ 141427178Sminshall 141532531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 141627178Sminshall 141732531Sminshall /* Now, look at the input rings, looking for work to do. */ 141832377Sminshall 141932531Sminshall if (ring_full_count(&ttyiring)) { 142032377Sminshall # if defined(TN3270) 142132377Sminshall if (In3270) { 142234848Sminshall int c; 142334848Sminshall 142433804Sminshall c = DataFromTerminal(ttyiring.consume, 142532528Sminshall ring_full_consecutive(&ttyiring)); 142632377Sminshall if (c) { 142732377Sminshall returnValue = 1; 142832667Sminshall ring_consumed(&ttyiring, c); 142932377Sminshall } 143032377Sminshall } else { 143132377Sminshall # endif /* defined(TN3270) */ 143232554Sminshall returnValue |= telsnd(); 143332377Sminshall # if defined(TN3270) 143427178Sminshall } 143532531Sminshall # endif /* defined(TN3270) */ 143627178Sminshall } 143732377Sminshall 143832528Sminshall if (ring_full_count(&netiring)) { 143932377Sminshall # if !defined(TN3270) 144032385Sminshall returnValue |= telrcv(); 144132377Sminshall # else /* !defined(TN3270) */ 144232377Sminshall returnValue = Push3270(); 144332377Sminshall # endif /* !defined(TN3270) */ 144432377Sminshall } 144532377Sminshall return returnValue; 144627178Sminshall } 144727178Sminshall 144827178Sminshall /* 144932377Sminshall * Select from tty and network... 145027088Sminshall */ 145132377Sminshall void 145232377Sminshall telnet() 145327088Sminshall { 145432531Sminshall sys_telnet_init(); 145527088Sminshall 145632377Sminshall # if !defined(TN3270) 145732377Sminshall if (telnetport) { 1458*38689Sborman send_do(TELOPT_SGA, 1); 1459*38689Sborman send_will(TELOPT_TTYPE, 1); 1460*38689Sborman send_will(TELOPT_NAWS, 1); 1461*38689Sborman send_will(TELOPT_TSPEED, 1); 1462*38689Sborman send_will(TELOPT_LFLOW, 1); 1463*38689Sborman send_will(TELOPT_LINEMODE, 1); 146427178Sminshall } 146532377Sminshall # endif /* !defined(TN3270) */ 146627088Sminshall 146732377Sminshall # if !defined(TN3270) 146832377Sminshall for (;;) { 146932385Sminshall int schedValue; 147032385Sminshall 147132385Sminshall while ((schedValue = Scheduler(0)) != 0) { 147232385Sminshall if (schedValue == -1) { 147332385Sminshall setcommandmode(); 147432385Sminshall return; 147532385Sminshall } 147632385Sminshall } 147732385Sminshall 147832531Sminshall if (Scheduler(1) == -1) { 147932377Sminshall setcommandmode(); 148032377Sminshall return; 148132377Sminshall } 148232377Sminshall } 148332377Sminshall # else /* !defined(TN3270) */ 148432377Sminshall for (;;) { 148532377Sminshall int schedValue; 148627088Sminshall 148732377Sminshall while (!In3270 && !shell_active) { 148832531Sminshall if (Scheduler(1) == -1) { 148932377Sminshall setcommandmode(); 149032377Sminshall return; 149132377Sminshall } 149227088Sminshall } 149332377Sminshall 149432377Sminshall while ((schedValue = Scheduler(0)) != 0) { 149532377Sminshall if (schedValue == -1) { 149632377Sminshall setcommandmode(); 149732377Sminshall return; 149832377Sminshall } 149927088Sminshall } 150032377Sminshall /* If there is data waiting to go out to terminal, don't 150132377Sminshall * schedule any more data for the terminal. 150232377Sminshall */ 150334304Sminshall if (ring_full_count(&ttyoring)) { 150432377Sminshall schedValue = 1; 150527088Sminshall } else { 150632377Sminshall if (shell_active) { 150732377Sminshall if (shell_continue() == 0) { 150832377Sminshall ConnectScreen(); 150927088Sminshall } 151032377Sminshall } else if (In3270) { 151132377Sminshall schedValue = DoTerminalOutput(); 151232377Sminshall } 151327088Sminshall } 151432377Sminshall if (schedValue && (shell_active == 0)) { 151532531Sminshall if (Scheduler(1) == -1) { 151632377Sminshall setcommandmode(); 151732377Sminshall return; 151832377Sminshall } 151927088Sminshall } 152032377Sminshall } 152132377Sminshall # endif /* !defined(TN3270) */ 152227088Sminshall } 152332377Sminshall 152434848Sminshall #if 0 /* XXX - this not being in is a bug */ 152527088Sminshall /* 152632554Sminshall * nextitem() 152732554Sminshall * 152832554Sminshall * Return the address of the next "item" in the TELNET data 152932554Sminshall * stream. This will be the address of the next character if 153032554Sminshall * the current address is a user data character, or it will 153132554Sminshall * be the address of the character following the TELNET command 153232554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 153332554Sminshall * character. 153432554Sminshall */ 153532554Sminshall 153632554Sminshall static char * 153732554Sminshall nextitem(current) 153832554Sminshall char *current; 153932554Sminshall { 154032554Sminshall if ((*current&0xff) != IAC) { 154132554Sminshall return current+1; 154232554Sminshall } 154332554Sminshall switch (*(current+1)&0xff) { 154432554Sminshall case DO: 154532554Sminshall case DONT: 154632554Sminshall case WILL: 154732554Sminshall case WONT: 154832554Sminshall return current+3; 154932554Sminshall case SB: /* loop forever looking for the SE */ 155032554Sminshall { 155132554Sminshall register char *look = current+2; 155232554Sminshall 155332554Sminshall for (;;) { 155432554Sminshall if ((*look++&0xff) == IAC) { 155532554Sminshall if ((*look++&0xff) == SE) { 155632554Sminshall return look; 155732554Sminshall } 155832554Sminshall } 155932554Sminshall } 156032554Sminshall } 156132554Sminshall default: 156232554Sminshall return current+2; 156332554Sminshall } 156432554Sminshall } 156534848Sminshall #endif /* 0 */ 156632554Sminshall 156732554Sminshall /* 156832554Sminshall * netclear() 156932554Sminshall * 157032554Sminshall * We are about to do a TELNET SYNCH operation. Clear 157132554Sminshall * the path to the network. 157232554Sminshall * 157332554Sminshall * Things are a bit tricky since we may have sent the first 157432554Sminshall * byte or so of a previous TELNET command into the network. 157532554Sminshall * So, we have to scan the network buffer from the beginning 157632554Sminshall * until we are up to where we want to be. 157732554Sminshall * 157832554Sminshall * A side effect of what we do, just to keep things 157932554Sminshall * simple, is to clear the urgent data pointer. The principal 158032554Sminshall * caller should be setting the urgent data pointer AFTER calling 158132554Sminshall * us in any case. 158232554Sminshall */ 158332554Sminshall 158432554Sminshall static void 158532554Sminshall netclear() 158632554Sminshall { 158732554Sminshall #if 0 /* XXX */ 158832554Sminshall register char *thisitem, *next; 158932554Sminshall char *good; 159032554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 159132554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 159232554Sminshall 159332554Sminshall thisitem = netobuf; 159432554Sminshall 159532554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 159632554Sminshall thisitem = next; 159732554Sminshall } 159832554Sminshall 159932554Sminshall /* Now, thisitem is first before/at boundary. */ 160032554Sminshall 160132554Sminshall good = netobuf; /* where the good bytes go */ 160232554Sminshall 160332554Sminshall while (netoring.add > thisitem) { 160432554Sminshall if (wewant(thisitem)) { 160532554Sminshall int length; 160632554Sminshall 160732554Sminshall next = thisitem; 160832554Sminshall do { 160932554Sminshall next = nextitem(next); 161032554Sminshall } while (wewant(next) && (nfrontp > next)); 161132554Sminshall length = next-thisitem; 161232554Sminshall memcpy(good, thisitem, length); 161332554Sminshall good += length; 161432554Sminshall thisitem = next; 161532554Sminshall } else { 161632554Sminshall thisitem = nextitem(thisitem); 161732554Sminshall } 161832554Sminshall } 161932554Sminshall 162032554Sminshall #endif /* 0 */ 162132554Sminshall } 162232554Sminshall 162332554Sminshall /* 162432377Sminshall * These routines add various telnet commands to the data stream. 162527088Sminshall */ 162632377Sminshall 162732554Sminshall static void 162832554Sminshall doflush() 162932554Sminshall { 163032554Sminshall NET2ADD(IAC, DO); 163132554Sminshall NETADD(TELOPT_TM); 163232554Sminshall flushline = 1; 163332554Sminshall flushout = 1; 163432554Sminshall ttyflush(1); /* Flush/drop output */ 163532554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 163637226Sminshall printoption("SENT", "do", TELOPT_TM); 163732554Sminshall } 163832554Sminshall 163932377Sminshall void 164032377Sminshall xmitAO() 164127088Sminshall { 164232377Sminshall NET2ADD(IAC, AO); 164332377Sminshall if (autoflush) { 164432377Sminshall doflush(); 164532377Sminshall } 164632377Sminshall } 164727088Sminshall 164832377Sminshall 164932377Sminshall void 165032377Sminshall xmitEL() 165127088Sminshall { 165232377Sminshall NET2ADD(IAC, EL); 165327088Sminshall } 165427088Sminshall 165532377Sminshall void 165632377Sminshall xmitEC() 165727088Sminshall { 165832377Sminshall NET2ADD(IAC, EC); 165927088Sminshall } 166027088Sminshall 166132377Sminshall 166232377Sminshall #if defined(NOT43) 166332377Sminshall int 166432377Sminshall #else /* defined(NOT43) */ 166532377Sminshall void 166632377Sminshall #endif /* defined(NOT43) */ 166732377Sminshall dosynch() 166827088Sminshall { 166932377Sminshall netclear(); /* clear the path to the network */ 167033294Sminshall NETADD(IAC); 167133294Sminshall setneturg(); 167233294Sminshall NETADD(DM); 167327088Sminshall 167432377Sminshall #if defined(NOT43) 167532377Sminshall return 0; 167632377Sminshall #endif /* defined(NOT43) */ 167727088Sminshall } 167827088Sminshall 167932377Sminshall void 168032377Sminshall intp() 168127088Sminshall { 168232377Sminshall NET2ADD(IAC, IP); 168332377Sminshall flushline = 1; 168432377Sminshall if (autoflush) { 168532377Sminshall doflush(); 168632377Sminshall } 168732377Sminshall if (autosynch) { 168832377Sminshall dosynch(); 168932377Sminshall } 169027088Sminshall } 169127186Sminshall 169232377Sminshall void 169332377Sminshall sendbrk() 169427186Sminshall { 169532377Sminshall NET2ADD(IAC, BREAK); 169632377Sminshall flushline = 1; 169732377Sminshall if (autoflush) { 169832377Sminshall doflush(); 169932377Sminshall } 170032377Sminshall if (autosynch) { 170132377Sminshall dosynch(); 170232377Sminshall } 170327186Sminshall } 1704*38689Sborman 1705*38689Sborman void 1706*38689Sborman sendabort() 1707*38689Sborman { 1708*38689Sborman NET2ADD(IAC, ABORT); 1709*38689Sborman flushline = 1; 1710*38689Sborman if (autoflush) { 1711*38689Sborman doflush(); 1712*38689Sborman } 1713*38689Sborman if (autosynch) { 1714*38689Sborman dosynch(); 1715*38689Sborman } 1716*38689Sborman } 1717*38689Sborman 1718*38689Sborman void 1719*38689Sborman sendsusp() 1720*38689Sborman { 1721*38689Sborman NET2ADD(IAC, SUSP); 1722*38689Sborman flushline = 1; 1723*38689Sborman if (autoflush) { 1724*38689Sborman doflush(); 1725*38689Sborman } 1726*38689Sborman if (autosynch) { 1727*38689Sborman dosynch(); 1728*38689Sborman } 1729*38689Sborman } 1730*38689Sborman 1731*38689Sborman void 1732*38689Sborman sendeof() 1733*38689Sborman { 1734*38689Sborman NET2ADD(IAC, xEOF); 1735*38689Sborman } 1736*38689Sborman 173737219Sminshall /* 173837219Sminshall * Send a window size update to the remote system. 173937219Sminshall */ 174037219Sminshall 174137219Sminshall void 174237219Sminshall sendnaws() 174337219Sminshall { 174437219Sminshall long rows, cols; 1745*38689Sborman unsigned char tmp[16]; 1746*38689Sborman register unsigned char *cp; 174737219Sminshall 1748*38689Sborman if (my_state_is_wont(TELOPT_NAWS)) 1749*38689Sborman return; 175037219Sminshall 1751*38689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 1752*38689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 1753*38689Sborman 175437219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 175537219Sminshall return; 175637219Sminshall } 175737219Sminshall 1758*38689Sborman cp = tmp; 1759*38689Sborman 1760*38689Sborman *cp++ = IAC; 1761*38689Sborman *cp++ = SB; 1762*38689Sborman *cp++ = TELOPT_NAWS; 1763*38689Sborman PUTSHORT(cp, cols); 1764*38689Sborman PUTSHORT(cp, rows); 1765*38689Sborman *cp++ = IAC; 1766*38689Sborman *cp++ = SE; 1767*38689Sborman if (NETROOM() >= cp - tmp) { 1768*38689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 1769*38689Sborman printsub('>', tmp+2, cp - tmp - 2); 177037219Sminshall } 177137219Sminshall } 177237226Sminshall 177337226Sminshall tel_enter_binary() 177437226Sminshall { 1775*38689Sborman send_do(TELOPT_BINARY, 1); 1776*38689Sborman send_will(TELOPT_BINARY, 1); 177737226Sminshall } 177837226Sminshall 177937226Sminshall tel_leave_binary() 178037226Sminshall { 1781*38689Sborman send_dont(TELOPT_BINARY, 1); 1782*38689Sborman send_wont(TELOPT_BINARY, 1); 178337226Sminshall } 1784